1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2019 The Qt Company Ltd. |
4 | ** Contact: http://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Gui module |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL3$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see http://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at http://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or later as published by the Free |
28 | ** Software Foundation and appearing in the file LICENSE.GPL included in |
29 | ** the packaging of this file. Please review the following information to |
30 | ** ensure the GNU General Public License version 2.0 requirements will be |
31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
32 | ** |
33 | ** $QT_END_LICENSE$ |
34 | ** |
35 | ****************************************************************************/ |
36 | |
37 | #ifndef QRHI_P_H |
38 | #define QRHI_P_H |
39 | |
40 | // |
41 | // W A R N I N G |
42 | // ------------- |
43 | // |
44 | // This file is not part of the Qt API. It exists purely as an |
45 | // implementation detail. This header file may change from version to |
46 | // version without notice, or even be removed. |
47 | // |
48 | // We mean it. |
49 | // |
50 | |
51 | #include "qrhi_p.h" |
52 | #include "qrhiprofiler_p_p.h" |
53 | #include <QBitArray> |
54 | #include <QAtomicInt> |
55 | #include <QLoggingCategory> |
56 | |
57 | QT_BEGIN_NAMESPACE |
58 | |
59 | #define QRHI_RES(t, x) static_cast<t *>(x) |
60 | #define QRHI_RES_RHI(t) t *rhiD = static_cast<t *>(m_rhi) |
61 | #define QRHI_PROF QRhiProfilerPrivate *rhiP = m_rhi->profilerPrivateOrNull() |
62 | #define QRHI_PROF_F(f) for (bool qrhip_enabled = rhiP != nullptr; qrhip_enabled; qrhip_enabled = false) rhiP->f |
63 | |
64 | Q_DECLARE_LOGGING_CATEGORY(QRHI_LOG_INFO) |
65 | |
66 | class QRhiImplementation |
67 | { |
68 | public: |
69 | virtual ~QRhiImplementation(); |
70 | |
71 | virtual bool create(QRhi::Flags flags) = 0; |
72 | virtual void destroy() = 0; |
73 | |
74 | virtual QRhiGraphicsPipeline *createGraphicsPipeline() = 0; |
75 | virtual QRhiComputePipeline *createComputePipeline() = 0; |
76 | virtual QRhiShaderResourceBindings *createShaderResourceBindings() = 0; |
77 | virtual QRhiBuffer *createBuffer(QRhiBuffer::Type type, |
78 | QRhiBuffer::UsageFlags usage, |
79 | int size) = 0; |
80 | virtual QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type, |
81 | const QSize &pixelSize, |
82 | int sampleCount, |
83 | QRhiRenderBuffer::Flags flags, |
84 | QRhiTexture::Format backingFormatHint) = 0; |
85 | virtual QRhiTexture *createTexture(QRhiTexture::Format format, |
86 | const QSize &pixelSize, |
87 | int sampleCount, |
88 | QRhiTexture::Flags flags) = 0; |
89 | virtual QRhiSampler *createSampler(QRhiSampler::Filter magFilter, |
90 | QRhiSampler::Filter minFilter, |
91 | QRhiSampler::Filter mipmapMode, |
92 | QRhiSampler:: AddressMode u, |
93 | QRhiSampler::AddressMode v, |
94 | QRhiSampler::AddressMode w) = 0; |
95 | |
96 | virtual QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, |
97 | QRhiTextureRenderTarget::Flags flags) = 0; |
98 | |
99 | virtual QRhiSwapChain *createSwapChain() = 0; |
100 | virtual QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) = 0; |
101 | virtual QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) = 0; |
102 | virtual QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) = 0; |
103 | virtual QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) = 0; |
104 | virtual QRhi::FrameOpResult finish() = 0; |
105 | |
106 | virtual void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0; |
107 | |
108 | virtual void beginPass(QRhiCommandBuffer *cb, |
109 | QRhiRenderTarget *rt, |
110 | const QColor &colorClearValue, |
111 | const QRhiDepthStencilClearValue &depthStencilClearValue, |
112 | QRhiResourceUpdateBatch *resourceUpdates, |
113 | QRhiCommandBuffer::BeginPassFlags flags) = 0; |
114 | virtual void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0; |
115 | |
116 | virtual void setGraphicsPipeline(QRhiCommandBuffer *cb, |
117 | QRhiGraphicsPipeline *ps) = 0; |
118 | |
119 | virtual void setShaderResources(QRhiCommandBuffer *cb, |
120 | QRhiShaderResourceBindings *srb, |
121 | int dynamicOffsetCount, |
122 | const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) = 0; |
123 | |
124 | virtual void setVertexInput(QRhiCommandBuffer *cb, |
125 | int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings, |
126 | QRhiBuffer *indexBuf, quint32 indexOffset, |
127 | QRhiCommandBuffer::IndexFormat indexFormat) = 0; |
128 | |
129 | virtual void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) = 0; |
130 | virtual void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) = 0; |
131 | virtual void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) = 0; |
132 | virtual void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) = 0; |
133 | |
134 | virtual void draw(QRhiCommandBuffer *cb, quint32 vertexCount, |
135 | quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) = 0; |
136 | virtual void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount, |
137 | quint32 instanceCount, quint32 firstIndex, |
138 | qint32 vertexOffset, quint32 firstInstance) = 0; |
139 | |
140 | virtual void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) = 0; |
141 | virtual void debugMarkEnd(QRhiCommandBuffer *cb) = 0; |
142 | virtual void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) = 0; |
143 | |
144 | virtual void beginComputePass(QRhiCommandBuffer *cb, |
145 | QRhiResourceUpdateBatch *resourceUpdates, |
146 | QRhiCommandBuffer::BeginPassFlags flags) = 0; |
147 | virtual void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0; |
148 | virtual void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) = 0; |
149 | virtual void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) = 0; |
150 | |
151 | virtual const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) = 0; |
152 | virtual void beginExternal(QRhiCommandBuffer *cb) = 0; |
153 | virtual void endExternal(QRhiCommandBuffer *cb) = 0; |
154 | |
155 | virtual QList<int> supportedSampleCounts() const = 0; |
156 | virtual int ubufAlignment() const = 0; |
157 | virtual bool isYUpInFramebuffer() const = 0; |
158 | virtual bool isYUpInNDC() const = 0; |
159 | virtual bool isClipDepthZeroToOne() const = 0; |
160 | virtual QMatrix4x4 clipSpaceCorrMatrix() const = 0; |
161 | virtual bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const = 0; |
162 | virtual bool isFeatureSupported(QRhi::Feature feature) const = 0; |
163 | virtual int resourceLimit(QRhi::ResourceLimit limit) const = 0; |
164 | virtual const QRhiNativeHandles *nativeHandles() = 0; |
165 | virtual void sendVMemStatsToProfiler() = 0; |
166 | virtual bool makeThreadLocalNativeContextCurrent() = 0; |
167 | virtual void releaseCachedResources() = 0; |
168 | virtual bool isDeviceLost() const = 0; |
169 | |
170 | bool isCompressedFormat(QRhiTexture::Format format) const; |
171 | void compressedFormatInfo(QRhiTexture::Format format, const QSize &size, |
172 | quint32 *bpl, quint32 *byteSize, |
173 | QSize *blockDim) const; |
174 | void textureFormatInfo(QRhiTexture::Format format, const QSize &size, |
175 | quint32 *bpl, quint32 *byteSize) const; |
176 | quint32 approxByteSizeForTexture(QRhiTexture::Format format, const QSize &baseSize, |
177 | int mipCount, int layerCount); |
178 | |
179 | QRhiProfilerPrivate *profilerPrivateOrNull() |
180 | { |
181 | // return null when QRhi::EnableProfiling was not set |
182 | QRhiProfilerPrivate *p = QRhiProfilerPrivate::get(&profiler); |
183 | return p->rhiDWhenEnabled ? p : nullptr; |
184 | } |
185 | |
186 | // only really care about resources that own native graphics resources underneath |
187 | void registerResource(QRhiResource *res) |
188 | { |
189 | resources.insert(res); |
190 | } |
191 | |
192 | void unregisterResource(QRhiResource *res) |
193 | { |
194 | resources.remove(res); |
195 | } |
196 | |
197 | QSet<QRhiResource *> activeResources() const |
198 | { |
199 | return resources; |
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 | bool sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps); |
216 | bool sanityCheckShaderResourceBindings(QRhiShaderResourceBindings *srb); |
217 | void updateLayoutDesc(QRhiShaderResourceBindings *srb); |
218 | |
219 | QRhi *q; |
220 | |
221 | static const int MAX_SHADER_CACHE_ENTRIES = 128; |
222 | |
223 | bool debugMarkers = false; |
224 | int currentFrameSlot = 0; // for vk, mtl, and similar. unused by gl and d3d11. |
225 | bool inFrame = false; |
226 | |
227 | private: |
228 | QRhi::Implementation implType; |
229 | QThread *implThread; |
230 | QRhiProfiler profiler; |
231 | QVarLengthArray<QRhiResourceUpdateBatch *, 4> resUpdPool; |
232 | quint64 resUpdPoolMap = 0; |
233 | int lastResUpdIdx = -1; |
234 | QSet<QRhiResource *> resources; |
235 | QSet<QRhiResource *> pendingDeleteResources; |
236 | QVarLengthArray<QRhi::CleanupCallback, 4> cleanupCallbacks; |
237 | |
238 | friend class QRhi; |
239 | friend class QRhiResourceUpdateBatchPrivate; |
240 | }; |
241 | |
242 | template<typename T, size_t N> |
243 | bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array<T, N> &r, |
244 | T *x, T *y, T *w, T *h) |
245 | { |
246 | // x,y are bottom-left in QRhiScissor and QRhiViewport but top-left in |
247 | // Vulkan/Metal/D3D. Our input is an OpenGL-style scissor rect where both |
248 | // negative x or y, and partly or completely out of bounds rects are |
249 | // allowed. The only thing the input here cannot have is a negative width |
250 | // or height. We must handle all other input gracefully, clamping to a zero |
251 | // width or height rect in the worst case, and ensuring the resulting rect |
252 | // is inside the rendertarget's bounds because some APIs' validation/debug |
253 | // layers are allergic to out of bounds scissor or viewport rects. |
254 | |
255 | const T outputWidth = outputSize.width(); |
256 | const T outputHeight = outputSize.height(); |
257 | const T inputWidth = r[2]; |
258 | const T inputHeight = r[3]; |
259 | |
260 | if (inputWidth < 0 || inputHeight < 0) |
261 | return false; |
262 | |
263 | *x = r[0]; |
264 | *y = outputHeight - (r[1] + inputHeight); |
265 | |
266 | const T widthOffset = *x < 0 ? -*x : 0; |
267 | const T heightOffset = *y < 0 ? -*y : 0; |
268 | *w = *x < outputWidth ? qMax<T>(0, inputWidth - widthOffset) : 0; |
269 | *h = *y < outputHeight ? qMax<T>(0, inputHeight - heightOffset) : 0; |
270 | |
271 | *x = qBound<T>(0, *x, outputWidth - 1); |
272 | *y = qBound<T>(0, *y, outputHeight - 1); |
273 | |
274 | if (*x + *w > outputWidth) |
275 | *w = qMax<T>(0, outputWidth - *x); |
276 | if (*y + *h > outputHeight) |
277 | *h = qMax<T>(0, outputHeight - *y); |
278 | |
279 | return true; |
280 | } |
281 | |
282 | struct QRhiBufferDataPrivate |
283 | { |
284 | Q_DISABLE_COPY_MOVE(QRhiBufferDataPrivate) |
285 | QRhiBufferDataPrivate() { } |
286 | ~QRhiBufferDataPrivate() { delete[] largeData; } |
287 | int ref = 1; |
288 | int size = 0; |
289 | int largeAlloc = 0; |
290 | char *largeData = nullptr; |
291 | static constexpr int SMALL_DATA_SIZE = 1024; |
292 | char data[SMALL_DATA_SIZE]; |
293 | }; |
294 | |
295 | // no detach-with-contents, no atomic refcount, no shrink |
296 | class QRhiBufferData |
297 | { |
298 | public: |
299 | QRhiBufferData() = default; |
300 | ~QRhiBufferData() |
301 | { |
302 | if (d && !--d->ref) |
303 | delete d; |
304 | } |
305 | QRhiBufferData(const QRhiBufferData &other) |
306 | : d(other.d) |
307 | { |
308 | if (d) |
309 | d->ref += 1; |
310 | } |
311 | QRhiBufferData &operator=(const QRhiBufferData &other) |
312 | { |
313 | if (d == other.d) |
314 | return *this; |
315 | if (other.d) |
316 | other.d->ref += 1; |
317 | if (d && !--d->ref) |
318 | delete d; |
319 | d = other.d; |
320 | return *this; |
321 | } |
322 | const char *constData() const |
323 | { |
324 | return d->size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE ? d->data : d->largeData; |
325 | } |
326 | int size() const |
327 | { |
328 | return d->size; |
329 | } |
330 | void assign(const char *s, int size) |
331 | { |
332 | if (!d) { |
333 | d = new QRhiBufferDataPrivate; |
334 | } else if (d->ref != 1) { |
335 | d->ref -= 1; |
336 | d = new QRhiBufferDataPrivate; |
337 | } |
338 | d->size = size; |
339 | if (size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE) { |
340 | memcpy(d->data, s, size); |
341 | } else { |
342 | if (d->largeAlloc < size) { |
343 | delete[] d->largeData; |
344 | d->largeAlloc = size; |
345 | d->largeData = new char[size]; |
346 | } |
347 | memcpy(d->largeData, s, size); |
348 | } |
349 | } |
350 | private: |
351 | QRhiBufferDataPrivate *d = nullptr; |
352 | }; |
353 | |
354 | Q_DECLARE_TYPEINFO(QRhiBufferData, Q_MOVABLE_TYPE); |
355 | |
356 | class QRhiResourceUpdateBatchPrivate |
357 | { |
358 | public: |
359 | struct BufferOp { |
360 | enum Type { |
361 | DynamicUpdate, |
362 | StaticUpload, |
363 | Read |
364 | }; |
365 | Type type; |
366 | QRhiBuffer *buf; |
367 | int offset; |
368 | QRhiBufferData data; |
369 | int readSize; |
370 | QRhiBufferReadbackResult *result; |
371 | |
372 | static BufferOp dynamicUpdate(QRhiBuffer *buf, int offset, int size, const void *data) |
373 | { |
374 | BufferOp op = {}; |
375 | op.type = DynamicUpdate; |
376 | op.buf = buf; |
377 | op.offset = offset; |
378 | const int effectiveSize = size ? size : buf->size(); |
379 | op.data.assign(reinterpret_cast<const char *>(data), effectiveSize); |
380 | return op; |
381 | } |
382 | |
383 | static void changeToDynamicUpdate(BufferOp *op, QRhiBuffer *buf, int offset, int size, const void *data) |
384 | { |
385 | op->type = DynamicUpdate; |
386 | op->buf = buf; |
387 | op->offset = offset; |
388 | const int effectiveSize = size ? size : buf->size(); |
389 | op->data.assign(reinterpret_cast<const char *>(data), effectiveSize); |
390 | } |
391 | |
392 | static BufferOp staticUpload(QRhiBuffer *buf, int offset, int size, const void *data) |
393 | { |
394 | BufferOp op = {}; |
395 | op.type = StaticUpload; |
396 | op.buf = buf; |
397 | op.offset = offset; |
398 | const int effectiveSize = size ? size : buf->size(); |
399 | op.data.assign(reinterpret_cast<const char *>(data), effectiveSize); |
400 | return op; |
401 | } |
402 | |
403 | static void changeToStaticUpload(BufferOp *op, QRhiBuffer *buf, int offset, int size, const void *data) |
404 | { |
405 | op->type = StaticUpload; |
406 | op->buf = buf; |
407 | op->offset = offset; |
408 | const int effectiveSize = size ? size : buf->size(); |
409 | op->data.assign(reinterpret_cast<const char *>(data), effectiveSize); |
410 | } |
411 | |
412 | static BufferOp read(QRhiBuffer *buf, int offset, int size, QRhiBufferReadbackResult *result) |
413 | { |
414 | BufferOp op = {}; |
415 | op.type = Read; |
416 | op.buf = buf; |
417 | op.offset = offset; |
418 | op.readSize = size; |
419 | op.result = result; |
420 | return op; |
421 | } |
422 | }; |
423 | |
424 | struct TextureOp { |
425 | enum Type { |
426 | Upload, |
427 | Copy, |
428 | Read, |
429 | GenMips |
430 | }; |
431 | Type type; |
432 | QRhiTexture *dst; |
433 | // Specifying multiple uploads for a subresource must be supported. |
434 | // In the backend this can then end up, where applicable, as a |
435 | // single, batched copy operation with only one set of barriers. |
436 | // This helps when doing for example glyph cache fills. |
437 | QList<QRhiTextureSubresourceUploadDescription> subresDesc[QRhi::MAX_LAYERS][QRhi::MAX_LEVELS]; |
438 | QRhiTexture *src; |
439 | QRhiTextureCopyDescription desc; |
440 | QRhiReadbackDescription rb; |
441 | QRhiReadbackResult *result; |
442 | |
443 | static TextureOp upload(QRhiTexture *tex, const QRhiTextureUploadDescription &desc) |
444 | { |
445 | TextureOp op = {}; |
446 | op.type = Upload; |
447 | op.dst = tex; |
448 | for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it) |
449 | op.subresDesc[it->layer()][it->level()].append(it->description()); |
450 | return op; |
451 | } |
452 | |
453 | static TextureOp copy(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc) |
454 | { |
455 | TextureOp op = {}; |
456 | op.type = Copy; |
457 | op.dst = dst; |
458 | op.src = src; |
459 | op.desc = desc; |
460 | return op; |
461 | } |
462 | |
463 | static TextureOp read(const QRhiReadbackDescription &rb, QRhiReadbackResult *result) |
464 | { |
465 | TextureOp op = {}; |
466 | op.type = Read; |
467 | op.rb = rb; |
468 | op.result = result; |
469 | return op; |
470 | } |
471 | |
472 | static TextureOp genMips(QRhiTexture *tex) |
473 | { |
474 | TextureOp op = {}; |
475 | op.type = GenMips; |
476 | op.dst = tex; |
477 | return op; |
478 | } |
479 | }; |
480 | |
481 | int activeBufferOpCount = 0; // this is the real number of used elements in bufferOps, not bufferOps.count() |
482 | static const int BUFFER_OPS_STATIC_ALLOC = 1024; |
483 | QVarLengthArray<BufferOp, BUFFER_OPS_STATIC_ALLOC> bufferOps; |
484 | |
485 | int activeTextureOpCount = 0; // this is the real number of used elements in textureOps, not textureOps.count() |
486 | static const int TEXTURE_OPS_STATIC_ALLOC = 256; |
487 | QVarLengthArray<TextureOp, TEXTURE_OPS_STATIC_ALLOC> textureOps; |
488 | |
489 | QRhiResourceUpdateBatch *q = nullptr; |
490 | QRhiImplementation *rhi = nullptr; |
491 | int poolIndex = -1; |
492 | |
493 | void free(); |
494 | void merge(QRhiResourceUpdateBatchPrivate *other); |
495 | bool hasOptimalCapacity() const; |
496 | void trimOpLists(); |
497 | |
498 | static QRhiResourceUpdateBatchPrivate *get(QRhiResourceUpdateBatch *b) { return b->d; } |
499 | }; |
500 | |
501 | Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::BufferOp, Q_MOVABLE_TYPE); |
502 | Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureOp, Q_MOVABLE_TYPE); |
503 | |
504 | template<typename T> |
505 | struct QRhiBatchedBindings |
506 | { |
507 | void feed(int binding, T resource) { // binding must be strictly increasing |
508 | if (curBinding == -1 || binding > curBinding + 1) { |
509 | finish(); |
510 | curBatch.startBinding = binding; |
511 | curBatch.resources.clear(); |
512 | curBatch.resources.append(resource); |
513 | } else { |
514 | Q_ASSERT(binding == curBinding + 1); |
515 | curBatch.resources.append(resource); |
516 | } |
517 | curBinding = binding; |
518 | } |
519 | |
520 | bool finish() { |
521 | if (!curBatch.resources.isEmpty()) |
522 | batches.append(curBatch); |
523 | return !batches.isEmpty(); |
524 | } |
525 | |
526 | void clear() { |
527 | batches.clear(); |
528 | curBatch.resources.clear(); |
529 | curBinding = -1; |
530 | } |
531 | |
532 | struct Batch { |
533 | uint startBinding; |
534 | QVarLengthArray<T, 4> resources; |
535 | |
536 | bool operator==(const Batch &other) const |
537 | { |
538 | return startBinding == other.startBinding && resources == other.resources; |
539 | } |
540 | |
541 | bool operator!=(const Batch &other) const |
542 | { |
543 | return !operator==(other); |
544 | } |
545 | }; |
546 | |
547 | QVarLengthArray<Batch, 4> batches; // sorted by startBinding |
548 | |
549 | bool operator==(const QRhiBatchedBindings<T> &other) const |
550 | { |
551 | return batches == other.batches; |
552 | } |
553 | |
554 | bool operator!=(const QRhiBatchedBindings<T> &other) const |
555 | { |
556 | return !operator==(other); |
557 | } |
558 | |
559 | private: |
560 | Batch curBatch; |
561 | int curBinding = -1; |
562 | }; |
563 | |
564 | class QRhiGlobalObjectIdGenerator |
565 | { |
566 | public: |
567 | #ifdef Q_ATOMIC_INT64_IS_SUPPORTED |
568 | using Type = quint64; |
569 | #else |
570 | using Type = quint32; |
571 | #endif |
572 | static Type newId(); |
573 | }; |
574 | |
575 | class QRhiPassResourceTracker |
576 | { |
577 | public: |
578 | bool isEmpty() const; |
579 | void reset(); |
580 | |
581 | struct UsageState { |
582 | int layout; |
583 | int access; |
584 | int stage; |
585 | }; |
586 | |
587 | enum BufferStage { |
588 | BufVertexInputStage, |
589 | BufVertexStage, |
590 | BufFragmentStage, |
591 | BufComputeStage |
592 | }; |
593 | |
594 | enum BufferAccess { |
595 | BufVertexInput, |
596 | BufIndexRead, |
597 | BufUniformRead, |
598 | BufStorageLoad, |
599 | BufStorageStore, |
600 | BufStorageLoadStore |
601 | }; |
602 | |
603 | void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage, |
604 | const UsageState &state); |
605 | |
606 | enum TextureStage { |
607 | TexVertexStage, |
608 | TexFragmentStage, |
609 | TexColorOutputStage, |
610 | TexDepthOutputStage, |
611 | TexComputeStage |
612 | }; |
613 | |
614 | enum TextureAccess { |
615 | TexSample, |
616 | TexColorOutput, |
617 | TexDepthOutput, |
618 | TexStorageLoad, |
619 | TexStorageStore, |
620 | TexStorageLoadStore |
621 | }; |
622 | |
623 | void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage, |
624 | const UsageState &state); |
625 | |
626 | struct Buffer { |
627 | int slot; |
628 | BufferAccess access; |
629 | BufferStage stage; |
630 | UsageState stateAtPassBegin; |
631 | }; |
632 | |
633 | using BufferIterator = QHash<QRhiBuffer *, Buffer>::const_iterator; |
634 | BufferIterator cbeginBuffers() const { return m_buffers.cbegin(); } |
635 | BufferIterator cendBuffers() const { return m_buffers.cend(); } |
636 | |
637 | struct Texture { |
638 | TextureAccess access; |
639 | TextureStage stage; |
640 | UsageState stateAtPassBegin; |
641 | }; |
642 | |
643 | using TextureIterator = QHash<QRhiTexture *, Texture>::const_iterator; |
644 | TextureIterator cbeginTextures() const { return m_textures.cbegin(); } |
645 | TextureIterator cendTextures() const { return m_textures.cend(); } |
646 | |
647 | static BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages); |
648 | static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages); |
649 | |
650 | private: |
651 | QHash<QRhiBuffer *, Buffer> m_buffers; |
652 | QHash<QRhiTexture *, Texture> m_textures; |
653 | }; |
654 | |
655 | Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Buffer, Q_MOVABLE_TYPE); |
656 | Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Texture, Q_MOVABLE_TYPE); |
657 | |
658 | template<typename T, int GROW = 1024> |
659 | class QRhiBackendCommandList |
660 | { |
661 | public: |
662 | QRhiBackendCommandList() = default; |
663 | ~QRhiBackendCommandList() { delete[] v; } |
664 | inline void reset() { p = 0; } |
665 | inline bool isEmpty() const { return p == 0; } |
666 | inline T &get() { |
667 | if (p == a) { |
668 | a += GROW; |
669 | T *nv = new T[a]; |
670 | if (v) { |
671 | memcpy(nv, v, p * sizeof(T)); |
672 | delete[] v; |
673 | } |
674 | v = nv; |
675 | } |
676 | return v[p++]; |
677 | } |
678 | inline void unget() { --p; } |
679 | inline T *cbegin() const { return v; } |
680 | inline T *cend() const { return v + p; } |
681 | inline T *begin() { return v; } |
682 | inline T *end() { return v + p; } |
683 | private: |
684 | Q_DISABLE_COPY(QRhiBackendCommandList) |
685 | T *v = nullptr; |
686 | int a = 0; |
687 | int p = 0; |
688 | }; |
689 | |
690 | QT_END_NAMESPACE |
691 | |
692 | #endif |
693 | |