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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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