1// Copyright (C) 2023 The Qt Company Ltd.
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 "qrhinull_p.h"
5#include <qmath.h>
6#include <QPainter>
7
8QT_BEGIN_NAMESPACE
9
10/*!
11 \class QRhiNullInitParams
12 \inmodule QtGuiPrivate
13 \inheaderfile rhi/qrhi.h
14 \since 6.6
15 \brief Null backend specific initialization parameters.
16
17 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
18 for details.
19
20 A Null QRhi needs no special parameters for initialization.
21
22 \badcode
23 QRhiNullInitParams params;
24 rhi = QRhi::create(QRhi::Null, &params);
25 \endcode
26
27 The Null backend does not issue any graphics calls and creates no
28 resources. All QRhi operations will succeed as normal so applications can
29 still be run, albeit potentially at an unthrottled speed, depending on
30 their frame rendering strategy.
31 */
32
33/*!
34 \class QRhiNullNativeHandles
35 \inmodule QtGuiPrivate
36 \inheaderfile rhi/qrhi.h
37 \since 6.6
38 \brief Empty.
39
40 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
41 for details.
42 */
43
44QRhiNull::QRhiNull(QRhiNullInitParams *params)
45 : offscreenCommandBuffer(this)
46{
47 Q_UNUSED(params);
48}
49
50bool QRhiNull::create(QRhi::Flags flags)
51{
52 Q_UNUSED(flags);
53 return true;
54}
55
56void QRhiNull::destroy()
57{
58}
59
60QList<int> QRhiNull::supportedSampleCounts() const
61{
62 return { 1 };
63}
64
65QList<QSize> QRhiNull::supportedShadingRates(int sampleCount) const
66{
67 Q_UNUSED(sampleCount);
68 return { QSize(1, 1) };
69}
70
71QRhiSwapChain *QRhiNull::createSwapChain()
72{
73 return new QNullSwapChain(this);
74}
75
76QRhiBuffer *QRhiNull::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
77{
78 return new QNullBuffer(this, type, usage, size);
79}
80
81int QRhiNull::ubufAlignment() const
82{
83 return 256;
84}
85
86bool QRhiNull::isYUpInFramebuffer() const
87{
88 return false;
89}
90
91bool QRhiNull::isYUpInNDC() const
92{
93 return true;
94}
95
96bool QRhiNull::isClipDepthZeroToOne() const
97{
98 return true;
99}
100
101QMatrix4x4 QRhiNull::clipSpaceCorrMatrix() const
102{
103 return QMatrix4x4(); // identity
104}
105
106bool QRhiNull::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const
107{
108 Q_UNUSED(format);
109 Q_UNUSED(flags);
110 return true;
111}
112
113bool QRhiNull::isFeatureSupported(QRhi::Feature feature) const
114{
115 Q_UNUSED(feature);
116 return true;
117}
118
119int QRhiNull::resourceLimit(QRhi::ResourceLimit limit) const
120{
121 switch (limit) {
122 case QRhi::TextureSizeMin:
123 return 1;
124 case QRhi::TextureSizeMax:
125 return 16384;
126 case QRhi::MaxColorAttachments:
127 return 8;
128 case QRhi::FramesInFlight:
129 return 1;
130 case QRhi::MaxAsyncReadbackFrames:
131 return 1;
132 case QRhi::MaxThreadGroupsPerDimension:
133 return 0;
134 case QRhi::MaxThreadsPerThreadGroup:
135 return 0;
136 case QRhi::MaxThreadGroupX:
137 return 0;
138 case QRhi::MaxThreadGroupY:
139 return 0;
140 case QRhi::MaxThreadGroupZ:
141 return 0;
142 case QRhi::TextureArraySizeMax:
143 return 2048;
144 case QRhi::MaxUniformBufferRange:
145 return 65536;
146 case QRhi::MaxVertexInputs:
147 return 32;
148 case QRhi::MaxVertexOutputs:
149 return 32;
150 case QRhi::ShadingRateImageTileSize:
151 return 0;
152 }
153
154 Q_UNREACHABLE_RETURN(0);
155}
156
157const QRhiNativeHandles *QRhiNull::nativeHandles()
158{
159 return &nativeHandlesStruct;
160}
161
162QRhiDriverInfo QRhiNull::driverInfo() const
163{
164 QRhiDriverInfo info;
165 info.deviceName = QByteArrayLiteral("Null");
166 return info;
167}
168
169QRhiStats QRhiNull::statistics()
170{
171 return {};
172}
173
174bool QRhiNull::makeThreadLocalNativeContextCurrent()
175{
176 // not applicable
177 return false;
178}
179
180void QRhiNull::setQueueSubmitParams(QRhiNativeHandles *)
181{
182 // not applicable
183}
184
185void QRhiNull::releaseCachedResources()
186{
187 // nothing to do here
188}
189
190bool QRhiNull::isDeviceLost() const
191{
192 return false;
193}
194
195QByteArray QRhiNull::pipelineCacheData()
196{
197 return QByteArray();
198}
199
200void QRhiNull::setPipelineCacheData(const QByteArray &data)
201{
202 Q_UNUSED(data);
203}
204
205QRhiRenderBuffer *QRhiNull::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
206 int sampleCount, QRhiRenderBuffer::Flags flags,
207 QRhiTexture::Format backingFormatHint)
208{
209 return new QNullRenderBuffer(this, type, pixelSize, sampleCount, flags, backingFormatHint);
210}
211
212QRhiTexture *QRhiNull::createTexture(QRhiTexture::Format format,
213 const QSize &pixelSize, int depth, int arraySize,
214 int sampleCount, QRhiTexture::Flags flags)
215{
216 return new QNullTexture(this, format, pixelSize, depth, arraySize, sampleCount, flags);
217}
218
219QRhiSampler *QRhiNull::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
220 QRhiSampler::Filter mipmapMode,
221 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
222{
223 return new QNullSampler(this, magFilter, minFilter, mipmapMode, u, v, w);
224}
225
226QRhiTextureRenderTarget *QRhiNull::createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
227 QRhiTextureRenderTarget::Flags flags)
228{
229 return new QNullTextureRenderTarget(this, desc, flags);
230}
231
232QRhiShadingRateMap *QRhiNull::createShadingRateMap()
233{
234 return nullptr;
235}
236
237QRhiGraphicsPipeline *QRhiNull::createGraphicsPipeline()
238{
239 return new QNullGraphicsPipeline(this);
240}
241
242QRhiComputePipeline *QRhiNull::createComputePipeline()
243{
244 return new QNullComputePipeline(this);
245}
246
247QRhiShaderResourceBindings *QRhiNull::createShaderResourceBindings()
248{
249 return new QNullShaderResourceBindings(this);
250}
251
252void QRhiNull::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
253{
254 Q_UNUSED(cb);
255 Q_UNUSED(ps);
256}
257
258void QRhiNull::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
259 int dynamicOffsetCount,
260 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
261{
262 Q_UNUSED(cb);
263 Q_UNUSED(srb);
264 Q_UNUSED(dynamicOffsetCount);
265 Q_UNUSED(dynamicOffsets);
266}
267
268void QRhiNull::setVertexInput(QRhiCommandBuffer *cb,
269 int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
270 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
271{
272 Q_UNUSED(cb);
273 Q_UNUSED(startBinding);
274 Q_UNUSED(bindingCount);
275 Q_UNUSED(bindings);
276 Q_UNUSED(indexBuf);
277 Q_UNUSED(indexOffset);
278 Q_UNUSED(indexFormat);
279}
280
281void QRhiNull::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
282{
283 Q_UNUSED(cb);
284 Q_UNUSED(viewport);
285}
286
287void QRhiNull::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
288{
289 Q_UNUSED(cb);
290 Q_UNUSED(scissor);
291}
292
293void QRhiNull::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c)
294{
295 Q_UNUSED(cb);
296 Q_UNUSED(c);
297}
298
299void QRhiNull::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
300{
301 Q_UNUSED(cb);
302 Q_UNUSED(refValue);
303}
304
305void QRhiNull::setShadingRate(QRhiCommandBuffer *cb, const QSize &coarsePixelSize)
306{
307 Q_UNUSED(cb);
308 Q_UNUSED(coarsePixelSize);
309}
310
311void QRhiNull::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
312 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
313{
314 Q_UNUSED(cb);
315 Q_UNUSED(vertexCount);
316 Q_UNUSED(instanceCount);
317 Q_UNUSED(firstVertex);
318 Q_UNUSED(firstInstance);
319}
320
321void QRhiNull::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
322 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
323{
324 Q_UNUSED(cb);
325 Q_UNUSED(indexCount);
326 Q_UNUSED(instanceCount);
327 Q_UNUSED(firstIndex);
328 Q_UNUSED(vertexOffset);
329 Q_UNUSED(firstInstance);
330}
331
332void QRhiNull::debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name)
333{
334 Q_UNUSED(cb);
335 Q_UNUSED(name);
336}
337
338void QRhiNull::debugMarkEnd(QRhiCommandBuffer *cb)
339{
340 Q_UNUSED(cb);
341}
342
343void QRhiNull::debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg)
344{
345 Q_UNUSED(cb);
346 Q_UNUSED(msg);
347}
348
349void QRhiNull::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
350{
351 Q_UNUSED(cb);
352 Q_UNUSED(ps);
353}
354
355void QRhiNull::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
356{
357 Q_UNUSED(cb);
358 Q_UNUSED(x);
359 Q_UNUSED(y);
360 Q_UNUSED(z);
361}
362
363const QRhiNativeHandles *QRhiNull::nativeHandles(QRhiCommandBuffer *cb)
364{
365 Q_UNUSED(cb);
366 return nullptr;
367}
368
369void QRhiNull::beginExternal(QRhiCommandBuffer *cb)
370{
371 Q_UNUSED(cb);
372}
373
374void QRhiNull::endExternal(QRhiCommandBuffer *cb)
375{
376 Q_UNUSED(cb);
377}
378
379double QRhiNull::lastCompletedGpuTime(QRhiCommandBuffer *cb)
380{
381 Q_UNUSED(cb);
382 return 0;
383}
384
385QRhi::FrameOpResult QRhiNull::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
386{
387 Q_UNUSED(flags);
388 currentSwapChain = swapChain;
389 return QRhi::FrameOpSuccess;
390}
391
392QRhi::FrameOpResult QRhiNull::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
393{
394 Q_UNUSED(flags);
395 QNullSwapChain *swapChainD = QRHI_RES(QNullSwapChain, swapChain);
396 swapChainD->frameCount += 1;
397 currentSwapChain = nullptr;
398 return QRhi::FrameOpSuccess;
399}
400
401QRhi::FrameOpResult QRhiNull::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags)
402{
403 Q_UNUSED(flags);
404 *cb = &offscreenCommandBuffer;
405 return QRhi::FrameOpSuccess;
406}
407
408QRhi::FrameOpResult QRhiNull::endOffscreenFrame(QRhi::EndFrameFlags flags)
409{
410 Q_UNUSED(flags);
411 return QRhi::FrameOpSuccess;
412}
413
414QRhi::FrameOpResult QRhiNull::finish()
415{
416 return QRhi::FrameOpSuccess;
417}
418
419void QRhiNull::simulateTextureUpload(const QRhiResourceUpdateBatchPrivate::TextureOp &u)
420{
421 QNullTexture *texD = QRHI_RES(QNullTexture, u.dst);
422 for (int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
423 for (int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
424 for (const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(t: u.subresDesc[layer][level])) {
425 if (!subresDesc.image().isNull()) {
426 const QImage src = subresDesc.image();
427 QPainter painter(&texD->image[layer][level]);
428 const QSize srcSize = subresDesc.sourceSize().isEmpty()
429 ? src.size() : subresDesc.sourceSize();
430 painter.setCompositionMode(QPainter::CompositionMode_Source);
431 painter.drawImage(p: subresDesc.destinationTopLeft(), image: src,
432 sr: QRect(subresDesc.sourceTopLeft(), srcSize));
433 } else if (!subresDesc.data().isEmpty()) {
434 const QSize subresSize = q->sizeForMipLevel(mipLevel: level, baseLevelSize: texD->pixelSize());
435 int w = subresSize.width();
436 int h = subresSize.height();
437 if (!subresDesc.sourceSize().isEmpty()) {
438 w = subresDesc.sourceSize().width();
439 h = subresDesc.sourceSize().height();
440 }
441 // sourceTopLeft is not supported on this path as per QRhi docs
442 const char *src = subresDesc.data().constData();
443 const int srcBpl = w * 4;
444 int srcStride = srcBpl;
445 if (subresDesc.dataStride())
446 srcStride = subresDesc.dataStride();
447 const QPoint dstOffset = subresDesc.destinationTopLeft();
448 uchar *dst = texD->image[layer][level].bits();
449 const int dstBpl = texD->image[layer][level].bytesPerLine();
450 for (int y = 0; y < h; ++y) {
451 memcpy(dest: dst + dstOffset.x() * 4 + (y + dstOffset.y()) * dstBpl,
452 src: src + y * srcStride,
453 n: size_t(srcBpl));
454 }
455 }
456 }
457 }
458 }
459}
460
461void QRhiNull::simulateTextureCopy(const QRhiResourceUpdateBatchPrivate::TextureOp &u)
462{
463 QNullTexture *srcD = QRHI_RES(QNullTexture, u.src);
464 QNullTexture *dstD = QRHI_RES(QNullTexture, u.dst);
465 const QImage &srcImage(srcD->image[u.desc.sourceLayer()][u.desc.sourceLevel()]);
466 QImage &dstImage(dstD->image[u.desc.destinationLayer()][u.desc.destinationLevel()]);
467 const QPoint dstPos = u.desc.destinationTopLeft();
468 const QSize size = u.desc.pixelSize().isEmpty() ? srcD->pixelSize() : u.desc.pixelSize();
469 const QPoint srcPos = u.desc.sourceTopLeft();
470
471 QPainter painter(&dstImage);
472 painter.setCompositionMode(QPainter::CompositionMode_Source);
473 painter.drawImage(targetRect: QRect(dstPos, size), image: srcImage, sourceRect: QRect(srcPos, size));
474}
475
476void QRhiNull::simulateTextureGenMips(const QRhiResourceUpdateBatchPrivate::TextureOp &u)
477{
478 QNullTexture *texD = QRHI_RES(QNullTexture, u.dst);
479 const QSize baseSize = texD->pixelSize();
480 const int levelCount = q->mipLevelsForSize(size: baseSize);
481 for (int level = 1; level < levelCount; ++level)
482 texD->image[0][level] = texD->image[0][0].scaled(s: q->sizeForMipLevel(mipLevel: level, baseLevelSize: baseSize));
483}
484
485void QRhiNull::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
486{
487 Q_UNUSED(cb);
488 QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(b: resourceUpdates);
489 for (int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
490 const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
491 if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate
492 || u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload)
493 {
494 QNullBuffer *bufD = QRHI_RES(QNullBuffer, u.buf);
495 memcpy(dest: bufD->data + u.offset, src: u.data.constData(), n: size_t(u.data.size()));
496 } else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
497 QRhiReadbackResult *result = u.result;
498 result->data.resize(size: u.readSize);
499 QNullBuffer *bufD = QRHI_RES(QNullBuffer, u.buf);
500 memcpy(dest: result->data.data(), src: bufD->data + u.offset, n: size_t(u.readSize));
501 if (result->completed)
502 result->completed();
503 }
504 }
505 for (int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
506 const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
507 if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
508 if (u.dst->format() == QRhiTexture::RGBA8)
509 simulateTextureUpload(u);
510 } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
511 if (u.src->format() == QRhiTexture::RGBA8 && u.dst->format() == QRhiTexture::RGBA8)
512 simulateTextureCopy(u);
513 } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
514 QRhiReadbackResult *result = u.result;
515 QNullTexture *texD = QRHI_RES(QNullTexture, u.rb.texture());
516 if (texD) {
517 result->format = texD->format();
518 if (u.rb.rect().isValid())
519 result->pixelSize = u.rb.rect().size();
520 else
521 result->pixelSize = q->sizeForMipLevel(mipLevel: u.rb.level(), baseLevelSize: texD->pixelSize());
522 } else {
523 Q_ASSERT(currentSwapChain);
524 result->format = QRhiTexture::RGBA8;
525 if (u.rb.rect().isValid())
526 result->pixelSize = u.rb.rect().size();
527 else
528 result->pixelSize = currentSwapChain->currentPixelSize();
529 }
530 quint32 bytesPerLine = 0;
531 quint32 byteSize = 0;
532 textureFormatInfo(format: result->format, size: result->pixelSize, bpl: &bytesPerLine, byteSize: &byteSize, bytesPerPixel: nullptr);
533 if (texD && texD->format() == QRhiTexture::RGBA8) {
534 result->data.resize(size: int(byteSize));
535 const QImage &src(texD->image[u.rb.layer()][u.rb.level()]);
536 char *dst = result->data.data();
537 for (int y = 0, h = src.height(); y < h; ++y) {
538 memcpy(dest: dst, src: src.constScanLine(y), n: bytesPerLine);
539 dst += bytesPerLine;
540 }
541 } else {
542 result->data.fill(c: 0, size: int(byteSize));
543 }
544 if (result->completed)
545 result->completed();
546 } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
547 if (u.dst->format() == QRhiTexture::RGBA8)
548 simulateTextureGenMips(u);
549 }
550 }
551 ud->free();
552}
553
554void QRhiNull::beginPass(QRhiCommandBuffer *cb,
555 QRhiRenderTarget *rt,
556 const QColor &colorClearValue,
557 const QRhiDepthStencilClearValue &depthStencilClearValue,
558 QRhiResourceUpdateBatch *resourceUpdates,
559 QRhiCommandBuffer::BeginPassFlags flags)
560{
561 Q_UNUSED(colorClearValue);
562 Q_UNUSED(depthStencilClearValue);
563 Q_UNUSED(flags);
564
565 if (resourceUpdates)
566 resourceUpdate(cb, resourceUpdates);
567
568 if (rt->resourceType() == QRhiRenderTarget::TextureRenderTarget) {
569 QNullTextureRenderTarget *rtTex = QRHI_RES(QNullTextureRenderTarget, rt);
570 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QNullTexture, QNullRenderBuffer>(desc: rtTex->description(), currentResIdList: rtTex->d.currentResIdList))
571 rtTex->create();
572 }
573}
574
575void QRhiNull::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
576{
577 if (resourceUpdates)
578 resourceUpdate(cb, resourceUpdates);
579}
580
581void QRhiNull::beginComputePass(QRhiCommandBuffer *cb,
582 QRhiResourceUpdateBatch *resourceUpdates,
583 QRhiCommandBuffer::BeginPassFlags flags)
584{
585 Q_UNUSED(flags);
586 if (resourceUpdates)
587 resourceUpdate(cb, resourceUpdates);
588}
589
590void QRhiNull::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
591{
592 if (resourceUpdates)
593 resourceUpdate(cb, resourceUpdates);
594}
595
596QNullBuffer::QNullBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
597 : QRhiBuffer(rhi, type, usage, size)
598{
599}
600
601QNullBuffer::~QNullBuffer()
602{
603 destroy();
604}
605
606void QNullBuffer::destroy()
607{
608 delete[] data;
609 data = nullptr;
610
611 QRHI_RES_RHI(QRhiNull);
612 if (rhiD)
613 rhiD->unregisterResource(res: this);
614}
615
616bool QNullBuffer::create()
617{
618 if (data)
619 destroy();
620
621 data = new char[m_size];
622 memset(s: data, c: 0, n: m_size);
623
624 QRHI_RES_RHI(QRhiNull);
625 rhiD->registerResource(res: this);
626
627 return true;
628}
629
630char *QNullBuffer::beginFullDynamicBufferUpdateForCurrentFrame()
631{
632 Q_ASSERT(m_type == Dynamic);
633 return data;
634}
635
636QNullRenderBuffer::QNullRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
637 int sampleCount, QRhiRenderBuffer::Flags flags,
638 QRhiTexture::Format backingFormatHint)
639 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
640{
641}
642
643QNullRenderBuffer::~QNullRenderBuffer()
644{
645 destroy();
646}
647
648void QNullRenderBuffer::destroy()
649{
650 valid = false;
651
652 QRHI_RES_RHI(QRhiNull);
653 if (rhiD)
654 rhiD->unregisterResource(res: this);
655}
656
657bool QNullRenderBuffer::create()
658{
659 if (valid)
660 destroy();
661
662 valid = true;
663 generation += 1;
664
665 QRHI_RES_RHI(QRhiNull);
666 rhiD->registerResource(res: this);
667
668 return true;
669}
670
671QRhiTexture::Format QNullRenderBuffer::backingFormat() const
672{
673 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
674}
675
676QNullTexture::QNullTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
677 int arraySize, int sampleCount, Flags flags)
678 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
679{
680}
681
682QNullTexture::~QNullTexture()
683{
684 destroy();
685}
686
687void QNullTexture::destroy()
688{
689 valid = false;
690
691 QRHI_RES_RHI(QRhiNull);
692 if (rhiD)
693 rhiD->unregisterResource(res: this);
694}
695
696bool QNullTexture::create()
697{
698 if (valid)
699 destroy();
700
701 valid = true;
702
703 QRHI_RES_RHI(QRhiNull);
704 const bool isCube = m_flags.testFlag(flag: CubeMap);
705 const bool is3D = m_flags.testFlag(flag: ThreeDimensional);
706 const bool isArray = m_flags.testFlag(flag: TextureArray);
707 const bool hasMipMaps = m_flags.testFlag(flag: MipMapped);
708 const bool is1D = m_flags.testFlags(flags: OneDimensional);
709 QSize size = is1D ? QSize(qMax(a: 1, b: m_pixelSize.width()), 1)
710 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
711 const int mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1;
712 const int layerCount = is3D ? qMax(a: 1, b: m_depth)
713 : (isCube ? 6
714 : (isArray ? qMax(a: 0, b: m_arraySize)
715 : 1));
716
717 if (m_format == RGBA8) {
718 image.resize(sz: layerCount);
719 for (int layer = 0; layer < layerCount; ++layer) {
720 for (int level = 0; level < mipLevelCount; ++level) {
721 image[layer][level] = QImage(rhiD->q->sizeForMipLevel(mipLevel: level, baseLevelSize: size),
722 QImage::Format_RGBA8888_Premultiplied);
723 image[layer][level].fill(color: Qt::yellow);
724 }
725 }
726 }
727
728 generation += 1;
729
730 rhiD->registerResource(res: this);
731
732 return true;
733}
734
735bool QNullTexture::createFrom(QRhiTexture::NativeTexture src)
736{
737 Q_UNUSED(src);
738 if (valid)
739 destroy();
740
741 valid = true;
742
743 generation += 1;
744
745 QRHI_RES_RHI(QRhiNull);
746 rhiD->registerResource(res: this);
747
748 return true;
749}
750
751QNullSampler::QNullSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
752 AddressMode u, AddressMode v, AddressMode w)
753 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
754{
755}
756
757QNullSampler::~QNullSampler()
758{
759 destroy();
760}
761
762void QNullSampler::destroy()
763{
764 QRHI_RES_RHI(QRhiNull);
765 if (rhiD)
766 rhiD->unregisterResource(res: this);
767}
768
769bool QNullSampler::create()
770{
771 QRHI_RES_RHI(QRhiNull);
772 rhiD->registerResource(res: this);
773 return true;
774}
775
776QNullRenderPassDescriptor::QNullRenderPassDescriptor(QRhiImplementation *rhi)
777 : QRhiRenderPassDescriptor(rhi)
778{
779}
780
781QNullRenderPassDescriptor::~QNullRenderPassDescriptor()
782{
783 destroy();
784}
785
786void QNullRenderPassDescriptor::destroy()
787{
788 QRHI_RES_RHI(QRhiNull);
789 if (rhiD)
790 rhiD->unregisterResource(res: this);
791}
792
793bool QNullRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const
794{
795 Q_UNUSED(other);
796 return true;
797}
798
799QRhiRenderPassDescriptor *QNullRenderPassDescriptor::newCompatibleRenderPassDescriptor() const
800{
801 QNullRenderPassDescriptor *rpD = new QNullRenderPassDescriptor(m_rhi);
802 QRHI_RES_RHI(QRhiNull);
803 rhiD->registerResource(res: rpD, ownsNativeResources: false);
804 return rpD;
805}
806
807QVector<quint32> QNullRenderPassDescriptor::serializedFormat() const
808{
809 return {};
810}
811
812QNullSwapChainRenderTarget::QNullSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
813 : QRhiSwapChainRenderTarget(rhi, swapchain),
814 d(rhi)
815{
816}
817
818QNullSwapChainRenderTarget::~QNullSwapChainRenderTarget()
819{
820 destroy();
821}
822
823void QNullSwapChainRenderTarget::destroy()
824{
825}
826
827QSize QNullSwapChainRenderTarget::pixelSize() const
828{
829 return d.pixelSize;
830}
831
832float QNullSwapChainRenderTarget::devicePixelRatio() const
833{
834 return d.dpr;
835}
836
837int QNullSwapChainRenderTarget::sampleCount() const
838{
839 return 1;
840}
841
842QNullTextureRenderTarget::QNullTextureRenderTarget(QRhiImplementation *rhi,
843 const QRhiTextureRenderTargetDescription &desc,
844 Flags flags)
845 : QRhiTextureRenderTarget(rhi, desc, flags),
846 d(rhi)
847{
848}
849
850QNullTextureRenderTarget::~QNullTextureRenderTarget()
851{
852 destroy();
853}
854
855void QNullTextureRenderTarget::destroy()
856{
857 QRHI_RES_RHI(QRhiNull);
858 if (rhiD)
859 rhiD->unregisterResource(res: this);
860}
861
862QRhiRenderPassDescriptor *QNullTextureRenderTarget::newCompatibleRenderPassDescriptor()
863{
864 QNullRenderPassDescriptor *rpD = new QNullRenderPassDescriptor(m_rhi);
865 QRHI_RES_RHI(QRhiNull);
866 rhiD->registerResource(res: rpD, ownsNativeResources: false);
867 return rpD;
868}
869
870bool QNullTextureRenderTarget::create()
871{
872 QRHI_RES_RHI(QRhiNull);
873 d.rp = QRHI_RES(QNullRenderPassDescriptor, m_renderPassDesc);
874 if (m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments()) {
875 const QRhiColorAttachment *colorAtt = m_desc.cbeginColorAttachments();
876 QRhiTexture *tex = colorAtt->texture();
877 QRhiRenderBuffer *rb = colorAtt->renderBuffer();
878 d.pixelSize = tex ? rhiD->q->sizeForMipLevel(mipLevel: colorAtt->level(), baseLevelSize: tex->pixelSize()) : rb->pixelSize();
879 } else if (m_desc.depthStencilBuffer()) {
880 d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
881 } else if (m_desc.depthTexture()) {
882 d.pixelSize = m_desc.depthTexture()->pixelSize();
883 }
884 QRhiRenderTargetAttachmentTracker::updateResIdList<QNullTexture, QNullRenderBuffer>(desc: m_desc, dst: &d.currentResIdList);
885 rhiD->registerResource(res: this);
886 return true;
887}
888
889QSize QNullTextureRenderTarget::pixelSize() const
890{
891 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QNullTexture, QNullRenderBuffer>(desc: m_desc, currentResIdList: d.currentResIdList))
892 const_cast<QNullTextureRenderTarget *>(this)->create();
893
894 return d.pixelSize;
895}
896
897float QNullTextureRenderTarget::devicePixelRatio() const
898{
899 return d.dpr;
900}
901
902int QNullTextureRenderTarget::sampleCount() const
903{
904 return 1;
905}
906
907QNullShaderResourceBindings::QNullShaderResourceBindings(QRhiImplementation *rhi)
908 : QRhiShaderResourceBindings(rhi)
909{
910}
911
912QNullShaderResourceBindings::~QNullShaderResourceBindings()
913{
914 destroy();
915}
916
917void QNullShaderResourceBindings::destroy()
918{
919 QRHI_RES_RHI(QRhiNull);
920 if (rhiD)
921 rhiD->unregisterResource(res: this);
922}
923
924bool QNullShaderResourceBindings::create()
925{
926 QRHI_RES_RHI(QRhiNull);
927 if (!rhiD->sanityCheckShaderResourceBindings(srb: this))
928 return false;
929
930 rhiD->updateLayoutDesc(srb: this);
931
932 rhiD->registerResource(res: this, ownsNativeResources: false);
933 return true;
934}
935
936void QNullShaderResourceBindings::updateResources(UpdateFlags flags)
937{
938 Q_UNUSED(flags);
939}
940
941QNullGraphicsPipeline::QNullGraphicsPipeline(QRhiImplementation *rhi)
942 : QRhiGraphicsPipeline(rhi)
943{
944}
945
946QNullGraphicsPipeline::~QNullGraphicsPipeline()
947{
948 destroy();
949}
950
951void QNullGraphicsPipeline::destroy()
952{
953 QRHI_RES_RHI(QRhiNull);
954 if (rhiD)
955 rhiD->unregisterResource(res: this);
956}
957
958bool QNullGraphicsPipeline::create()
959{
960 QRHI_RES_RHI(QRhiNull);
961 if (!rhiD->sanityCheckGraphicsPipeline(ps: this))
962 return false;
963
964 rhiD->registerResource(res: this);
965 return true;
966}
967
968QNullComputePipeline::QNullComputePipeline(QRhiImplementation *rhi)
969 : QRhiComputePipeline(rhi)
970{
971}
972
973QNullComputePipeline::~QNullComputePipeline()
974{
975 destroy();
976}
977
978void QNullComputePipeline::destroy()
979{
980 QRHI_RES_RHI(QRhiNull);
981 if (rhiD)
982 rhiD->unregisterResource(res: this);
983}
984
985bool QNullComputePipeline::create()
986{
987 QRHI_RES_RHI(QRhiNull);
988 rhiD->registerResource(res: this);
989 return true;
990}
991
992QNullCommandBuffer::QNullCommandBuffer(QRhiImplementation *rhi)
993 : QRhiCommandBuffer(rhi)
994{
995}
996
997QNullCommandBuffer::~QNullCommandBuffer()
998{
999 destroy();
1000}
1001
1002void QNullCommandBuffer::destroy()
1003{
1004 // nothing to do here
1005}
1006
1007QNullSwapChain::QNullSwapChain(QRhiImplementation *rhi)
1008 : QRhiSwapChain(rhi),
1009 rt(rhi, this),
1010 cb(rhi)
1011{
1012}
1013
1014QNullSwapChain::~QNullSwapChain()
1015{
1016 destroy();
1017}
1018
1019void QNullSwapChain::destroy()
1020{
1021 QRHI_RES_RHI(QRhiNull);
1022 if (rhiD)
1023 rhiD->unregisterResource(res: this);
1024}
1025
1026QRhiCommandBuffer *QNullSwapChain::currentFrameCommandBuffer()
1027{
1028 return &cb;
1029}
1030
1031QRhiRenderTarget *QNullSwapChain::currentFrameRenderTarget()
1032{
1033 return &rt;
1034}
1035
1036QSize QNullSwapChain::surfacePixelSize()
1037{
1038 return QSize(1280, 720);
1039}
1040
1041bool QNullSwapChain::isFormatSupported(Format f)
1042{
1043 return f == SDR;
1044}
1045
1046QRhiRenderPassDescriptor *QNullSwapChain::newCompatibleRenderPassDescriptor()
1047{
1048 QNullRenderPassDescriptor *rpD = new QNullRenderPassDescriptor(m_rhi);
1049 QRHI_RES_RHI(QRhiNull);
1050 rhiD->registerResource(res: rpD, ownsNativeResources: false);
1051 return rpD;
1052}
1053
1054bool QNullSwapChain::createOrResize()
1055{
1056 const bool needsRegistration = !window || window != m_window;
1057 if (window && window != m_window)
1058 destroy();
1059
1060 window = m_window;
1061 m_currentPixelSize = surfacePixelSize();
1062 rt.setRenderPassDescriptor(m_renderPassDesc); // for the public getter in QRhiRenderTarget
1063 rt.d.rp = QRHI_RES(QNullRenderPassDescriptor, m_renderPassDesc);
1064 rt.d.pixelSize = m_currentPixelSize;
1065 frameCount = 0;
1066
1067 if (needsRegistration) {
1068 QRHI_RES_RHI(QRhiNull);
1069 rhiD->registerResource(res: this);
1070 }
1071
1072 return true;
1073}
1074
1075QT_END_NAMESPACE
1076

source code of qtbase/src/gui/rhi/qrhinull.cpp