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
40QT_BEGIN_NAMESPACE
41
42/*!
43 \class QRhiNullInitParams
44 \inmodule QtRhi
45 \brief Null backend specific initialization parameters.
46
47 A Null QRhi needs no special parameters for initialization.
48
49 \badcode
50 QRhiNullInitParams params;
51 rhi = QRhi::create(QRhi::Null, &params);
52 \endcode
53
54 The Null backend does not issue any graphics calls and creates no
55 resources. All QRhi operations will succeed as normal so applications can
56 still be run, albeit potentially at an unthrottled speed, depending on
57 their frame rendering strategy. The backend reports resources to
58 QRhiProfiler as usual.
59 */
60
61/*!
62 \class QRhiNullNativeHandles
63 \inmodule QtRhi
64 \brief Empty.
65 */
66
67/*!
68 \class QRhiNullTextureNativeHandles
69 \inmodule QtRhi
70 \brief Empty.
71 */
72
73QRhiNull::QRhiNull(QRhiNullInitParams *params)
74 : offscreenCommandBuffer(this)
75{
76 Q_UNUSED(params);
77}
78
79bool QRhiNull::create(QRhi::Flags flags)
80{
81 Q_UNUSED(flags);
82 return true;
83}
84
85void QRhiNull::destroy()
86{
87}
88
89QVector<int> QRhiNull::supportedSampleCounts() const
90{
91 return { 1 };
92}
93
94QRhiSwapChain *QRhiNull::createSwapChain()
95{
96 return new QNullSwapChain(this);
97}
98
99QRhiBuffer *QRhiNull::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, int size)
100{
101 return new QNullBuffer(this, type, usage, size);
102}
103
104int QRhiNull::ubufAlignment() const
105{
106 return 256;
107}
108
109bool QRhiNull::isYUpInFramebuffer() const
110{
111 return false;
112}
113
114bool QRhiNull::isYUpInNDC() const
115{
116 return true;
117}
118
119bool QRhiNull::isClipDepthZeroToOne() const
120{
121 return true;
122}
123
124QMatrix4x4 QRhiNull::clipSpaceCorrMatrix() const
125{
126 return QMatrix4x4(); // identity
127}
128
129bool QRhiNull::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const
130{
131 Q_UNUSED(format);
132 Q_UNUSED(flags);
133 return true;
134}
135
136bool QRhiNull::isFeatureSupported(QRhi::Feature feature) const
137{
138 Q_UNUSED(feature);
139 return true;
140}
141
142int QRhiNull::resourceLimit(QRhi::ResourceLimit limit) const
143{
144 switch (limit) {
145 case QRhi::TextureSizeMin:
146 return 1;
147 case QRhi::TextureSizeMax:
148 return 16384;
149 case QRhi::MaxColorAttachments:
150 return 8;
151 case QRhi::FramesInFlight:
152 return 2; // dummy
153 default:
154 Q_UNREACHABLE();
155 return 0;
156 }
157}
158
159const QRhiNativeHandles *QRhiNull::nativeHandles()
160{
161 return &nativeHandlesStruct;
162}
163
164void QRhiNull::sendVMemStatsToProfiler()
165{
166 // nothing to do here
167}
168
169void QRhiNull::makeThreadLocalNativeContextCurrent()
170{
171 // nothing to do here
172}
173
174QRhiRenderBuffer *QRhiNull::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
175 int sampleCount, QRhiRenderBuffer::Flags flags)
176{
177 return new QNullRenderBuffer(this, type, pixelSize, sampleCount, flags);
178}
179
180QRhiTexture *QRhiNull::createTexture(QRhiTexture::Format format, const QSize &pixelSize,
181 int sampleCount, QRhiTexture::Flags flags)
182{
183 return new QNullTexture(this, format, pixelSize, sampleCount, flags);
184}
185
186QRhiSampler *QRhiNull::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
187 QRhiSampler::Filter mipmapMode,
188 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v)
189{
190 return new QNullSampler(this, magFilter, minFilter, mipmapMode, u, v);
191}
192
193QRhiTextureRenderTarget *QRhiNull::createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
194 QRhiTextureRenderTarget::Flags flags)
195{
196 return new QNullTextureRenderTarget(this, desc, flags);
197}
198
199QRhiGraphicsPipeline *QRhiNull::createGraphicsPipeline()
200{
201 return new QNullGraphicsPipeline(this);
202}
203
204QRhiComputePipeline *QRhiNull::createComputePipeline()
205{
206 return new QNullComputePipeline(this);
207}
208
209QRhiShaderResourceBindings *QRhiNull::createShaderResourceBindings()
210{
211 return new QNullShaderResourceBindings(this);
212}
213
214void QRhiNull::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
215{
216 Q_UNUSED(cb);
217 Q_UNUSED(ps);
218}
219
220void QRhiNull::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
221 int dynamicOffsetCount,
222 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
223{
224 Q_UNUSED(cb);
225 Q_UNUSED(srb);
226 Q_UNUSED(dynamicOffsetCount);
227 Q_UNUSED(dynamicOffsets);
228}
229
230void QRhiNull::setVertexInput(QRhiCommandBuffer *cb,
231 int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
232 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
233{
234 Q_UNUSED(cb);
235 Q_UNUSED(startBinding);
236 Q_UNUSED(bindingCount);
237 Q_UNUSED(bindings);
238 Q_UNUSED(indexBuf);
239 Q_UNUSED(indexOffset);
240 Q_UNUSED(indexFormat);
241}
242
243void QRhiNull::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
244{
245 Q_UNUSED(cb);
246 Q_UNUSED(viewport);
247}
248
249void QRhiNull::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
250{
251 Q_UNUSED(cb);
252 Q_UNUSED(scissor);
253}
254
255void QRhiNull::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c)
256{
257 Q_UNUSED(cb);
258 Q_UNUSED(c);
259}
260
261void QRhiNull::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
262{
263 Q_UNUSED(cb);
264 Q_UNUSED(refValue);
265}
266
267void QRhiNull::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
268 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
269{
270 Q_UNUSED(cb);
271 Q_UNUSED(vertexCount);
272 Q_UNUSED(instanceCount);
273 Q_UNUSED(firstVertex);
274 Q_UNUSED(firstInstance);
275}
276
277void QRhiNull::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
278 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
279{
280 Q_UNUSED(cb);
281 Q_UNUSED(indexCount);
282 Q_UNUSED(instanceCount);
283 Q_UNUSED(firstIndex);
284 Q_UNUSED(vertexOffset);
285 Q_UNUSED(firstInstance);
286}
287
288void QRhiNull::debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name)
289{
290 Q_UNUSED(cb);
291 Q_UNUSED(name);
292}
293
294void QRhiNull::debugMarkEnd(QRhiCommandBuffer *cb)
295{
296 Q_UNUSED(cb);
297}
298
299void QRhiNull::debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg)
300{
301 Q_UNUSED(cb);
302 Q_UNUSED(msg);
303}
304
305void QRhiNull::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
306{
307 Q_UNUSED(cb);
308 Q_UNUSED(ps);
309}
310
311void QRhiNull::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
312{
313 Q_UNUSED(cb);
314 Q_UNUSED(x);
315 Q_UNUSED(y);
316 Q_UNUSED(z);
317}
318
319const QRhiNativeHandles *QRhiNull::nativeHandles(QRhiCommandBuffer *cb)
320{
321 Q_UNUSED(cb);
322 return nullptr;
323}
324
325void QRhiNull::beginExternal(QRhiCommandBuffer *cb)
326{
327 Q_UNUSED(cb);
328}
329
330void QRhiNull::endExternal(QRhiCommandBuffer *cb)
331{
332 Q_UNUSED(cb);
333}
334
335QRhi::FrameOpResult QRhiNull::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
336{
337 Q_UNUSED(flags);
338 currentSwapChain = swapChain;
339 QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
340 QRHI_PROF_F(beginSwapChainFrame(swapChain));
341 return QRhi::FrameOpSuccess;
342}
343
344QRhi::FrameOpResult QRhiNull::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
345{
346 Q_UNUSED(flags);
347 QNullSwapChain *swapChainD = QRHI_RES(QNullSwapChain, swapChain);
348 QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
349 QRHI_PROF_F(endSwapChainFrame(swapChain, swapChainD->frameCount + 1));
350 QRHI_PROF_F(swapChainFrameGpuTime(swapChain, 0.000666f));
351 swapChainD->frameCount += 1;
352 currentSwapChain = nullptr;
353 return QRhi::FrameOpSuccess;
354}
355
356QRhi::FrameOpResult QRhiNull::beginOffscreenFrame(QRhiCommandBuffer **cb)
357{
358 *cb = &offscreenCommandBuffer;
359 return QRhi::FrameOpSuccess;
360}
361
362QRhi::FrameOpResult QRhiNull::endOffscreenFrame()
363{
364 return QRhi::FrameOpSuccess;
365}
366
367QRhi::FrameOpResult QRhiNull::finish()
368{
369 return QRhi::FrameOpSuccess;
370}
371
372void QRhiNull::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
373{
374 Q_UNUSED(cb);
375 QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
376 for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
377 if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
378 QRhiReadbackResult *result = u.read.result;
379 QRhiTexture *tex = u.read.rb.texture();
380 if (tex) {
381 result->format = tex->format();
382 result->pixelSize = q->sizeForMipLevel(u.read.rb.level(), tex->pixelSize());
383 } else {
384 Q_ASSERT(currentSwapChain);
385 result->format = QRhiTexture::RGBA8;
386 result->pixelSize = currentSwapChain->currentPixelSize();
387 }
388 quint32 byteSize = 0;
389 textureFormatInfo(result->format, result->pixelSize, nullptr, &byteSize);
390 result->data.fill(0, byteSize);
391 if (result->completed)
392 result->completed();
393 }
394 }
395 ud->free();
396}
397
398void QRhiNull::beginPass(QRhiCommandBuffer *cb,
399 QRhiRenderTarget *rt,
400 const QColor &colorClearValue,
401 const QRhiDepthStencilClearValue &depthStencilClearValue,
402 QRhiResourceUpdateBatch *resourceUpdates)
403{
404 Q_UNUSED(rt);
405 Q_UNUSED(colorClearValue);
406 Q_UNUSED(depthStencilClearValue);
407 if (resourceUpdates)
408 resourceUpdate(cb, resourceUpdates);
409}
410
411void QRhiNull::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
412{
413 if (resourceUpdates)
414 resourceUpdate(cb, resourceUpdates);
415}
416
417void QRhiNull::beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
418{
419 if (resourceUpdates)
420 resourceUpdate(cb, resourceUpdates);
421}
422
423void QRhiNull::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
424{
425 if (resourceUpdates)
426 resourceUpdate(cb, resourceUpdates);
427}
428
429QNullBuffer::QNullBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size)
430 : QRhiBuffer(rhi, type, usage, size)
431{
432}
433
434QNullBuffer::~QNullBuffer()
435{
436 release();
437}
438
439void QNullBuffer::release()
440{
441 QRHI_PROF;
442 QRHI_PROF_F(releaseBuffer(this));
443}
444
445bool QNullBuffer::build()
446{
447 QRHI_PROF;
448 QRHI_PROF_F(newBuffer(this, m_size, 1, 0));
449 return true;
450}
451
452QNullRenderBuffer::QNullRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
453 int sampleCount, QRhiRenderBuffer::Flags flags)
454 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags)
455{
456}
457
458QNullRenderBuffer::~QNullRenderBuffer()
459{
460 release();
461}
462
463void QNullRenderBuffer::release()
464{
465 QRHI_PROF;
466 QRHI_PROF_F(releaseRenderBuffer(this));
467}
468
469bool QNullRenderBuffer::build()
470{
471 QRHI_PROF;
472 QRHI_PROF_F(newRenderBuffer(this, false, false, 1));
473 return true;
474}
475
476QRhiTexture::Format QNullRenderBuffer::backingFormat() const
477{
478 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
479}
480
481QNullTexture::QNullTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize,
482 int sampleCount, Flags flags)
483 : QRhiTexture(rhi, format, pixelSize, sampleCount, flags)
484{
485}
486
487QNullTexture::~QNullTexture()
488{
489 release();
490}
491
492void QNullTexture::release()
493{
494 QRHI_PROF;
495 QRHI_PROF_F(releaseTexture(this));
496}
497
498bool QNullTexture::build()
499{
500 const bool isCube = m_flags.testFlag(CubeMap);
501 const bool hasMipMaps = m_flags.testFlag(MipMapped);
502 QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
503 const int mipLevelCount = hasMipMaps ? qCeil(log2(qMax(size.width(), size.height()))) + 1 : 1;
504 QRHI_PROF;
505 QRHI_PROF_F(newTexture(this, true, mipLevelCount, isCube ? 6 : 1, 1));
506 return true;
507}
508
509bool QNullTexture::buildFrom(const QRhiNativeHandles *src)
510{
511 Q_UNUSED(src);
512 const bool isCube = m_flags.testFlag(CubeMap);
513 const bool hasMipMaps = m_flags.testFlag(MipMapped);
514 QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
515 const int mipLevelCount = hasMipMaps ? qCeil(log2(qMax(size.width(), size.height()))) + 1 : 1;
516 QRHI_PROF;
517 QRHI_PROF_F(newTexture(this, false, mipLevelCount, isCube ? 6 : 1, 1));
518 return true;
519}
520
521const QRhiNativeHandles *QNullTexture::nativeHandles()
522{
523 return &nativeHandlesStruct;
524}
525
526QNullSampler::QNullSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
527 AddressMode u, AddressMode v)
528 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v)
529{
530}
531
532QNullSampler::~QNullSampler()
533{
534 release();
535}
536
537void QNullSampler::release()
538{
539}
540
541bool QNullSampler::build()
542{
543 return true;
544}
545
546QNullRenderPassDescriptor::QNullRenderPassDescriptor(QRhiImplementation *rhi)
547 : QRhiRenderPassDescriptor(rhi)
548{
549}
550
551QNullRenderPassDescriptor::~QNullRenderPassDescriptor()
552{
553 release();
554}
555
556void QNullRenderPassDescriptor::release()
557{
558}
559
560QNullReferenceRenderTarget::QNullReferenceRenderTarget(QRhiImplementation *rhi)
561 : QRhiRenderTarget(rhi),
562 d(rhi)
563{
564}
565
566QNullReferenceRenderTarget::~QNullReferenceRenderTarget()
567{
568 release();
569}
570
571void QNullReferenceRenderTarget::release()
572{
573}
574
575QSize QNullReferenceRenderTarget::pixelSize() const
576{
577 return d.pixelSize;
578}
579
580float QNullReferenceRenderTarget::devicePixelRatio() const
581{
582 return d.dpr;
583}
584
585int QNullReferenceRenderTarget::sampleCount() const
586{
587 return 1;
588}
589
590QNullTextureRenderTarget::QNullTextureRenderTarget(QRhiImplementation *rhi,
591 const QRhiTextureRenderTargetDescription &desc,
592 Flags flags)
593 : QRhiTextureRenderTarget(rhi, desc, flags),
594 d(rhi)
595{
596}
597
598QNullTextureRenderTarget::~QNullTextureRenderTarget()
599{
600 release();
601}
602
603void QNullTextureRenderTarget::release()
604{
605}
606
607QRhiRenderPassDescriptor *QNullTextureRenderTarget::newCompatibleRenderPassDescriptor()
608{
609 return new QNullRenderPassDescriptor(m_rhi);
610}
611
612bool QNullTextureRenderTarget::build()
613{
614 d.rp = QRHI_RES(QNullRenderPassDescriptor, m_renderPassDesc);
615 const QVector<QRhiColorAttachment> colorAttachments = m_desc.colorAttachments();
616 if (!colorAttachments.isEmpty()) {
617 QRhiTexture *tex = colorAttachments.first().texture();
618 QRhiRenderBuffer *rb = colorAttachments.first().renderBuffer();
619 d.pixelSize = tex ? tex->pixelSize() : rb->pixelSize();
620 } else if (m_desc.depthStencilBuffer()) {
621 d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
622 } else if (m_desc.depthTexture()) {
623 d.pixelSize = m_desc.depthTexture()->pixelSize();
624 }
625 return true;
626}
627
628QSize QNullTextureRenderTarget::pixelSize() const
629{
630 return d.pixelSize;
631}
632
633float QNullTextureRenderTarget::devicePixelRatio() const
634{
635 return d.dpr;
636}
637
638int QNullTextureRenderTarget::sampleCount() const
639{
640 return 1;
641}
642
643QNullShaderResourceBindings::QNullShaderResourceBindings(QRhiImplementation *rhi)
644 : QRhiShaderResourceBindings(rhi)
645{
646}
647
648QNullShaderResourceBindings::~QNullShaderResourceBindings()
649{
650 release();
651}
652
653void QNullShaderResourceBindings::release()
654{
655}
656
657bool QNullShaderResourceBindings::build()
658{
659 return true;
660}
661
662QNullGraphicsPipeline::QNullGraphicsPipeline(QRhiImplementation *rhi)
663 : QRhiGraphicsPipeline(rhi)
664{
665}
666
667QNullGraphicsPipeline::~QNullGraphicsPipeline()
668{
669 release();
670}
671
672void QNullGraphicsPipeline::release()
673{
674}
675
676bool QNullGraphicsPipeline::build()
677{
678 return true;
679}
680
681QNullComputePipeline::QNullComputePipeline(QRhiImplementation *rhi)
682 : QRhiComputePipeline(rhi)
683{
684}
685
686QNullComputePipeline::~QNullComputePipeline()
687{
688 release();
689}
690
691void QNullComputePipeline::release()
692{
693}
694
695bool QNullComputePipeline::build()
696{
697 return true;
698}
699
700QNullCommandBuffer::QNullCommandBuffer(QRhiImplementation *rhi)
701 : QRhiCommandBuffer(rhi)
702{
703}
704
705QNullCommandBuffer::~QNullCommandBuffer()
706{
707 release();
708}
709
710void QNullCommandBuffer::release()
711{
712 // nothing to do here
713}
714
715QNullSwapChain::QNullSwapChain(QRhiImplementation *rhi)
716 : QRhiSwapChain(rhi),
717 rt(rhi),
718 cb(rhi)
719{
720}
721
722QNullSwapChain::~QNullSwapChain()
723{
724 release();
725}
726
727void QNullSwapChain::release()
728{
729 QRHI_PROF;
730 QRHI_PROF_F(releaseSwapChain(this));
731}
732
733QRhiCommandBuffer *QNullSwapChain::currentFrameCommandBuffer()
734{
735 return &cb;
736}
737
738QRhiRenderTarget *QNullSwapChain::currentFrameRenderTarget()
739{
740 return &rt;
741}
742
743QSize QNullSwapChain::surfacePixelSize()
744{
745 return QSize(1280, 720);
746}
747
748QRhiRenderPassDescriptor *QNullSwapChain::newCompatibleRenderPassDescriptor()
749{
750 return new QNullRenderPassDescriptor(m_rhi);
751}
752
753bool QNullSwapChain::buildOrResize()
754{
755 m_currentPixelSize = surfacePixelSize();
756 rt.d.rp = QRHI_RES(QNullRenderPassDescriptor, m_renderPassDesc);
757 rt.d.pixelSize = m_currentPixelSize;
758 frameCount = 0;
759 QRHI_PROF;
760 QRHI_PROF_F(resizeSwapChain(this, 1, 0, 1));
761 return true;
762}
763
764QT_END_NAMESPACE
765