Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qrhi_p.h
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
5#ifndef QRHI_P_H
6#define QRHI_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <rhi/qrhi.h>
20#include <QBitArray>
21#include <QAtomicInt>
22#include <QElapsedTimer>
23#include <QLoggingCategory>
24#include <QtCore/qset.h>
25#include <QtCore/qvarlengtharray.h>
26#include <QtCore/private/qflatmap_p.h>
27
29
30#define QRHI_RES(t, x) static_cast<t *>(x)
31#define QRHI_RES_RHI(t) t *rhiD = static_cast<t *>(m_rhi)
32
33Q_DECLARE_LOGGING_CATEGORY(QRHI_LOG_INFO)
34Q_DECLARE_LOGGING_CATEGORY(QRHI_LOG_RUB)
35
36class QRhiImplementation
37{
38public:
39 virtual ~QRhiImplementation();
40
41 virtual bool create(QRhi::Flags flags) = 0;
42 virtual void destroy() = 0;
43 virtual QRhi::AdapterList enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles) const;
44
45 virtual QRhiGraphicsPipeline *createGraphicsPipeline() = 0;
46 virtual QRhiComputePipeline *createComputePipeline() = 0;
47 virtual QRhiShaderResourceBindings *createShaderResourceBindings() = 0;
48 virtual QRhiBuffer *createBuffer(QRhiBuffer::Type type,
49 QRhiBuffer::UsageFlags usage,
50 quint32 size) = 0;
51 virtual QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
52 const QSize &pixelSize,
53 int sampleCount,
54 QRhiRenderBuffer::Flags flags,
55 QRhiTexture::Format backingFormatHint) = 0;
56 virtual QRhiTexture *createTexture(QRhiTexture::Format format,
57 const QSize &pixelSize,
58 int depth,
59 int arraySize,
60 int sampleCount,
61 QRhiTexture::Flags flags) = 0;
62 virtual QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
63 QRhiSampler::Filter minFilter,
64 QRhiSampler::Filter mipmapMode,
65 QRhiSampler:: AddressMode u,
66 QRhiSampler::AddressMode v,
67 QRhiSampler::AddressMode w) = 0;
68
69 virtual QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
70 QRhiTextureRenderTarget::Flags flags) = 0;
71
72 virtual QRhiShadingRateMap *createShadingRateMap() = 0;
73
74 virtual QRhiIndirectCommandBuffer *createIndirectCommandBuffer(QRhiIndirectCommandBuffer::Type type,
75 quint32 maxCommandCount);
76 virtual void buildIndirect(QRhiCommandBuffer *cb, QRhiIndirectCommandBuffer *icb,
77 const QRhiIndirectCommandBufferBuildInfo &info);
78 virtual void executeIndirect(QRhiCommandBuffer *cb, QRhiIndirectCommandBuffer *icb,
79 quint32 firstCommand, quint32 commandCount);
80 virtual void commitIndirectCommandBuffer(QRhiResourceUpdateBatch *u,
81 QRhiIndirectCommandBuffer *icb);
82
83 virtual QRhiSwapChain *createSwapChain() = 0;
84 virtual QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) = 0;
85 virtual QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) = 0;
86 virtual QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) = 0;
87 virtual QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) = 0;
88 virtual QRhi::FrameOpResult finish() = 0;
89
90 virtual void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
91
92 virtual void beginPass(QRhiCommandBuffer *cb,
93 QRhiRenderTarget *rt,
94 const QColor &colorClearValue,
95 const QRhiDepthStencilClearValue &depthStencilClearValue,
96 QRhiResourceUpdateBatch *resourceUpdates,
97 QRhiCommandBuffer::BeginPassFlags flags) = 0;
98 virtual void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
99
100 virtual void setGraphicsPipeline(QRhiCommandBuffer *cb,
101 QRhiGraphicsPipeline *ps) = 0;
102
103 virtual void setShaderResources(QRhiCommandBuffer *cb,
104 QRhiShaderResourceBindings *srb,
105 int dynamicOffsetCount,
106 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) = 0;
107
108 virtual void setVertexInput(QRhiCommandBuffer *cb,
109 int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
110 QRhiBuffer *indexBuf, quint32 indexOffset,
111 QRhiCommandBuffer::IndexFormat indexFormat) = 0;
112
113 virtual void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) = 0;
114 virtual void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) = 0;
115 virtual void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) = 0;
116 virtual void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) = 0;
117 virtual void setShadingRate(QRhiCommandBuffer *cb, const QSize &coarsePixelSize) = 0;
118
119 virtual void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
120 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) = 0;
121 virtual void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
122 quint32 instanceCount, quint32 firstIndex,
123 qint32 vertexOffset, quint32 firstInstance) = 0;
124 virtual void drawIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
125 quint32 offset, quint32 drawCount, quint32 stride) = 0;
126 virtual void drawIndexedIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
127 quint32 offset, quint32 drawCount, quint32 stride) = 0;
128 virtual void drawIndirectCount(QRhiCommandBuffer *cb,
129 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
130 QRhiBuffer *countBuffer, quint32 countBufferOffset,
131 quint32 maxDrawCount, quint32 stride) = 0;
132 virtual void drawIndexedIndirectCount(QRhiCommandBuffer *cb,
133 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
134 QRhiBuffer *countBuffer, quint32 countBufferOffset,
135 quint32 maxDrawCount, quint32 stride) = 0;
136
137 virtual void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) = 0;
138 virtual void debugMarkEnd(QRhiCommandBuffer *cb) = 0;
139 virtual void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) = 0;
140
141 virtual void beginComputePass(QRhiCommandBuffer *cb,
142 QRhiResourceUpdateBatch *resourceUpdates,
143 QRhiCommandBuffer::BeginPassFlags flags) = 0;
144 virtual void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
145 virtual void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) = 0;
146 virtual void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) = 0;
147 virtual void dispatchIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
148 quint32 offset) = 0;
149
150 virtual const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) = 0;
151 virtual void beginExternal(QRhiCommandBuffer *cb) = 0;
152 virtual void endExternal(QRhiCommandBuffer *cb) = 0;
153 virtual double lastCompletedGpuTime(QRhiCommandBuffer *cb) = 0;
154
155 virtual QList<int> supportedSampleCounts() const = 0;
156 virtual int ubufAlignment() const = 0;
157 virtual QList<QSize> supportedShadingRates(int sampleCount) const = 0;
158 virtual bool isYUpInFramebuffer() const = 0;
159 virtual bool isYUpInNDC() const = 0;
160 virtual bool isClipDepthZeroToOne() const = 0;
161 virtual QMatrix4x4 clipSpaceCorrMatrix() const = 0;
162 virtual bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const = 0;
163 virtual bool isFeatureSupported(QRhi::Feature feature) const = 0;
164 virtual int resourceLimit(QRhi::ResourceLimit limit) const = 0;
165 virtual const QRhiNativeHandles *nativeHandles() = 0;
166 virtual QRhiDriverInfo driverInfo() const = 0;
167 virtual QRhiStats statistics() = 0;
168 virtual bool makeThreadLocalNativeContextCurrent() = 0;
169 virtual void setQueueSubmitParams(QRhiNativeHandles *params) = 0;
170 virtual void releaseCachedResources() = 0;
171 virtual bool isDeviceLost() const = 0;
172
173 virtual QByteArray pipelineCacheData() = 0;
174 virtual void setPipelineCacheData(const QByteArray &data) = 0;
175
176 static QRhiImplementation *newInstance(QRhi::Implementation impl, QRhiInitParams *params, QRhiNativeHandles *importDevice);
177 void prepareForCreate(QRhi *rhi, QRhi::Implementation impl, QRhi::Flags flags, QRhiAdapter *adapter);
178
179 bool isCompressedFormat(QRhiTexture::Format format) const;
180 bool compressedFormatInfo(QRhiTexture::Format format, const QSize &size,
181 quint32 *bpl, quint32 *byteSize,
182 QSize *blockDim) const;
183 bool textureFormatInfo(QRhiTexture::Format format, const QSize &size,
184 quint32 *bpl, quint32 *byteSize, quint32 *bytesPerPixel) const;
185 bool isStencilSupportingFormat(QRhiTexture::Format format) const;
186
187 void registerResource(QRhiResource *res, bool ownsNativeResources = true)
188 {
189 // The ownsNativeResources is relevant for the (graphics resource) leak
190 // check in ~QRhiImplementation; when false, the registration's sole
191 // purpose is to automatically null out the resource's m_rhi pointer in
192 // case the rhi goes away first. (which should not happen in
193 // well-written applications but we try to be graceful)
194 resources.insert(res, ownsNativeResources);
195 }
196
197 void unregisterResource(QRhiResource *res)
198 {
199 resources.remove(res);
200 }
201
202 void addDeleteLater(QRhiResource *res)
203 {
204 if (inFrame)
205 pendingDeleteResources.insert(res);
206 else
207 delete res;
208 }
209
210 void addCleanupCallback(const QRhi::CleanupCallback &callback)
211 {
212 cleanupCallbacks.append(callback);
213 }
214
215 void addCleanupCallback(const void *key, const QRhi::CleanupCallback &callback)
216 {
217 keyedCleanupCallbacks[key] = callback;
218 }
219
220 void removeCleanupCallback(const void *key)
221 {
222 keyedCleanupCallbacks.remove(key);
223 }
224
225 bool sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps);
226 bool sanityCheckShaderResourceBindings(QRhiShaderResourceBindings *srb);
227 bool sanityCheckResourceOwnership(QRhiResource *maybeResource);
228 void updateLayoutDesc(QRhiShaderResourceBindings *srb);
229
230 quint32 pipelineCacheRhiId() const
231 {
232 const quint32 ver = (QT_VERSION_MAJOR << 16) | (QT_VERSION_MINOR << 8) | (QT_VERSION_PATCH);
233 return (quint32(implType) << 24) | ver;
234 }
235
236 void pipelineCreationStart()
237 {
238 pipelineCreationTimer.start();
239 }
240
241 void pipelineCreationEnd()
242 {
243 accumulatedPipelineCreationTime += pipelineCreationTimer.elapsed();
244 }
245
246 qint64 totalPipelineCreationTime() const
247 {
248 return accumulatedPipelineCreationTime;
249 }
250
251 QRhiVertexInputAttribute::Format shaderDescVariableFormatToVertexInputFormat(QShaderDescription::VariableType type) const;
252 quint32 byteSizePerVertexForVertexInputFormat(QRhiVertexInputAttribute::Format format) const;
253
254 static const QRhiShaderResourceBinding::Data *shaderResourceBindingData(const QRhiShaderResourceBinding &binding)
255 {
256 return &binding.d;
257 }
258
259 static QRhiShaderResourceBinding::Data *shaderResourceBindingData(QRhiShaderResourceBinding &binding)
260 {
261 return &binding.d;
262 }
263
264 static bool sortedBindingLessThan(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
265 {
266 return a.d.binding < b.d.binding;
267 }
268
269 int effectiveSampleCount(int sampleCount) const;
270 QSize clampedSubResourceUploadSize(QSize size, QPoint dstPos, int level, QSize textureSizeAtLevelZero, bool warn = true);
271 QSize clampedSubResourceUploadSizeForSourceData(QSize size, quint32 bpl, quint32 bytesPerPixel,
272 qsizetype dataSize, bool warn = true);
273
274 void runCleanup();
275
276 QRhi *q;
277
278 static const int MAX_SHADER_CACHE_ENTRIES = 128;
279
280 bool debugMarkers = false;
281 int currentFrameSlot = 0; // for vk, mtl, and similar. unused by gl and d3d11.
282 bool inFrame = false;
283
284 QRhiAdapter *requestedRhiAdapter = nullptr;
285
286private:
287 QRhi::Implementation implType;
288 QThread *implThread;
289 QVarLengthArray<QRhiResourceUpdateBatch *, 4> resUpdPool;
290 quint64 resUpdPoolMap = 0;
291 int lastResUpdIdx = -1;
292 QHash<QRhiResource *, bool> resources;
293 QSet<QRhiResource *> pendingDeleteResources;
294 QVarLengthArray<QRhi::CleanupCallback, 4> cleanupCallbacks;
295 QHash<const void *, QRhi::CleanupCallback> keyedCleanupCallbacks;
296 QElapsedTimer pipelineCreationTimer;
297 qint64 accumulatedPipelineCreationTime = 0;
298
299 friend class QRhi;
300 friend class QRhiResourceUpdateBatchPrivate;
301 friend class QRhiBufferData;
302};
303
305{
306public:
307 QRhiBufferBackedIndirectCommandBuffer(QRhiImplementation *rhi, Type type, quint32 maxCommandCount);
309
310 void destroy() override;
311 bool create() override;
312
313 // no-op if uploadedGeneration matches the current one, so safe to call regularly
314 void enqueueUpload(QRhiResourceUpdateBatch *u);
315
316 void execute(QRhiCommandBuffer *cb, quint32 firstCommand, quint32 commandCount);
317 void build(const QRhiIndirectCommandBufferBuildInfo &info);
318
319 bool valid = false;
320 QRhiBuffer *buffer = nullptr;
322 QRhiIndirectCommandBufferBuildInfo buildInfo;
323};
324
330
331template<QRhiTargetRectBoundMode boundingMode, typename T, size_t N>
332bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array<T, N> &r,
333 T *x, T *y, T *w, T *h)
334{
335 // x,y are bottom-left in QRhiScissor and QRhiViewport but top-left in
336 // Vulkan/Metal/D3D. Our input is an OpenGL-style scissor rect where both
337 // negative x or y, and partly or completely out of bounds rects are
338 // allowed. The only thing the input here cannot have is a negative width
339 // or height. We must handle all other input gracefully, clamping to a zero
340 // width or height rect in the worst case, and ensuring the resulting rect
341 // is inside the rendertarget's bounds because some APIs' validation/debug
342 // layers are allergic to out of bounds scissor rects.
343
344 const T outputWidth = outputSize.width();
345 const T outputHeight = outputSize.height();
346 const T inputWidth = r[2];
347 const T inputHeight = r[3];
348
349 if (inputWidth < 0 || inputHeight < 0)
350 return false;
351
352 *x = r[0];
353 *y = outputHeight - (r[1] + inputHeight);
354 *w = inputWidth;
355 *h = inputHeight;
356
357 if (boundingMode == Bounded) {
358 const T widthOffset = *x < 0 ? -*x : 0;
359 const T heightOffset = *y < 0 ? -*y : 0;
360 *w = *x < outputWidth ? qMax<T>(0, inputWidth - widthOffset) : 0;
361 *h = *y < outputHeight ? qMax<T>(0, inputHeight - heightOffset) : 0;
362
363 if (outputWidth > 0)
364 *x = qBound<T>(0, *x, outputWidth - 1);
365 if (outputHeight > 0)
366 *y = qBound<T>(0, *y, outputHeight - 1);
367
368 if (*x + *w > outputWidth)
369 *w = qMax<T>(0, outputWidth - *x);
370 if (*y + *h > outputHeight)
371 *h = qMax<T>(0, outputHeight - *y);
372 }
373 return true;
374}
375
377{
379 QRhiBufferDataPrivate() { } // don't value-initialize smallData
380 int ref = 1;
383 static constexpr quint32 SMALL_DATA_SIZE = 1024;
384 char smallData[SMALL_DATA_SIZE];
385};
386
387// no detach-with-contents, no atomic refcount, no shrink
389{
390public:
391 QRhiBufferData() = default;
393 {
394 if (d && !--d->ref)
395 delete d;
396 }
398 : d(other.d)
399 {
400 if (d)
401 d->ref += 1;
402 }
404 {
405 if (d == other.d)
406 return *this;
407 if (other.d)
408 other.d->ref += 1;
409 if (d && !--d->ref)
410 delete d;
411 d = other.d;
412 return *this;
413 }
414 const char *constData() const
415 {
416 return d ? (d->size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE ? d->smallData : d->largeData.constData()) : nullptr;
417 }
418 quint32 size() const
419 {
420 return d ? d->size : 0;
421 }
423 {
424 return d ? d->largeData.size() : 0;
425 }
426 void assign(const char *s, quint32 size)
427 {
428 if (!d) {
429 d = new QRhiBufferDataPrivate;
430 } else if (d->ref != 1) {
431 if (QRHI_LOG_RUB().isDebugEnabled())
432 qDebug("[rub] QRhiBufferData %p/%p new backing due to no-copy detach, ref was %d", this, d, d->ref);
433 d->ref -= 1;
434 d = new QRhiBufferDataPrivate;
435 }
436 d->size = size;
437 if (size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE) {
438 memcpy(d->smallData, s, size);
439 } else {
440 if (QRHI_LOG_RUB().isDebugEnabled() && largeAlloc() < size)
441 qDebug("[rub] QRhiBufferData %p/%p new large data allocation %u -> %u", this, d, largeAlloc(), size);
442 d->largeData.assign(QByteArrayView(s, size)); // keeps capacity
443 }
444 }
445 void assign(QByteArray data)
446 {
447 if (!d) {
448 d = new QRhiBufferDataPrivate;
449 } else if (d->ref != 1) {
450 if (QRHI_LOG_RUB().isDebugEnabled())
451 qDebug("[rub] QRhiBufferData %p/%p new backing due to no-copy detach, ref was %d", this, d, d->ref);
452 d->ref -= 1;
453 d = new QRhiBufferDataPrivate;
454 }
455 d->size = data.size();
456 if (d->size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE) {
457 memcpy(d->smallData, data.constData(), data.size());
458 } else {
459 d->largeData = std::move(data);
460 }
461 }
462private:
463 QRhiBufferDataPrivate *d = nullptr;
464};
465
467
469{
470public:
471 struct BufferOp {
478 QRhiBuffer *buf;
483
484 static BufferOp dynamicUpdate(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
485 {
486 BufferOp op = {};
487 changeToDynamicUpdate(&op, buf, offset, size, data);
488 return op;
489 }
490
491 static void changeToDynamicUpdate(BufferOp *op, QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
492 {
494 op->buf = buf;
495 op->offset = offset;
496 const int effectiveSize = size ? size : buf->size();
497 op->data.assign(reinterpret_cast<const char *>(data), effectiveSize);
498 }
499
500 static BufferOp dynamicUpdate(QRhiBuffer *buf, quint32 offset, QByteArray data)
501 {
502 BufferOp op = {};
503 changeToDynamicUpdate(&op, buf, offset, std::move(data));
504 return op;
505 }
506
507 static void changeToDynamicUpdate(BufferOp *op, QRhiBuffer *buf, quint32 offset, QByteArray data)
508 {
510 op->buf = buf;
511 op->offset = offset;
512 op->data.assign(std::move(data));
513 }
514
515 static BufferOp staticUpload(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
516 {
517 BufferOp op = {};
518 changeToStaticUpload(&op, buf, offset, size, data);
519 return op;
520 }
521
522 static void changeToStaticUpload(BufferOp *op, QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
523 {
525 op->buf = buf;
526 op->offset = offset;
527 const int effectiveSize = size ? size : buf->size();
528 op->data.assign(reinterpret_cast<const char *>(data), effectiveSize);
529 }
530
531 static BufferOp staticUpload(QRhiBuffer *buf, quint32 offset, QByteArray data)
532 {
533 BufferOp op = {};
534 changeToStaticUpload(&op, buf, offset, std::move(data));
535 return op;
536 }
537
538 static void changeToStaticUpload(BufferOp *op, QRhiBuffer *buf, quint32 offset, QByteArray data)
539 {
541 op->buf = buf;
542 op->offset = offset;
543 op->data.assign(std::move(data));
544 }
545
546 static BufferOp read(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiReadbackResult *result)
547 {
548 BufferOp op = {};
549 op.type = Read;
550 op.buf = buf;
551 op.offset = offset;
552 op.readSize = size;
553 op.result = result;
554 return op;
555 }
556 };
557
558 struct TextureOp {
566 QRhiTexture *dst;
567 // Specifying multiple uploads for a subresource must be supported.
568 // In the backend this can then end up, where applicable, as a
569 // single, batched copy operation with only one set of barriers.
570 // This helps when doing for example glyph cache fills.
573 QRhiTexture *src;
577
578 static TextureOp upload(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
579 {
580 TextureOp op = {};
581 op.type = Upload;
582 op.dst = tex;
583 int maxLayer = -1;
584 for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it) {
585 if (it->layer() > maxLayer)
586 maxLayer = it->layer();
587 }
588 op.subresDesc.resize(maxLayer + 1);
589 for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it)
590 op.subresDesc[it->layer()][it->level()].append(it->description());
591 return op;
592 }
593
594 static TextureOp copy(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
595 {
596 TextureOp op = {};
597 op.type = Copy;
598 op.dst = dst;
599 op.src = src;
600 op.desc = desc;
601 return op;
602 }
603
604 static TextureOp read(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
605 {
606 TextureOp op = {};
607 op.type = Read;
608 op.rb = rb;
609 op.result = result;
610 return op;
611 }
612
613 static TextureOp genMips(QRhiTexture *tex)
614 {
615 TextureOp op = {};
616 op.type = GenMips;
617 op.dst = tex;
618 return op;
619 }
620 };
621
622 int activeBufferOpCount = 0; // this is the real number of used elements in bufferOps, not bufferOps.count()
623 static const int BUFFER_OPS_STATIC_ALLOC = 64;
625
626 int activeTextureOpCount = 0; // this is the real number of used elements in textureOps, not textureOps.count()
627 static const int TEXTURE_OPS_STATIC_ALLOC = 32;
629
630 QRhiResourceUpdateBatch *q = nullptr;
631 QRhiImplementation *rhi = nullptr;
632 int poolIndex = -1;
633
634 void free();
636 bool hasOptimalCapacity() const;
637 void trimOpLists();
638
639 static QRhiResourceUpdateBatchPrivate *get(QRhiResourceUpdateBatch *b) { return b->d; }
640};
641
642template<typename T>
644{
645 void feed(int binding, T resource) { // binding must be strictly increasing
646 if (curBinding == -1 || binding > curBinding + 1) {
647 finish();
648 curBatch.startBinding = binding;
649 curBatch.resources.clear();
650 curBatch.resources.append(resource);
651 } else {
652 Q_ASSERT(binding == curBinding + 1);
653 curBatch.resources.append(resource);
654 }
655 curBinding = binding;
656 }
657
658 bool finish() {
659 if (!curBatch.resources.isEmpty())
660 batches.append(curBatch);
661 return !batches.isEmpty();
662 }
663
664 void clear() {
665 batches.clear();
666 curBatch.resources.clear();
667 curBinding = -1;
668 }
669
670 struct Batch {
673
674 bool operator==(const Batch &other) const
675 {
676 return startBinding == other.startBinding && resources == other.resources;
677 }
678
679 bool operator!=(const Batch &other) const
680 {
681 return !operator==(other);
682 }
683 };
684
685 // some backends make copies of QRhiBatchedBindings -> implicit sharing and
686 // not having a (possibly wasted) prealloc are beneficial -> use QVector
687 // instead of QVLA
688 QVector<Batch> batches; // sorted by startBinding
689
690 bool operator==(const QRhiBatchedBindings<T> &other) const
691 {
692 return batches == other.batches;
693 }
694
695 bool operator!=(const QRhiBatchedBindings<T> &other) const
696 {
697 return !operator==(other);
698 }
699
700private:
701 Batch curBatch;
702 int curBinding = -1;
703};
704
706{
707public:
708#ifdef Q_ATOMIC_INT64_IS_SUPPORTED
709 using Type = quint64;
710#else
711 using Type = quint32;
712#endif
713 static Type newId();
714};
715
717{
718public:
719 bool isEmpty() const;
720 void reset();
721
722 struct UsageState {
725 int stage;
726 };
727
738
748
749 void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage,
750 const UsageState &state);
751
762
773
774 void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage,
775 const UsageState &state);
776
783
784 const QVarLengthFlatMap<QRhiBuffer *, Buffer, 12> &buffers() const { return m_buffers; }
785
791
792 const QVarLengthFlatMap<QRhiTexture *, Texture, 12> &textures() const { return m_textures; }
793
794 static BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages);
795 static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages);
796
797private:
798 QVarLengthFlatMap<QRhiBuffer *, Buffer, 12> m_buffers;
799 QVarLengthFlatMap<QRhiTexture *, Texture, 12> m_textures;
800};
801
804
805template<typename T, int GROW = 1024>
807{
808public:
810 ~QRhiBackendCommandList() { delete[] v; }
811 inline void reset() { p = 0; }
812 inline bool isEmpty() const { return p == 0; }
813 inline T &get() {
814 if (p == a) {
815 a += GROW;
816 T *nv = new T[a];
817 if (v) {
818 memcpy(nv, v, p * sizeof(T));
819 delete[] v;
820 }
821 v = nv;
822 }
823 return v[p++];
824 }
825 inline void unget() { --p; }
826 inline T *cbegin() const { return v; }
827 inline T *cend() const { return v + p; }
828 inline T *begin() { return v; }
829 inline T *end() { return v + p; }
830private:
832 T *v = nullptr;
833 int a = 0;
834 int p = 0;
835};
836
838{
840 using ResIdList = QVarLengthArray<ResId, 8 * 2 + 1>; // color, resolve, ds
841
842 template<typename TexType, typename RenderBufferType>
843 static void updateResIdList(const QRhiTextureRenderTargetDescription &desc, ResIdList *dst);
844
845 template<typename TexType, typename RenderBufferType>
846 static bool isUpToDate(const QRhiTextureRenderTargetDescription &desc, const ResIdList &currentResIdList);
847};
848
850{
851 return a.id == b.id && a.generation == b.generation;
852}
853
855{
856 return !(a == b);
857}
858
859template<typename TexType, typename RenderBufferType>
860void QRhiRenderTargetAttachmentTracker::updateResIdList(const QRhiTextureRenderTargetDescription &desc, ResIdList *dst)
861{
862 const bool hasDepthStencil = desc.depthStencilBuffer() || desc.depthTexture();
863 dst->resize(desc.colorAttachmentCount() * 2 + (hasDepthStencil ? 1 : 0));
864 int n = 0;
865 for (auto it = desc.cbeginColorAttachments(), itEnd = desc.cendColorAttachments(); it != itEnd; ++it, ++n) {
866 const QRhiColorAttachment &colorAtt(*it);
867 if (colorAtt.texture()) {
868 TexType *texD = QRHI_RES(TexType, colorAtt.texture());
869 (*dst)[n] = { texD->globalResourceId(), texD->generation };
870 } else if (colorAtt.renderBuffer()) {
871 RenderBufferType *rbD = QRHI_RES(RenderBufferType, colorAtt.renderBuffer());
872 (*dst)[n] = { rbD->globalResourceId(), rbD->generation };
873 } else {
874 (*dst)[n] = { 0, 0 };
875 }
876 ++n;
877 if (colorAtt.resolveTexture()) {
878 TexType *texD = QRHI_RES(TexType, colorAtt.resolveTexture());
879 (*dst)[n] = { texD->globalResourceId(), texD->generation };
880 } else {
881 (*dst)[n] = { 0, 0 };
882 }
883 }
884 if (hasDepthStencil) {
885 if (desc.depthTexture()) {
886 TexType *depthTexD = QRHI_RES(TexType, desc.depthTexture());
887 (*dst)[n] = { depthTexD->globalResourceId(), depthTexD->generation };
888 } else if (desc.depthStencilBuffer()) {
889 RenderBufferType *depthRbD = QRHI_RES(RenderBufferType, desc.depthStencilBuffer());
890 (*dst)[n] = { depthRbD->globalResourceId(), depthRbD->generation };
891 } else {
892 (*dst)[n] = { 0, 0 };
893 }
894 }
895}
896
897template<typename TexType, typename RenderBufferType>
898bool QRhiRenderTargetAttachmentTracker::isUpToDate(const QRhiTextureRenderTargetDescription &desc, const ResIdList &currentResIdList)
899{
900 // Just as setShaderResources() recognizes if an srb's referenced
901 // resources have been rebuilt (got a create() since the srb's
902 // create()), we should do the same for the textures and renderbuffers
903 // referenced from the rendertarget. It is not uncommon that a texture
904 // or ds buffer gets resized due to following a window size in some
905 // form, which involves a create() on them. It is then nice if the
906 // render target auto-rebuilds in beginPass().
907
908 ResIdList resIdList;
909 updateResIdList<TexType, RenderBufferType>(desc, &resIdList);
910 return resIdList == currentResIdList;
911}
912
913template<typename T>
914inline T *qrhi_objectFromProxyData(QRhiSwapChainProxyData *pd, QWindow *window, QRhi::Implementation impl, uint objectIndex)
915{
916 Q_ASSERT(objectIndex < std::size(pd->reserved));
917 if (!pd->reserved[objectIndex]) // // was not set, no other choice, do it here, whatever thread this is
918 *pd = QRhi::updateSwapChainProxyData(impl, window);
919 return static_cast<T *>(pd->reserved[objectIndex]);
920}
921
923{
924public:
925 QRhiPipelineCacheDataReader(const char *data, quint32 size)
926 : m_p(data), m_end(data + size)
927 {
928 }
929
930 bool readUInt32(quint32 *dst)
931 {
932 if (m_end - m_p < qptrdiff(sizeof(quint32)))
933 return false;
934 memcpy(dst, m_p, sizeof(quint32));
935 m_p += sizeof(quint32);
936 return true;
937 }
938
939 // Reads a 32-bit length, followed by that many bytes.
940 bool readByteArray(QByteArray *dst)
941 {
942 quint32 len = 0;
943 if (!readUInt32(&len))
944 return false;
945 if (quint64(m_end - m_p) < len)
946 return false;
947 *dst = QByteArray(m_p, qsizetype(len));
948 m_p += len;
949 return true;
950 }
951
952private:
953 const char *m_p;
954 const char *m_end;
955};
956
957QT_END_NAMESPACE
958
959#endif
friend bool operator==(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
Returns true if lhs and rhs are equal, otherwise returns false.
Definition qbytearray.h:838
friend bool operator!=(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
Returns true if lhs and rhs are different, otherwise returns false.
Definition qbytearray.h:849
QRhiBackendCommandList()=default
T * cend() const
Definition qrhi_p.h:827
T * cbegin() const
Definition qrhi_p.h:826
bool isEmpty() const
Definition qrhi_p.h:812
void execute(QRhiCommandBuffer *cb, quint32 firstCommand, quint32 commandCount)
Definition qrhi.cpp:9183
QRhiBufferBackedIndirectCommandBuffer(QRhiImplementation *rhi, Type type, quint32 maxCommandCount)
\variable QRhiIndirectCommandBufferBuildInfo::topology
Definition qrhi.cpp:9093
void enqueueUpload(QRhiResourceUpdateBatch *u)
Definition qrhi.cpp:9147
QRhiIndirectCommandBufferBuildInfo buildInfo
Definition qrhi_p.h:322
void build(const QRhiIndirectCommandBufferBuildInfo &info)
Definition qrhi.cpp:9170
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
Definition qrhi.cpp:9105
bool create() override
Creates the corresponding native objects.
Definition qrhi.cpp:9128
void assign(QByteArray data)
Definition qrhi_p.h:445
QRhiBufferData()=default
void assign(const char *s, quint32 size)
Definition qrhi_p.h:426
quint32 size() const
Definition qrhi_p.h:418
QRhiBufferData(const QRhiBufferData &other)
Definition qrhi_p.h:397
quint32 largeAlloc() const
Definition qrhi_p.h:422
QRhiBufferData & operator=(const QRhiBufferData &other)
Definition qrhi_p.h:403
const char * constData() const
Definition qrhi_p.h:414
static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages)
Definition qrhi.cpp:13327
const QVarLengthFlatMap< QRhiBuffer *, Buffer, 12 > & buffers() const
Definition qrhi_p.h:784
static BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages)
Definition qrhi.cpp:13308
const QVarLengthFlatMap< QRhiTexture *, Texture, 12 > & textures() const
Definition qrhi_p.h:792
bool isEmpty() const
Definition qrhi.cpp:13217
void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage, const UsageState &state)
Definition qrhi.cpp:13234
void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage, const UsageState &state)
Definition qrhi.cpp:13274
QRhiPipelineCacheDataReader(const char *data, quint32 size)
Definition qrhi_p.h:925
bool readByteArray(QByteArray *dst)
Definition qrhi_p.h:940
bool readUInt32(quint32 *dst)
Definition qrhi_p.h:930
QVarLengthArray< BufferOp, BUFFER_OPS_STATIC_ALLOC > bufferOps
Definition qrhi_p.h:624
QRhiImplementation * rhi
Definition qrhi_p.h:631
QVarLengthArray< TextureOp, TEXTURE_OPS_STATIC_ALLOC > textureOps
Definition qrhi_p.h:628
static const int BUFFER_OPS_STATIC_ALLOC
Definition qrhi_p.h:623
static QRhiResourceUpdateBatchPrivate * get(QRhiResourceUpdateBatch *b)
Definition qrhi_p.h:639
void merge(QRhiResourceUpdateBatchPrivate *other)
Definition qrhi.cpp:11063
QRhiResourceUpdateBatch * q
Definition qrhi_p.h:630
static const int TEXTURE_OPS_STATIC_ALLOC
Definition qrhi_p.h:627
Combined button and popup list for selecting options.
QDebug operator<<(QDebug dbg, const QFileInfo &fi)
static const char * resourceTypeStr(const QRhiResource *res)
Definition qrhi.cpp:9344
static QRhiPassResourceTracker::BufferStage earlierStage(QRhiPassResourceTracker::BufferStage a, QRhiPassResourceTracker::BufferStage b)
Definition qrhi.cpp:13228
QDebug operator<<(QDebug dbg, const QRhiSwapChainHdrInfo &info)
Definition qrhi.cpp:8396
static bool isImageLoadStore(QRhiPassResourceTracker::TextureAccess access)
Definition qrhi.cpp:13267
static const char * deviceTypeStr(QRhiDriverInfo::DeviceType type)
\variable QRhiDriverInfo::deviceName
Definition qrhi.cpp:10323
static QRhiPassResourceTracker::TextureStage earlierStage(QRhiPassResourceTracker::TextureStage a, QRhiPassResourceTracker::TextureStage b)
Definition qrhi.cpp:13261
QRhiTargetRectBoundMode
Definition qrhi_p.h:326
@ UnBounded
Definition qrhi_p.h:327
@ Bounded
Definition qrhi_p.h:328
Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Texture, Q_RELOCATABLE_TYPE)
Q_DECLARE_TYPEINFO(QRhiBufferData, Q_RELOCATABLE_TYPE)
T * qrhi_objectFromProxyData(QRhiSwapChainProxyData *pd, QWindow *window, QRhi::Implementation impl, uint objectIndex)
Definition qrhi_p.h:914
bool operator!=(const QRhiRenderTargetAttachmentTracker::ResId &a, const QRhiRenderTargetAttachmentTracker::ResId &b)
Definition qrhi_p.h:854
Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Buffer, Q_RELOCATABLE_TYPE)
#define QRHI_RES(t, x)
Definition qrhi_p.h:30
bool operator==(const QRhiRenderTargetAttachmentTracker::ResId &a, const QRhiRenderTargetAttachmentTracker::ResId &b)
Definition qrhi_p.h:849
bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array< T, N > &r, T *x, T *y, T *w, T *h)
Definition qrhi_p.h:332
constexpr size_t qHash(const QSize &s, size_t seed=0) noexcept
Definition qsize.h:192
bool operator!=(const Batch &other) const
Definition qrhi_p.h:679
QVector< T > resources
Definition qrhi_p.h:672
bool operator==(const Batch &other) const
Definition qrhi_p.h:674
void feed(int binding, T resource)
Definition qrhi_p.h:645
QVector< Batch > batches
Definition qrhi_p.h:688
bool operator!=(const QRhiBatchedBindings< T > &other) const
Definition qrhi_p.h:695
bool operator==(const QRhiBatchedBindings< T > &other) const
Definition qrhi_p.h:690
char smallData[SMALL_DATA_SIZE]
Definition qrhi_p.h:384
QByteArray largeData
Definition qrhi_p.h:382
static constexpr quint32 SMALL_DATA_SIZE
Definition qrhi_p.h:383
static void updateResIdList(const QRhiTextureRenderTargetDescription &desc, ResIdList *dst)
Definition qrhi_p.h:860
static bool isUpToDate(const QRhiTextureRenderTargetDescription &desc, const ResIdList &currentResIdList)
Definition qrhi_p.h:898
static void changeToDynamicUpdate(BufferOp *op, QRhiBuffer *buf, quint32 offset, QByteArray data)
Definition qrhi_p.h:507
static void changeToStaticUpload(BufferOp *op, QRhiBuffer *buf, quint32 offset, QByteArray data)
Definition qrhi_p.h:538
static void changeToStaticUpload(BufferOp *op, QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
Definition qrhi_p.h:522
static BufferOp dynamicUpdate(QRhiBuffer *buf, quint32 offset, QByteArray data)
Definition qrhi_p.h:500
static BufferOp staticUpload(QRhiBuffer *buf, quint32 offset, QByteArray data)
Definition qrhi_p.h:531
static BufferOp staticUpload(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
Definition qrhi_p.h:515
static BufferOp read(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiReadbackResult *result)
Definition qrhi_p.h:546
static BufferOp dynamicUpdate(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
Definition qrhi_p.h:484
static void changeToDynamicUpdate(BufferOp *op, QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
Definition qrhi_p.h:491
QRhiTextureCopyDescription desc
Definition qrhi_p.h:574
static TextureOp copy(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
Definition qrhi_p.h:594
QVarLengthArray< MipLevelUploadList, 6 > subresDesc
Definition qrhi_p.h:572
static TextureOp upload(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
Definition qrhi_p.h:578
static TextureOp genMips(QRhiTexture *tex)
Definition qrhi_p.h:613
static TextureOp read(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
Definition qrhi_p.h:604
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:1566
LimitsType limitsType
Definition qrhi.h:1577
float maxPotentialColorComponentValue
Definition qrhi.h:1585
LuminanceBehavior luminanceBehavior
Definition qrhi.h:1588
float maxColorComponentValue
Definition qrhi.h:1584
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:1599
void * reserved[2]
Definition qrhi.h:1600