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 "qquickrendertarget_p.h" |
5 | #include <rhi/qrhi.h> |
6 | #include <QtQuick/private/qquickitem_p.h> |
7 | #include <QtQuick/private/qquickwindow_p.h> |
8 | #include <QtQuick/private/qsgrhisupport_p.h> |
9 | |
10 | QT_BEGIN_NAMESPACE |
11 | |
12 | /*! |
13 | \class QQuickRenderTarget |
14 | \since 6.0 |
15 | \inmodule QtQuick |
16 | |
17 | \brief The QQuickRenderTarget class provides an opaque container for native |
18 | graphics resources specifying a render target, and associated metadata. |
19 | |
20 | \sa QQuickWindow::setRenderTarget(), QQuickGraphicsDevice |
21 | */ |
22 | |
23 | QQuickRenderTargetPrivate::QQuickRenderTargetPrivate() |
24 | : ref(1) |
25 | { |
26 | } |
27 | |
28 | QQuickRenderTargetPrivate::QQuickRenderTargetPrivate(const QQuickRenderTargetPrivate *other) |
29 | : ref(1), |
30 | type(other->type), |
31 | pixelSize(other->pixelSize), |
32 | devicePixelRatio(other->devicePixelRatio), |
33 | sampleCount(other->sampleCount), |
34 | u(other->u), |
35 | mirrorVertically(other->mirrorVertically) |
36 | { |
37 | } |
38 | |
39 | /*! |
40 | Constructs a default QQuickRenderTarget that does not reference any native |
41 | objects. |
42 | */ |
43 | QQuickRenderTarget::QQuickRenderTarget() |
44 | : d(new QQuickRenderTargetPrivate) |
45 | { |
46 | } |
47 | |
48 | /*! |
49 | \internal |
50 | */ |
51 | void QQuickRenderTarget::detach() |
52 | { |
53 | qAtomicDetach(d); |
54 | } |
55 | |
56 | /*! |
57 | \internal |
58 | */ |
59 | QQuickRenderTarget::QQuickRenderTarget(const QQuickRenderTarget &other) |
60 | : d(other.d) |
61 | { |
62 | d->ref.ref(); |
63 | } |
64 | |
65 | /*! |
66 | \internal |
67 | */ |
68 | QQuickRenderTarget &QQuickRenderTarget::operator=(const QQuickRenderTarget &other) |
69 | { |
70 | qAtomicAssign(d, x: other.d); |
71 | return *this; |
72 | } |
73 | |
74 | /*! |
75 | Destructor. |
76 | */ |
77 | QQuickRenderTarget::~QQuickRenderTarget() |
78 | { |
79 | if (!d->ref.deref()) |
80 | delete d; |
81 | } |
82 | |
83 | /*! |
84 | \return true if this QQuickRenderTarget is default constructed, referencing |
85 | no native objects. |
86 | */ |
87 | bool QQuickRenderTarget::isNull() const |
88 | { |
89 | return d->type == QQuickRenderTargetPrivate::Type::Null; |
90 | } |
91 | |
92 | /*! |
93 | \return the device pixel ratio for the render target. This is the ratio |
94 | between \e{device pixels} and \e{device independent pixels}. |
95 | |
96 | The default device pixel ratio is 1.0. |
97 | |
98 | \since 6.3 |
99 | |
100 | \sa setDevicePixelRatio() |
101 | */ |
102 | qreal QQuickRenderTarget::devicePixelRatio() const |
103 | { |
104 | return d->devicePixelRatio; |
105 | } |
106 | |
107 | /*! |
108 | Sets the device pixel ratio for this render target to \a ratio. This is |
109 | the ratio between \e{device pixels} and \e{device independent pixels}. |
110 | |
111 | Note that the specified device pixel ratio value will be ignored if |
112 | QQuickRenderControl::renderWindow() is re-implemented to return a valid |
113 | QWindow. |
114 | |
115 | \since 6.3 |
116 | |
117 | \sa devicePixelRatio() |
118 | */ |
119 | void QQuickRenderTarget::setDevicePixelRatio(qreal ratio) |
120 | { |
121 | if (d->devicePixelRatio == ratio) |
122 | return; |
123 | |
124 | detach(); |
125 | d->devicePixelRatio = ratio; |
126 | } |
127 | |
128 | /*! |
129 | \return Returns whether the render target is mirrored vertically. |
130 | |
131 | The default value is \c {false}. |
132 | |
133 | \since 6.4 |
134 | |
135 | \sa setMirrorVertically() |
136 | */ |
137 | bool QQuickRenderTarget::mirrorVertically() const |
138 | { |
139 | return d->mirrorVertically; |
140 | } |
141 | |
142 | |
143 | /*! |
144 | Sets the size of the render target contents should be mirrored vertically to |
145 | \a enable when drawing. This allows easy integration of third-party rendering |
146 | code that does not follow the standard expectations. |
147 | |
148 | \note This function should not be used when using the \c software backend. |
149 | |
150 | \since 6.4 |
151 | |
152 | \sa mirrorVertically() |
153 | */ |
154 | void QQuickRenderTarget::setMirrorVertically(bool enable) |
155 | { |
156 | if (d->mirrorVertically == enable) |
157 | return; |
158 | |
159 | detach(); |
160 | d->mirrorVertically = enable; |
161 | } |
162 | |
163 | /*! |
164 | \return a new QQuickRenderTarget referencing an OpenGL texture object |
165 | specified by \a textureId. |
166 | |
167 | \a format specifies the native internal format of the |
168 | texture. Only texture formats that are supported by Qt's rendering |
169 | infrastructure should be used. |
170 | |
171 | \a pixelSize specifies the size of the image, in pixels. Currently only 2D |
172 | textures are supported. |
173 | |
174 | \a sampleCount specific the number of samples. 0 or 1 means no |
175 | multisampling, while a value like 4 or 8 states that the native object is a |
176 | multisample texture. |
177 | |
178 | The texture is used as the first color attachment of the render target used |
179 | by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is |
180 | created and used automatically. |
181 | |
182 | The OpenGL object name \a textureId must be a valid name in the rendering |
183 | context used by the Qt Quick scenegraph. |
184 | |
185 | \note the resulting QQuickRenderTarget does not own any native resources, |
186 | it merely contains references and the associated metadata of the size and |
187 | sample count. It is the caller's responsibility to ensure that the native |
188 | resource exists as long as necessary. |
189 | |
190 | \since 6.4 |
191 | |
192 | \sa QQuickWindow::setRenderTarget(), QQuickRenderControl |
193 | */ |
194 | #if QT_CONFIG(opengl) || defined(Q_QDOC) |
195 | QQuickRenderTarget QQuickRenderTarget::fromOpenGLTexture(uint textureId, uint format, |
196 | const QSize &pixelSize, int sampleCount) |
197 | { |
198 | QQuickRenderTarget rt; |
199 | QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(rt: &rt); |
200 | |
201 | if (!textureId) { |
202 | qWarning(msg: "QQuickRenderTarget: textureId is invalid" ); |
203 | return rt; |
204 | } |
205 | |
206 | if (pixelSize.isEmpty()) { |
207 | qWarning(msg: "QQuickRenderTarget: Cannot create with empty size" ); |
208 | return rt; |
209 | } |
210 | |
211 | d->type = QQuickRenderTargetPrivate::Type::NativeTexture; |
212 | d->pixelSize = pixelSize; |
213 | d->sampleCount = qMax(a: 1, b: sampleCount); |
214 | |
215 | auto rhiFormat = QSGRhiSupport::toRhiTextureFormatFromGL(format); |
216 | d->u.nativeTexture = { .object: textureId, .layoutOrState: 0, .rhiFormat: uint(rhiFormat), .rhiFlags: 0 }; |
217 | |
218 | return rt; |
219 | } |
220 | |
221 | /*! |
222 | \overload |
223 | |
224 | \return a new QQuickRenderTarget referencing an OpenGL texture |
225 | object specified by \a textureId. The texture is assumed to have a |
226 | format of GL_RGBA (GL_RGBA8). |
227 | |
228 | \a pixelSize specifies the size of the image, in pixels. Currently |
229 | only 2D textures are supported. |
230 | |
231 | \a sampleCount specific the number of samples. 0 or 1 means no |
232 | multisampling, while a value like 4 or 8 states that the native |
233 | object is a multisample texture. |
234 | |
235 | The texture is used as the first color attachment of the render target used |
236 | by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is |
237 | created and used automatically. |
238 | |
239 | The OpenGL object name \a textureId must be a valid name in the rendering |
240 | context used by the Qt Quick scenegraph. |
241 | |
242 | \note the resulting QQuickRenderTarget does not own any native resources, |
243 | it merely contains references and the associated metadata of the size and |
244 | sample count. It is the caller's responsibility to ensure that the native |
245 | resource exists as long as necessary. |
246 | |
247 | \sa QQuickWindow::setRenderTarget(), QQuickRenderControl |
248 | */ |
249 | QQuickRenderTarget QQuickRenderTarget::fromOpenGLTexture(uint textureId, const QSize &pixelSize, int sampleCount) |
250 | { |
251 | return fromOpenGLTexture(textureId, format: 0, pixelSize, sampleCount); |
252 | } |
253 | |
254 | /*! |
255 | \return a new QQuickRenderTarget referencing an OpenGL renderbuffer object |
256 | specified by \a renderbufferId. |
257 | |
258 | The renderbuffer will be used as the color attachment for the internal |
259 | framebuffer object. This function is provided to allow targeting |
260 | renderbuffers that are created by the application with some external buffer |
261 | underneath, such as an EGLImageKHR. Once the application has called |
262 | \l{https://www.khronos.org/registry/OpenGL/extensions/OES/OES_EGL_image.txt}{glEGLImageTargetRenderbufferStorageOES}, |
263 | the renderbuffer can be passed to this function. |
264 | |
265 | \a pixelSize specifies the size of the image, in pixels. |
266 | |
267 | \a sampleCount specific the number of samples. 0 or 1 means no |
268 | multisampling, while a value like 4 or 8 states that the native object is a |
269 | multisample renderbuffer. |
270 | |
271 | \note the resulting QQuickRenderTarget does not own any native resources, |
272 | it merely contains references and the associated metadata of the size and |
273 | sample count. It is the caller's responsibility to ensure that the native |
274 | resource exists as long as necessary. |
275 | |
276 | \since 6.2 |
277 | |
278 | \sa QQuickWindow::setRenderTarget(), QQuickRenderControl |
279 | */ |
280 | QQuickRenderTarget QQuickRenderTarget::fromOpenGLRenderBuffer(uint renderbufferId, const QSize &pixelSize, int sampleCount) |
281 | { |
282 | QQuickRenderTarget rt; |
283 | QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(rt: &rt); |
284 | |
285 | if (!renderbufferId) { |
286 | qWarning(msg: "QQuickRenderTarget: renderbufferId is invalid" ); |
287 | return rt; |
288 | } |
289 | |
290 | if (pixelSize.isEmpty()) { |
291 | qWarning(msg: "QQuickRenderTarget: Cannot create with empty size" ); |
292 | return rt; |
293 | } |
294 | |
295 | d->type = QQuickRenderTargetPrivate::Type::NativeRenderbuffer; |
296 | d->pixelSize = pixelSize; |
297 | d->sampleCount = qMax(a: 1, b: sampleCount); |
298 | d->u.nativeRenderbufferObject = renderbufferId; |
299 | |
300 | return rt; |
301 | } |
302 | #endif |
303 | |
304 | /*! |
305 | \return a new QQuickRenderTarget referencing a D3D11 texture object |
306 | specified by \a texture. |
307 | |
308 | \a format specifies the DXGI_FORMAT of the texture. Only texture formats |
309 | that are supported by Qt's rendering infrastructure should be used. |
310 | |
311 | \a pixelSize specifies the size of the image, in pixels. Currently only 2D |
312 | textures are supported. |
313 | |
314 | \a sampleCount specific the number of samples. 0 or 1 means no |
315 | multisampling, while a value like 4 or 8 states that the native object is a |
316 | multisample texture. |
317 | |
318 | The texture is used as the first color attachment of the render target used |
319 | by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is |
320 | created and used automatically. |
321 | |
322 | \note the resulting QQuickRenderTarget does not own any native resources, |
323 | it merely contains references and the associated metadata of the size and |
324 | sample count. It is the caller's responsibility to ensure that the native |
325 | resource exists as long as necessary. |
326 | |
327 | \since 6.4 |
328 | |
329 | \sa QQuickWindow::setRenderTarget(), QQuickRenderControl |
330 | */ |
331 | #if defined(Q_OS_WIN) || defined(Q_QDOC) |
332 | QQuickRenderTarget QQuickRenderTarget::fromD3D11Texture(void *texture, uint format, |
333 | const QSize &pixelSize, int sampleCount) |
334 | { |
335 | QQuickRenderTarget rt; |
336 | QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt); |
337 | |
338 | if (!texture) { |
339 | qWarning("QQuickRenderTarget: texture is null" ); |
340 | return rt; |
341 | } |
342 | |
343 | if (pixelSize.isEmpty()) { |
344 | qWarning("QQuickRenderTarget: Cannot create with empty size" ); |
345 | return rt; |
346 | } |
347 | |
348 | d->type = QQuickRenderTargetPrivate::Type::NativeTexture; |
349 | d->pixelSize = pixelSize; |
350 | d->sampleCount = qMax(1, sampleCount); |
351 | |
352 | QRhiTexture::Flags flags; |
353 | auto rhiFormat = QSGRhiSupport::toRhiTextureFormatFromDXGI(format, &flags); |
354 | d->u.nativeTexture = { quint64(texture), 0, uint(rhiFormat), uint(flags) }; |
355 | |
356 | return rt; |
357 | } |
358 | |
359 | /*! |
360 | \overload |
361 | |
362 | \return a new QQuickRenderTarget referencing a D3D11 texture |
363 | object specified by \a texture. The texture is assumed to have a |
364 | format of DXGI_FORMAT_R8G8B8A8_UNORM. |
365 | |
366 | \a pixelSize specifies the size of the image, in pixels. Currently only 2D |
367 | textures are supported. |
368 | |
369 | \a sampleCount specific the number of samples. 0 or 1 means no |
370 | multisampling, while a value like 4 or 8 states that the native object is a |
371 | multisample texture. |
372 | |
373 | The texture is used as the first color attachment of the render target used |
374 | by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is |
375 | created and used automatically. |
376 | |
377 | \note the resulting QQuickRenderTarget does not own any native resources, |
378 | it merely contains references and the associated metadata of the size and |
379 | sample count. It is the caller's responsibility to ensure that the native |
380 | resource exists as long as necessary. |
381 | |
382 | \sa QQuickWindow::setRenderTarget(), QQuickRenderControl |
383 | */ |
384 | QQuickRenderTarget QQuickRenderTarget::fromD3D11Texture(void *texture, const QSize &pixelSize, int sampleCount) |
385 | { |
386 | return fromD3D11Texture(texture, 0 /* DXGI_FORMAT_UNKNOWN */, pixelSize, sampleCount); |
387 | } |
388 | |
389 | /*! |
390 | \return a new QQuickRenderTarget referencing a D3D12 texture object |
391 | specified by \a texture. |
392 | |
393 | \a resourceState must a valid bitmask with bits from D3D12_RESOURCE_STATES, |
394 | specifying the resource's current state. |
395 | |
396 | \a format specifies the DXGI_FORMAT of the texture. Only texture formats |
397 | that are supported by Qt's rendering infrastructure should be used. |
398 | |
399 | \a pixelSize specifies the size of the image, in pixels. Currently only 2D |
400 | textures are supported. |
401 | |
402 | \a sampleCount specific the number of samples. 0 or 1 means no |
403 | multisampling, while a value like 4 or 8 states that the native object is a |
404 | multisample texture. |
405 | |
406 | The texture is used as the first color attachment of the render target used |
407 | by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is |
408 | created and used automatically. |
409 | |
410 | \note the resulting QQuickRenderTarget does not own any native resources, |
411 | it merely contains references and the associated metadata of the size and |
412 | sample count. It is the caller's responsibility to ensure that the native |
413 | resource exists as long as necessary. |
414 | |
415 | \since 6.6 |
416 | |
417 | \sa QQuickWindow::setRenderTarget(), QQuickRenderControl |
418 | */ |
419 | QQuickRenderTarget QQuickRenderTarget::fromD3D12Texture(void *texture, |
420 | int resourceState, |
421 | uint format, |
422 | const QSize &pixelSize, |
423 | int sampleCount) |
424 | { |
425 | QQuickRenderTarget rt; |
426 | QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt); |
427 | |
428 | if (!texture) { |
429 | qWarning("QQuickRenderTarget: texture is null" ); |
430 | return rt; |
431 | } |
432 | |
433 | if (pixelSize.isEmpty()) { |
434 | qWarning("QQuickRenderTarget: Cannot create with empty size" ); |
435 | return rt; |
436 | } |
437 | |
438 | d->type = QQuickRenderTargetPrivate::Type::NativeTexture; |
439 | d->pixelSize = pixelSize; |
440 | d->sampleCount = qMax(1, sampleCount); |
441 | |
442 | QRhiTexture::Flags flags; |
443 | auto rhiFormat = QSGRhiSupport::toRhiTextureFormatFromDXGI(format, &flags); |
444 | d->u.nativeTexture = { quint64(texture), resourceState, uint(rhiFormat), uint(flags) }; |
445 | |
446 | return rt; |
447 | } |
448 | #endif |
449 | |
450 | /*! |
451 | \return a new QQuickRenderTarget referencing a Metal texture object |
452 | specified by \a texture. |
453 | |
454 | \a format specifies the MTLPixelFormat of the texture. Only texture formats |
455 | that are supported by Qt's rendering infrastructure should be used. |
456 | |
457 | \a pixelSize specifies the size of the image, in pixels. Currently only 2D |
458 | textures are supported. |
459 | |
460 | \a sampleCount specific the number of samples. 0 or 1 means no |
461 | multisampling, while a value like 4 or 8 states that the native object is a |
462 | multisample texture. |
463 | |
464 | The texture is used as the first color attachment of the render target used |
465 | by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is |
466 | created and used automatically. |
467 | |
468 | \note the resulting QQuickRenderTarget does not own any native resources, |
469 | it merely contains references and the associated metadata of the size and |
470 | sample count. It is the caller's responsibility to ensure that the native |
471 | resource exists as long as necessary. |
472 | |
473 | \since 6.4 |
474 | |
475 | \sa QQuickWindow::setRenderTarget(), QQuickRenderControl |
476 | */ |
477 | #if defined(Q_OS_MACOS) || defined(Q_OS_IOS) || defined(Q_QDOC) |
478 | QQuickRenderTarget QQuickRenderTarget::fromMetalTexture(MTLTexture *texture, uint format, |
479 | const QSize &pixelSize, int sampleCount) |
480 | { |
481 | QQuickRenderTarget rt; |
482 | QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt); |
483 | |
484 | if (!texture) { |
485 | qWarning("QQuickRenderTarget: texture is null" ); |
486 | return rt; |
487 | } |
488 | |
489 | if (pixelSize.isEmpty()) { |
490 | qWarning("QQuickRenderTarget: Cannot create with empty size" ); |
491 | return rt; |
492 | } |
493 | |
494 | d->type = QQuickRenderTargetPrivate::Type::NativeTexture; |
495 | d->pixelSize = pixelSize; |
496 | d->sampleCount = qMax(1, sampleCount); |
497 | |
498 | QRhiTexture::Flags flags; |
499 | auto rhiFormat = QSGRhiSupport::toRhiTextureFormatFromMetal(format, &flags); |
500 | d->u.nativeTexture = { quint64(texture), 0, uint(rhiFormat), uint(flags) }; |
501 | |
502 | return rt; |
503 | } |
504 | |
505 | /*! |
506 | \overload |
507 | |
508 | \return a new QQuickRenderTarget referencing a Metal texture object |
509 | specified by \a texture. The texture is assumed to have a format of |
510 | MTLPixelFormatRGBA8Unorm. |
511 | |
512 | \a pixelSize specifies the size of the image, in pixels. Currently only 2D |
513 | textures are supported. |
514 | |
515 | \a sampleCount specific the number of samples. 0 or 1 means no |
516 | multisampling, while a value like 4 or 8 states that the native object is a |
517 | multisample texture. |
518 | |
519 | The texture is used as the first color attachment of the render target used |
520 | by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is |
521 | created and used automatically. |
522 | |
523 | \note the resulting QQuickRenderTarget does not own any native resources, |
524 | it merely contains references and the associated metadata of the size and |
525 | sample count. It is the caller's responsibility to ensure that the native |
526 | resource exists as long as necessary. |
527 | |
528 | \sa QQuickWindow::setRenderTarget(), QQuickRenderControl |
529 | */ |
530 | QQuickRenderTarget QQuickRenderTarget::fromMetalTexture(MTLTexture *texture, const QSize &pixelSize, int sampleCount) |
531 | { |
532 | return fromMetalTexture(texture, 0 /* MTLPixelFormatInvalid */, pixelSize, sampleCount); |
533 | } |
534 | #endif |
535 | |
536 | /*! |
537 | \return a new QQuickRenderTarget referencing a Vulkan image object |
538 | specified by \a image. The current \a layout of the image must be provided |
539 | as well. |
540 | |
541 | \a format specifies the VkFormat of the image. Only image formats that are |
542 | supported by Qt's rendering infrastructure should be used. |
543 | |
544 | \a pixelSize specifies the size of the image, in pixels. Currently only 2D |
545 | textures are supported. |
546 | |
547 | \a sampleCount specific the number of samples. 0 or 1 means no |
548 | multisampling, while a value like 4 or 8 states that the native object is a |
549 | multisample texture. |
550 | |
551 | The image is used as the first color attachment of the render target used |
552 | by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is |
553 | created and used automatically. |
554 | |
555 | \note the resulting QQuickRenderTarget does not own any native resources, |
556 | it merely contains references and the associated metadata of the size and |
557 | sample count. It is the caller's responsibility to ensure that the native |
558 | resource exists as long as necessary. |
559 | |
560 | \since 6.4 |
561 | |
562 | \sa QQuickWindow::setRenderTarget(), QQuickRenderControl |
563 | */ |
564 | #if QT_CONFIG(vulkan) || defined(Q_QDOC) |
565 | QQuickRenderTarget QQuickRenderTarget::fromVulkanImage(VkImage image, VkImageLayout layout, VkFormat format, |
566 | const QSize &pixelSize, int sampleCount) |
567 | { |
568 | QQuickRenderTarget rt; |
569 | QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(rt: &rt); |
570 | |
571 | if (image == VK_NULL_HANDLE) { |
572 | qWarning(msg: "QQuickRenderTarget: image is invalid" ); |
573 | return rt; |
574 | } |
575 | |
576 | if (pixelSize.isEmpty()) { |
577 | qWarning(msg: "QQuickRenderTarget: Cannot create with empty size" ); |
578 | return rt; |
579 | } |
580 | |
581 | d->type = QQuickRenderTargetPrivate::Type::NativeTexture; |
582 | d->pixelSize = pixelSize; |
583 | d->sampleCount = qMax(a: 1, b: sampleCount); |
584 | |
585 | QRhiTexture::Flags flags; |
586 | auto rhiFormat = QSGRhiSupport::toRhiTextureFormatFromVulkan(format, flags: &flags); |
587 | d->u.nativeTexture = { .object: quint64(image), .layoutOrState: layout, .rhiFormat: uint(rhiFormat), .rhiFlags: uint(flags) }; |
588 | |
589 | return rt; |
590 | } |
591 | |
592 | /*! |
593 | \overload |
594 | |
595 | \return a new QQuickRenderTarget referencing a Vulkan image object specified |
596 | by \a image. The image is assumed to have a format of |
597 | VK_FORMAT_R8G8B8A8_UNORM. |
598 | |
599 | \a pixelSize specifies the size of the image, in pixels. Currently only 2D |
600 | textures are supported. |
601 | |
602 | \a sampleCount specific the number of samples. 0 or 1 means no |
603 | multisampling, while a value like 4 or 8 states that the native object is a |
604 | multisample texture. |
605 | |
606 | The texture is used as the first color attachment of the render target used |
607 | by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is |
608 | created and used automatically. |
609 | |
610 | \note the resulting QQuickRenderTarget does not own any native resources, |
611 | it merely contains references and the associated metadata of the size and |
612 | sample count. It is the caller's responsibility to ensure that the native |
613 | resource exists as long as necessary. |
614 | |
615 | \sa QQuickWindow::setRenderTarget(), QQuickRenderControl |
616 | */ |
617 | QQuickRenderTarget QQuickRenderTarget::fromVulkanImage(VkImage image, VkImageLayout layout, const QSize &pixelSize, int sampleCount) |
618 | { |
619 | return fromVulkanImage(image, layout, format: VK_FORMAT_UNDEFINED, pixelSize, sampleCount); |
620 | } |
621 | #endif |
622 | |
623 | /*! |
624 | \return a new QQuickRenderTarget referencing an existing \a renderTarget. |
625 | |
626 | \a renderTarget will in most cases be a QRhiTextureRenderTarget, which |
627 | allows directing the Qt Quick scene's rendering into a QRhiTexture. |
628 | |
629 | \note the resulting QQuickRenderTarget does not own \a renderTarget and any |
630 | underlying native resources, it merely contains references and the |
631 | associated metadata of the size and sample count. It is the caller's |
632 | responsibility to ensure that the referenced resources exists as long as |
633 | necessary. |
634 | |
635 | \since 6.6 |
636 | |
637 | \sa QQuickWindow::setRenderTarget(), QQuickRenderControl |
638 | */ |
639 | QQuickRenderTarget QQuickRenderTarget::fromRhiRenderTarget(QRhiRenderTarget *renderTarget) |
640 | { |
641 | QQuickRenderTarget rt; |
642 | QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(rt: &rt); |
643 | |
644 | if (!renderTarget) { |
645 | qWarning(msg: "QQuickRenderTarget: Needs a valid QRhiRenderTarget" ); |
646 | return rt; |
647 | } |
648 | |
649 | d->type = QQuickRenderTargetPrivate::Type::RhiRenderTarget; |
650 | d->pixelSize = renderTarget->pixelSize(); |
651 | d->sampleCount = renderTarget->sampleCount(); |
652 | d->u.rhiRt = renderTarget; |
653 | |
654 | return rt; |
655 | } |
656 | |
657 | /*! |
658 | \return a new QQuickRenderTarget referencing a paint device object |
659 | specified by \a device. |
660 | |
661 | This option of redirecting rendering to a QPaintDevice is available only |
662 | when running with the \c software backend of Qt Quick. |
663 | |
664 | \note The QQuickRenderTarget does not take ownship of \a device, it is the |
665 | caller's responsibility to ensure the object exists as long as necessary. |
666 | |
667 | \since 6.4 |
668 | |
669 | \sa QQuickWindow::setRenderTarget(), QQuickRenderControl |
670 | */ |
671 | QQuickRenderTarget QQuickRenderTarget::fromPaintDevice(QPaintDevice *device) |
672 | { |
673 | QQuickRenderTarget rt; |
674 | QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(rt: &rt); |
675 | |
676 | d->type = QQuickRenderTargetPrivate::Type::PaintDevice; |
677 | d->pixelSize = QSize(device->width(), device->height()); |
678 | d->u.paintDevice = device; |
679 | |
680 | return rt; |
681 | } |
682 | |
683 | /*! |
684 | \fn bool QQuickRenderTarget::operator==(const QQuickRenderTarget &a, const QQuickRenderTarget &b) noexcept |
685 | \return true if \a a and \a b refer to the same set of native objects and |
686 | have matching associated data (size, sample count). |
687 | */ |
688 | /*! |
689 | \fn bool QQuickRenderTarget::operator!=(const QQuickRenderTarget &a, const QQuickRenderTarget &b) noexcept |
690 | |
691 | \return true if \a a and \a b refer to a different set of native objects, |
692 | or the associated data (size, sample count) does not match. |
693 | */ |
694 | |
695 | /*! |
696 | \internal |
697 | */ |
698 | bool QQuickRenderTarget::isEqual(const QQuickRenderTarget &other) const noexcept |
699 | { |
700 | if (d->type != other.d->type |
701 | || d->pixelSize != other.d->pixelSize |
702 | || d->devicePixelRatio != other.d->devicePixelRatio |
703 | || d->sampleCount != other.d->sampleCount |
704 | || d->mirrorVertically != other.d->mirrorVertically) |
705 | { |
706 | return false; |
707 | } |
708 | |
709 | switch (d->type) { |
710 | case QQuickRenderTargetPrivate::Type::Null: |
711 | break; |
712 | case QQuickRenderTargetPrivate::Type::NativeTexture: |
713 | if (d->u.nativeTexture.object != other.d->u.nativeTexture.object |
714 | || d->u.nativeTexture.layoutOrState != other.d->u.nativeTexture.layoutOrState |
715 | || d->u.nativeTexture.rhiFormat != other.d->u.nativeTexture.rhiFormat |
716 | || d->u.nativeTexture.rhiFlags != other.d->u.nativeTexture.rhiFlags) |
717 | return false; |
718 | break; |
719 | case QQuickRenderTargetPrivate::Type::NativeRenderbuffer: |
720 | if (d->u.nativeRenderbufferObject != other.d->u.nativeRenderbufferObject) |
721 | return false; |
722 | break; |
723 | case QQuickRenderTargetPrivate::Type::RhiRenderTarget: |
724 | if (d->u.rhiRt != other.d->u.rhiRt) |
725 | return false; |
726 | break; |
727 | case QQuickRenderTargetPrivate::Type::PaintDevice: |
728 | if (d->u.paintDevice != other.d->u.paintDevice) |
729 | return false; |
730 | break; |
731 | default: |
732 | break; |
733 | } |
734 | |
735 | return true; |
736 | } |
737 | |
738 | static bool createRhiRenderTarget(const QRhiColorAttachment &colorAttachment, |
739 | const QSize &pixelSize, |
740 | int sampleCount, |
741 | QRhi *rhi, |
742 | QQuickWindowRenderTarget *dst) |
743 | { |
744 | std::unique_ptr<QRhiRenderBuffer> depthStencil(rhi->newRenderBuffer(type: QRhiRenderBuffer::DepthStencil, pixelSize, sampleCount)); |
745 | if (!depthStencil->create()) { |
746 | qWarning(msg: "Failed to build depth-stencil buffer for QQuickRenderTarget" ); |
747 | return false; |
748 | } |
749 | |
750 | QRhiTextureRenderTargetDescription rtDesc(colorAttachment); |
751 | rtDesc.setDepthStencilBuffer(depthStencil.get()); |
752 | std::unique_ptr<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(desc: rtDesc)); |
753 | std::unique_ptr<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor()); |
754 | rt->setRenderPassDescriptor(rp.get()); |
755 | |
756 | if (!rt->create()) { |
757 | qWarning(msg: "Failed to build texture render target for QQuickRenderTarget" ); |
758 | return false; |
759 | } |
760 | |
761 | dst->renderTarget = rt.release(); |
762 | dst->rpDesc = rp.release(); |
763 | dst->depthStencil = depthStencil.release(); |
764 | dst->owns = true; // ownership of the native resource itself is not transferred but the QRhi objects are on us now |
765 | |
766 | return true; |
767 | } |
768 | |
769 | bool QQuickRenderTargetPrivate::resolve(QRhi *rhi, QQuickWindowRenderTarget *dst) |
770 | { |
771 | switch (type) { |
772 | case Type::Null: |
773 | dst->renderTarget = nullptr; |
774 | dst->paintDevice = nullptr; |
775 | dst->owns = false; |
776 | return true; |
777 | |
778 | case Type::NativeTexture: |
779 | { |
780 | const auto format = u.nativeTexture.rhiFormat == QRhiTexture::UnknownFormat ? QRhiTexture::RGBA8 |
781 | : QRhiTexture::Format(u.nativeTexture.rhiFormat); |
782 | const auto flags = QRhiTexture::RenderTarget | QRhiTexture::Flags(u.nativeTexture.rhiFlags); |
783 | std::unique_ptr<QRhiTexture> texture(rhi->newTexture(format, pixelSize, sampleCount, flags)); |
784 | if (!texture->createFrom(src: { .object: u.nativeTexture.object, .layout: u.nativeTexture.layoutOrState })) { |
785 | qWarning(msg: "Failed to build wrapper texture for QQuickRenderTarget" ); |
786 | return false; |
787 | } |
788 | QRhiColorAttachment att(texture.get()); |
789 | if (!createRhiRenderTarget(colorAttachment: att, pixelSize, sampleCount, rhi, dst)) |
790 | return false; |
791 | dst->texture = texture.release(); |
792 | } |
793 | return true; |
794 | |
795 | case Type::NativeRenderbuffer: |
796 | { |
797 | std::unique_ptr<QRhiRenderBuffer> renderbuffer(rhi->newRenderBuffer(type: QRhiRenderBuffer::Color, pixelSize, sampleCount)); |
798 | if (!renderbuffer->createFrom(src: { .object: u.nativeRenderbufferObject })) { |
799 | qWarning(msg: "Failed to build wrapper renderbuffer for QQuickRenderTarget" ); |
800 | return false; |
801 | } |
802 | QRhiColorAttachment att(renderbuffer.get()); |
803 | if (!createRhiRenderTarget(colorAttachment: att, pixelSize, sampleCount, rhi, dst)) |
804 | return false; |
805 | dst->renderBuffer = renderbuffer.release(); |
806 | } |
807 | return true; |
808 | |
809 | case Type::RhiRenderTarget: |
810 | dst->renderTarget = u.rhiRt; |
811 | dst->rpDesc = u.rhiRt->renderPassDescriptor(); // just for QQuickWindowRenderTarget::reset() |
812 | dst->owns = false; |
813 | return true; |
814 | case Type::PaintDevice: |
815 | dst->paintDevice = u.paintDevice; |
816 | dst->owns = false; |
817 | return true; |
818 | |
819 | default: |
820 | break; |
821 | } |
822 | return false; |
823 | } |
824 | |
825 | QT_END_NAMESPACE |
826 | |