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 QRhiSwapChain *createSwapChain() = 0;
75 virtual QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) = 0;
76 virtual QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) = 0;
77 virtual QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) = 0;
78 virtual QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) = 0;
79 virtual QRhi::FrameOpResult finish() = 0;
80
81 virtual void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
82
83 virtual void beginPass(QRhiCommandBuffer *cb,
84 QRhiRenderTarget *rt,
85 const QColor &colorClearValue,
86 const QRhiDepthStencilClearValue &depthStencilClearValue,
87 QRhiResourceUpdateBatch *resourceUpdates,
88 QRhiCommandBuffer::BeginPassFlags flags) = 0;
89 virtual void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
90
91 virtual void setGraphicsPipeline(QRhiCommandBuffer *cb,
92 QRhiGraphicsPipeline *ps) = 0;
93
94 virtual void setShaderResources(QRhiCommandBuffer *cb,
95 QRhiShaderResourceBindings *srb,
96 int dynamicOffsetCount,
97 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) = 0;
98
99 virtual void setVertexInput(QRhiCommandBuffer *cb,
100 int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
101 QRhiBuffer *indexBuf, quint32 indexOffset,
102 QRhiCommandBuffer::IndexFormat indexFormat) = 0;
103
104 virtual void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) = 0;
105 virtual void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) = 0;
106 virtual void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) = 0;
107 virtual void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) = 0;
108 virtual void setShadingRate(QRhiCommandBuffer *cb, const QSize &coarsePixelSize) = 0;
109
110 virtual void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
111 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) = 0;
112 virtual void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
113 quint32 instanceCount, quint32 firstIndex,
114 qint32 vertexOffset, quint32 firstInstance) = 0;
115 virtual void drawIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
116 quint32 offset, quint32 drawCount, quint32 stride) = 0;
117 virtual void drawIndexedIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
118 quint32 offset, quint32 drawCount, quint32 stride) = 0;
119
120 virtual void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) = 0;
121 virtual void debugMarkEnd(QRhiCommandBuffer *cb) = 0;
122 virtual void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) = 0;
123
124 virtual void beginComputePass(QRhiCommandBuffer *cb,
125 QRhiResourceUpdateBatch *resourceUpdates,
126 QRhiCommandBuffer::BeginPassFlags flags) = 0;
127 virtual void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
128 virtual void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) = 0;
129 virtual void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) = 0;
130
131 virtual const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) = 0;
132 virtual void beginExternal(QRhiCommandBuffer *cb) = 0;
133 virtual void endExternal(QRhiCommandBuffer *cb) = 0;
134 virtual double lastCompletedGpuTime(QRhiCommandBuffer *cb) = 0;
135
136 virtual QList<int> supportedSampleCounts() const = 0;
137 virtual int ubufAlignment() const = 0;
138 virtual QList<QSize> supportedShadingRates(int sampleCount) const = 0;
139 virtual bool isYUpInFramebuffer() const = 0;
140 virtual bool isYUpInNDC() const = 0;
141 virtual bool isClipDepthZeroToOne() const = 0;
142 virtual QMatrix4x4 clipSpaceCorrMatrix() const = 0;
143 virtual bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const = 0;
144 virtual bool isFeatureSupported(QRhi::Feature feature) const = 0;
145 virtual int resourceLimit(QRhi::ResourceLimit limit) const = 0;
146 virtual const QRhiNativeHandles *nativeHandles() = 0;
147 virtual QRhiDriverInfo driverInfo() const = 0;
148 virtual QRhiStats statistics() = 0;
149 virtual bool makeThreadLocalNativeContextCurrent() = 0;
150 virtual void setQueueSubmitParams(QRhiNativeHandles *params) = 0;
151 virtual void releaseCachedResources() = 0;
152 virtual bool isDeviceLost() const = 0;
153
154 virtual QByteArray pipelineCacheData() = 0;
155 virtual void setPipelineCacheData(const QByteArray &data) = 0;
156
157 static QRhiImplementation *newInstance(QRhi::Implementation impl, QRhiInitParams *params, QRhiNativeHandles *importDevice);
158 void prepareForCreate(QRhi *rhi, QRhi::Implementation impl, QRhi::Flags flags, QRhiAdapter *adapter);
159
160 bool isCompressedFormat(QRhiTexture::Format format) const;
161 bool compressedFormatInfo(QRhiTexture::Format format, const QSize &size,
162 quint32 *bpl, quint32 *byteSize,
163 QSize *blockDim) const;
164 bool textureFormatInfo(QRhiTexture::Format format, const QSize &size,
165 quint32 *bpl, quint32 *byteSize, quint32 *bytesPerPixel) const;
166 bool isStencilSupportingFormat(QRhiTexture::Format format) const;
167
168 void registerResource(QRhiResource *res, bool ownsNativeResources = true)
169 {
170 // The ownsNativeResources is relevant for the (graphics resource) leak
171 // check in ~QRhiImplementation; when false, the registration's sole
172 // purpose is to automatically null out the resource's m_rhi pointer in
173 // case the rhi goes away first. (which should not happen in
174 // well-written applications but we try to be graceful)
175 resources.insert(res, ownsNativeResources);
176 }
177
178 void unregisterResource(QRhiResource *res)
179 {
180 resources.remove(res);
181 }
182
183 void addDeleteLater(QRhiResource *res)
184 {
185 if (inFrame)
186 pendingDeleteResources.insert(res);
187 else
188 delete res;
189 }
190
191 void addCleanupCallback(const QRhi::CleanupCallback &callback)
192 {
193 cleanupCallbacks.append(callback);
194 }
195
196 void addCleanupCallback(const void *key, const QRhi::CleanupCallback &callback)
197 {
198 keyedCleanupCallbacks[key] = callback;
199 }
200
201 void removeCleanupCallback(const void *key)
202 {
203 keyedCleanupCallbacks.remove(key);
204 }
205
206 bool sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps);
207 bool sanityCheckShaderResourceBindings(QRhiShaderResourceBindings *srb);
208 bool sanityCheckResourceOwnership(QRhiResource *maybeResource);
209 void updateLayoutDesc(QRhiShaderResourceBindings *srb);
210
211 quint32 pipelineCacheRhiId() const
212 {
213 const quint32 ver = (QT_VERSION_MAJOR << 16) | (QT_VERSION_MINOR << 8) | (QT_VERSION_PATCH);
214 return (quint32(implType) << 24) | ver;
215 }
216
217 void pipelineCreationStart()
218 {
219 pipelineCreationTimer.start();
220 }
221
222 void pipelineCreationEnd()
223 {
224 accumulatedPipelineCreationTime += pipelineCreationTimer.elapsed();
225 }
226
227 qint64 totalPipelineCreationTime() const
228 {
229 return accumulatedPipelineCreationTime;
230 }
231
232 QRhiVertexInputAttribute::Format shaderDescVariableFormatToVertexInputFormat(QShaderDescription::VariableType type) const;
233 quint32 byteSizePerVertexForVertexInputFormat(QRhiVertexInputAttribute::Format format) const;
234
235 static const QRhiShaderResourceBinding::Data *shaderResourceBindingData(const QRhiShaderResourceBinding &binding)
236 {
237 return &binding.d;
238 }
239
240 static QRhiShaderResourceBinding::Data *shaderResourceBindingData(QRhiShaderResourceBinding &binding)
241 {
242 return &binding.d;
243 }
244
245 static bool sortedBindingLessThan(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
246 {
247 return a.d.binding < b.d.binding;
248 }
249
250 int effectiveSampleCount(int sampleCount) const;
251 QSize clampedSubResourceUploadSize(QSize size, QPoint dstPos, int level, QSize textureSizeAtLevelZero, bool warn = true);
252 QSize clampedSubResourceUploadSizeForSourceData(QSize size, quint32 bpl, quint32 bytesPerPixel,
253 qsizetype dataSize, bool warn = true);
254
255 void runCleanup();
256
257 QRhi *q;
258
259 static const int MAX_SHADER_CACHE_ENTRIES = 128;
260
261 bool debugMarkers = false;
262 int currentFrameSlot = 0; // for vk, mtl, and similar. unused by gl and d3d11.
263 bool inFrame = false;
264
265 QRhiAdapter *requestedRhiAdapter = nullptr;
266
267private:
268 QRhi::Implementation implType;
269 QThread *implThread;
270 QVarLengthArray<QRhiResourceUpdateBatch *, 4> resUpdPool;
271 quint64 resUpdPoolMap = 0;
272 int lastResUpdIdx = -1;
273 QHash<QRhiResource *, bool> resources;
274 QSet<QRhiResource *> pendingDeleteResources;
275 QVarLengthArray<QRhi::CleanupCallback, 4> cleanupCallbacks;
276 QHash<const void *, QRhi::CleanupCallback> keyedCleanupCallbacks;
277 QElapsedTimer pipelineCreationTimer;
278 qint64 accumulatedPipelineCreationTime = 0;
279
280 friend class QRhi;
281 friend class QRhiResourceUpdateBatchPrivate;
282 friend class QRhiBufferData;
283};
284
290
291template<QRhiTargetRectBoundMode boundingMode, typename T, size_t N>
292bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array<T, N> &r,
293 T *x, T *y, T *w, T *h)
294{
295 // x,y are bottom-left in QRhiScissor and QRhiViewport but top-left in
296 // Vulkan/Metal/D3D. Our input is an OpenGL-style scissor rect where both
297 // negative x or y, and partly or completely out of bounds rects are
298 // allowed. The only thing the input here cannot have is a negative width
299 // or height. We must handle all other input gracefully, clamping to a zero
300 // width or height rect in the worst case, and ensuring the resulting rect
301 // is inside the rendertarget's bounds because some APIs' validation/debug
302 // layers are allergic to out of bounds scissor rects.
303
304 const T outputWidth = outputSize.width();
305 const T outputHeight = outputSize.height();
306 const T inputWidth = r[2];
307 const T inputHeight = r[3];
308
309 if (inputWidth < 0 || inputHeight < 0)
310 return false;
311
312 *x = r[0];
313 *y = outputHeight - (r[1] + inputHeight);
314 *w = inputWidth;
315 *h = inputHeight;
316
317 if (boundingMode == Bounded) {
318 const T widthOffset = *x < 0 ? -*x : 0;
319 const T heightOffset = *y < 0 ? -*y : 0;
320 *w = *x < outputWidth ? qMax<T>(0, inputWidth - widthOffset) : 0;
321 *h = *y < outputHeight ? qMax<T>(0, inputHeight - heightOffset) : 0;
322
323 if (outputWidth > 0)
324 *x = qBound<T>(0, *x, outputWidth - 1);
325 if (outputHeight > 0)
326 *y = qBound<T>(0, *y, outputHeight - 1);
327
328 if (*x + *w > outputWidth)
329 *w = qMax<T>(0, outputWidth - *x);
330 if (*y + *h > outputHeight)
331 *h = qMax<T>(0, outputHeight - *y);
332 }
333 return true;
334}
335
337{
339 QRhiBufferDataPrivate() { } // don't value-initialize smallData
340 int ref = 1;
343 static constexpr quint32 SMALL_DATA_SIZE = 1024;
344 char smallData[SMALL_DATA_SIZE];
345};
346
347// no detach-with-contents, no atomic refcount, no shrink
349{
350public:
351 QRhiBufferData() = default;
353 {
354 if (d && !--d->ref)
355 delete d;
356 }
358 : d(other.d)
359 {
360 if (d)
361 d->ref += 1;
362 }
364 {
365 if (d == other.d)
366 return *this;
367 if (other.d)
368 other.d->ref += 1;
369 if (d && !--d->ref)
370 delete d;
371 d = other.d;
372 return *this;
373 }
374 const char *constData() const
375 {
376 return d ? (d->size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE ? d->smallData : d->largeData.constData()) : nullptr;
377 }
378 quint32 size() const
379 {
380 return d ? d->size : 0;
381 }
383 {
384 return d ? d->largeData.size() : 0;
385 }
386 void assign(const char *s, quint32 size)
387 {
388 if (!d) {
389 d = new QRhiBufferDataPrivate;
390 } else if (d->ref != 1) {
391 if (QRHI_LOG_RUB().isDebugEnabled())
392 qDebug("[rub] QRhiBufferData %p/%p new backing due to no-copy detach, ref was %d", this, d, d->ref);
393 d->ref -= 1;
394 d = new QRhiBufferDataPrivate;
395 }
396 d->size = size;
397 if (size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE) {
398 memcpy(d->smallData, s, size);
399 } else {
400 if (QRHI_LOG_RUB().isDebugEnabled() && largeAlloc() < size)
401 qDebug("[rub] QRhiBufferData %p/%p new large data allocation %u -> %u", this, d, largeAlloc(), size);
402 d->largeData.assign(QByteArrayView(s, size)); // keeps capacity
403 }
404 }
405 void assign(QByteArray data)
406 {
407 if (!d) {
408 d = new QRhiBufferDataPrivate;
409 } else if (d->ref != 1) {
410 if (QRHI_LOG_RUB().isDebugEnabled())
411 qDebug("[rub] QRhiBufferData %p/%p new backing due to no-copy detach, ref was %d", this, d, d->ref);
412 d->ref -= 1;
413 d = new QRhiBufferDataPrivate;
414 }
415 d->size = data.size();
416 if (d->size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE) {
417 memcpy(d->smallData, data.constData(), data.size());
418 } else {
419 d->largeData = std::move(data);
420 }
421 }
422private:
423 QRhiBufferDataPrivate *d = nullptr;
424};
425
427
429{
430public:
431 struct BufferOp {
438 QRhiBuffer *buf;
443
444 static BufferOp dynamicUpdate(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
445 {
446 BufferOp op = {};
447 changeToDynamicUpdate(&op, buf, offset, size, data);
448 return op;
449 }
450
451 static void changeToDynamicUpdate(BufferOp *op, QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
452 {
454 op->buf = buf;
455 op->offset = offset;
456 const int effectiveSize = size ? size : buf->size();
457 op->data.assign(reinterpret_cast<const char *>(data), effectiveSize);
458 }
459
460 static BufferOp dynamicUpdate(QRhiBuffer *buf, quint32 offset, QByteArray data)
461 {
462 BufferOp op = {};
463 changeToDynamicUpdate(&op, buf, offset, std::move(data));
464 return op;
465 }
466
467 static void changeToDynamicUpdate(BufferOp *op, QRhiBuffer *buf, quint32 offset, QByteArray data)
468 {
470 op->buf = buf;
471 op->offset = offset;
472 op->data.assign(std::move(data));
473 }
474
475 static BufferOp staticUpload(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
476 {
477 BufferOp op = {};
478 changeToStaticUpload(&op, buf, offset, size, data);
479 return op;
480 }
481
482 static void changeToStaticUpload(BufferOp *op, QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
483 {
485 op->buf = buf;
486 op->offset = offset;
487 const int effectiveSize = size ? size : buf->size();
488 op->data.assign(reinterpret_cast<const char *>(data), effectiveSize);
489 }
490
491 static BufferOp staticUpload(QRhiBuffer *buf, quint32 offset, QByteArray data)
492 {
493 BufferOp op = {};
494 changeToStaticUpload(&op, buf, offset, std::move(data));
495 return op;
496 }
497
498 static void changeToStaticUpload(BufferOp *op, QRhiBuffer *buf, quint32 offset, QByteArray data)
499 {
501 op->buf = buf;
502 op->offset = offset;
503 op->data.assign(std::move(data));
504 }
505
506 static BufferOp read(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiReadbackResult *result)
507 {
508 BufferOp op = {};
509 op.type = Read;
510 op.buf = buf;
511 op.offset = offset;
512 op.readSize = size;
513 op.result = result;
514 return op;
515 }
516 };
517
518 struct TextureOp {
526 QRhiTexture *dst;
527 // Specifying multiple uploads for a subresource must be supported.
528 // In the backend this can then end up, where applicable, as a
529 // single, batched copy operation with only one set of barriers.
530 // This helps when doing for example glyph cache fills.
533 QRhiTexture *src;
537
538 static TextureOp upload(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
539 {
540 TextureOp op = {};
541 op.type = Upload;
542 op.dst = tex;
543 int maxLayer = -1;
544 for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it) {
545 if (it->layer() > maxLayer)
546 maxLayer = it->layer();
547 }
548 op.subresDesc.resize(maxLayer + 1);
549 for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it)
550 op.subresDesc[it->layer()][it->level()].append(it->description());
551 return op;
552 }
553
554 static TextureOp copy(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
555 {
556 TextureOp op = {};
557 op.type = Copy;
558 op.dst = dst;
559 op.src = src;
560 op.desc = desc;
561 return op;
562 }
563
564 static TextureOp read(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
565 {
566 TextureOp op = {};
567 op.type = Read;
568 op.rb = rb;
569 op.result = result;
570 return op;
571 }
572
573 static TextureOp genMips(QRhiTexture *tex)
574 {
575 TextureOp op = {};
576 op.type = GenMips;
577 op.dst = tex;
578 return op;
579 }
580 };
581
582 int activeBufferOpCount = 0; // this is the real number of used elements in bufferOps, not bufferOps.count()
583 static const int BUFFER_OPS_STATIC_ALLOC = 64;
585
586 int activeTextureOpCount = 0; // this is the real number of used elements in textureOps, not textureOps.count()
587 static const int TEXTURE_OPS_STATIC_ALLOC = 32;
589
590 QRhiResourceUpdateBatch *q = nullptr;
591 QRhiImplementation *rhi = nullptr;
592 int poolIndex = -1;
593
594 void free();
596 bool hasOptimalCapacity() const;
597 void trimOpLists();
598
599 static QRhiResourceUpdateBatchPrivate *get(QRhiResourceUpdateBatch *b) { return b->d; }
600};
601
602template<typename T>
604{
605 void feed(int binding, T resource) { // binding must be strictly increasing
606 if (curBinding == -1 || binding > curBinding + 1) {
607 finish();
608 curBatch.startBinding = binding;
609 curBatch.resources.clear();
610 curBatch.resources.append(resource);
611 } else {
612 Q_ASSERT(binding == curBinding + 1);
613 curBatch.resources.append(resource);
614 }
615 curBinding = binding;
616 }
617
618 bool finish() {
619 if (!curBatch.resources.isEmpty())
620 batches.append(curBatch);
621 return !batches.isEmpty();
622 }
623
624 void clear() {
625 batches.clear();
626 curBatch.resources.clear();
627 curBinding = -1;
628 }
629
630 struct Batch {
633
634 bool operator==(const Batch &other) const
635 {
636 return startBinding == other.startBinding && resources == other.resources;
637 }
638
639 bool operator!=(const Batch &other) const
640 {
641 return !operator==(other);
642 }
643 };
644
645 // some backends make copies of QRhiBatchedBindings -> implicit sharing and
646 // not having a (possibly wasted) prealloc are beneficial -> use QVector
647 // instead of QVLA
648 QVector<Batch> batches; // sorted by startBinding
649
650 bool operator==(const QRhiBatchedBindings<T> &other) const
651 {
652 return batches == other.batches;
653 }
654
655 bool operator!=(const QRhiBatchedBindings<T> &other) const
656 {
657 return !operator==(other);
658 }
659
660private:
661 Batch curBatch;
662 int curBinding = -1;
663};
664
666{
667public:
668#ifdef Q_ATOMIC_INT64_IS_SUPPORTED
669 using Type = quint64;
670#else
671 using Type = quint32;
672#endif
673 static Type newId();
674};
675
677{
678public:
679 bool isEmpty() const;
680 void reset();
681
682 struct UsageState {
685 int stage;
686 };
687
698
708
709 void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage,
710 const UsageState &state);
711
722
732
733 void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage,
734 const UsageState &state);
735
742
743 const QVarLengthFlatMap<QRhiBuffer *, Buffer, 12> &buffers() const { return m_buffers; }
744
750
751 const QVarLengthFlatMap<QRhiTexture *, Texture, 12> &textures() const { return m_textures; }
752
753 static BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages);
754 static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages);
755
756private:
757 QVarLengthFlatMap<QRhiBuffer *, Buffer, 12> m_buffers;
758 QVarLengthFlatMap<QRhiTexture *, Texture, 12> m_textures;
759};
760
763
764template<typename T, int GROW = 1024>
766{
767public:
769 ~QRhiBackendCommandList() { delete[] v; }
770 inline void reset() { p = 0; }
771 inline bool isEmpty() const { return p == 0; }
772 inline T &get() {
773 if (p == a) {
774 a += GROW;
775 T *nv = new T[a];
776 if (v) {
777 memcpy(nv, v, p * sizeof(T));
778 delete[] v;
779 }
780 v = nv;
781 }
782 return v[p++];
783 }
784 inline void unget() { --p; }
785 inline T *cbegin() const { return v; }
786 inline T *cend() const { return v + p; }
787 inline T *begin() { return v; }
788 inline T *end() { return v + p; }
789private:
791 T *v = nullptr;
792 int a = 0;
793 int p = 0;
794};
795
797{
799 using ResIdList = QVarLengthArray<ResId, 8 * 2 + 1>; // color, resolve, ds
800
801 template<typename TexType, typename RenderBufferType>
802 static void updateResIdList(const QRhiTextureRenderTargetDescription &desc, ResIdList *dst);
803
804 template<typename TexType, typename RenderBufferType>
805 static bool isUpToDate(const QRhiTextureRenderTargetDescription &desc, const ResIdList &currentResIdList);
806};
807
809{
810 return a.id == b.id && a.generation == b.generation;
811}
812
814{
815 return !(a == b);
816}
817
818template<typename TexType, typename RenderBufferType>
819void QRhiRenderTargetAttachmentTracker::updateResIdList(const QRhiTextureRenderTargetDescription &desc, ResIdList *dst)
820{
821 const bool hasDepthStencil = desc.depthStencilBuffer() || desc.depthTexture();
822 dst->resize(desc.colorAttachmentCount() * 2 + (hasDepthStencil ? 1 : 0));
823 int n = 0;
824 for (auto it = desc.cbeginColorAttachments(), itEnd = desc.cendColorAttachments(); it != itEnd; ++it, ++n) {
825 const QRhiColorAttachment &colorAtt(*it);
826 if (colorAtt.texture()) {
827 TexType *texD = QRHI_RES(TexType, colorAtt.texture());
828 (*dst)[n] = { texD->globalResourceId(), texD->generation };
829 } else if (colorAtt.renderBuffer()) {
830 RenderBufferType *rbD = QRHI_RES(RenderBufferType, colorAtt.renderBuffer());
831 (*dst)[n] = { rbD->globalResourceId(), rbD->generation };
832 } else {
833 (*dst)[n] = { 0, 0 };
834 }
835 ++n;
836 if (colorAtt.resolveTexture()) {
837 TexType *texD = QRHI_RES(TexType, colorAtt.resolveTexture());
838 (*dst)[n] = { texD->globalResourceId(), texD->generation };
839 } else {
840 (*dst)[n] = { 0, 0 };
841 }
842 }
843 if (hasDepthStencil) {
844 if (desc.depthTexture()) {
845 TexType *depthTexD = QRHI_RES(TexType, desc.depthTexture());
846 (*dst)[n] = { depthTexD->globalResourceId(), depthTexD->generation };
847 } else if (desc.depthStencilBuffer()) {
848 RenderBufferType *depthRbD = QRHI_RES(RenderBufferType, desc.depthStencilBuffer());
849 (*dst)[n] = { depthRbD->globalResourceId(), depthRbD->generation };
850 } else {
851 (*dst)[n] = { 0, 0 };
852 }
853 }
854}
855
856template<typename TexType, typename RenderBufferType>
857bool QRhiRenderTargetAttachmentTracker::isUpToDate(const QRhiTextureRenderTargetDescription &desc, const ResIdList &currentResIdList)
858{
859 // Just as setShaderResources() recognizes if an srb's referenced
860 // resources have been rebuilt (got a create() since the srb's
861 // create()), we should do the same for the textures and renderbuffers
862 // referenced from the rendertarget. It is not uncommon that a texture
863 // or ds buffer gets resized due to following a window size in some
864 // form, which involves a create() on them. It is then nice if the
865 // render target auto-rebuilds in beginPass().
866
867 ResIdList resIdList;
868 updateResIdList<TexType, RenderBufferType>(desc, &resIdList);
869 return resIdList == currentResIdList;
870}
871
872template<typename T>
873inline T *qrhi_objectFromProxyData(QRhiSwapChainProxyData *pd, QWindow *window, QRhi::Implementation impl, uint objectIndex)
874{
875 Q_ASSERT(objectIndex < std::size(pd->reserved));
876 if (!pd->reserved[objectIndex]) // // was not set, no other choice, do it here, whatever thread this is
877 *pd = QRhi::updateSwapChainProxyData(impl, window);
878 return static_cast<T *>(pd->reserved[objectIndex]);
879}
880
882{
883public:
884 QRhiPipelineCacheDataReader(const char *data, quint32 size)
885 : m_p(data), m_end(data + size)
886 {
887 }
888
889 bool readUInt32(quint32 *dst)
890 {
891 if (m_end - m_p < qptrdiff(sizeof(quint32)))
892 return false;
893 memcpy(dst, m_p, sizeof(quint32));
894 m_p += sizeof(quint32);
895 return true;
896 }
897
898 // Reads a 32-bit length, followed by that many bytes.
899 bool readByteArray(QByteArray *dst)
900 {
901 quint32 len = 0;
902 if (!readUInt32(&len))
903 return false;
904 if (quint64(m_end - m_p) < len)
905 return false;
906 *dst = QByteArray(m_p, qsizetype(len));
907 m_p += len;
908 return true;
909 }
910
911private:
912 const char *m_p;
913 const char *m_end;
914};
915
916QT_END_NAMESPACE
917
918#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:815
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:826
QRhiBackendCommandList()=default
T * cend() const
Definition qrhi_p.h:786
T * cbegin() const
Definition qrhi_p.h:785
bool isEmpty() const
Definition qrhi_p.h:771
void assign(QByteArray data)
Definition qrhi_p.h:405
QRhiBufferData()=default
void assign(const char *s, quint32 size)
Definition qrhi_p.h:386
quint32 size() const
Definition qrhi_p.h:378
QRhiBufferData(const QRhiBufferData &other)
Definition qrhi_p.h:357
quint32 largeAlloc() const
Definition qrhi_p.h:382
QRhiBufferData & operator=(const QRhiBufferData &other)
Definition qrhi_p.h:363
const char * constData() const
Definition qrhi_p.h:374
static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages)
Definition qrhi.cpp:12185
const QVarLengthFlatMap< QRhiBuffer *, Buffer, 12 > & buffers() const
Definition qrhi_p.h:743
static BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages)
Definition qrhi.cpp:12166
const QVarLengthFlatMap< QRhiTexture *, Texture, 12 > & textures() const
Definition qrhi_p.h:751
bool isEmpty() const
Definition qrhi.cpp:12075
void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage, const UsageState &state)
Definition qrhi.cpp:12092
void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage, const UsageState &state)
Definition qrhi.cpp:12132
QRhiPipelineCacheDataReader(const char *data, quint32 size)
Definition qrhi_p.h:884
bool readByteArray(QByteArray *dst)
Definition qrhi_p.h:899
bool readUInt32(quint32 *dst)
Definition qrhi_p.h:889
QVarLengthArray< BufferOp, BUFFER_OPS_STATIC_ALLOC > bufferOps
Definition qrhi_p.h:584
QRhiImplementation * rhi
Definition qrhi_p.h:591
QVarLengthArray< TextureOp, TEXTURE_OPS_STATIC_ALLOC > textureOps
Definition qrhi_p.h:588
static const int BUFFER_OPS_STATIC_ALLOC
Definition qrhi_p.h:583
static QRhiResourceUpdateBatchPrivate * get(QRhiResourceUpdateBatch *b)
Definition qrhi_p.h:599
void merge(QRhiResourceUpdateBatchPrivate *other)
Definition qrhi.cpp:10243
QRhiResourceUpdateBatch * q
Definition qrhi_p.h:590
static const int TEXTURE_OPS_STATIC_ALLOC
Definition qrhi_p.h:587
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:8554
static QRhiPassResourceTracker::BufferStage earlierStage(QRhiPassResourceTracker::BufferStage a, QRhiPassResourceTracker::BufferStage b)
Definition qrhi.cpp:12086
QDebug operator<<(QDebug dbg, const QRhiSwapChainHdrInfo &info)
Definition qrhi.cpp:8301
static bool isImageLoadStore(QRhiPassResourceTracker::TextureAccess access)
Definition qrhi.cpp:12125
static const char * deviceTypeStr(QRhiDriverInfo::DeviceType type)
\variable QRhiDriverInfo::deviceName
Definition qrhi.cpp:9531
static QRhiPassResourceTracker::TextureStage earlierStage(QRhiPassResourceTracker::TextureStage a, QRhiPassResourceTracker::TextureStage b)
Definition qrhi.cpp:12119
QRhiTargetRectBoundMode
Definition qrhi_p.h:286
@ UnBounded
Definition qrhi_p.h:287
@ Bounded
Definition qrhi_p.h:288
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:873
bool operator!=(const QRhiRenderTargetAttachmentTracker::ResId &a, const QRhiRenderTargetAttachmentTracker::ResId &b)
Definition qrhi_p.h:813
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:808
bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array< T, N > &r, T *x, T *y, T *w, T *h)
Definition qrhi_p.h:292
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:639
QVector< T > resources
Definition qrhi_p.h:632
bool operator==(const Batch &other) const
Definition qrhi_p.h:634
void feed(int binding, T resource)
Definition qrhi_p.h:605
QVector< Batch > batches
Definition qrhi_p.h:648
bool operator!=(const QRhiBatchedBindings< T > &other) const
Definition qrhi_p.h:655
bool operator==(const QRhiBatchedBindings< T > &other) const
Definition qrhi_p.h:650
char smallData[SMALL_DATA_SIZE]
Definition qrhi_p.h:344
QByteArray largeData
Definition qrhi_p.h:342
static constexpr quint32 SMALL_DATA_SIZE
Definition qrhi_p.h:343
static void updateResIdList(const QRhiTextureRenderTargetDescription &desc, ResIdList *dst)
Definition qrhi_p.h:819
static bool isUpToDate(const QRhiTextureRenderTargetDescription &desc, const ResIdList &currentResIdList)
Definition qrhi_p.h:857
static void changeToDynamicUpdate(BufferOp *op, QRhiBuffer *buf, quint32 offset, QByteArray data)
Definition qrhi_p.h:467
static void changeToStaticUpload(BufferOp *op, QRhiBuffer *buf, quint32 offset, QByteArray data)
Definition qrhi_p.h:498
static void changeToStaticUpload(BufferOp *op, QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
Definition qrhi_p.h:482
static BufferOp dynamicUpdate(QRhiBuffer *buf, quint32 offset, QByteArray data)
Definition qrhi_p.h:460
static BufferOp staticUpload(QRhiBuffer *buf, quint32 offset, QByteArray data)
Definition qrhi_p.h:491
static BufferOp staticUpload(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
Definition qrhi_p.h:475
static BufferOp read(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiReadbackResult *result)
Definition qrhi_p.h:506
static BufferOp dynamicUpdate(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
Definition qrhi_p.h:444
static void changeToDynamicUpdate(BufferOp *op, QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
Definition qrhi_p.h:451
QRhiTextureCopyDescription desc
Definition qrhi_p.h:534
static TextureOp copy(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
Definition qrhi_p.h:554
QVarLengthArray< MipLevelUploadList, 6 > subresDesc
Definition qrhi_p.h:532
static TextureOp upload(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
Definition qrhi_p.h:538
static TextureOp genMips(QRhiTexture *tex)
Definition qrhi_p.h:573
static TextureOp read(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
Definition qrhi_p.h:564
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:1562
LimitsType limitsType
Definition qrhi.h:1573
float maxPotentialColorComponentValue
Definition qrhi.h:1581
LuminanceBehavior luminanceBehavior
Definition qrhi.h:1584
float maxColorComponentValue
Definition qrhi.h:1580
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:1595
void * reserved[2]
Definition qrhi.h:1596