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