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
41QT_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
70QRhiNull::QRhiNull(QRhiNullInitParams *params)
71 : offscreenCommandBuffer(this)
72{
73 Q_UNUSED(params);
74}
75
76bool QRhiNull::create(QRhi::Flags flags)
77{
78 Q_UNUSED(flags);
79 return true;
80}
81
82void QRhiNull::destroy()
83{
84}
85
86QList<int> QRhiNull::supportedSampleCounts() const
87{
88 return { 1 };
89}
90
91QRhiSwapChain *QRhiNull::createSwapChain()
92{
93 return new QNullSwapChain(this);
94}
95
96QRhiBuffer *QRhiNull::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, int size)
97{
98 return new QNullBuffer(this, type, usage, size);
99}
100
101int QRhiNull::ubufAlignment() const
102{
103 return 256;
104}
105
106bool QRhiNull::isYUpInFramebuffer() const
107{
108 return false;
109}
110
111bool QRhiNull::isYUpInNDC() const
112{
113 return true;
114}
115
116bool QRhiNull::isClipDepthZeroToOne() const
117{
118 return true;
119}
120
121QMatrix4x4 QRhiNull::clipSpaceCorrMatrix() const
122{
123 return QMatrix4x4(); // identity
124}
125
126bool QRhiNull::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const
127{
128 Q_UNUSED(format);
129 Q_UNUSED(flags);
130 return true;
131}
132
133bool QRhiNull::isFeatureSupported(QRhi::Feature feature) const
134{
135 Q_UNUSED(feature);
136 return true;
137}
138
139int 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 case QRhi::MaxThreadGroupsPerDimension:
153 return 0;
154 case QRhi::MaxThreadsPerThreadGroup:
155 return 0;
156 case QRhi::MaxThreadGroupX:
157 return 0;
158 case QRhi::MaxThreadGroupY:
159 return 0;
160 case QRhi::MaxThreadGroupZ:
161 return 0;
162 default:
163 Q_UNREACHABLE();
164 return 0;
165 }
166}
167
168const QRhiNativeHandles *QRhiNull::nativeHandles()
169{
170 return &nativeHandlesStruct;
171}
172
173void QRhiNull::sendVMemStatsToProfiler()
174{
175 // nothing to do here
176}
177
178bool QRhiNull::makeThreadLocalNativeContextCurrent()
179{
180 // not applicable
181 return false;
182}
183
184void QRhiNull::releaseCachedResources()
185{
186 // nothing to do here
187}
188
189bool QRhiNull::isDeviceLost() const
190{
191 return false;
192}
193
194QRhiRenderBuffer *QRhiNull::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
195 int sampleCount, QRhiRenderBuffer::Flags flags,
196 QRhiTexture::Format backingFormatHint)
197{
198 return new QNullRenderBuffer(this, type, pixelSize, sampleCount, flags, backingFormatHint);
199}
200
201QRhiTexture *QRhiNull::createTexture(QRhiTexture::Format format, const QSize &pixelSize,
202 int sampleCount, QRhiTexture::Flags flags)
203{
204 return new QNullTexture(this, format, pixelSize, sampleCount, flags);
205}
206
207QRhiSampler *QRhiNull::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
208 QRhiSampler::Filter mipmapMode,
209 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
210{
211 return new QNullSampler(this, magFilter, minFilter, mipmapMode, u, v, w);
212}
213
214QRhiTextureRenderTarget *QRhiNull::createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
215 QRhiTextureRenderTarget::Flags flags)
216{
217 return new QNullTextureRenderTarget(this, desc, flags);
218}
219
220QRhiGraphicsPipeline *QRhiNull::createGraphicsPipeline()
221{
222 return new QNullGraphicsPipeline(this);
223}
224
225QRhiComputePipeline *QRhiNull::createComputePipeline()
226{
227 return new QNullComputePipeline(this);
228}
229
230QRhiShaderResourceBindings *QRhiNull::createShaderResourceBindings()
231{
232 return new QNullShaderResourceBindings(this);
233}
234
235void QRhiNull::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
236{
237 Q_UNUSED(cb);
238 Q_UNUSED(ps);
239}
240
241void QRhiNull::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
242 int dynamicOffsetCount,
243 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
244{
245 Q_UNUSED(cb);
246 Q_UNUSED(srb);
247 Q_UNUSED(dynamicOffsetCount);
248 Q_UNUSED(dynamicOffsets);
249}
250
251void QRhiNull::setVertexInput(QRhiCommandBuffer *cb,
252 int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
253 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
254{
255 Q_UNUSED(cb);
256 Q_UNUSED(startBinding);
257 Q_UNUSED(bindingCount);
258 Q_UNUSED(bindings);
259 Q_UNUSED(indexBuf);
260 Q_UNUSED(indexOffset);
261 Q_UNUSED(indexFormat);
262}
263
264void QRhiNull::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
265{
266 Q_UNUSED(cb);
267 Q_UNUSED(viewport);
268}
269
270void QRhiNull::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
271{
272 Q_UNUSED(cb);
273 Q_UNUSED(scissor);
274}
275
276void QRhiNull::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c)
277{
278 Q_UNUSED(cb);
279 Q_UNUSED(c);
280}
281
282void QRhiNull::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
283{
284 Q_UNUSED(cb);
285 Q_UNUSED(refValue);
286}
287
288void QRhiNull::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
289 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
290{
291 Q_UNUSED(cb);
292 Q_UNUSED(vertexCount);
293 Q_UNUSED(instanceCount);
294 Q_UNUSED(firstVertex);
295 Q_UNUSED(firstInstance);
296}
297
298void QRhiNull::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
299 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
300{
301 Q_UNUSED(cb);
302 Q_UNUSED(indexCount);
303 Q_UNUSED(instanceCount);
304 Q_UNUSED(firstIndex);
305 Q_UNUSED(vertexOffset);
306 Q_UNUSED(firstInstance);
307}
308
309void QRhiNull::debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name)
310{
311 Q_UNUSED(cb);
312 Q_UNUSED(name);
313}
314
315void QRhiNull::debugMarkEnd(QRhiCommandBuffer *cb)
316{
317 Q_UNUSED(cb);
318}
319
320void QRhiNull::debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg)
321{
322 Q_UNUSED(cb);
323 Q_UNUSED(msg);
324}
325
326void QRhiNull::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
327{
328 Q_UNUSED(cb);
329 Q_UNUSED(ps);
330}
331
332void QRhiNull::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
333{
334 Q_UNUSED(cb);
335 Q_UNUSED(x);
336 Q_UNUSED(y);
337 Q_UNUSED(z);
338}
339
340const QRhiNativeHandles *QRhiNull::nativeHandles(QRhiCommandBuffer *cb)
341{
342 Q_UNUSED(cb);
343 return nullptr;
344}
345
346void QRhiNull::beginExternal(QRhiCommandBuffer *cb)
347{
348 Q_UNUSED(cb);
349}
350
351void QRhiNull::endExternal(QRhiCommandBuffer *cb)
352{
353 Q_UNUSED(cb);
354}
355
356QRhi::FrameOpResult QRhiNull::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
357{
358 Q_UNUSED(flags);
359 currentSwapChain = swapChain;
360 QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
361 QRHI_PROF_F(beginSwapChainFrame(swapChain));
362 return QRhi::FrameOpSuccess;
363}
364
365QRhi::FrameOpResult QRhiNull::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
366{
367 Q_UNUSED(flags);
368 QNullSwapChain *swapChainD = QRHI_RES(QNullSwapChain, swapChain);
369 QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
370 QRHI_PROF_F(endSwapChainFrame(swapChain, swapChainD->frameCount + 1));
371 QRHI_PROF_F(swapChainFrameGpuTime(swapChain, 0.000666f));
372 swapChainD->frameCount += 1;
373 currentSwapChain = nullptr;
374 return QRhi::FrameOpSuccess;
375}
376
377QRhi::FrameOpResult QRhiNull::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags)
378{
379 Q_UNUSED(flags);
380 *cb = &offscreenCommandBuffer;
381 return QRhi::FrameOpSuccess;
382}
383
384QRhi::FrameOpResult QRhiNull::endOffscreenFrame(QRhi::EndFrameFlags flags)
385{
386 Q_UNUSED(flags);
387 return QRhi::FrameOpSuccess;
388}
389
390QRhi::FrameOpResult QRhiNull::finish()
391{
392 return QRhi::FrameOpSuccess;
393}
394
395void QRhiNull::simulateTextureUpload(const QRhiResourceUpdateBatchPrivate::TextureOp &u)
396{
397 QNullTexture *texD = QRHI_RES(QNullTexture, u.dst);
398 for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
399 for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
400 for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.subresDesc[layer][level])) {
401 if (!subresDesc.image().isNull()) {
402 const QImage src = subresDesc.image();
403 QPainter painter(&texD->image[layer][level]);
404 const QSize srcSize = subresDesc.sourceSize().isEmpty()
405 ? src.size() : subresDesc.sourceSize();
406 painter.setCompositionMode(QPainter::CompositionMode_Source);
407 painter.drawImage(subresDesc.destinationTopLeft(), src,
408 QRect(subresDesc.sourceTopLeft(), srcSize));
409 } else if (!subresDesc.data().isEmpty()) {
410 const QSize subresSize = q->sizeForMipLevel(level, texD->pixelSize());
411 int w = subresSize.width();
412 int h = subresSize.height();
413 if (!subresDesc.sourceSize().isEmpty()) {
414 w = subresDesc.sourceSize().width();
415 h = subresDesc.sourceSize().height();
416 }
417 // sourceTopLeft is not supported on this path as per QRhi docs
418 const char *src = subresDesc.data().constData();
419 const int srcBpl = w * 4;
420 const QPoint dstOffset = subresDesc.destinationTopLeft();
421 uchar *dst = texD->image[layer][level].bits();
422 const int dstBpl = texD->image[layer][level].bytesPerLine();
423 for (int y = 0; y < h; ++y) {
424 memcpy(dst + dstOffset.x() * 4 + (y + dstOffset.y()) * dstBpl,
425 src + y * srcBpl,
426 size_t(srcBpl));
427 }
428 }
429 }
430 }
431 }
432}
433
434void QRhiNull::simulateTextureCopy(const QRhiResourceUpdateBatchPrivate::TextureOp &u)
435{
436 QNullTexture *srcD = QRHI_RES(QNullTexture, u.src);
437 QNullTexture *dstD = QRHI_RES(QNullTexture, u.dst);
438 const QImage &srcImage(srcD->image[u.desc.sourceLayer()][u.desc.sourceLevel()]);
439 QImage &dstImage(dstD->image[u.desc.destinationLayer()][u.desc.destinationLevel()]);
440 const QPoint dstPos = u.desc.destinationTopLeft();
441 const QSize size = u.desc.pixelSize().isEmpty() ? srcD->pixelSize() : u.desc.pixelSize();
442 const QPoint srcPos = u.desc.sourceTopLeft();
443
444 QPainter painter(&dstImage);
445 painter.setCompositionMode(QPainter::CompositionMode_Source);
446 painter.drawImage(QRect(dstPos, size), srcImage, QRect(srcPos, size));
447}
448
449void QRhiNull::simulateTextureGenMips(const QRhiResourceUpdateBatchPrivate::TextureOp &u)
450{
451 QNullTexture *texD = QRHI_RES(QNullTexture, u.dst);
452 const QSize baseSize = texD->pixelSize();
453 const int levelCount = q->mipLevelsForSize(baseSize);
454 for (int level = 1; level < levelCount; ++level)
455 texD->image[0][level] = texD->image[0][0].scaled(q->sizeForMipLevel(level, baseSize));
456}
457
458void QRhiNull::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
459{
460 Q_UNUSED(cb);
461 QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
462 for (int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
463 const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
464 if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate
465 || u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload)
466 {
467 QNullBuffer *bufD = QRHI_RES(QNullBuffer, u.buf);
468 memcpy(bufD->data + u.offset, u.data.constData(), size_t(u.data.size()));
469 } else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
470 QRhiBufferReadbackResult *result = u.result;
471 result->data.resize(u.readSize);
472 QNullBuffer *bufD = QRHI_RES(QNullBuffer, u.buf);
473 memcpy(result->data.data(), bufD->data + u.offset, size_t(u.readSize));
474 if (result->completed)
475 result->completed();
476 }
477 }
478 for (int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
479 const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
480 if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
481 if (u.dst->format() == QRhiTexture::RGBA8)
482 simulateTextureUpload(u);
483 } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
484 if (u.src->format() == QRhiTexture::RGBA8 && u.dst->format() == QRhiTexture::RGBA8)
485 simulateTextureCopy(u);
486 } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
487 QRhiReadbackResult *result = u.result;
488 QNullTexture *texD = QRHI_RES(QNullTexture, u.rb.texture());
489 if (texD) {
490 result->format = texD->format();
491 result->pixelSize = q->sizeForMipLevel(u.rb.level(), texD->pixelSize());
492 } else {
493 Q_ASSERT(currentSwapChain);
494 result->format = QRhiTexture::RGBA8;
495 result->pixelSize = currentSwapChain->currentPixelSize();
496 }
497 quint32 bytesPerLine = 0;
498 quint32 byteSize = 0;
499 textureFormatInfo(result->format, result->pixelSize, &bytesPerLine, &byteSize);
500 if (texD && texD->format() == QRhiTexture::RGBA8) {
501 result->data.resize(int(byteSize));
502 const QImage &src(texD->image[u.rb.layer()][u.rb.level()]);
503 char *dst = result->data.data();
504 for (int y = 0, h = src.height(); y < h; ++y) {
505 memcpy(dst, src.constScanLine(y), bytesPerLine);
506 dst += bytesPerLine;
507 }
508 } else {
509 result->data.fill(0, int(byteSize));
510 }
511 if (result->completed)
512 result->completed();
513 } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
514 if (u.dst->format() == QRhiTexture::RGBA8)
515 simulateTextureGenMips(u);
516 }
517 }
518 ud->free();
519}
520
521void QRhiNull::beginPass(QRhiCommandBuffer *cb,
522 QRhiRenderTarget *rt,
523 const QColor &colorClearValue,
524 const QRhiDepthStencilClearValue &depthStencilClearValue,
525 QRhiResourceUpdateBatch *resourceUpdates,
526 QRhiCommandBuffer::BeginPassFlags flags)
527{
528 Q_UNUSED(rt);
529 Q_UNUSED(colorClearValue);
530 Q_UNUSED(depthStencilClearValue);
531 Q_UNUSED(flags);
532 if (resourceUpdates)
533 resourceUpdate(cb, resourceUpdates);
534}
535
536void QRhiNull::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
537{
538 if (resourceUpdates)
539 resourceUpdate(cb, resourceUpdates);
540}
541
542void QRhiNull::beginComputePass(QRhiCommandBuffer *cb,
543 QRhiResourceUpdateBatch *resourceUpdates,
544 QRhiCommandBuffer::BeginPassFlags flags)
545{
546 Q_UNUSED(flags);
547 if (resourceUpdates)
548 resourceUpdate(cb, resourceUpdates);
549}
550
551void QRhiNull::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
552{
553 if (resourceUpdates)
554 resourceUpdate(cb, resourceUpdates);
555}
556
557QNullBuffer::QNullBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size)
558 : QRhiBuffer(rhi, type, usage, size)
559{
560}
561
562QNullBuffer::~QNullBuffer()
563{
564 destroy();
565}
566
567void QNullBuffer::destroy()
568{
569 delete[] data;
570 data = nullptr;
571
572 QRHI_PROF;
573 QRHI_PROF_F(releaseBuffer(this));
574}
575
576bool QNullBuffer::create()
577{
578 data = new char[m_size];
579 memset(data, 0, m_size);
580
581 QRHI_PROF;
582 QRHI_PROF_F(newBuffer(this, uint(m_size), 1, 0));
583 return true;
584}
585
586char *QNullBuffer::beginFullDynamicBufferUpdateForCurrentFrame()
587{
588 Q_ASSERT(m_type == Dynamic);
589 return data;
590}
591
592QNullRenderBuffer::QNullRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
593 int sampleCount, QRhiRenderBuffer::Flags flags,
594 QRhiTexture::Format backingFormatHint)
595 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
596{
597}
598
599QNullRenderBuffer::~QNullRenderBuffer()
600{
601 destroy();
602}
603
604void QNullRenderBuffer::destroy()
605{
606 QRHI_PROF;
607 QRHI_PROF_F(releaseRenderBuffer(this));
608}
609
610bool QNullRenderBuffer::create()
611{
612 QRHI_PROF;
613 QRHI_PROF_F(newRenderBuffer(this, false, false, 1));
614 return true;
615}
616
617QRhiTexture::Format QNullRenderBuffer::backingFormat() const
618{
619 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
620}
621
622QNullTexture::QNullTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize,
623 int sampleCount, Flags flags)
624 : QRhiTexture(rhi, format, pixelSize, sampleCount, flags)
625{
626}
627
628QNullTexture::~QNullTexture()
629{
630 destroy();
631}
632
633void QNullTexture::destroy()
634{
635 QRHI_PROF;
636 QRHI_PROF_F(releaseTexture(this));
637}
638
639bool QNullTexture::create()
640{
641 QRHI_RES_RHI(QRhiNull);
642 const bool isCube = m_flags.testFlag(CubeMap);
643 const bool hasMipMaps = m_flags.testFlag(MipMapped);
644 QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
645 const int mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1;
646 const int layerCount = isCube ? 6 : 1;
647
648 if (m_format == RGBA8) {
649 for (int layer = 0; layer < layerCount; ++layer) {
650 for (int level = 0; level < mipLevelCount; ++level) {
651 image[layer][level] = QImage(rhiD->q->sizeForMipLevel(level, size),
652 QImage::Format_RGBA8888_Premultiplied);
653 image[layer][level].fill(Qt::yellow);
654 }
655 }
656 }
657
658 QRHI_PROF;
659 QRHI_PROF_F(newTexture(this, true, mipLevelCount, layerCount, 1));
660 return true;
661}
662
663bool QNullTexture::createFrom(QRhiTexture::NativeTexture src)
664{
665 Q_UNUSED(src);
666 QRHI_RES_RHI(QRhiNull);
667 const bool isCube = m_flags.testFlag(CubeMap);
668 const bool hasMipMaps = m_flags.testFlag(MipMapped);
669 QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
670 const int mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1;
671 QRHI_PROF;
672 QRHI_PROF_F(newTexture(this, false, mipLevelCount, isCube ? 6 : 1, 1));
673 return true;
674}
675
676QNullSampler::QNullSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
677 AddressMode u, AddressMode v, AddressMode w)
678 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
679{
680}
681
682QNullSampler::~QNullSampler()
683{
684 destroy();
685}
686
687void QNullSampler::destroy()
688{
689}
690
691bool QNullSampler::create()
692{
693 return true;
694}
695
696QNullRenderPassDescriptor::QNullRenderPassDescriptor(QRhiImplementation *rhi)
697 : QRhiRenderPassDescriptor(rhi)
698{
699}
700
701QNullRenderPassDescriptor::~QNullRenderPassDescriptor()
702{
703 destroy();
704}
705
706void QNullRenderPassDescriptor::destroy()
707{
708}
709
710bool QNullRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const
711{
712 Q_UNUSED(other);
713 return true;
714}
715
716QNullReferenceRenderTarget::QNullReferenceRenderTarget(QRhiImplementation *rhi)
717 : QRhiRenderTarget(rhi),
718 d(rhi)
719{
720}
721
722QNullReferenceRenderTarget::~QNullReferenceRenderTarget()
723{
724 destroy();
725}
726
727void QNullReferenceRenderTarget::destroy()
728{
729}
730
731QSize QNullReferenceRenderTarget::pixelSize() const
732{
733 return d.pixelSize;
734}
735
736float QNullReferenceRenderTarget::devicePixelRatio() const
737{
738 return d.dpr;
739}
740
741int QNullReferenceRenderTarget::sampleCount() const
742{
743 return 1;
744}
745
746QNullTextureRenderTarget::QNullTextureRenderTarget(QRhiImplementation *rhi,
747 const QRhiTextureRenderTargetDescription &desc,
748 Flags flags)
749 : QRhiTextureRenderTarget(rhi, desc, flags),
750 d(rhi)
751{
752}
753
754QNullTextureRenderTarget::~QNullTextureRenderTarget()
755{
756 destroy();
757}
758
759void QNullTextureRenderTarget::destroy()
760{
761}
762
763QRhiRenderPassDescriptor *QNullTextureRenderTarget::newCompatibleRenderPassDescriptor()
764{
765 return new QNullRenderPassDescriptor(m_rhi);
766}
767
768bool QNullTextureRenderTarget::create()
769{
770 QRHI_RES_RHI(QRhiNull);
771 d.rp = QRHI_RES(QNullRenderPassDescriptor, m_renderPassDesc);
772 if (m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments()) {
773 const QRhiColorAttachment *colorAtt = m_desc.cbeginColorAttachments();
774 QRhiTexture *tex = colorAtt->texture();
775 QRhiRenderBuffer *rb = colorAtt->renderBuffer();
776 d.pixelSize = tex ? rhiD->q->sizeForMipLevel(colorAtt->level(), tex->pixelSize()) : rb->pixelSize();
777 } else if (m_desc.depthStencilBuffer()) {
778 d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
779 } else if (m_desc.depthTexture()) {
780 d.pixelSize = m_desc.depthTexture()->pixelSize();
781 }
782 return true;
783}
784
785QSize QNullTextureRenderTarget::pixelSize() const
786{
787 return d.pixelSize;
788}
789
790float QNullTextureRenderTarget::devicePixelRatio() const
791{
792 return d.dpr;
793}
794
795int QNullTextureRenderTarget::sampleCount() const
796{
797 return 1;
798}
799
800QNullShaderResourceBindings::QNullShaderResourceBindings(QRhiImplementation *rhi)
801 : QRhiShaderResourceBindings(rhi)
802{
803}
804
805QNullShaderResourceBindings::~QNullShaderResourceBindings()
806{
807 destroy();
808}
809
810void QNullShaderResourceBindings::destroy()
811{
812}
813
814bool QNullShaderResourceBindings::create()
815{
816 QRHI_RES_RHI(QRhiNull);
817 if (!rhiD->sanityCheckShaderResourceBindings(this))
818 return false;
819
820 rhiD->updateLayoutDesc(this);
821
822 return true;
823}
824
825QNullGraphicsPipeline::QNullGraphicsPipeline(QRhiImplementation *rhi)
826 : QRhiGraphicsPipeline(rhi)
827{
828}
829
830QNullGraphicsPipeline::~QNullGraphicsPipeline()
831{
832 destroy();
833}
834
835void QNullGraphicsPipeline::destroy()
836{
837}
838
839bool QNullGraphicsPipeline::create()
840{
841 QRHI_RES_RHI(QRhiNull);
842 if (!rhiD->sanityCheckGraphicsPipeline(this))
843 return false;
844
845 return true;
846}
847
848QNullComputePipeline::QNullComputePipeline(QRhiImplementation *rhi)
849 : QRhiComputePipeline(rhi)
850{
851}
852
853QNullComputePipeline::~QNullComputePipeline()
854{
855 destroy();
856}
857
858void QNullComputePipeline::destroy()
859{
860}
861
862bool QNullComputePipeline::create()
863{
864 return true;
865}
866
867QNullCommandBuffer::QNullCommandBuffer(QRhiImplementation *rhi)
868 : QRhiCommandBuffer(rhi)
869{
870}
871
872QNullCommandBuffer::~QNullCommandBuffer()
873{
874 destroy();
875}
876
877void QNullCommandBuffer::destroy()
878{
879 // nothing to do here
880}
881
882QNullSwapChain::QNullSwapChain(QRhiImplementation *rhi)
883 : QRhiSwapChain(rhi),
884 rt(rhi),
885 cb(rhi)
886{
887}
888
889QNullSwapChain::~QNullSwapChain()
890{
891 destroy();
892}
893
894void QNullSwapChain::destroy()
895{
896 QRHI_PROF;
897 QRHI_PROF_F(releaseSwapChain(this));
898}
899
900QRhiCommandBuffer *QNullSwapChain::currentFrameCommandBuffer()
901{
902 return &cb;
903}
904
905QRhiRenderTarget *QNullSwapChain::currentFrameRenderTarget()
906{
907 return &rt;
908}
909
910QSize QNullSwapChain::surfacePixelSize()
911{
912 return QSize(1280, 720);
913}
914
915QRhiRenderPassDescriptor *QNullSwapChain::newCompatibleRenderPassDescriptor()
916{
917 return new QNullRenderPassDescriptor(m_rhi);
918}
919
920bool QNullSwapChain::createOrResize()
921{
922 m_currentPixelSize = surfacePixelSize();
923 rt.d.rp = QRHI_RES(QNullRenderPassDescriptor, m_renderPassDesc);
924 rt.d.pixelSize = m_currentPixelSize;
925 frameCount = 0;
926 QRHI_PROF;
927 QRHI_PROF_F(resizeSwapChain(this, 1, 0, 1));
928 return true;
929}
930
931QT_END_NAMESPACE
932