Coverage Report

Created: 2026-02-10 07:39

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