1 /****************************************************************************
2 **
3 ** Copyright (C) 2008-2012 NVIDIA Corporation.
4 ** Copyright (C) 2019 The Qt Company Ltd.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of Qt Quick 3D.
8 **
9 ** $QT_BEGIN_LICENSE:GPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU
20 ** General Public License version 3 or (at your option) any later version
21 ** approved by the KDE Free Qt Foundation. The licenses are as published by
22 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
23 ** included in the packaging of this file. Please review the following
24 ** information to ensure the GNU General Public License requirements will
25 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
26 **
27 ** $QT_END_LICENSE$
28 **
29 ****************************************************************************/
30
31 #include <QtQuick3DRender/private/qssgrendercontext_p.h>
32 #include <QtQuick3DUtils/private/qssgutils_p.h>
33 #include <QtQuick/QSGTexture>
34
35 QT_BEGIN_NAMESPACE
36
QSSGRenderTexture2D(const QSSGRef<QSSGRenderContext> & context)37 QSSGRenderTexture2D::QSSGRenderTexture2D(const QSSGRef<QSSGRenderContext> &context)
38 : QSSGRenderTextureBase(context, QSSGRenderTextureTargetType::Texture2D), m_width(0), m_height(0)
39 {
40 }
41
QSSGRenderTexture2D(const QSSGRef<QSSGRenderContext> & context,QSGTexture * qsgTexture)42 QSSGRenderTexture2D::QSSGRenderTexture2D(const QSSGRef<QSSGRenderContext> &context, QSGTexture *qsgTexture)
43 : QSSGRenderTextureBase(context, QSSGRenderTextureTargetType::Texture2D, false),
44 m_width(qsgTexture->textureSize().width()),
45 m_height(qsgTexture->textureSize().height())
46 {
47 Q_ASSERT(!m_ownsTexture);
48 Q_ASSERT(!m_handle);
49 m_handle = reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendTextureObject>(quintptr(qsgTexture->textureId()));
50 m_texTarget = QSSGRenderTextureTargetType::Texture2D;
51
52 m_format = qsgTexture->hasAlphaChannel() ? QSSGRenderTextureFormat::RGBA8
53 : QSSGRenderTextureFormat::RGB8;
54 m_sampleCount = 1; // TODO
55 }
56
~QSSGRenderTexture2D()57 QSSGRenderTexture2D::~QSSGRenderTexture2D()
58 {
59 }
60
textureDetails() const61 QSSGTextureDetails QSSGRenderTexture2D::textureDetails() const
62 {
63 return QSSGTextureDetails(m_width, m_height, 0, m_sampleCount, m_format);
64 }
65
setTextureData(QSSGByteView newBuffer,quint8 inMipLevel,qint32 width,qint32 height,QSSGRenderTextureFormat format,QSSGRenderTextureFormat formatDest)66 void QSSGRenderTexture2D::setTextureData(QSSGByteView newBuffer,
67 quint8 inMipLevel,
68 qint32 width,
69 qint32 height,
70 QSSGRenderTextureFormat format,
71 QSSGRenderTextureFormat formatDest)
72 {
73 Q_ASSERT(m_handle);
74
75 // check if we should compress this texture
76
77 if (inMipLevel == 0) {
78 m_width = width;
79 m_height = height;
80 m_format = format;
81
82 // We re-use textures and this might have been a MSAA texture before
83 // for resue we must completely destroy the texture object and create a new one
84 // The same is true for immutable textures
85 if (m_texTarget == QSSGRenderTextureTargetType::Texture2D_MS || m_immutable) {
86 m_backend->releaseTexture(m_handle);
87 m_texTarget = QSSGRenderTextureTargetType::Texture2D;
88 m_sampleCount = 1;
89 m_handle = m_backend->createTexture();
90 }
91
92 if (formatDest.isCompressedTextureFormat()) {
93 bool compress = format.isUncompressedTextureFormat();
94 bool appropriateSizes = !((width % 4) || (height % 4));
95
96 // we only compress multiple of 4 textures
97 if (compress && !appropriateSizes)
98 compress = false;
99
100 if (compress) {
101 // This seems like a very dubious line here. If we are compressing then the
102 // image
103 // is really 1/4 the width and height? - CN
104 m_width = width / 4;
105 m_height = height / 4;
106 m_format = formatDest;
107 }
108 } else if (formatDest.isUncompressedTextureFormat()) {
109 m_format = formatDest;
110 }
111 }
112
113 if (m_maxMipLevel < inMipLevel) {
114 m_maxMipLevel = inMipLevel;
115 }
116
117 // get max size and check value
118 qint32 maxWidth, maxHeight;
119 m_context->maxTextureSize(maxWidth, maxHeight);
120 if (width > maxWidth || height > maxHeight) {
121 qCCritical(RENDER_INVALID_OPERATION, "Width or height is greater than max texture size (%d, %d)", maxWidth, maxHeight);
122 }
123 if (format.isUncompressedTextureFormat() || format.isDepthTextureFormat()) {
124 m_backend->setTextureData2D(m_handle,
125 m_texTarget,
126 inMipLevel,
127 m_format,
128 width,
129 height,
130 0,
131 format,
132 newBuffer);
133 } else if (format.isCompressedTextureFormat()) {
134 m_backend->setCompressedTextureData2D(m_handle,
135 m_texTarget,
136 inMipLevel,
137 format,
138 width,
139 height,
140 0,
141 newBuffer);
142 }
143 // Set our texture parameters to a default that will look the best
144 if (inMipLevel > 0)
145 setMinFilter(QSSGRenderTextureMinifyingOp::LinearMipmapLinear);
146 }
147
setTextureStorage(qint32 inLevels,qint32 width,qint32 height,QSSGRenderTextureFormat formaInternal,QSSGRenderTextureFormat format,QSSGByteView dataBuffer)148 void QSSGRenderTexture2D::setTextureStorage(qint32 inLevels,
149 qint32 width,
150 qint32 height,
151 QSSGRenderTextureFormat formaInternal,
152 QSSGRenderTextureFormat format,
153 QSSGByteView dataBuffer)
154 {
155 Q_ASSERT(m_handle);
156
157 if (!m_context->supportsShaderImageLoadStore()) {
158 qCCritical(RENDER_INVALID_OPERATION, "The extension Shader_Image_Load_Store is not supported");
159 return;
160 }
161
162 m_width = width;
163 m_height = height;
164 m_format = formaInternal;
165 if (format == QSSGRenderTextureFormat::Unknown)
166 format = formaInternal;
167
168 // get max size and check value
169 qint32 maxWidth, maxHeight;
170 m_context->maxTextureSize(maxWidth, maxHeight);
171 if (width > maxWidth || height > maxHeight) {
172 qCCritical(RENDER_INVALID_OPERATION, "Width or height is greater than max texture size (%d, %d)", maxWidth, maxHeight);
173 }
174
175 if (inLevels < 1) {
176 qCCritical(RENDER_INVALID_PARAMETER, "inLevels is less than 1 (%d)", inLevels);
177 }
178
179 m_maxMipLevel = inLevels - 1; // we count from 0
180
181 // only uncompressed formats are supported and no depth
182 if (formaInternal.isUncompressedTextureFormat()) {
183 m_backend->createTextureStorage2D(m_handle, m_texTarget, inLevels, formaInternal, width, height);
184
185 m_immutable = true;
186 m_texTarget = QSSGRenderTextureTargetType::Texture2D;
187
188 if (dataBuffer.size() > 0)
189 m_backend->setTextureSubData2D(m_handle, m_texTarget, 0, 0, 0, width, height, format, dataBuffer);
190
191 if (inLevels > 1)
192 setMinFilter(QSSGRenderTextureMinifyingOp::LinearMipmapLinear);
193 }
194 }
195
setTextureDataMultisample(qint32 sampleCount,qint32 width,qint32 height,QSSGRenderTextureFormat format)196 void QSSGRenderTexture2D::setTextureDataMultisample(qint32 sampleCount,
197 qint32 width,
198 qint32 height,
199 QSSGRenderTextureFormat format)
200 {
201 Q_ASSERT(m_handle);
202 Q_ASSERT(m_maxMipLevel == 0);
203
204 m_texTarget = QSSGRenderTextureTargetType::Texture2D_MS;
205
206 qint32 maxWidth, maxHeight;
207 m_context->maxTextureSize(maxWidth, maxHeight);
208 if (width > maxWidth || height > maxHeight) {
209 qCCritical(RENDER_INVALID_OPERATION, "Width or height is greater than max texture size (%d, %d)", maxWidth, maxHeight);
210 }
211
212 Q_ASSERT(format.isUncompressedTextureFormat()
213 || format.isDepthTextureFormat());
214
215 m_backend->setMultisampledTextureData2D(m_handle, m_texTarget, sampleCount, format, width, height, true);
216
217 m_width = width;
218 m_height = height;
219 m_sampleCount = sampleCount;
220 m_format = format;
221 }
222
setTextureSubData(QSSGByteView newBuffer,quint8 inMipLevel,qint32 inXOffset,qint32 inYOffset,qint32 width,qint32 height,QSSGRenderTextureFormat format)223 void QSSGRenderTexture2D::setTextureSubData(QSSGByteView newBuffer,
224 quint8 inMipLevel,
225 qint32 inXOffset,
226 qint32 inYOffset,
227 qint32 width,
228 qint32 height,
229 QSSGRenderTextureFormat format)
230 {
231 Q_ASSERT(m_handle);
232 Q_ASSERT(inXOffset >= 0 && inYOffset >= 0 && width >= 0 && height >= 0);
233
234 if (!format.isUncompressedTextureFormat()) {
235 qCCritical(RENDER_INVALID_PARAMETER, "Cannot set sub data for depth or compressed formats");
236 Q_ASSERT(false);
237 return;
238 }
239 qint32 subRectStride = width * format.getSizeofFormat();
240 if (qint32(newBuffer.size()) < subRectStride * height) {
241 qCCritical(RENDER_INVALID_PARAMETER, "Invalid sub rect buffer size");
242 Q_ASSERT(false);
243 return;
244 }
245 // nop
246 if (width == 0 || height == 0)
247 return;
248
249 if (inXOffset + width > m_width || inYOffset + height > m_height) {
250 qCCritical(RENDER_INVALID_PARAMETER, "Sub rect outside existing image bounds");
251 Q_ASSERT(false);
252 return;
253 }
254
255 // not handled yet
256 Q_ASSERT(!format.isDepthTextureFormat());
257
258 m_backend->setTextureSubData2D(m_handle,
259 m_texTarget,
260 inMipLevel,
261 inXOffset,
262 inYOffset,
263 width,
264 height,
265 format,
266 newBuffer);
267 }
268
generateMipmaps(QSSGRenderHint genType)269 void QSSGRenderTexture2D::generateMipmaps(QSSGRenderHint genType)
270 {
271 applyTexParams();
272 m_backend->generateMipMaps(m_handle, m_texTarget, genType);
273 qint32 maxDim = (m_width >= m_height) ? m_width : m_height;
274 m_maxMipLevel = qint32(float(std::log(maxDim)) / std::log(2.0f));
275 // we never create more level than m_maxLevel
276 m_maxMipLevel = qMin(m_maxMipLevel, m_maxLevel);
277 }
278
bind()279 void QSSGRenderTexture2D::bind()
280 {
281 m_textureUnit = m_context->nextTextureUnit();
282
283 m_backend->bindTexture(m_handle, m_texTarget, m_textureUnit);
284
285 applyTexParams();
286 applyTexSwizzle();
287 }
288
289 QT_END_NAMESPACE
290