1 | // Copyright (C) 2019 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 "qsgtexture_p.h" |
5 | #include "qsgtexture_platform.h" |
6 | #include <private/qqmlglobal_p.h> |
7 | #include <private/qsgmaterialshader_p.h> |
8 | #include <private/qsgrenderer_p.h> |
9 | #include <private/qquickitem_p.h> // qquickwindow_p.h cannot be included on its own due to template nonsense |
10 | #include <private/qquickwindow_p.h> |
11 | #include <QtCore/private/qnativeinterface_p.h> |
12 | #include <rhi/qrhi.h> |
13 | |
14 | #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && defined(__GLIBC__) |
15 | #define CAN_BACKTRACE_EXECINFO |
16 | #endif |
17 | |
18 | #if defined(Q_OS_MAC) |
19 | #define CAN_BACKTRACE_EXECINFO |
20 | #endif |
21 | |
22 | #if defined(QT_NO_DEBUG) |
23 | #undef CAN_BACKTRACE_EXECINFO |
24 | #endif |
25 | |
26 | #if defined(CAN_BACKTRACE_EXECINFO) |
27 | #include <execinfo.h> |
28 | #include <QHash> |
29 | #endif |
30 | |
31 | #ifndef QT_NO_DEBUG |
32 | Q_GLOBAL_STATIC(QSet<QSGTexture *>, qsg_valid_texture_set) |
33 | Q_GLOBAL_STATIC(QMutex, qsg_valid_texture_mutex) |
34 | #endif |
35 | |
36 | QT_BEGIN_NAMESPACE |
37 | |
38 | bool operator==(const QSGSamplerDescription &a, const QSGSamplerDescription &b) noexcept |
39 | { |
40 | return a.filtering == b.filtering |
41 | && a.mipmapFiltering == b.mipmapFiltering |
42 | && a.horizontalWrap == b.horizontalWrap |
43 | && a.verticalWrap == b.verticalWrap |
44 | && a.anisotropylevel == b.anisotropylevel; |
45 | } |
46 | |
47 | bool operator!=(const QSGSamplerDescription &a, const QSGSamplerDescription &b) noexcept |
48 | { |
49 | return !(a == b); |
50 | } |
51 | |
52 | size_t qHash(const QSGSamplerDescription &s, size_t seed) noexcept |
53 | { |
54 | const int f = s.filtering; |
55 | const int m = s.mipmapFiltering; |
56 | const int w = s.horizontalWrap; |
57 | const int a = s.anisotropylevel; |
58 | return (((f & 7) << 24) | ((m & 7) << 16) | ((w & 7) << 8) | (a & 7)) ^ seed; |
59 | } |
60 | |
61 | QSGSamplerDescription QSGSamplerDescription::fromTexture(QSGTexture *t) |
62 | { |
63 | QSGSamplerDescription s; |
64 | s.filtering = t->filtering(); |
65 | s.mipmapFiltering = t->mipmapFiltering(); |
66 | s.horizontalWrap = t->horizontalWrapMode(); |
67 | s.verticalWrap = t->verticalWrapMode(); |
68 | s.anisotropylevel = t->anisotropyLevel(); |
69 | return s; |
70 | } |
71 | |
72 | QSGTexturePrivate::QSGTexturePrivate(QSGTexture *t) |
73 | : wrapChanged(false) |
74 | , filteringChanged(false) |
75 | , anisotropyChanged(false) |
76 | , horizontalWrap(QSGTexture::ClampToEdge) |
77 | , verticalWrap(QSGTexture::ClampToEdge) |
78 | , mipmapMode(QSGTexture::None) |
79 | , filterMode(QSGTexture::Nearest) |
80 | , anisotropyLevel(QSGTexture::AnisotropyNone) |
81 | #if QT_CONFIG(opengl) |
82 | , m_openglTextureAccessor(t) |
83 | #endif |
84 | #ifdef Q_OS_WIN |
85 | , m_d3d11TextureAccessor(t) |
86 | , m_d3d12TextureAccessor(t) |
87 | #endif |
88 | #if defined(__OBJC__) |
89 | , m_metalTextureAccessor(t) |
90 | #endif |
91 | #if QT_CONFIG(vulkan) |
92 | , m_vulkanTextureAccessor(t) |
93 | #endif |
94 | { |
95 | #if !QT_CONFIG(opengl) |
96 | Q_UNUSED(t); |
97 | #endif |
98 | } |
99 | |
100 | #ifndef QT_NO_DEBUG |
101 | |
102 | static int qt_debug_texture_count = 0; |
103 | |
104 | #if (defined(Q_OS_LINUX) || defined (Q_OS_MAC)) && !defined(Q_OS_ANDROID) |
105 | DEFINE_BOOL_CONFIG_OPTION(qmlDebugLeakBacktrace, QML_DEBUG_LEAK_BACKTRACE) |
106 | |
107 | #define BACKTRACE_SIZE 20 |
108 | class SGTextureTraceItem |
109 | { |
110 | public: |
111 | void *backTrace[BACKTRACE_SIZE]; |
112 | size_t backTraceSize; |
113 | }; |
114 | |
115 | static QHash<QSGTexture*, SGTextureTraceItem*> qt_debug_allocated_textures; |
116 | #endif |
117 | |
118 | inline static void qt_debug_print_texture_count() |
119 | { |
120 | qDebug(msg: "Number of leaked textures: %i" , qt_debug_texture_count); |
121 | qt_debug_texture_count = -1; |
122 | |
123 | #if defined(CAN_BACKTRACE_EXECINFO) |
124 | if (qmlDebugLeakBacktrace()) { |
125 | while (!qt_debug_allocated_textures.isEmpty()) { |
126 | QHash<QSGTexture*, SGTextureTraceItem*>::Iterator it = qt_debug_allocated_textures.begin(); |
127 | QSGTexture* texture = it.key(); |
128 | SGTextureTraceItem* item = it.value(); |
129 | |
130 | qt_debug_allocated_textures.erase(it); |
131 | |
132 | qDebug() << "------" ; |
133 | qDebug() << "Leaked" << texture << "backtrace:" ; |
134 | |
135 | char** symbols = backtrace_symbols(array: item->backTrace, size: item->backTraceSize); |
136 | |
137 | if (symbols) { |
138 | for (int i=0; i<(int) item->backTraceSize; i++) |
139 | qDebug(msg: "Backtrace <%02d>: %s" , i, symbols[i]); |
140 | free(ptr: symbols); |
141 | } |
142 | |
143 | qDebug() << "------" ; |
144 | |
145 | delete item; |
146 | } |
147 | } |
148 | #endif |
149 | } |
150 | |
151 | inline static void qt_debug_add_texture(QSGTexture* texture) |
152 | { |
153 | #if defined(CAN_BACKTRACE_EXECINFO) |
154 | if (qmlDebugLeakBacktrace()) { |
155 | SGTextureTraceItem* item = new SGTextureTraceItem; |
156 | item->backTraceSize = backtrace(array: item->backTrace, BACKTRACE_SIZE); |
157 | qt_debug_allocated_textures.insert(key: texture, value: item); |
158 | } |
159 | #else |
160 | Q_UNUSED(texture); |
161 | #endif // Q_OS_LINUX |
162 | |
163 | ++qt_debug_texture_count; |
164 | |
165 | static bool atexit_registered = false; |
166 | if (!atexit_registered) { |
167 | atexit(func: qt_debug_print_texture_count); |
168 | atexit_registered = true; |
169 | } |
170 | } |
171 | |
172 | static void qt_debug_remove_texture(QSGTexture* texture) |
173 | { |
174 | #if defined(CAN_BACKTRACE_EXECINFO) |
175 | if (qmlDebugLeakBacktrace()) { |
176 | SGTextureTraceItem* item = qt_debug_allocated_textures.value(key: texture, defaultValue: 0); |
177 | if (item) { |
178 | qt_debug_allocated_textures.remove(key: texture); |
179 | delete item; |
180 | } |
181 | } |
182 | #else |
183 | Q_UNUSED(texture); |
184 | #endif |
185 | |
186 | --qt_debug_texture_count; |
187 | |
188 | if (qt_debug_texture_count < 0) |
189 | qDebug(msg: "Texture destroyed after qt_debug_print_texture_count() was called." ); |
190 | } |
191 | |
192 | #endif // QT_NO_DEBUG |
193 | |
194 | /*! |
195 | \class QSGTexture |
196 | |
197 | \inmodule QtQuick |
198 | |
199 | \brief The QSGTexture class is the base class for textures used in |
200 | the scene graph. |
201 | |
202 | Users can freely implement their own texture classes to support arbitrary |
203 | input textures, such as YUV video frames or 8 bit alpha masks. The scene |
204 | graph provides a default implementation for RGBA textures.The default |
205 | implementation is not instantiated directly, rather they are constructed |
206 | via factory functions, such as QQuickWindow::createTextureFromImage(). |
207 | |
208 | With the default implementation, each QSGTexture is backed by a |
209 | QRhiTexture, which in turn contains a native texture object, such as an |
210 | OpenGL texture or a Vulkan image. |
211 | |
212 | The size in pixels is given by textureSize(). hasAlphaChannel() reports if |
213 | the texture contains opacity values and hasMipmaps() reports if the texture |
214 | contains mipmap levels. |
215 | |
216 | \l{QSGMaterial}{Materials} that work with textures reimplement |
217 | \l{QSGMaterialShader::updateSampledImage()}{updateSampledImage()} to |
218 | provide logic that decides which QSGTexture's underlying native texture |
219 | should be exposed at a given shader resource binding point. |
220 | |
221 | QSGTexture does not separate image (texture) and sampler objects. The |
222 | parameters for filtering and wrapping can be specified with |
223 | setMipmapFiltering(), setFiltering(), setHorizontalWrapMode() and |
224 | setVerticalWrapMode(). The scene graph and Qt's graphics abstraction takes |
225 | care of creating separate sampler objects, when applicable. |
226 | |
227 | \section1 Texture Atlases |
228 | |
229 | Some scene graph backends use texture atlasses, grouping multiple small |
230 | textures into one large texture. If this is the case, the function |
231 | isAtlasTexture() will return true. Atlases are used to aid the rendering |
232 | algorithm to do better sorting which increases performance. Atlases are |
233 | also essential for batching (merging together geometry to reduce the number |
234 | of draw calls), because two instances of the same material using two |
235 | different QSGTextures are not batchable, whereas if both QSGTextures refer |
236 | to the same atlas, batching can happen, assuming the materials are |
237 | otherwise compatible. |
238 | |
239 | The location of the texture inside the atlas is given with the |
240 | normalizedTextureSubRect() function. |
241 | |
242 | If the texture is used in such a way that atlas is not preferable, the |
243 | function removedFromAtlas() can be used to extract a non-atlased copy. |
244 | |
245 | \note All classes with QSG prefix should be used solely on the scene graph's |
246 | rendering thread. See \l {Scene Graph and Rendering} for more information. |
247 | */ |
248 | |
249 | /*! |
250 | \enum QSGTexture::WrapMode |
251 | |
252 | Specifies how the sampler should treat texture coordinates. |
253 | |
254 | \value Repeat Only the fractional part of the texture coordinate is |
255 | used, causing values above 1 and below 0 to repeat. |
256 | |
257 | \value ClampToEdge Values above 1 are clamped to 1 and values |
258 | below 0 are clamped to 0. |
259 | |
260 | \value MirroredRepeat When the texture coordinate is even, only the |
261 | fractional part is used. When odd, the texture coordinate is set to |
262 | \c{1 - fractional part}. This value has been introduced in Qt 5.10. |
263 | */ |
264 | |
265 | /*! |
266 | \enum QSGTexture::Filtering |
267 | |
268 | Specifies how sampling of texels should filter when texture |
269 | coordinates are not pixel aligned. |
270 | |
271 | \value None No filtering should occur. This value is only used |
272 | together with setMipmapFiltering(). |
273 | |
274 | \value Nearest Sampling returns the nearest texel. |
275 | |
276 | \value Linear Sampling returns a linear interpolation of the |
277 | neighboring texels. |
278 | */ |
279 | |
280 | /*! |
281 | \enum QSGTexture::AnisotropyLevel |
282 | |
283 | Specifies the anisotropic filtering level to be used when |
284 | the texture is not screen aligned. |
285 | |
286 | \value AnisotropyNone No anisotropic filtering. |
287 | |
288 | \value Anisotropy2x 2x anisotropic filtering. |
289 | |
290 | \value Anisotropy4x 4x anisotropic filtering. |
291 | |
292 | \value Anisotropy8x 8x anisotropic filtering. |
293 | |
294 | \value Anisotropy16x 16x anisotropic filtering. |
295 | |
296 | \since 5.9 |
297 | */ |
298 | |
299 | /*! |
300 | Constructs the QSGTexture base class. |
301 | */ |
302 | QSGTexture::QSGTexture() |
303 | : QObject(*(new QSGTexturePrivate(this))) |
304 | { |
305 | #ifndef QT_NO_DEBUG |
306 | if (_q_sg_leak_check) |
307 | qt_debug_add_texture(texture: this); |
308 | |
309 | QMutexLocker locker(qsg_valid_texture_mutex()); |
310 | qsg_valid_texture_set()->insert(value: this); |
311 | #endif |
312 | } |
313 | |
314 | /*! |
315 | \internal |
316 | */ |
317 | QSGTexture::QSGTexture(QSGTexturePrivate &dd) |
318 | : QObject(dd) |
319 | { |
320 | #ifndef QT_NO_DEBUG |
321 | if (_q_sg_leak_check) |
322 | qt_debug_add_texture(texture: this); |
323 | |
324 | QMutexLocker locker(qsg_valid_texture_mutex()); |
325 | qsg_valid_texture_set()->insert(value: this); |
326 | #endif |
327 | } |
328 | |
329 | /*! |
330 | Destroys the QSGTexture. |
331 | */ |
332 | QSGTexture::~QSGTexture() |
333 | { |
334 | #ifndef QT_NO_DEBUG |
335 | if (_q_sg_leak_check) |
336 | qt_debug_remove_texture(texture: this); |
337 | |
338 | QMutexLocker locker(qsg_valid_texture_mutex()); |
339 | qsg_valid_texture_set()->remove(value: this); |
340 | #endif |
341 | } |
342 | |
343 | /*! |
344 | \fn QRectF QSGTexture::convertToNormalizedSourceRect(const QRectF &rect) const |
345 | |
346 | Returns \a rect converted to normalized coordinates. |
347 | |
348 | \sa normalizedTextureSubRect() |
349 | */ |
350 | |
351 | /*! |
352 | This function returns a copy of the current texture which is removed |
353 | from its atlas. |
354 | |
355 | The current texture remains unchanged, so texture coordinates do not |
356 | need to be updated. |
357 | |
358 | Removing a texture from an atlas is primarily useful when passing |
359 | it to a shader that operates on the texture coordinates 0-1 instead |
360 | of the texture subrect inside the atlas. |
361 | |
362 | If the texture is not part of a texture atlas, this function returns 0. |
363 | |
364 | Implementations of this function are recommended to return the same instance |
365 | for multiple calls to limit memory usage. |
366 | |
367 | \a resourceUpdates is an optional resource update batch, on which texture |
368 | operations, if any, are enqueued. Materials can retrieve an instance from |
369 | QSGMaterialShader::RenderState. When null, the removedFromAtlas() |
370 | implementation creates its own batch and submit it right away. However, |
371 | when a valid instance is specified, this function will not submit the |
372 | update batch. |
373 | |
374 | \warning This function can only be called from the rendering thread. |
375 | */ |
376 | |
377 | QSGTexture *QSGTexture::removedFromAtlas(QRhiResourceUpdateBatch *resourceUpdates) const |
378 | { |
379 | Q_UNUSED(resourceUpdates); |
380 | Q_ASSERT_X(!isAtlasTexture(), "QSGTexture::removedFromAtlas()" , "Called on a non-atlas texture" ); |
381 | return nullptr; |
382 | } |
383 | |
384 | /*! |
385 | Returns whether this texture is part of an atlas or not. |
386 | |
387 | The default implementation returns false. |
388 | */ |
389 | bool QSGTexture::isAtlasTexture() const |
390 | { |
391 | return false; |
392 | } |
393 | |
394 | /*! |
395 | \fn qint64 QSGTexture::comparisonKey() const |
396 | |
397 | Returns a key suitable for comparing textures. Typically used in |
398 | QSGMaterial::compare() implementations. |
399 | |
400 | Just comparing QSGTexture pointers is not always sufficient because two |
401 | QSGTexture instances that refer to the same native texture object |
402 | underneath should also be considered equal. Hence the need for this function. |
403 | |
404 | Implementations of this function are not expected to, and should not create |
405 | any graphics resources (native texture objects) in case there are none yet. |
406 | |
407 | A QSGTexture that does not have a native texture object underneath is |
408 | typically \b not equal to any other QSGTexture, so the return value has to |
409 | be crafted accordingly. There are exceptions to this, in particular when |
410 | atlasing is used (where multiple textures share the same atlas texture |
411 | under the hood), that is then up to the subclass implementations to deal |
412 | with as appropriate. |
413 | |
414 | \warning This function can only be called from the rendering thread. |
415 | |
416 | \since 5.14 |
417 | */ |
418 | |
419 | /*! |
420 | \fn QSize QSGTexture::textureSize() const |
421 | |
422 | Returns the size of the texture in pixels. |
423 | */ |
424 | |
425 | /*! |
426 | Returns the rectangle inside textureSize() that this texture |
427 | represents in normalized coordinates. |
428 | |
429 | The default implementation returns a rect at position (0, 0) with |
430 | width and height of 1. |
431 | */ |
432 | QRectF QSGTexture::normalizedTextureSubRect() const |
433 | { |
434 | return QRectF(0, 0, 1, 1); |
435 | } |
436 | |
437 | /*! |
438 | \fn bool QSGTexture::hasAlphaChannel() const |
439 | |
440 | Returns true if the texture data contains an alpha channel. |
441 | */ |
442 | |
443 | /*! |
444 | \fn bool QSGTexture::hasMipmaps() const |
445 | |
446 | Returns true if the texture data contains mipmap levels. |
447 | */ |
448 | |
449 | |
450 | /*! |
451 | Sets the mipmap sampling mode to \a filter. |
452 | |
453 | Setting the mipmap filtering has no effect it the texture does not have mipmaps. |
454 | |
455 | \sa hasMipmaps() |
456 | */ |
457 | void QSGTexture::setMipmapFiltering(Filtering filter) |
458 | { |
459 | Q_D(QSGTexture); |
460 | if (d->mipmapMode != (uint) filter) { |
461 | d->mipmapMode = filter; |
462 | d->filteringChanged = true; |
463 | } |
464 | } |
465 | |
466 | /*! |
467 | Returns whether mipmapping should be used when sampling from this texture. |
468 | */ |
469 | QSGTexture::Filtering QSGTexture::mipmapFiltering() const |
470 | { |
471 | return (QSGTexture::Filtering) d_func()->mipmapMode; |
472 | } |
473 | |
474 | |
475 | /*! |
476 | Sets the sampling mode to \a filter. |
477 | */ |
478 | void QSGTexture::setFiltering(QSGTexture::Filtering filter) |
479 | { |
480 | Q_D(QSGTexture); |
481 | if (d->filterMode != (uint) filter) { |
482 | d->filterMode = filter; |
483 | d->filteringChanged = true; |
484 | } |
485 | } |
486 | |
487 | /*! |
488 | Returns the sampling mode to be used for this texture. |
489 | */ |
490 | QSGTexture::Filtering QSGTexture::filtering() const |
491 | { |
492 | return (QSGTexture::Filtering) d_func()->filterMode; |
493 | } |
494 | |
495 | /*! |
496 | Sets the level of anisotropic filtering to \a level. The default value is |
497 | QSGTexture::AnisotropyNone, which means no anisotropic filtering is |
498 | enabled. |
499 | |
500 | \note The request may be ignored depending on the graphics API in use. |
501 | There is no guarantee anisotropic filtering is supported at run time. |
502 | |
503 | \since 5.9 |
504 | */ |
505 | void QSGTexture::setAnisotropyLevel(AnisotropyLevel level) |
506 | { |
507 | Q_D(QSGTexture); |
508 | if (d->anisotropyLevel != (uint) level) { |
509 | d->anisotropyLevel = level; |
510 | d->anisotropyChanged = true; |
511 | } |
512 | } |
513 | |
514 | /*! |
515 | Returns the anisotropy level in use for filtering this texture. |
516 | |
517 | \since 5.9 |
518 | */ |
519 | QSGTexture::AnisotropyLevel QSGTexture::anisotropyLevel() const |
520 | { |
521 | return (QSGTexture::AnisotropyLevel) d_func()->anisotropyLevel; |
522 | } |
523 | |
524 | |
525 | |
526 | /*! |
527 | Sets the horizontal wrap mode to \a hwrap |
528 | */ |
529 | |
530 | void QSGTexture::setHorizontalWrapMode(WrapMode hwrap) |
531 | { |
532 | Q_D(QSGTexture); |
533 | if ((uint) hwrap != d->horizontalWrap) { |
534 | d->horizontalWrap = hwrap; |
535 | d->wrapChanged = true; |
536 | } |
537 | } |
538 | |
539 | /*! |
540 | Returns the horizontal wrap mode to be used for this texture. |
541 | */ |
542 | QSGTexture::WrapMode QSGTexture::horizontalWrapMode() const |
543 | { |
544 | return (QSGTexture::WrapMode) d_func()->horizontalWrap; |
545 | } |
546 | |
547 | |
548 | |
549 | /*! |
550 | Sets the vertical wrap mode to \a vwrap |
551 | */ |
552 | void QSGTexture::setVerticalWrapMode(WrapMode vwrap) |
553 | { |
554 | Q_D(QSGTexture); |
555 | if ((uint) vwrap != d->verticalWrap) { |
556 | d->verticalWrap = vwrap; |
557 | d->wrapChanged = true; |
558 | } |
559 | } |
560 | |
561 | /*! |
562 | Returns the vertical wrap mode to be used for this texture. |
563 | */ |
564 | QSGTexture::WrapMode QSGTexture::verticalWrapMode() const |
565 | { |
566 | return (QSGTexture::WrapMode) d_func()->verticalWrap; |
567 | } |
568 | |
569 | /*! |
570 | \return the QRhiTexture for this QSGTexture or null if there is none (either |
571 | because a valid texture has not been created internally yet, or because the |
572 | concept is not applicable to the scenegraph backend in use). |
573 | |
574 | This function is not expected to create a new QRhiTexture in case there is |
575 | none. It should return null in that case. The expectation towards the |
576 | renderer is that a null texture leads to using a transparent, dummy texture |
577 | instead. |
578 | |
579 | \warning This function can only be called from the rendering thread. |
580 | |
581 | \since 6.0 |
582 | */ |
583 | QRhiTexture *QSGTexture::rhiTexture() const |
584 | { |
585 | return nullptr; |
586 | } |
587 | |
588 | /*! |
589 | Call this function to enqueue image upload operations to \a |
590 | resourceUpdates, in case there are any pending ones. When there is no new |
591 | data (for example, because there was no setImage() since the last call to |
592 | this function), the function does nothing. |
593 | |
594 | Materials involving \a rhi textures are expected to call this function from |
595 | their \l{QSGMaterialShader::updateSampledImage()}{updateSampledImage()} |
596 | implementation, typically without any conditions, passing \c{state.rhi()} |
597 | and \c{state.resourceUpdateBatch()} from the QSGMaterialShader::RenderState. |
598 | |
599 | \warning This function can only be called from the rendering thread. |
600 | |
601 | \since 6.0 |
602 | */ |
603 | void QSGTexture::commitTextureOperations(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates) |
604 | { |
605 | Q_UNUSED(rhi); |
606 | Q_UNUSED(resourceUpdates); |
607 | } |
608 | |
609 | bool QSGTexturePrivate::hasDirtySamplerOptions() const |
610 | { |
611 | return wrapChanged || filteringChanged || anisotropyChanged; |
612 | } |
613 | |
614 | void QSGTexturePrivate::resetDirtySamplerOptions() |
615 | { |
616 | wrapChanged = filteringChanged = anisotropyChanged = false; |
617 | } |
618 | |
619 | /*! |
620 | \class QSGDynamicTexture |
621 | \brief The QSGDynamicTexture class serves as a baseclass for dynamically changing textures, |
622 | such as content that is rendered to FBO's. |
623 | \inmodule QtQuick |
624 | |
625 | To update the content of the texture, call updateTexture() explicitly. |
626 | |
627 | \note All classes with QSG prefix should be used solely on the scene graph's |
628 | rendering thread. See \l {Scene Graph and Rendering} for more information. |
629 | */ |
630 | |
631 | |
632 | /*! |
633 | \fn bool QSGDynamicTexture::updateTexture() |
634 | |
635 | Call this function to explicitly update the dynamic texture. |
636 | |
637 | The function returns true if the texture was changed as a resul of the update; otherwise |
638 | returns false. |
639 | |
640 | \note This function is typically called from QQuickItem::updatePaintNode() |
641 | or QSGNode::preprocess(), meaning during the \c{synchronization} or the |
642 | \c{node preprocessing} phases of the scenegraph. Calling it at other times |
643 | is discouraged and can lead to unexpected behavior. |
644 | */ |
645 | |
646 | /*! |
647 | \internal |
648 | */ |
649 | QSGDynamicTexture::QSGDynamicTexture(QSGTexturePrivate &dd) |
650 | : QSGTexture(dd) |
651 | { |
652 | } |
653 | |
654 | /*! |
655 | \internal |
656 | */ |
657 | QSGDynamicTexture::~QSGDynamicTexture() |
658 | = default; |
659 | |
660 | /*! |
661 | \fn template <typename QNativeInterface> NativeInterface *QSGTexture::nativeInterface() const |
662 | |
663 | Returns a native interface of the given type for the texture. |
664 | |
665 | This function provides access to platform specific functionality of |
666 | QSGTexture, as declared in the QNativeInterface namespace: |
667 | |
668 | \annotatedlist native-interfaces-qsgtexture |
669 | |
670 | This allows accessing the underlying native texture object, such as, the \c GLuint |
671 | texture ID with OpenGL, or the \c VkImage handle with Vulkan. |
672 | |
673 | If the requested interface is not available a \nullptr is returned. |
674 | */ |
675 | |
676 | |
677 | #if QT_CONFIG(opengl) || defined(Q_QDOC) |
678 | namespace QNativeInterface { |
679 | /*! |
680 | \class QNativeInterface::QSGOpenGLTexture |
681 | \inmodule QtQuick |
682 | \ingroup native-interfaces |
683 | \ingroup native-interfaces-qsgtexture |
684 | \inheaderfile QSGTexture |
685 | \brief Provides access to and enables adopting OpenGL texture objects. |
686 | \since 6.0 |
687 | */ |
688 | |
689 | /*! |
690 | \fn VkImage QNativeInterface::QSGOpenGLTexture::nativeTexture() const |
691 | \return the OpenGL texture ID. |
692 | */ |
693 | |
694 | QT_DEFINE_NATIVE_INTERFACE(QSGOpenGLTexture); |
695 | |
696 | /*! |
697 | Creates a new QSGTexture wrapping an existing OpenGL texture object for |
698 | \a window. |
699 | |
700 | The native object specified in \a textureId is wrapped, but not owned, by |
701 | the resulting QSGTexture. The caller of the function is responsible for |
702 | deleting the returned QSGTexture, but that will not destroy the underlying |
703 | native object. |
704 | |
705 | This function is currently suitable for 2D RGBA textures only. |
706 | |
707 | \warning This function will return null if the scenegraph has not yet been |
708 | initialized. |
709 | |
710 | Use \a options to customize the texture attributes. Only the |
711 | TextureHasAlphaChannel and TextureHasMipmaps are taken into account here. |
712 | |
713 | \a size specifies the size in pixels. |
714 | |
715 | \note This function must be called on the scenegraph rendering thread. |
716 | |
717 | \sa QQuickWindow::sceneGraphInitialized(), QSGTexture, |
718 | {Scene Graph - Metal Texture Import}, {Scene Graph - Vulkan Texture Import} |
719 | |
720 | \since 6.0 |
721 | */ |
722 | QSGTexture *QSGOpenGLTexture::fromNative(GLuint textureId, |
723 | QQuickWindow *window, |
724 | const QSize &size, |
725 | QQuickWindow::CreateTextureOptions options) |
726 | { |
727 | return QQuickWindowPrivate::get(c: window)->createTextureFromNativeTexture(nativeObjectHandle: quint64(textureId), nativeLayoutOrState: 0, size, options); |
728 | } |
729 | |
730 | /*! |
731 | Creates a new QSGTexture wrapping an existing OpenGL ES texture object for |
732 | \a window. |
733 | |
734 | The native object specified in \a textureId is wrapped, but not owned, by |
735 | the resulting QSGTexture. The caller of the function is responsible for |
736 | deleting the returned QSGTexture, but that will not destroy the underlying |
737 | native object. |
738 | |
739 | This function is suitable only for textures that are meant to be |
740 | used with the \c{GL_TEXTURE_EXTERNAL_OES} target: usually textures |
741 | to which another device (such as a camera) writes data. |
742 | |
743 | \warning This function will return null if the scenegraph has not yet been |
744 | initialized. |
745 | |
746 | Use \a options to customize the texture attributes. Only the |
747 | TextureHasAlphaChannel and TextureHasMipmaps are taken into account here. |
748 | |
749 | \a size specifies the size in pixels. |
750 | |
751 | \note This function must be called on the scenegraph rendering thread. |
752 | |
753 | \since 6.1 |
754 | |
755 | \sa fromNative() |
756 | */ |
757 | QSGTexture *QSGOpenGLTexture::fromNativeExternalOES(GLuint textureId, |
758 | QQuickWindow *window, |
759 | const QSize &size, |
760 | QQuickWindow::CreateTextureOptions options) |
761 | { |
762 | return QQuickWindowPrivate::get(c: window)->createTextureFromNativeTexture(nativeObjectHandle: quint64(textureId), |
763 | nativeLayoutOrState: 0, |
764 | size, |
765 | options, |
766 | flags: QQuickWindowPrivate::NativeTextureIsExternalOES); |
767 | } |
768 | } // QNativeInterface |
769 | |
770 | GLuint QSGTexturePlatformOpenGL::nativeTexture() const |
771 | { |
772 | if (auto *tex = m_texture->rhiTexture()) |
773 | return GLuint(tex->nativeTexture().object); |
774 | return 0; |
775 | } |
776 | #endif // opengl |
777 | |
778 | #if defined(Q_OS_WIN) || defined(Q_QDOC) |
779 | namespace QNativeInterface { |
780 | /*! |
781 | \class QNativeInterface::QSGD3D11Texture |
782 | \inmodule QtQuick |
783 | \ingroup native-interfaces |
784 | \ingroup native-interfaces-qsgtexture |
785 | \inheaderfile QSGTexture |
786 | \brief Provides access to and enables adopting Direct3D 11 texture objects. |
787 | \since 6.0 |
788 | */ |
789 | |
790 | /*! |
791 | \fn void *QNativeInterface::QSGD3D11Texture::nativeTexture() const |
792 | \return the ID3D11Texture2D object. |
793 | */ |
794 | |
795 | QT_DEFINE_NATIVE_INTERFACE(QSGD3D11Texture); |
796 | |
797 | /*! |
798 | Creates a new QSGTexture wrapping an existing Direct 3D 11 \a texture object |
799 | for \a window. |
800 | |
801 | The native object is wrapped, but not owned, by the resulting QSGTexture. |
802 | The caller of the function is responsible for deleting the returned |
803 | QSGTexture, but that will not destroy the underlying native object. |
804 | |
805 | This function is currently suitable for 2D RGBA textures only. |
806 | |
807 | \warning This function will return null if the scene graph has not yet been |
808 | initialized. |
809 | |
810 | Use \a options to customize the texture attributes. Only the |
811 | TextureHasAlphaChannel and TextureHasMipmaps are taken into account here. |
812 | |
813 | \a size specifies the size in pixels. |
814 | |
815 | \note This function must be called on the scene graph rendering thread. |
816 | |
817 | \sa QQuickWindow::sceneGraphInitialized(), QSGTexture, |
818 | {Scene Graph - Metal Texture Import}, {Scene Graph - Vulkan Texture Import} |
819 | |
820 | \since 6.0 |
821 | */ |
822 | QSGTexture *QSGD3D11Texture::fromNative(void *texture, |
823 | QQuickWindow *window, |
824 | const QSize &size, |
825 | QQuickWindow::CreateTextureOptions options) |
826 | { |
827 | return QQuickWindowPrivate::get(window)->createTextureFromNativeTexture(quint64(texture), 0, size, options); |
828 | } |
829 | } // QNativeInterface |
830 | |
831 | void *QSGTexturePlatformD3D11::nativeTexture() const |
832 | { |
833 | if (auto *tex = m_texture->rhiTexture()) |
834 | return reinterpret_cast<void *>(quintptr(tex->nativeTexture().object)); |
835 | return 0; |
836 | } |
837 | |
838 | namespace QNativeInterface { |
839 | /*! |
840 | \class QNativeInterface::QSGD3D12Texture |
841 | \inmodule QtQuick |
842 | \ingroup native-interfaces |
843 | \ingroup native-interfaces-qsgtexture |
844 | \inheaderfile QSGTexture |
845 | \brief Provides access to and enables adopting Direct3D 12 texture objects. |
846 | \since 6.6 |
847 | */ |
848 | |
849 | /*! |
850 | \fn void *QNativeInterface::QSGD3D12Texture::nativeTexture() const |
851 | \return the ID3D12Texture object. |
852 | */ |
853 | |
854 | QT_DEFINE_NATIVE_INTERFACE(QSGD3D12Texture); |
855 | |
856 | /*! |
857 | Creates a new QSGTexture wrapping an existing Direct 3D 12 \a texture object |
858 | for \a window. |
859 | |
860 | The native object is wrapped, but not owned, by the resulting QSGTexture. |
861 | The caller of the function is responsible for deleting the returned |
862 | QSGTexture, but that will not destroy the underlying native object. |
863 | |
864 | This function is currently suitable for 2D RGBA textures only. |
865 | |
866 | \warning This function will return null if the scene graph has not yet been |
867 | initialized. |
868 | |
869 | Use \a options to customize the texture attributes. Only the |
870 | TextureHasAlphaChannel and TextureHasMipmaps are taken into account here. |
871 | |
872 | \a size specifies the size in pixels. |
873 | |
874 | \a resourceState must specify the |
875 | \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_resource_states}{current state} |
876 | of the texture resource. |
877 | |
878 | \note This function must be called on the scene graph rendering thread. |
879 | |
880 | \sa QQuickWindow::sceneGraphInitialized(), QSGTexture, |
881 | {Scene Graph - Metal Texture Import}, {Scene Graph - Vulkan Texture Import} |
882 | |
883 | \since 6.6 |
884 | */ |
885 | QSGTexture *QSGD3D12Texture::fromNative(void *texture, |
886 | int resourceState, |
887 | QQuickWindow *window, |
888 | const QSize &size, |
889 | QQuickWindow::CreateTextureOptions options) |
890 | { |
891 | return QQuickWindowPrivate::get(window)->createTextureFromNativeTexture(quint64(texture), resourceState, size, options); |
892 | } |
893 | } // QNativeInterface |
894 | |
895 | int QSGTexturePlatformD3D12::nativeResourceState() const |
896 | { |
897 | if (auto *tex = m_texture->rhiTexture()) |
898 | return tex->nativeTexture().layout; |
899 | return 0; |
900 | } |
901 | |
902 | void *QSGTexturePlatformD3D12::nativeTexture() const |
903 | { |
904 | if (auto *tex = m_texture->rhiTexture()) |
905 | return reinterpret_cast<void *>(quintptr(tex->nativeTexture().object)); |
906 | return 0; |
907 | } |
908 | |
909 | #endif // win |
910 | |
911 | #if defined(__OBJC__) || defined(Q_QDOC) |
912 | namespace QNativeInterface { |
913 | /*! |
914 | \class QNativeInterface::QSGMetalTexture |
915 | \inmodule QtQuick |
916 | \ingroup native-interfaces |
917 | \ingroup native-interfaces-qsgtexture |
918 | \inheaderfile QSGTexture |
919 | \brief Provides access to and enables adopting Metal texture objects. |
920 | \since 6.0 |
921 | */ |
922 | |
923 | /*! |
924 | \fn id<MTLTexture> QNativeInterface::QSGMetalTexture::nativeTexture() const |
925 | \return the Metal texture object. |
926 | */ |
927 | |
928 | /*! |
929 | \fn QSGTexture *QNativeInterface::QSGMetalTexture::fromNative(id<MTLTexture> texture, QQuickWindow *window, const QSize &size, QQuickWindow::CreateTextureOptions options) |
930 | |
931 | Creates a new QSGTexture wrapping an existing Metal \a texture object for |
932 | \a window. |
933 | |
934 | The native object is wrapped, but not owned, by the resulting QSGTexture. |
935 | The caller of the function is responsible for deleting the returned |
936 | QSGTexture, but that will not destroy the underlying native object. |
937 | |
938 | This function is currently suitable for 2D RGBA textures only. |
939 | |
940 | \warning This function will return null if the scene graph has not yet been |
941 | initialized. |
942 | |
943 | Use \a options to customize the texture attributes. Only the |
944 | TextureHasAlphaChannel and TextureHasMipmaps are taken into account here. |
945 | |
946 | \a size specifies the size in pixels. |
947 | |
948 | \note This function must be called on the scene graph rendering thread. |
949 | |
950 | \sa QQuickWindow::sceneGraphInitialized(), QSGTexture, |
951 | {Scene Graph - Metal Texture Import}, {Scene Graph - Vulkan Texture Import} |
952 | |
953 | \since 6.0 |
954 | */ |
955 | |
956 | } // QNativeInterface |
957 | #endif // OBJC |
958 | |
959 | #if QT_CONFIG(vulkan) || defined(Q_QDOC) |
960 | namespace QNativeInterface { |
961 | /*! |
962 | \class QNativeInterface::QSGVulkanTexture |
963 | \inmodule QtQuick |
964 | \ingroup native-interfaces |
965 | \ingroup native-interfaces-qsgtexture |
966 | \inheaderfile QSGTexture |
967 | \brief Provides access to and enables adopting Vulkan image objects. |
968 | \since 6.0 |
969 | */ |
970 | |
971 | /*! |
972 | \fn VkImage QNativeInterface::QSGVulkanTexture::nativeImage() const |
973 | \return the VkImage handle. |
974 | */ |
975 | |
976 | /*! |
977 | \fn VkImageLayout QNativeInterface::QSGVulkanTexture::nativeImageLayout() const |
978 | \return the image layout. |
979 | */ |
980 | |
981 | QT_DEFINE_NATIVE_INTERFACE(QSGVulkanTexture); |
982 | |
983 | /*! |
984 | Creates a new QSGTexture wrapping an existing Vulkan \a image object for |
985 | \a window. |
986 | |
987 | The native object is wrapped, but not owned, by the resulting QSGTexture. |
988 | The caller of the function is responsible for deleting the returned |
989 | QSGTexture, but that will not destroy the underlying native object. |
990 | |
991 | This function is currently suitable for 2D RGBA textures only. |
992 | |
993 | \warning This function will return null if the scene graph has not yet been |
994 | initialized. |
995 | |
996 | \a layout must specify the current layout of the image. |
997 | |
998 | Use \a options to customize the texture attributes. Only the |
999 | TextureHasAlphaChannel and TextureHasMipmaps are taken into account here. |
1000 | |
1001 | \a size specifies the size in pixels. |
1002 | |
1003 | \note This function must be called on the scene graph rendering thread. |
1004 | |
1005 | \sa QQuickWindow::sceneGraphInitialized(), QSGTexture, |
1006 | {Scene Graph - Metal Texture Import}, {Scene Graph - Vulkan Texture Import} |
1007 | |
1008 | \since 6.0 |
1009 | */ |
1010 | QSGTexture *QSGVulkanTexture::fromNative(VkImage image, |
1011 | VkImageLayout layout, |
1012 | QQuickWindow *window, |
1013 | const QSize &size, |
1014 | QQuickWindow::CreateTextureOptions options) |
1015 | { |
1016 | return QQuickWindowPrivate::get(c: window)->createTextureFromNativeTexture(nativeObjectHandle: quint64(image), nativeLayoutOrState: layout, size, options); |
1017 | } |
1018 | } // QNativeInterface |
1019 | |
1020 | VkImage QSGTexturePlatformVulkan::nativeImage() const |
1021 | { |
1022 | if (auto *tex = m_texture->rhiTexture()) |
1023 | return VkImage(tex->nativeTexture().object); |
1024 | return VK_NULL_HANDLE; |
1025 | } |
1026 | |
1027 | VkImageLayout QSGTexturePlatformVulkan::nativeImageLayout() const |
1028 | { |
1029 | if (auto *tex = m_texture->rhiTexture()) |
1030 | return VkImageLayout(tex->nativeTexture().layout); |
1031 | return VK_IMAGE_LAYOUT_UNDEFINED; |
1032 | } |
1033 | #endif // vulkan |
1034 | |
1035 | void *QSGTexture::resolveInterface(const char *name, int revision) const |
1036 | { |
1037 | using namespace QNativeInterface; |
1038 | Q_UNUSED(name); |
1039 | Q_UNUSED(revision); |
1040 | |
1041 | Q_D(const QSGTexture); |
1042 | auto *dd = const_cast<QSGTexturePrivate *>(d); |
1043 | Q_UNUSED(dd); |
1044 | |
1045 | #if QT_CONFIG(vulkan) |
1046 | QT_NATIVE_INTERFACE_RETURN_IF(QSGVulkanTexture, &dd->m_vulkanTextureAccessor); |
1047 | #endif |
1048 | #if defined(__OBJC__) |
1049 | QT_NATIVE_INTERFACE_RETURN_IF(QSGMetalTexture, &dd->m_metalTextureAccessor); |
1050 | #endif |
1051 | #if defined(Q_OS_WIN) |
1052 | QT_NATIVE_INTERFACE_RETURN_IF(QSGD3D11Texture, &dd->m_d3d11TextureAccessor); |
1053 | QT_NATIVE_INTERFACE_RETURN_IF(QSGD3D12Texture, &dd->m_d3d12TextureAccessor); |
1054 | #endif |
1055 | #if QT_CONFIG(opengl) |
1056 | QT_NATIVE_INTERFACE_RETURN_IF(QSGOpenGLTexture, &dd->m_openglTextureAccessor); |
1057 | #endif |
1058 | |
1059 | return nullptr; |
1060 | } |
1061 | |
1062 | QT_END_NAMESPACE |
1063 | |
1064 | #include "moc_qsgtexture.cpp" |
1065 | |