1// Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
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 "texture_p.h"
5
6#include <QDebug>
7#include <QOpenGLFunctions>
8#include <QOpenGLTexture>
9
10#include <Qt3DRender/private/texture_p.h>
11#include <Qt3DRender/private/qabstracttexture_p.h>
12#include <Qt3DRender/private/managers_p.h>
13
14QT_BEGIN_NAMESPACE
15
16using namespace Qt3DCore;
17
18namespace Qt3DRender {
19namespace Render {
20
21Texture::Texture()
22 // We need backend -> frontend notifications to update the status of the texture
23 : BackendNode(ReadWrite)
24 , m_dirty(DirtyImageGenerators|DirtyProperties|DirtyParameters|DirtyDataGenerator)
25 , m_sharedTextureId(-1)
26{
27}
28
29Texture::~Texture()
30{
31 // We do not abandon the api texture
32 // because if the dtor is called that means
33 // the manager was destroyed otherwise cleanup
34 // would have been called
35}
36
37void Texture::addDirtyFlag(DirtyFlags flags)
38{
39 QMutexLocker lock(&m_flagsMutex);
40 m_dirty |= flags;
41 if (m_renderer)
42 markDirty(changes: AbstractRenderer::TexturesDirty);
43}
44
45Texture::DirtyFlags Texture::dirtyFlags()
46{
47 QMutexLocker lock(&m_flagsMutex);
48 return m_dirty;
49}
50
51void Texture::unsetDirty()
52{
53 QMutexLocker lock(&m_flagsMutex);
54 m_dirty = Texture::NotDirty;
55}
56
57// This is called by Renderer::updateGLResources
58// when the texture has been marked for cleanup
59void Texture::cleanup()
60{
61 // Whoever calls this must make sure to also check if this
62 // texture is being referenced by a shared API specific texture (GLTexture)
63 m_dataFunctor.reset();
64 m_textureImageIds.clear();
65 m_pendingTextureDataUpdates.clear();
66 m_sharedTextureId = -1;
67
68 // set default values
69 m_properties = {};
70 m_parameters = {};
71
72 m_dirty = NotDirty;
73}
74
75void Texture::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
76{
77 BackendNode::syncFromFrontEnd(frontEnd, firstTime);
78 const QAbstractTexture *node = qobject_cast<const QAbstractTexture *>(object: frontEnd);
79 if (!node)
80 return;
81
82 TextureProperties p = m_properties;
83 p.width = node->width();
84 p.height = node->height();
85 p.depth = node->depth();
86 p.format = node->format();
87 p.target = node->target();
88 p.generateMipMaps = node->generateMipMaps();
89 p.layers = node->layers();
90 p.samples = node->samples();
91 p.mipLevels = node->mipLevels();
92 if (p != m_properties) {
93 m_properties = p;
94 addDirtyFlag(flags: DirtyProperties);
95 }
96
97 TextureParameters q = m_parameters;
98 q.magnificationFilter = node->magnificationFilter();
99 q.minificationFilter = node->minificationFilter();
100 q.wrapModeX = const_cast<QAbstractTexture *>(node)->wrapMode()->x();
101 q.wrapModeY = const_cast<QAbstractTexture *>(node)->wrapMode()->y();
102 q.wrapModeZ = const_cast<QAbstractTexture *>(node)->wrapMode()->z();
103 q.maximumAnisotropy = node->maximumAnisotropy();
104 q.comparisonFunction = node->comparisonFunction();
105 q.comparisonMode = node->comparisonMode();
106 if (q != m_parameters) {
107 m_parameters = q;
108 addDirtyFlag(flags: DirtyParameters);
109 }
110
111 QAbstractTexturePrivate *dnode = static_cast<QAbstractTexturePrivate *>(QAbstractTexturePrivate::get(q: const_cast<QAbstractTexture *>(node)));
112 auto newGenerator = dnode->dataFunctor();
113 if (newGenerator != m_dataFunctor) {
114 setDataGenerator(newGenerator);
115 QAbstractTexturePrivate *dTexture = static_cast<QAbstractTexturePrivate *>(QNodePrivate::get(q: const_cast<QNode *>(frontEnd)));
116 dTexture->setStatus(QAbstractTexture::Loading);
117 }
118
119 if (dnode) {
120 for (const QTextureDataUpdate &pendingUpdate : dnode->m_pendingDataUpdates)
121 addTextureDataUpdate(update: pendingUpdate);
122 dnode->m_pendingDataUpdates.clear();
123
124 auto ids = Qt3DCore::qIdsForNodes(nodes: dnode->m_textureImages);
125 std::sort(first: std::begin(cont&: ids), last: std::end(cont&: ids));
126 if (ids != m_textureImageIds) {
127 m_textureImageIds = ids;
128 addDirtyFlag(flags: DirtyImageGenerators);
129 }
130
131 if (dnode->m_sharedTextureId != m_sharedTextureId) {
132 m_sharedTextureId = dnode->m_sharedTextureId;
133 addDirtyFlag(flags: DirtySharedTextureId);
134 }
135 }
136}
137
138// Called by syncFromFrontend or TextureDownloadRequest (both in AspectThread context)
139void Texture::setDataGenerator(const QTextureGeneratorPtr &generator)
140{
141 m_dataFunctor = generator;
142 addDirtyFlag(flags: DirtyDataGenerator);
143}
144
145bool Texture::isValid(TextureImageManager *manager) const
146{
147 for (const QNodeId &id : m_textureImageIds) {
148 TextureImage *img = manager->lookupResource(id);
149 if (img == nullptr)
150 return false;
151 }
152 return true;
153}
154
155void Texture::addTextureDataUpdate(const QTextureDataUpdate &update)
156{
157 m_pendingTextureDataUpdates.push_back(x: update);
158 addDirtyFlag(flags: DirtyPendingDataUpdates);
159}
160
161
162TextureFunctor::TextureFunctor(AbstractRenderer *renderer,
163 TextureManager *textureNodeManager)
164 : m_renderer(renderer)
165 , m_textureNodeManager(textureNodeManager)
166{
167}
168
169Qt3DCore::QBackendNode *TextureFunctor::create(Qt3DCore::QNodeId id) const
170{
171 Texture *backend = m_textureNodeManager->getOrCreateResource(id);
172 backend->setRenderer(m_renderer);
173 // Remove id from cleanupList if for some reason we were in the dirty list of texture
174 // (Can happen when a node destroyed is followed by a node created change
175 // in the same loop, when changing parent for instance)
176 m_textureNodeManager->removeTextureIdToCleanup(id);
177 return backend;
178}
179
180Qt3DCore::QBackendNode *TextureFunctor::get(Qt3DCore::QNodeId id) const
181{
182 return m_textureNodeManager->lookupResource(id);
183}
184
185void TextureFunctor::destroy(Qt3DCore::QNodeId id) const
186{
187 m_textureNodeManager->addTextureIdToCleanup(id);
188 // We add ourselves to the dirty list to tell the shared texture managers
189 // in the renderer that this texture has been destroyed
190 m_textureNodeManager->releaseResource(id);
191}
192
193
194} // namespace Render
195} // namespace Qt3DRender
196
197QT_END_NAMESPACE
198

source code of qt3d/src/render/texture/texture.cpp