1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt Gui module
7 **
8 ** $QT_BEGIN_LICENSE:LGPL3$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or later as published by the Free
28 ** Software Foundation and appearing in the file LICENSE.GPL included in
29 ** the packaging of this file. Please review the following information to
30 ** ensure the GNU General Public License version 2.0 requirements will be
31 ** met: http://www.gnu.org/licenses/gpl-2.0.html.
32 **
33 ** $QT_END_LICENSE$
34 **
35 ****************************************************************************/
36 
37 #include "qrhinull_p_p.h"
38 #include <qmath.h>
39 #include <QPainter>
40 
41 QT_BEGIN_NAMESPACE
42 
43 /*!
44     \class QRhiNullInitParams
45     \internal
46     \inmodule QtGui
47     \brief Null backend specific initialization parameters.
48 
49     A Null QRhi needs no special parameters for initialization.
50 
51     \badcode
52         QRhiNullInitParams params;
53         rhi = QRhi::create(QRhi::Null, &params);
54     \endcode
55 
56     The Null backend does not issue any graphics calls and creates no
57     resources. All QRhi operations will succeed as normal so applications can
58     still be run, albeit potentially at an unthrottled speed, depending on
59     their frame rendering strategy. The backend reports resources to
60     QRhiProfiler as usual.
61  */
62 
63 /*!
64     \class QRhiNullNativeHandles
65     \internal
66     \inmodule QtGui
67     \brief Empty.
68  */
69 
QRhiNull(QRhiNullInitParams * params)70 QRhiNull::QRhiNull(QRhiNullInitParams *params)
71     : offscreenCommandBuffer(this)
72 {
73     Q_UNUSED(params);
74 }
75 
create(QRhi::Flags flags)76 bool QRhiNull::create(QRhi::Flags flags)
77 {
78     Q_UNUSED(flags);
79     return true;
80 }
81 
destroy()82 void QRhiNull::destroy()
83 {
84 }
85 
supportedSampleCounts() const86 QVector<int> QRhiNull::supportedSampleCounts() const
87 {
88     return { 1 };
89 }
90 
createSwapChain()91 QRhiSwapChain *QRhiNull::createSwapChain()
92 {
93     return new QNullSwapChain(this);
94 }
95 
createBuffer(QRhiBuffer::Type type,QRhiBuffer::UsageFlags usage,int size)96 QRhiBuffer *QRhiNull::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, int size)
97 {
98     return new QNullBuffer(this, type, usage, size);
99 }
100 
ubufAlignment() const101 int QRhiNull::ubufAlignment() const
102 {
103     return 256;
104 }
105 
isYUpInFramebuffer() const106 bool QRhiNull::isYUpInFramebuffer() const
107 {
108     return false;
109 }
110 
isYUpInNDC() const111 bool QRhiNull::isYUpInNDC() const
112 {
113     return true;
114 }
115 
isClipDepthZeroToOne() const116 bool QRhiNull::isClipDepthZeroToOne() const
117 {
118     return true;
119 }
120 
clipSpaceCorrMatrix() const121 QMatrix4x4 QRhiNull::clipSpaceCorrMatrix() const
122 {
123     return QMatrix4x4(); // identity
124 }
125 
isTextureFormatSupported(QRhiTexture::Format format,QRhiTexture::Flags flags) const126 bool QRhiNull::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const
127 {
128     Q_UNUSED(format);
129     Q_UNUSED(flags);
130     return true;
131 }
132 
isFeatureSupported(QRhi::Feature feature) const133 bool QRhiNull::isFeatureSupported(QRhi::Feature feature) const
134 {
135     Q_UNUSED(feature);
136     return true;
137 }
138 
resourceLimit(QRhi::ResourceLimit limit) const139 int QRhiNull::resourceLimit(QRhi::ResourceLimit limit) const
140 {
141     switch (limit) {
142     case QRhi::TextureSizeMin:
143         return 1;
144     case QRhi::TextureSizeMax:
145         return 16384;
146     case QRhi::MaxColorAttachments:
147         return 8;
148     case QRhi::FramesInFlight:
149         return 1;
150     case QRhi::MaxAsyncReadbackFrames:
151         return 1;
152     default:
153         Q_UNREACHABLE();
154         return 0;
155     }
156 }
157 
nativeHandles()158 const QRhiNativeHandles *QRhiNull::nativeHandles()
159 {
160     return &nativeHandlesStruct;
161 }
162 
sendVMemStatsToProfiler()163 void QRhiNull::sendVMemStatsToProfiler()
164 {
165     // nothing to do here
166 }
167 
makeThreadLocalNativeContextCurrent()168 bool QRhiNull::makeThreadLocalNativeContextCurrent()
169 {
170     // not applicable
171     return false;
172 }
173 
releaseCachedResources()174 void QRhiNull::releaseCachedResources()
175 {
176     // nothing to do here
177 }
178 
isDeviceLost() const179 bool QRhiNull::isDeviceLost() const
180 {
181     return false;
182 }
183 
createRenderBuffer(QRhiRenderBuffer::Type type,const QSize & pixelSize,int sampleCount,QRhiRenderBuffer::Flags flags)184 QRhiRenderBuffer *QRhiNull::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
185                                                int sampleCount, QRhiRenderBuffer::Flags flags)
186 {
187     return new QNullRenderBuffer(this, type, pixelSize, sampleCount, flags);
188 }
189 
createTexture(QRhiTexture::Format format,const QSize & pixelSize,int sampleCount,QRhiTexture::Flags flags)190 QRhiTexture *QRhiNull::createTexture(QRhiTexture::Format format, const QSize &pixelSize,
191                                      int sampleCount, QRhiTexture::Flags flags)
192 {
193     return new QNullTexture(this, format, pixelSize, sampleCount, flags);
194 }
195 
createSampler(QRhiSampler::Filter magFilter,QRhiSampler::Filter minFilter,QRhiSampler::Filter mipmapMode,QRhiSampler::AddressMode u,QRhiSampler::AddressMode v,QRhiSampler::AddressMode w)196 QRhiSampler *QRhiNull::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
197                                      QRhiSampler::Filter mipmapMode,
198                                      QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
199 {
200     return new QNullSampler(this, magFilter, minFilter, mipmapMode, u, v, w);
201 }
202 
createTextureRenderTarget(const QRhiTextureRenderTargetDescription & desc,QRhiTextureRenderTarget::Flags flags)203 QRhiTextureRenderTarget *QRhiNull::createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
204                                                              QRhiTextureRenderTarget::Flags flags)
205 {
206     return new QNullTextureRenderTarget(this, desc, flags);
207 }
208 
createGraphicsPipeline()209 QRhiGraphicsPipeline *QRhiNull::createGraphicsPipeline()
210 {
211     return new QNullGraphicsPipeline(this);
212 }
213 
createComputePipeline()214 QRhiComputePipeline *QRhiNull::createComputePipeline()
215 {
216     return new QNullComputePipeline(this);
217 }
218 
createShaderResourceBindings()219 QRhiShaderResourceBindings *QRhiNull::createShaderResourceBindings()
220 {
221     return new QNullShaderResourceBindings(this);
222 }
223 
setGraphicsPipeline(QRhiCommandBuffer * cb,QRhiGraphicsPipeline * ps)224 void QRhiNull::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
225 {
226     Q_UNUSED(cb);
227     Q_UNUSED(ps);
228 }
229 
setShaderResources(QRhiCommandBuffer * cb,QRhiShaderResourceBindings * srb,int dynamicOffsetCount,const QRhiCommandBuffer::DynamicOffset * dynamicOffsets)230 void QRhiNull::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
231                                   int dynamicOffsetCount,
232                                   const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
233 {
234     Q_UNUSED(cb);
235     Q_UNUSED(srb);
236     Q_UNUSED(dynamicOffsetCount);
237     Q_UNUSED(dynamicOffsets);
238 }
239 
setVertexInput(QRhiCommandBuffer * cb,int startBinding,int bindingCount,const QRhiCommandBuffer::VertexInput * bindings,QRhiBuffer * indexBuf,quint32 indexOffset,QRhiCommandBuffer::IndexFormat indexFormat)240 void QRhiNull::setVertexInput(QRhiCommandBuffer *cb,
241                               int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
242                               QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
243 {
244     Q_UNUSED(cb);
245     Q_UNUSED(startBinding);
246     Q_UNUSED(bindingCount);
247     Q_UNUSED(bindings);
248     Q_UNUSED(indexBuf);
249     Q_UNUSED(indexOffset);
250     Q_UNUSED(indexFormat);
251 }
252 
setViewport(QRhiCommandBuffer * cb,const QRhiViewport & viewport)253 void QRhiNull::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
254 {
255     Q_UNUSED(cb);
256     Q_UNUSED(viewport);
257 }
258 
setScissor(QRhiCommandBuffer * cb,const QRhiScissor & scissor)259 void QRhiNull::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
260 {
261     Q_UNUSED(cb);
262     Q_UNUSED(scissor);
263 }
264 
setBlendConstants(QRhiCommandBuffer * cb,const QColor & c)265 void QRhiNull::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c)
266 {
267     Q_UNUSED(cb);
268     Q_UNUSED(c);
269 }
270 
setStencilRef(QRhiCommandBuffer * cb,quint32 refValue)271 void QRhiNull::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
272 {
273     Q_UNUSED(cb);
274     Q_UNUSED(refValue);
275 }
276 
draw(QRhiCommandBuffer * cb,quint32 vertexCount,quint32 instanceCount,quint32 firstVertex,quint32 firstInstance)277 void QRhiNull::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
278                     quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
279 {
280     Q_UNUSED(cb);
281     Q_UNUSED(vertexCount);
282     Q_UNUSED(instanceCount);
283     Q_UNUSED(firstVertex);
284     Q_UNUSED(firstInstance);
285 }
286 
drawIndexed(QRhiCommandBuffer * cb,quint32 indexCount,quint32 instanceCount,quint32 firstIndex,qint32 vertexOffset,quint32 firstInstance)287 void QRhiNull::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
288                            quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
289 {
290     Q_UNUSED(cb);
291     Q_UNUSED(indexCount);
292     Q_UNUSED(instanceCount);
293     Q_UNUSED(firstIndex);
294     Q_UNUSED(vertexOffset);
295     Q_UNUSED(firstInstance);
296 }
297 
debugMarkBegin(QRhiCommandBuffer * cb,const QByteArray & name)298 void QRhiNull::debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name)
299 {
300     Q_UNUSED(cb);
301     Q_UNUSED(name);
302 }
303 
debugMarkEnd(QRhiCommandBuffer * cb)304 void QRhiNull::debugMarkEnd(QRhiCommandBuffer *cb)
305 {
306     Q_UNUSED(cb);
307 }
308 
debugMarkMsg(QRhiCommandBuffer * cb,const QByteArray & msg)309 void QRhiNull::debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg)
310 {
311     Q_UNUSED(cb);
312     Q_UNUSED(msg);
313 }
314 
setComputePipeline(QRhiCommandBuffer * cb,QRhiComputePipeline * ps)315 void QRhiNull::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
316 {
317     Q_UNUSED(cb);
318     Q_UNUSED(ps);
319 }
320 
dispatch(QRhiCommandBuffer * cb,int x,int y,int z)321 void QRhiNull::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
322 {
323     Q_UNUSED(cb);
324     Q_UNUSED(x);
325     Q_UNUSED(y);
326     Q_UNUSED(z);
327 }
328 
nativeHandles(QRhiCommandBuffer * cb)329 const QRhiNativeHandles *QRhiNull::nativeHandles(QRhiCommandBuffer *cb)
330 {
331     Q_UNUSED(cb);
332     return nullptr;
333 }
334 
beginExternal(QRhiCommandBuffer * cb)335 void QRhiNull::beginExternal(QRhiCommandBuffer *cb)
336 {
337     Q_UNUSED(cb);
338 }
339 
endExternal(QRhiCommandBuffer * cb)340 void QRhiNull::endExternal(QRhiCommandBuffer *cb)
341 {
342     Q_UNUSED(cb);
343 }
344 
beginFrame(QRhiSwapChain * swapChain,QRhi::BeginFrameFlags flags)345 QRhi::FrameOpResult QRhiNull::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
346 {
347     Q_UNUSED(flags);
348     currentSwapChain = swapChain;
349     QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
350     QRHI_PROF_F(beginSwapChainFrame(swapChain));
351     return QRhi::FrameOpSuccess;
352 }
353 
endFrame(QRhiSwapChain * swapChain,QRhi::EndFrameFlags flags)354 QRhi::FrameOpResult QRhiNull::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
355 {
356     Q_UNUSED(flags);
357     QNullSwapChain *swapChainD = QRHI_RES(QNullSwapChain, swapChain);
358     QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
359     QRHI_PROF_F(endSwapChainFrame(swapChain, swapChainD->frameCount + 1));
360     QRHI_PROF_F(swapChainFrameGpuTime(swapChain, 0.000666f));
361     swapChainD->frameCount += 1;
362     currentSwapChain = nullptr;
363     return QRhi::FrameOpSuccess;
364 }
365 
beginOffscreenFrame(QRhiCommandBuffer ** cb,QRhi::BeginFrameFlags flags)366 QRhi::FrameOpResult QRhiNull::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags)
367 {
368     Q_UNUSED(flags);
369     *cb = &offscreenCommandBuffer;
370     return QRhi::FrameOpSuccess;
371 }
372 
endOffscreenFrame(QRhi::EndFrameFlags flags)373 QRhi::FrameOpResult QRhiNull::endOffscreenFrame(QRhi::EndFrameFlags flags)
374 {
375     Q_UNUSED(flags);
376     return QRhi::FrameOpSuccess;
377 }
378 
finish()379 QRhi::FrameOpResult QRhiNull::finish()
380 {
381     return QRhi::FrameOpSuccess;
382 }
383 
simulateTextureUpload(const QRhiResourceUpdateBatchPrivate::TextureOp & u)384 void QRhiNull::simulateTextureUpload(const QRhiResourceUpdateBatchPrivate::TextureOp &u)
385 {
386     QNullTexture *texD = QRHI_RES(QNullTexture, u.dst);
387     for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
388         for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
389             for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.subresDesc[layer][level])) {
390                 if (!subresDesc.image().isNull()) {
391                     const QImage src = subresDesc.image();
392                     QPainter painter(&texD->image[layer][level]);
393                     const QSize srcSize = subresDesc.sourceSize().isEmpty()
394                             ? src.size() : subresDesc.sourceSize();
395                     painter.setCompositionMode(QPainter::CompositionMode_Source);
396                     painter.drawImage(subresDesc.destinationTopLeft(), src,
397                                       QRect(subresDesc.sourceTopLeft(), srcSize));
398                 } else if (!subresDesc.data().isEmpty()) {
399                     const QSize subresSize = q->sizeForMipLevel(level, texD->pixelSize());
400                     int w = subresSize.width();
401                     int h = subresSize.height();
402                     if (!subresDesc.sourceSize().isEmpty()) {
403                         w = subresDesc.sourceSize().width();
404                         h = subresDesc.sourceSize().height();
405                     }
406                     // sourceTopLeft is not supported on this path as per QRhi docs
407                     const char *src = subresDesc.data().constData();
408                     const int srcBpl = w * 4;
409                     const QPoint dstOffset = subresDesc.destinationTopLeft();
410                     uchar *dst = texD->image[layer][level].bits();
411                     const int dstBpl = texD->image[layer][level].bytesPerLine();
412                     for (int y = 0; y < h; ++y) {
413                         memcpy(dst + dstOffset.x() * 4 + (y + dstOffset.y()) * dstBpl,
414                                src + y * srcBpl,
415                                size_t(srcBpl));
416                     }
417                 }
418             }
419         }
420     }
421 }
422 
simulateTextureCopy(const QRhiResourceUpdateBatchPrivate::TextureOp & u)423 void QRhiNull::simulateTextureCopy(const QRhiResourceUpdateBatchPrivate::TextureOp &u)
424 {
425     QNullTexture *srcD = QRHI_RES(QNullTexture, u.src);
426     QNullTexture *dstD = QRHI_RES(QNullTexture, u.dst);
427     const QImage &srcImage(srcD->image[u.desc.sourceLayer()][u.desc.sourceLevel()]);
428     QImage &dstImage(dstD->image[u.desc.destinationLayer()][u.desc.destinationLevel()]);
429     const QPoint dstPos = u.desc.destinationTopLeft();
430     const QSize size = u.desc.pixelSize().isEmpty() ? srcD->pixelSize() : u.desc.pixelSize();
431     const QPoint srcPos = u.desc.sourceTopLeft();
432 
433     QPainter painter(&dstImage);
434     painter.setCompositionMode(QPainter::CompositionMode_Source);
435     painter.drawImage(QRect(dstPos, size), srcImage, QRect(srcPos, size));
436 }
437 
simulateTextureGenMips(const QRhiResourceUpdateBatchPrivate::TextureOp & u)438 void QRhiNull::simulateTextureGenMips(const QRhiResourceUpdateBatchPrivate::TextureOp &u)
439 {
440     QNullTexture *texD = QRHI_RES(QNullTexture, u.dst);
441     const QSize baseSize = texD->pixelSize();
442     const int levelCount = q->mipLevelsForSize(baseSize);
443     for (int level = 1; level < levelCount; ++level)
444         texD->image[0][level] = texD->image[0][0].scaled(q->sizeForMipLevel(level, baseSize));
445 }
446 
resourceUpdate(QRhiCommandBuffer * cb,QRhiResourceUpdateBatch * resourceUpdates)447 void QRhiNull::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
448 {
449     Q_UNUSED(cb);
450     QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
451     for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) {
452         if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate
453                 || u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload)
454         {
455             QNullBuffer *bufD = QRHI_RES(QNullBuffer, u.buf);
456             memcpy(bufD->data.data() + u.offset, u.data.constData(), size_t(u.data.size()));
457         } else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
458             QRhiBufferReadbackResult *result = u.result;
459             result->data.resize(u.readSize);
460             QNullBuffer *bufD = QRHI_RES(QNullBuffer, u.buf);
461             memcpy(result->data.data(), bufD->data.constData() + u.offset, size_t(u.readSize));
462             if (result->completed)
463                 result->completed();
464         }
465     }
466     for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
467         if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
468             if (u.dst->format() == QRhiTexture::RGBA8)
469                 simulateTextureUpload(u);
470         } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
471             if (u.src->format() == QRhiTexture::RGBA8 && u.dst->format() == QRhiTexture::RGBA8)
472                 simulateTextureCopy(u);
473         } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
474             QRhiReadbackResult *result = u.result;
475             QNullTexture *texD = QRHI_RES(QNullTexture, u.rb.texture());
476             if (texD) {
477                 result->format = texD->format();
478                 result->pixelSize = q->sizeForMipLevel(u.rb.level(), texD->pixelSize());
479             } else {
480                 Q_ASSERT(currentSwapChain);
481                 result->format = QRhiTexture::RGBA8;
482                 result->pixelSize = currentSwapChain->currentPixelSize();
483             }
484             quint32 bytesPerLine = 0;
485             quint32 byteSize = 0;
486             textureFormatInfo(result->format, result->pixelSize, &bytesPerLine, &byteSize);
487             if (texD && texD->format() == QRhiTexture::RGBA8) {
488                 result->data.resize(int(byteSize));
489                 const QImage &src(texD->image[u.rb.layer()][u.rb.level()]);
490                 char *dst = result->data.data();
491                 for (int y = 0, h = src.height(); y < h; ++y) {
492                     memcpy(dst, src.constScanLine(y), bytesPerLine);
493                     dst += bytesPerLine;
494                 }
495             } else {
496                 result->data.fill(0, int(byteSize));
497             }
498             if (result->completed)
499                 result->completed();
500         } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
501             if (u.dst->format() == QRhiTexture::RGBA8)
502                 simulateTextureGenMips(u);
503         }
504     }
505     ud->free();
506 }
507 
beginPass(QRhiCommandBuffer * cb,QRhiRenderTarget * rt,const QColor & colorClearValue,const QRhiDepthStencilClearValue & depthStencilClearValue,QRhiResourceUpdateBatch * resourceUpdates)508 void QRhiNull::beginPass(QRhiCommandBuffer *cb,
509                          QRhiRenderTarget *rt,
510                          const QColor &colorClearValue,
511                          const QRhiDepthStencilClearValue &depthStencilClearValue,
512                          QRhiResourceUpdateBatch *resourceUpdates)
513 {
514     Q_UNUSED(rt);
515     Q_UNUSED(colorClearValue);
516     Q_UNUSED(depthStencilClearValue);
517     if (resourceUpdates)
518         resourceUpdate(cb, resourceUpdates);
519 }
520 
endPass(QRhiCommandBuffer * cb,QRhiResourceUpdateBatch * resourceUpdates)521 void QRhiNull::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
522 {
523     if (resourceUpdates)
524         resourceUpdate(cb, resourceUpdates);
525 }
526 
beginComputePass(QRhiCommandBuffer * cb,QRhiResourceUpdateBatch * resourceUpdates)527 void QRhiNull::beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
528 {
529     if (resourceUpdates)
530         resourceUpdate(cb, resourceUpdates);
531 }
532 
endComputePass(QRhiCommandBuffer * cb,QRhiResourceUpdateBatch * resourceUpdates)533 void QRhiNull::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
534 {
535     if (resourceUpdates)
536         resourceUpdate(cb, resourceUpdates);
537 }
538 
QNullBuffer(QRhiImplementation * rhi,Type type,UsageFlags usage,int size)539 QNullBuffer::QNullBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size)
540     : QRhiBuffer(rhi, type, usage, size)
541 {
542 }
543 
~QNullBuffer()544 QNullBuffer::~QNullBuffer()
545 {
546     release();
547 }
548 
release()549 void QNullBuffer::release()
550 {
551     data.clear();
552 
553     QRHI_PROF;
554     QRHI_PROF_F(releaseBuffer(this));
555 }
556 
build()557 bool QNullBuffer::build()
558 {
559     data.fill('\0', m_size);
560 
561     QRHI_PROF;
562     QRHI_PROF_F(newBuffer(this, uint(m_size), 1, 0));
563     return true;
564 }
565 
QNullRenderBuffer(QRhiImplementation * rhi,Type type,const QSize & pixelSize,int sampleCount,QRhiRenderBuffer::Flags flags)566 QNullRenderBuffer::QNullRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
567                                      int sampleCount, QRhiRenderBuffer::Flags flags)
568     : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags)
569 {
570 }
571 
~QNullRenderBuffer()572 QNullRenderBuffer::~QNullRenderBuffer()
573 {
574     release();
575 }
576 
release()577 void QNullRenderBuffer::release()
578 {
579     QRHI_PROF;
580     QRHI_PROF_F(releaseRenderBuffer(this));
581 }
582 
build()583 bool QNullRenderBuffer::build()
584 {
585     QRHI_PROF;
586     QRHI_PROF_F(newRenderBuffer(this, false, false, 1));
587     return true;
588 }
589 
backingFormat() const590 QRhiTexture::Format QNullRenderBuffer::backingFormat() const
591 {
592     return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
593 }
594 
QNullTexture(QRhiImplementation * rhi,Format format,const QSize & pixelSize,int sampleCount,Flags flags)595 QNullTexture::QNullTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize,
596                            int sampleCount, Flags flags)
597     : QRhiTexture(rhi, format, pixelSize, sampleCount, flags)
598 {
599 }
600 
~QNullTexture()601 QNullTexture::~QNullTexture()
602 {
603     release();
604 }
605 
release()606 void QNullTexture::release()
607 {
608     QRHI_PROF;
609     QRHI_PROF_F(releaseTexture(this));
610 }
611 
build()612 bool QNullTexture::build()
613 {
614     QRHI_RES_RHI(QRhiNull);
615     const bool isCube = m_flags.testFlag(CubeMap);
616     const bool hasMipMaps = m_flags.testFlag(MipMapped);
617     QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
618     const int mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1;
619     const int layerCount = isCube ? 6 : 1;
620 
621     if (m_format == RGBA8) {
622         for (int layer = 0; layer < layerCount; ++layer) {
623             for (int level = 0; level < mipLevelCount; ++level) {
624                 image[layer][level] = QImage(rhiD->q->sizeForMipLevel(level, size),
625                                              QImage::Format_RGBA8888_Premultiplied);
626                 image[layer][level].fill(Qt::yellow);
627             }
628         }
629     }
630 
631     QRHI_PROF;
632     QRHI_PROF_F(newTexture(this, true, mipLevelCount, layerCount, 1));
633     return true;
634 }
635 
buildFrom(QRhiTexture::NativeTexture src)636 bool QNullTexture::buildFrom(QRhiTexture::NativeTexture src)
637 {
638     Q_UNUSED(src)
639     QRHI_RES_RHI(QRhiNull);
640     const bool isCube = m_flags.testFlag(CubeMap);
641     const bool hasMipMaps = m_flags.testFlag(MipMapped);
642     QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
643     const int mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1;
644     QRHI_PROF;
645     QRHI_PROF_F(newTexture(this, false, mipLevelCount, isCube ? 6 : 1, 1));
646     return true;
647 }
648 
QNullSampler(QRhiImplementation * rhi,Filter magFilter,Filter minFilter,Filter mipmapMode,AddressMode u,AddressMode v,AddressMode w)649 QNullSampler::QNullSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
650                            AddressMode u, AddressMode v, AddressMode w)
651     : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
652 {
653 }
654 
~QNullSampler()655 QNullSampler::~QNullSampler()
656 {
657     release();
658 }
659 
release()660 void QNullSampler::release()
661 {
662 }
663 
build()664 bool QNullSampler::build()
665 {
666     return true;
667 }
668 
QNullRenderPassDescriptor(QRhiImplementation * rhi)669 QNullRenderPassDescriptor::QNullRenderPassDescriptor(QRhiImplementation *rhi)
670     : QRhiRenderPassDescriptor(rhi)
671 {
672 }
673 
~QNullRenderPassDescriptor()674 QNullRenderPassDescriptor::~QNullRenderPassDescriptor()
675 {
676     release();
677 }
678 
release()679 void QNullRenderPassDescriptor::release()
680 {
681 }
682 
isCompatible(const QRhiRenderPassDescriptor * other) const683 bool QNullRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const
684 {
685     Q_UNUSED(other);
686     return true;
687 }
688 
QNullReferenceRenderTarget(QRhiImplementation * rhi)689 QNullReferenceRenderTarget::QNullReferenceRenderTarget(QRhiImplementation *rhi)
690     : QRhiRenderTarget(rhi),
691       d(rhi)
692 {
693 }
694 
~QNullReferenceRenderTarget()695 QNullReferenceRenderTarget::~QNullReferenceRenderTarget()
696 {
697     release();
698 }
699 
release()700 void QNullReferenceRenderTarget::release()
701 {
702 }
703 
pixelSize() const704 QSize QNullReferenceRenderTarget::pixelSize() const
705 {
706     return d.pixelSize;
707 }
708 
devicePixelRatio() const709 float QNullReferenceRenderTarget::devicePixelRatio() const
710 {
711     return d.dpr;
712 }
713 
sampleCount() const714 int QNullReferenceRenderTarget::sampleCount() const
715 {
716     return 1;
717 }
718 
QNullTextureRenderTarget(QRhiImplementation * rhi,const QRhiTextureRenderTargetDescription & desc,Flags flags)719 QNullTextureRenderTarget::QNullTextureRenderTarget(QRhiImplementation *rhi,
720                                                    const QRhiTextureRenderTargetDescription &desc,
721                                                    Flags flags)
722     : QRhiTextureRenderTarget(rhi, desc, flags),
723       d(rhi)
724 {
725 }
726 
~QNullTextureRenderTarget()727 QNullTextureRenderTarget::~QNullTextureRenderTarget()
728 {
729     release();
730 }
731 
release()732 void QNullTextureRenderTarget::release()
733 {
734 }
735 
newCompatibleRenderPassDescriptor()736 QRhiRenderPassDescriptor *QNullTextureRenderTarget::newCompatibleRenderPassDescriptor()
737 {
738     return new QNullRenderPassDescriptor(m_rhi);
739 }
740 
build()741 bool QNullTextureRenderTarget::build()
742 {
743     d.rp = QRHI_RES(QNullRenderPassDescriptor, m_renderPassDesc);
744     if (m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments()) {
745         QRhiTexture *tex = m_desc.cbeginColorAttachments()->texture();
746         QRhiRenderBuffer *rb = m_desc.cbeginColorAttachments()->renderBuffer();
747         d.pixelSize = tex ? tex->pixelSize() : rb->pixelSize();
748     } else if (m_desc.depthStencilBuffer()) {
749         d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
750     } else if (m_desc.depthTexture()) {
751         d.pixelSize = m_desc.depthTexture()->pixelSize();
752     }
753     return true;
754 }
755 
pixelSize() const756 QSize QNullTextureRenderTarget::pixelSize() const
757 {
758     return d.pixelSize;
759 }
760 
devicePixelRatio() const761 float QNullTextureRenderTarget::devicePixelRatio() const
762 {
763     return d.dpr;
764 }
765 
sampleCount() const766 int QNullTextureRenderTarget::sampleCount() const
767 {
768     return 1;
769 }
770 
QNullShaderResourceBindings(QRhiImplementation * rhi)771 QNullShaderResourceBindings::QNullShaderResourceBindings(QRhiImplementation *rhi)
772     : QRhiShaderResourceBindings(rhi)
773 {
774 }
775 
~QNullShaderResourceBindings()776 QNullShaderResourceBindings::~QNullShaderResourceBindings()
777 {
778     release();
779 }
780 
release()781 void QNullShaderResourceBindings::release()
782 {
783 }
784 
build()785 bool QNullShaderResourceBindings::build()
786 {
787     return true;
788 }
789 
QNullGraphicsPipeline(QRhiImplementation * rhi)790 QNullGraphicsPipeline::QNullGraphicsPipeline(QRhiImplementation *rhi)
791     : QRhiGraphicsPipeline(rhi)
792 {
793 }
794 
~QNullGraphicsPipeline()795 QNullGraphicsPipeline::~QNullGraphicsPipeline()
796 {
797     release();
798 }
799 
release()800 void QNullGraphicsPipeline::release()
801 {
802 }
803 
build()804 bool QNullGraphicsPipeline::build()
805 {
806     QRHI_RES_RHI(QRhiNull);
807     if (!rhiD->sanityCheckGraphicsPipeline(this))
808         return false;
809 
810     return true;
811 }
812 
QNullComputePipeline(QRhiImplementation * rhi)813 QNullComputePipeline::QNullComputePipeline(QRhiImplementation *rhi)
814     : QRhiComputePipeline(rhi)
815 {
816 }
817 
~QNullComputePipeline()818 QNullComputePipeline::~QNullComputePipeline()
819 {
820     release();
821 }
822 
release()823 void QNullComputePipeline::release()
824 {
825 }
826 
build()827 bool QNullComputePipeline::build()
828 {
829     return true;
830 }
831 
QNullCommandBuffer(QRhiImplementation * rhi)832 QNullCommandBuffer::QNullCommandBuffer(QRhiImplementation *rhi)
833     : QRhiCommandBuffer(rhi)
834 {
835 }
836 
~QNullCommandBuffer()837 QNullCommandBuffer::~QNullCommandBuffer()
838 {
839     release();
840 }
841 
release()842 void QNullCommandBuffer::release()
843 {
844     // nothing to do here
845 }
846 
QNullSwapChain(QRhiImplementation * rhi)847 QNullSwapChain::QNullSwapChain(QRhiImplementation *rhi)
848     : QRhiSwapChain(rhi),
849       rt(rhi),
850       cb(rhi)
851 {
852 }
853 
~QNullSwapChain()854 QNullSwapChain::~QNullSwapChain()
855 {
856     release();
857 }
858 
release()859 void QNullSwapChain::release()
860 {
861     QRHI_PROF;
862     QRHI_PROF_F(releaseSwapChain(this));
863 }
864 
currentFrameCommandBuffer()865 QRhiCommandBuffer *QNullSwapChain::currentFrameCommandBuffer()
866 {
867     return &cb;
868 }
869 
currentFrameRenderTarget()870 QRhiRenderTarget *QNullSwapChain::currentFrameRenderTarget()
871 {
872     return &rt;
873 }
874 
surfacePixelSize()875 QSize QNullSwapChain::surfacePixelSize()
876 {
877     return QSize(1280, 720);
878 }
879 
newCompatibleRenderPassDescriptor()880 QRhiRenderPassDescriptor *QNullSwapChain::newCompatibleRenderPassDescriptor()
881 {
882     return new QNullRenderPassDescriptor(m_rhi);
883 }
884 
buildOrResize()885 bool QNullSwapChain::buildOrResize()
886 {
887     m_currentPixelSize = surfacePixelSize();
888     rt.d.rp = QRHI_RES(QNullRenderPassDescriptor, m_renderPassDesc);
889     rt.d.pixelSize = m_currentPixelSize;
890     frameCount = 0;
891     QRHI_PROF;
892     QRHI_PROF_F(resizeSwapChain(this, 1, 0, 1));
893     return true;
894 }
895 
896 QT_END_NAMESPACE
897