diff options
Diffstat (limited to 'src/gui/rhi/qrhi_p.h')
-rw-r--r-- | src/gui/rhi/qrhi_p.h | 2317 |
1 files changed, 660 insertions, 1657 deletions
diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 1d0dce97c5..b5429372a8 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -1,8 +1,8 @@ -// Copyright (C) 2019 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -#ifndef QRHI_H -#define QRHI_H +#ifndef QRHI_P_H +#define QRHI_P_H // // W A R N I N G @@ -15,1800 +15,803 @@ // We mean it. // -#include <QtGui/qtguiglobal.h> -#include <QSize> -#include <QMatrix4x4> -#include <QList> -#include <QVarLengthArray> -#include <QThread> -#include <QColor> -#include <QImage> -#include <functional> -#include <array> -#include <private/qshader_p.h> +#include <rhi/qrhi.h> +#include <QBitArray> +#include <QAtomicInt> +#include <QElapsedTimer> +#include <QLoggingCategory> +#include <QtCore/qset.h> +#include <QtCore/qvarlengtharray.h> QT_BEGIN_NAMESPACE -class QWindow; -class QRhiImplementation; -class QRhiBuffer; -class QRhiRenderBuffer; -class QRhiTexture; -class QRhiSampler; -class QRhiCommandBuffer; -class QRhiResourceUpdateBatch; -class QRhiResourceUpdateBatchPrivate; -class QRhiSwapChain; - -class Q_GUI_EXPORT QRhiDepthStencilClearValue -{ -public: - QRhiDepthStencilClearValue() = default; - QRhiDepthStencilClearValue(float d, quint32 s); - - float depthClearValue() const { return m_d; } - void setDepthClearValue(float d) { m_d = d; } - - quint32 stencilClearValue() const { return m_s; } - void setStencilClearValue(quint32 s) { m_s = s; } +#define QRHI_RES(t, x) static_cast<t *>(x) +#define QRHI_RES_RHI(t) t *rhiD = static_cast<t *>(m_rhi) -private: - float m_d = 1.0f; - quint32 m_s = 0; -}; +Q_DECLARE_LOGGING_CATEGORY(QRHI_LOG_INFO) -Q_DECLARE_TYPEINFO(QRhiDepthStencilClearValue, Q_RELOCATABLE_TYPE); - -Q_GUI_EXPORT bool operator==(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept; -Q_GUI_EXPORT bool operator!=(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept; -Q_GUI_EXPORT size_t qHash(const QRhiDepthStencilClearValue &v, size_t seed = 0) noexcept; -#ifndef QT_NO_DEBUG_STREAM -Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiDepthStencilClearValue &); -#endif - -class Q_GUI_EXPORT QRhiViewport +class QRhiImplementation { public: - QRhiViewport() = default; - QRhiViewport(float x, float y, float w, float h, float minDepth = 0.0f, float maxDepth = 1.0f); - - std::array<float, 4> viewport() const { return m_rect; } - void setViewport(float x, float y, float w, float h) { - m_rect[0] = x; m_rect[1] = y; m_rect[2] = w; m_rect[3] = h; - } - - float minDepth() const { return m_minDepth; } - void setMinDepth(float minDepth) { m_minDepth = minDepth; } - - float maxDepth() const { return m_maxDepth; } - void setMaxDepth(float maxDepth) { m_maxDepth = maxDepth; } - -private: - std::array<float, 4> m_rect { { 0.0f, 0.0f, 0.0f, 0.0f } }; - float m_minDepth = 0.0f; - float m_maxDepth = 1.0f; -}; - -Q_DECLARE_TYPEINFO(QRhiViewport, Q_RELOCATABLE_TYPE); - -Q_GUI_EXPORT bool operator==(const QRhiViewport &a, const QRhiViewport &b) noexcept; -Q_GUI_EXPORT bool operator!=(const QRhiViewport &a, const QRhiViewport &b) noexcept; -Q_GUI_EXPORT size_t qHash(const QRhiViewport &v, size_t seed = 0) noexcept; -#ifndef QT_NO_DEBUG_STREAM -Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiViewport &); -#endif + virtual ~QRhiImplementation(); -class Q_GUI_EXPORT QRhiScissor -{ -public: - QRhiScissor() = default; - QRhiScissor(int x, int y, int w, int h); + virtual bool create(QRhi::Flags flags) = 0; + virtual void destroy() = 0; - std::array<int, 4> scissor() const { return m_rect; } - void setScissor(int x, int y, int w, int h) { - m_rect[0] = x; m_rect[1] = y; m_rect[2] = w; m_rect[3] = h; + virtual QRhiGraphicsPipeline *createGraphicsPipeline() = 0; + virtual QRhiComputePipeline *createComputePipeline() = 0; + virtual QRhiShaderResourceBindings *createShaderResourceBindings() = 0; + virtual QRhiBuffer *createBuffer(QRhiBuffer::Type type, + QRhiBuffer::UsageFlags usage, + quint32 size) = 0; + virtual QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type, + const QSize &pixelSize, + int sampleCount, + QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) = 0; + virtual QRhiTexture *createTexture(QRhiTexture::Format format, + const QSize &pixelSize, + int depth, + int arraySize, + int sampleCount, + QRhiTexture::Flags flags) = 0; + virtual QRhiSampler *createSampler(QRhiSampler::Filter magFilter, + QRhiSampler::Filter minFilter, + QRhiSampler::Filter mipmapMode, + QRhiSampler:: AddressMode u, + QRhiSampler::AddressMode v, + QRhiSampler::AddressMode w) = 0; + + virtual QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, + QRhiTextureRenderTarget::Flags flags) = 0; + + virtual QRhiSwapChain *createSwapChain() = 0; + virtual QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) = 0; + virtual QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) = 0; + virtual QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) = 0; + virtual QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) = 0; + virtual QRhi::FrameOpResult finish() = 0; + + virtual void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0; + + virtual void beginPass(QRhiCommandBuffer *cb, + QRhiRenderTarget *rt, + const QColor &colorClearValue, + const QRhiDepthStencilClearValue &depthStencilClearValue, + QRhiResourceUpdateBatch *resourceUpdates, + QRhiCommandBuffer::BeginPassFlags flags) = 0; + virtual void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0; + + virtual void setGraphicsPipeline(QRhiCommandBuffer *cb, + QRhiGraphicsPipeline *ps) = 0; + + virtual void setShaderResources(QRhiCommandBuffer *cb, + QRhiShaderResourceBindings *srb, + int dynamicOffsetCount, + const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) = 0; + + virtual void setVertexInput(QRhiCommandBuffer *cb, + int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings, + QRhiBuffer *indexBuf, quint32 indexOffset, + QRhiCommandBuffer::IndexFormat indexFormat) = 0; + + virtual void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) = 0; + virtual void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) = 0; + virtual void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) = 0; + virtual void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) = 0; + + virtual void draw(QRhiCommandBuffer *cb, quint32 vertexCount, + quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) = 0; + virtual void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount, + quint32 instanceCount, quint32 firstIndex, + qint32 vertexOffset, quint32 firstInstance) = 0; + + virtual void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) = 0; + virtual void debugMarkEnd(QRhiCommandBuffer *cb) = 0; + virtual void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) = 0; + + virtual void beginComputePass(QRhiCommandBuffer *cb, + QRhiResourceUpdateBatch *resourceUpdates, + QRhiCommandBuffer::BeginPassFlags flags) = 0; + virtual void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0; + virtual void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) = 0; + virtual void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) = 0; + + virtual const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) = 0; + virtual void beginExternal(QRhiCommandBuffer *cb) = 0; + virtual void endExternal(QRhiCommandBuffer *cb) = 0; + virtual double lastCompletedGpuTime(QRhiCommandBuffer *cb) = 0; + + virtual QList<int> supportedSampleCounts() const = 0; + virtual int ubufAlignment() const = 0; + virtual bool isYUpInFramebuffer() const = 0; + virtual bool isYUpInNDC() const = 0; + virtual bool isClipDepthZeroToOne() const = 0; + virtual QMatrix4x4 clipSpaceCorrMatrix() const = 0; + virtual bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const = 0; + virtual bool isFeatureSupported(QRhi::Feature feature) const = 0; + virtual int resourceLimit(QRhi::ResourceLimit limit) const = 0; + virtual const QRhiNativeHandles *nativeHandles() = 0; + virtual QRhiDriverInfo driverInfo() const = 0; + virtual QRhiStats statistics() = 0; + virtual bool makeThreadLocalNativeContextCurrent() = 0; + virtual void releaseCachedResources() = 0; + virtual bool isDeviceLost() const = 0; + + virtual QByteArray pipelineCacheData() = 0; + virtual void setPipelineCacheData(const QByteArray &data) = 0; + + void prepareForCreate(QRhi *rhi, QRhi::Implementation impl, QRhi::Flags flags); + + bool isCompressedFormat(QRhiTexture::Format format) const; + void compressedFormatInfo(QRhiTexture::Format format, const QSize &size, + quint32 *bpl, quint32 *byteSize, + QSize *blockDim) const; + void textureFormatInfo(QRhiTexture::Format format, const QSize &size, + quint32 *bpl, quint32 *byteSize, quint32 *bytesPerPixel) const; + bool isStencilSupportingFormat(QRhiTexture::Format format) const; + + void registerResource(QRhiResource *res, bool ownsNativeResources = true) + { + // The ownsNativeResources is relevant for the (graphics resource) leak + // check in ~QRhiImplementation; when false, the registration's sole + // purpose is to automatically null out the resource's m_rhi pointer in + // case the rhi goes away first. (which should not happen in + // well-written applications but we try to be graceful) + resources.insert(res, ownsNativeResources); } -private: - std::array<int, 4> m_rect { { 0, 0, 0, 0 } }; -}; - -Q_DECLARE_TYPEINFO(QRhiScissor, Q_RELOCATABLE_TYPE); - -Q_GUI_EXPORT bool operator==(const QRhiScissor &a, const QRhiScissor &b) noexcept; -Q_GUI_EXPORT bool operator!=(const QRhiScissor &a, const QRhiScissor &b) noexcept; -Q_GUI_EXPORT size_t qHash(const QRhiScissor &v, size_t seed = 0) noexcept; -#ifndef QT_NO_DEBUG_STREAM -Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiScissor &); -#endif - -class Q_GUI_EXPORT QRhiVertexInputBinding -{ -public: - enum Classification { - PerVertex, - PerInstance - }; - - QRhiVertexInputBinding() = default; - QRhiVertexInputBinding(quint32 stride, Classification cls = PerVertex, quint32 stepRate = 1); - - quint32 stride() const { return m_stride; } - void setStride(quint32 s) { m_stride = s; } - - Classification classification() const { return m_classification; } - void setClassification(Classification c) { m_classification = c; } - - quint32 instanceStepRate() const { return m_instanceStepRate; } - void setInstanceStepRate(quint32 rate) { m_instanceStepRate = rate; } - -private: - quint32 m_stride = 0; - Classification m_classification = PerVertex; - quint32 m_instanceStepRate = 1; -}; - -Q_DECLARE_TYPEINFO(QRhiVertexInputBinding, Q_RELOCATABLE_TYPE); - -Q_GUI_EXPORT bool operator==(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept; -Q_GUI_EXPORT bool operator!=(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept; -Q_GUI_EXPORT size_t qHash(const QRhiVertexInputBinding &v, size_t seed = 0) noexcept; -#ifndef QT_NO_DEBUG_STREAM -Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiVertexInputBinding &); -#endif - -class Q_GUI_EXPORT QRhiVertexInputAttribute -{ -public: - enum Format { - Float4, - Float3, - Float2, - Float, - UNormByte4, - UNormByte2, - UNormByte, - UInt4, - UInt3, - UInt2, - UInt, - SInt4, - SInt3, - SInt2, - SInt - }; - - QRhiVertexInputAttribute() = default; - QRhiVertexInputAttribute(int binding, int location, Format format, quint32 offset, int matrixSlice = -1); - - int binding() const { return m_binding; } - void setBinding(int b) { m_binding = b; } - - int location() const { return m_location; } - void setLocation(int loc) { m_location = loc; } - - Format format() const { return m_format; } - void setFormat(Format f) { m_format = f; } - - quint32 offset() const { return m_offset; } - void setOffset(quint32 ofs) { m_offset = ofs; } - - int matrixSlice() const { return m_matrixSlice; } - void setMatrixSlice(int slice) { m_matrixSlice = slice; } - -private: - int m_binding = 0; - int m_location = 0; - Format m_format = Float4; - quint32 m_offset = 0; - int m_matrixSlice = -1; -}; - -Q_DECLARE_TYPEINFO(QRhiVertexInputAttribute, Q_RELOCATABLE_TYPE); - -Q_GUI_EXPORT bool operator==(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept; -Q_GUI_EXPORT bool operator!=(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept; -Q_GUI_EXPORT size_t qHash(const QRhiVertexInputAttribute &v, size_t seed = 0) noexcept; -#ifndef QT_NO_DEBUG_STREAM -Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiVertexInputAttribute &); -#endif - -class Q_GUI_EXPORT QRhiVertexInputLayout -{ -public: - QRhiVertexInputLayout() = default; - - void setBindings(std::initializer_list<QRhiVertexInputBinding> list) { m_bindings = list; } - template<typename InputIterator> - void setBindings(InputIterator first, InputIterator last) + void unregisterResource(QRhiResource *res) { - m_bindings.clear(); - std::copy(first, last, std::back_inserter(m_bindings)); + resources.remove(res); } - const QRhiVertexInputBinding *cbeginBindings() const { return m_bindings.cbegin(); } - const QRhiVertexInputBinding *cendBindings() const { return m_bindings.cend(); } - const QRhiVertexInputBinding *bindingAt(int index) const { return &m_bindings.at(index); } - void setAttributes(std::initializer_list<QRhiVertexInputAttribute> list) { m_attributes = list; } - template<typename InputIterator> - void setAttributes(InputIterator first, InputIterator last) + void addDeleteLater(QRhiResource *res) { - m_attributes.clear(); - std::copy(first, last, std::back_inserter(m_attributes)); + if (inFrame) + pendingDeleteResources.insert(res); + else + delete res; } - const QRhiVertexInputAttribute *cbeginAttributes() const { return m_attributes.cbegin(); } - const QRhiVertexInputAttribute *cendAttributes() const { return m_attributes.cend(); } - -private: - QVarLengthArray<QRhiVertexInputBinding, 8> m_bindings; - QVarLengthArray<QRhiVertexInputAttribute, 8> m_attributes; - - friend Q_GUI_EXPORT bool operator==(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept; - friend Q_GUI_EXPORT size_t qHash(const QRhiVertexInputLayout &v, size_t seed) noexcept; - friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiVertexInputLayout &); -}; - -Q_GUI_EXPORT bool operator==(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept; -Q_GUI_EXPORT bool operator!=(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept; -Q_GUI_EXPORT size_t qHash(const QRhiVertexInputLayout &v, size_t seed = 0) noexcept; -#ifndef QT_NO_DEBUG_STREAM -Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiVertexInputLayout &); -#endif - -class Q_GUI_EXPORT QRhiShaderStage -{ -public: - enum Type { - Vertex, - TessellationControl, - TessellationEvaluation, - Geometry, - Fragment, - Compute - }; - - QRhiShaderStage() = default; - QRhiShaderStage(Type type, const QShader &shader, - QShader::Variant v = QShader::StandardShader); - - Type type() const { return m_type; } - void setType(Type t) { m_type = t; } - - QShader shader() const { return m_shader; } - void setShader(const QShader &s) { m_shader = s; } - - QShader::Variant shaderVariant() const { return m_shaderVariant; } - void setShaderVariant(QShader::Variant v) { m_shaderVariant = v; } - -private: - Type m_type = Vertex; - QShader m_shader; - QShader::Variant m_shaderVariant = QShader::StandardShader; -}; - -Q_DECLARE_TYPEINFO(QRhiShaderStage, Q_RELOCATABLE_TYPE); - -Q_GUI_EXPORT bool operator==(const QRhiShaderStage &a, const QRhiShaderStage &b) noexcept; -Q_GUI_EXPORT bool operator!=(const QRhiShaderStage &a, const QRhiShaderStage &b) noexcept; -Q_GUI_EXPORT size_t qHash(const QRhiShaderStage &s, size_t seed = 0) noexcept; -#ifndef QT_NO_DEBUG_STREAM -Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderStage &); -#endif - -using QRhiGraphicsShaderStage = QRhiShaderStage; - -class Q_GUI_EXPORT QRhiShaderResourceBinding -{ -public: - enum Type { - UniformBuffer, - SampledTexture, - Texture, - Sampler, - ImageLoad, - ImageStore, - ImageLoadStore, - BufferLoad, - BufferStore, - BufferLoadStore - }; - - enum StageFlag { - VertexStage = 1 << 0, - TessellationControlStage = 1 << 1, - TessellationEvaluationStage = 1 << 2, - GeometryStage = 1 << 3, - FragmentStage = 1 << 4, - ComputeStage = 1 << 5 - }; - Q_DECLARE_FLAGS(StageFlags, StageFlag) - QRhiShaderResourceBinding() = default; - - bool isLayoutCompatible(const QRhiShaderResourceBinding &other) const; - - static QRhiShaderResourceBinding uniformBuffer(int binding, StageFlags stage, QRhiBuffer *buf); - static QRhiShaderResourceBinding uniformBuffer(int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size); - static QRhiShaderResourceBinding uniformBufferWithDynamicOffset(int binding, StageFlags stage, QRhiBuffer *buf, quint32 size); - - static QRhiShaderResourceBinding sampledTexture(int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler); - - struct TextureAndSampler { - QRhiTexture *tex; - QRhiSampler *sampler; - }; - static QRhiShaderResourceBinding sampledTextures(int binding, StageFlags stage, int count, const TextureAndSampler *texSamplers); - - static QRhiShaderResourceBinding texture(int binding, StageFlags stage, QRhiTexture *tex); - static QRhiShaderResourceBinding textures(int binding, StageFlags stage, int count, QRhiTexture **tex); - static QRhiShaderResourceBinding sampler(int binding, StageFlags stage, QRhiSampler *sampler); - - static QRhiShaderResourceBinding imageLoad(int binding, StageFlags stage, QRhiTexture *tex, int level); - static QRhiShaderResourceBinding imageStore(int binding, StageFlags stage, QRhiTexture *tex, int level); - static QRhiShaderResourceBinding imageLoadStore(int binding, StageFlags stage, QRhiTexture *tex, int level); - - static QRhiShaderResourceBinding bufferLoad(int binding, StageFlags stage, QRhiBuffer *buf); - static QRhiShaderResourceBinding bufferLoad(int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size); - static QRhiShaderResourceBinding bufferStore(int binding, StageFlags stage, QRhiBuffer *buf); - static QRhiShaderResourceBinding bufferStore(int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size); - static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf); - static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size); - - struct Data + void addCleanupCallback(const QRhi::CleanupCallback &callback) { - int binding; - QRhiShaderResourceBinding::StageFlags stage; - QRhiShaderResourceBinding::Type type; - struct UniformBufferData { - QRhiBuffer *buf; - quint32 offset; - quint32 maybeSize; - bool hasDynamicOffset; - }; - static const int MAX_TEX_SAMPLER_ARRAY_SIZE = 16; - struct TextureAndOrSamplerData { - int count; - TextureAndSampler texSamplers[MAX_TEX_SAMPLER_ARRAY_SIZE]; - }; - struct StorageImageData { - QRhiTexture *tex; - int level; - }; - struct StorageBufferData { - QRhiBuffer *buf; - quint32 offset; - quint32 maybeSize; - }; - union { - UniformBufferData ubuf; - TextureAndOrSamplerData stex; - StorageImageData simage; - StorageBufferData sbuf; - } u; - - int arraySize() const - { - return type == QRhiShaderResourceBinding::SampledTexture || type == QRhiShaderResourceBinding::Texture - ? u.stex.count - : 1; - } - - template<typename Output> - Output serialize(Output dst) const - { - // must write out exactly LAYOUT_DESC_ENTRIES_PER_BINDING elements here - *dst++ = quint32(binding); - *dst++ = quint32(stage); - *dst++ = quint32(type); - *dst++ = quint32(arraySize()); - return dst; - } - }; - - Data *data() { return &d; } - const Data *data() const { return &d; } - - static const int LAYOUT_DESC_ENTRIES_PER_BINDING = 4; + cleanupCallbacks.append(callback); + } - template<typename Output> - static void serializeLayoutDescription(const QRhiShaderResourceBinding *first, - const QRhiShaderResourceBinding *last, - Output dst) + void addCleanupCallback(const void *key, const QRhi::CleanupCallback &callback) { - while (first != last) { - dst = first->data()->serialize(dst); - ++first; - } + keyedCleanupCallbacks[key] = callback; } -private: - Data d; -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiShaderResourceBinding::StageFlags) - -Q_DECLARE_TYPEINFO(QRhiShaderResourceBinding, Q_PRIMITIVE_TYPE); - -Q_GUI_EXPORT bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) noexcept; -Q_GUI_EXPORT bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) noexcept; -Q_GUI_EXPORT size_t qHash(const QRhiShaderResourceBinding &b, size_t seed = 0) noexcept; -#ifndef QT_NO_DEBUG_STREAM -Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBinding &); -#endif - -class Q_GUI_EXPORT QRhiColorAttachment -{ -public: - QRhiColorAttachment() = default; - QRhiColorAttachment(QRhiTexture *texture); - QRhiColorAttachment(QRhiRenderBuffer *renderBuffer); - - QRhiTexture *texture() const { return m_texture; } - void setTexture(QRhiTexture *tex) { m_texture = tex; } - - QRhiRenderBuffer *renderBuffer() const { return m_renderBuffer; } - void setRenderBuffer(QRhiRenderBuffer *rb) { m_renderBuffer = rb; } - - int layer() const { return m_layer; } - void setLayer(int layer) { m_layer = layer; } - - int level() const { return m_level; } - void setLevel(int level) { m_level = level; } - - QRhiTexture *resolveTexture() const { return m_resolveTexture; } - void setResolveTexture(QRhiTexture *tex) { m_resolveTexture = tex; } - - int resolveLayer() const { return m_resolveLayer; } - void setResolveLayer(int layer) { m_resolveLayer = layer; } - - int resolveLevel() const { return m_resolveLevel; } - void setResolveLevel(int level) { m_resolveLevel = level; } - -private: - QRhiTexture *m_texture = nullptr; - QRhiRenderBuffer *m_renderBuffer = nullptr; - int m_layer = 0; - int m_level = 0; - QRhiTexture *m_resolveTexture = nullptr; - int m_resolveLayer = 0; - int m_resolveLevel = 0; -}; - -Q_DECLARE_TYPEINFO(QRhiColorAttachment, Q_RELOCATABLE_TYPE); - -class Q_GUI_EXPORT QRhiTextureRenderTargetDescription -{ -public: - QRhiTextureRenderTargetDescription() = default; - QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment); - QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment, QRhiRenderBuffer *depthStencilBuffer); - QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment, QRhiTexture *depthTexture); - - void setColorAttachments(std::initializer_list<QRhiColorAttachment> list) { m_colorAttachments = list; } - template<typename InputIterator> - void setColorAttachments(InputIterator first, InputIterator last) + void removeCleanupCallback(const void *key) { - m_colorAttachments.clear(); - std::copy(first, last, std::back_inserter(m_colorAttachments)); + keyedCleanupCallbacks.remove(key); } - const QRhiColorAttachment *cbeginColorAttachments() const { return m_colorAttachments.cbegin(); } - const QRhiColorAttachment *cendColorAttachments() const { return m_colorAttachments.cend(); } - const QRhiColorAttachment *colorAttachmentAt(int index) const { return &m_colorAttachments.at(index); } - - QRhiRenderBuffer *depthStencilBuffer() const { return m_depthStencilBuffer; } - void setDepthStencilBuffer(QRhiRenderBuffer *renderBuffer) { m_depthStencilBuffer = renderBuffer; } - - QRhiTexture *depthTexture() const { return m_depthTexture; } - void setDepthTexture(QRhiTexture *texture) { m_depthTexture = texture; } - -private: - QVarLengthArray<QRhiColorAttachment, 8> m_colorAttachments; - QRhiRenderBuffer *m_depthStencilBuffer = nullptr; - QRhiTexture *m_depthTexture = nullptr; -}; - -class Q_GUI_EXPORT QRhiTextureSubresourceUploadDescription -{ -public: - QRhiTextureSubresourceUploadDescription() = default; - explicit QRhiTextureSubresourceUploadDescription(const QImage &image); - QRhiTextureSubresourceUploadDescription(const void *data, quint32 size); - explicit QRhiTextureSubresourceUploadDescription(const QByteArray &data); - - QImage image() const { return m_image; } - void setImage(const QImage &image) { m_image = image; } - - QByteArray data() const { return m_data; } - void setData(const QByteArray &data) { m_data = data; } - - quint32 dataStride() const { return m_dataStride; } - void setDataStride(quint32 stride) { m_dataStride = stride; } - - QPoint destinationTopLeft() const { return m_destinationTopLeft; } - void setDestinationTopLeft(const QPoint &p) { m_destinationTopLeft = p; } - - QSize sourceSize() const { return m_sourceSize; } - void setSourceSize(const QSize &size) { m_sourceSize = size; } - QPoint sourceTopLeft() const { return m_sourceTopLeft; } - void setSourceTopLeft(const QPoint &p) { m_sourceTopLeft = p; } + bool sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps); + bool sanityCheckShaderResourceBindings(QRhiShaderResourceBindings *srb); + void updateLayoutDesc(QRhiShaderResourceBindings *srb); -private: - QImage m_image; - QByteArray m_data; - quint32 m_dataStride = 0; - QPoint m_destinationTopLeft; - QSize m_sourceSize; - QPoint m_sourceTopLeft; -}; - -Q_DECLARE_TYPEINFO(QRhiTextureSubresourceUploadDescription, Q_RELOCATABLE_TYPE); - -class Q_GUI_EXPORT QRhiTextureUploadEntry -{ -public: - QRhiTextureUploadEntry() = default; - QRhiTextureUploadEntry(int layer, int level, const QRhiTextureSubresourceUploadDescription &desc); - - int layer() const { return m_layer; } - void setLayer(int layer) { m_layer = layer; } - - int level() const { return m_level; } - void setLevel(int level) { m_level = level; } - - QRhiTextureSubresourceUploadDescription description() const { return m_desc; } - void setDescription(const QRhiTextureSubresourceUploadDescription &desc) { m_desc = desc; } - -private: - int m_layer = 0; - int m_level = 0; - QRhiTextureSubresourceUploadDescription m_desc; -}; - -Q_DECLARE_TYPEINFO(QRhiTextureUploadEntry, Q_RELOCATABLE_TYPE); + quint32 pipelineCacheRhiId() const + { + const quint32 ver = (QT_VERSION_MAJOR << 16) | (QT_VERSION_MINOR << 8) | (QT_VERSION_PATCH); + return (quint32(implType) << 24) | ver; + } -class Q_GUI_EXPORT QRhiTextureUploadDescription -{ -public: - QRhiTextureUploadDescription() = default; - QRhiTextureUploadDescription(const QRhiTextureUploadEntry &entry); - QRhiTextureUploadDescription(std::initializer_list<QRhiTextureUploadEntry> list); + void pipelineCreationStart() + { + pipelineCreationTimer.start(); + } - void setEntries(std::initializer_list<QRhiTextureUploadEntry> list) { m_entries = list; } - template<typename InputIterator> - void setEntries(InputIterator first, InputIterator last) + void pipelineCreationEnd() { - m_entries.clear(); - std::copy(first, last, std::back_inserter(m_entries)); + accumulatedPipelineCreationTime += pipelineCreationTimer.elapsed(); } - const QRhiTextureUploadEntry *cbeginEntries() const { return m_entries.cbegin(); } - const QRhiTextureUploadEntry *cendEntries() const { return m_entries.cend(); } -private: - QVarLengthArray<QRhiTextureUploadEntry, 16> m_entries; -}; + qint64 totalPipelineCreationTime() const + { + return accumulatedPipelineCreationTime; + } -class Q_GUI_EXPORT QRhiTextureCopyDescription -{ -public: - QRhiTextureCopyDescription() = default; + QRhiVertexInputAttribute::Format shaderDescVariableFormatToVertexInputFormat(QShaderDescription::VariableType type) const; + quint32 byteSizePerVertexForVertexInputFormat(QRhiVertexInputAttribute::Format format) const; - QSize pixelSize() const { return m_pixelSize; } - void setPixelSize(const QSize &sz) { m_pixelSize = sz; } + static const QRhiShaderResourceBinding::Data *shaderResourceBindingData(const QRhiShaderResourceBinding &binding) + { + return &binding.d; + } - int sourceLayer() const { return m_sourceLayer; } - void setSourceLayer(int layer) { m_sourceLayer = layer; } + static QRhiShaderResourceBinding::Data *shaderResourceBindingData(QRhiShaderResourceBinding &binding) + { + return &binding.d; + } - int sourceLevel() const { return m_sourceLevel; } - void setSourceLevel(int level) { m_sourceLevel = level; } + static bool sortedBindingLessThan(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) + { + return a.d.binding < b.d.binding; + } - QPoint sourceTopLeft() const { return m_sourceTopLeft; } - void setSourceTopLeft(const QPoint &p) { m_sourceTopLeft = p; } + int effectiveSampleCount(int sampleCount) const; - int destinationLayer() const { return m_destinationLayer; } - void setDestinationLayer(int layer) { m_destinationLayer = layer; } + QRhi *q; - int destinationLevel() const { return m_destinationLevel; } - void setDestinationLevel(int level) { m_destinationLevel = level; } + static const int MAX_SHADER_CACHE_ENTRIES = 128; - QPoint destinationTopLeft() const { return m_destinationTopLeft; } - void setDestinationTopLeft(const QPoint &p) { m_destinationTopLeft = p; } + bool debugMarkers = false; + int currentFrameSlot = 0; // for vk, mtl, and similar. unused by gl and d3d11. + bool inFrame = false; private: - QSize m_pixelSize; - int m_sourceLayer = 0; - int m_sourceLevel = 0; - QPoint m_sourceTopLeft; - int m_destinationLayer = 0; - int m_destinationLevel = 0; - QPoint m_destinationTopLeft; -}; - -Q_DECLARE_TYPEINFO(QRhiTextureCopyDescription, Q_RELOCATABLE_TYPE); - -class Q_GUI_EXPORT QRhiReadbackDescription -{ -public: - QRhiReadbackDescription() = default; - QRhiReadbackDescription(QRhiTexture *texture); - - QRhiTexture *texture() const { return m_texture; } - void setTexture(QRhiTexture *tex) { m_texture = tex; } + QRhi::Implementation implType; + QThread *implThread; + QVarLengthArray<QRhiResourceUpdateBatch *, 4> resUpdPool; + quint64 resUpdPoolMap = 0; + int lastResUpdIdx = -1; + QHash<QRhiResource *, bool> resources; + QSet<QRhiResource *> pendingDeleteResources; + QVarLengthArray<QRhi::CleanupCallback, 4> cleanupCallbacks; + QHash<const void *, QRhi::CleanupCallback> keyedCleanupCallbacks; + QElapsedTimer pipelineCreationTimer; + qint64 accumulatedPipelineCreationTime = 0; - int layer() const { return m_layer; } - void setLayer(int layer) { m_layer = layer; } - - int level() const { return m_level; } - void setLevel(int level) { m_level = level; } - -private: - QRhiTexture *m_texture = nullptr; - int m_layer = 0; - int m_level = 0; + friend class QRhi; + friend class QRhiResourceUpdateBatchPrivate; }; -Q_DECLARE_TYPEINFO(QRhiReadbackDescription, Q_RELOCATABLE_TYPE); - -struct Q_GUI_EXPORT QRhiNativeHandles +enum QRhiTargetRectBoundMode { + UnBounded, + Bounded }; -class Q_GUI_EXPORT QRhiResource +template<QRhiTargetRectBoundMode boundingMode, typename T, size_t N> +bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array<T, N> &r, + T *x, T *y, T *w, T *h) { -public: - enum Type { - Buffer, - Texture, - Sampler, - RenderBuffer, - RenderPassDescriptor, - SwapChainRenderTarget, - TextureRenderTarget, - ShaderResourceBindings, - GraphicsPipeline, - SwapChain, - ComputePipeline, - CommandBuffer - }; - - virtual ~QRhiResource(); + // x,y are bottom-left in QRhiScissor and QRhiViewport but top-left in + // Vulkan/Metal/D3D. Our input is an OpenGL-style scissor rect where both + // negative x or y, and partly or completely out of bounds rects are + // allowed. The only thing the input here cannot have is a negative width + // or height. We must handle all other input gracefully, clamping to a zero + // width or height rect in the worst case, and ensuring the resulting rect + // is inside the rendertarget's bounds because some APIs' validation/debug + // layers are allergic to out of bounds scissor rects. - virtual Type resourceType() const = 0; + const T outputWidth = outputSize.width(); + const T outputHeight = outputSize.height(); + const T inputWidth = r[2]; + const T inputHeight = r[3]; - virtual void destroy() = 0; + if (inputWidth < 0 || inputHeight < 0) + return false; - void deleteLater(); + *x = r[0]; + *y = outputHeight - (r[1] + inputHeight); + *w = inputWidth; + *h = inputHeight; - QByteArray name() const; - void setName(const QByteArray &name); + if (boundingMode == Bounded) { + const T widthOffset = *x < 0 ? -*x : 0; + const T heightOffset = *y < 0 ? -*y : 0; + *w = *x < outputWidth ? qMax<T>(0, inputWidth - widthOffset) : 0; + *h = *y < outputHeight ? qMax<T>(0, inputHeight - heightOffset) : 0; - quint64 globalResourceId() const; + if (outputWidth > 0) + *x = qBound<T>(0, *x, outputWidth - 1); + if (outputHeight > 0) + *y = qBound<T>(0, *y, outputHeight - 1); -protected: - QRhiResource(QRhiImplementation *rhi); - Q_DISABLE_COPY(QRhiResource) - friend class QRhiImplementation; - QRhiImplementation *m_rhi = nullptr; - quint64 m_id; - QByteArray m_objectName; -}; + if (*x + *w > outputWidth) + *w = qMax<T>(0, outputWidth - *x); + if (*y + *h > outputHeight) + *h = qMax<T>(0, outputHeight - *y); + } + return true; +} -class Q_GUI_EXPORT QRhiBuffer : public QRhiResource +struct QRhiBufferDataPrivate { -public: - enum Type { - Immutable, - Static, - Dynamic - }; - - enum UsageFlag { - VertexBuffer = 1 << 0, - IndexBuffer = 1 << 1, - UniformBuffer = 1 << 2, - StorageBuffer = 1 << 3 - }; - Q_DECLARE_FLAGS(UsageFlags, UsageFlag) - - struct NativeBuffer { - const void *objects[3]; - int slotCount; - }; - - QRhiResource::Type resourceType() const override; - - Type type() const { return m_type; } - void setType(Type t) { m_type = t; } - - UsageFlags usage() const { return m_usage; } - void setUsage(UsageFlags u) { m_usage = u; } - - quint32 size() const { return m_size; } - void setSize(quint32 sz) { m_size = sz; } - - virtual bool create() = 0; - - virtual NativeBuffer nativeBuffer(); - - virtual char *beginFullDynamicBufferUpdateForCurrentFrame(); - virtual void endFullDynamicBufferUpdateForCurrentFrame(); - -protected: - QRhiBuffer(QRhiImplementation *rhi, Type type_, UsageFlags usage_, quint32 size_); - Type m_type; - UsageFlags m_usage; - quint32 m_size; + Q_DISABLE_COPY_MOVE(QRhiBufferDataPrivate) + QRhiBufferDataPrivate() { } + ~QRhiBufferDataPrivate() { delete[] largeData; } + int ref = 1; + quint32 size = 0; + quint32 largeAlloc = 0; + char *largeData = nullptr; + static constexpr quint32 SMALL_DATA_SIZE = 1024; + char data[SMALL_DATA_SIZE]; }; -Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiBuffer::UsageFlags) - -class Q_GUI_EXPORT QRhiTexture : public QRhiResource +// no detach-with-contents, no atomic refcount, no shrink +class QRhiBufferData { public: - enum Flag { - RenderTarget = 1 << 0, - CubeMap = 1 << 2, - MipMapped = 1 << 3, - sRGB = 1 << 4, - UsedAsTransferSource = 1 << 5, - UsedWithGenerateMips = 1 << 6, - UsedWithLoadStore = 1 << 7, - UsedAsCompressedAtlas = 1 << 8, - ExternalOES = 1 << 9, - ThreeDimensional = 1 << 10, - TextureRectangleGL = 1 << 11, - TextureArray = 1 << 12 - }; - Q_DECLARE_FLAGS(Flags, Flag) - - enum Format { - UnknownFormat, - - RGBA8, - BGRA8, - R8, - RG8, - R16, - RG16, - RED_OR_ALPHA8, - - RGBA16F, - RGBA32F, - R16F, - R32F, - - RGB10A2, - - D16, - D24, - D24S8, - D32F, - - BC1, - BC2, - BC3, - BC4, - BC5, - BC6H, - BC7, - - ETC2_RGB8, - ETC2_RGB8A1, - ETC2_RGBA8, - - ASTC_4x4, - ASTC_5x4, - ASTC_5x5, - ASTC_6x5, - ASTC_6x6, - ASTC_8x5, - ASTC_8x6, - ASTC_8x8, - ASTC_10x5, - ASTC_10x6, - ASTC_10x8, - ASTC_10x10, - ASTC_12x10, - ASTC_12x12 - }; - - struct NativeTexture { - quint64 object; - int layout; - }; - - QRhiResource::Type resourceType() const override; - - Format format() const { return m_format; } - void setFormat(Format fmt) { m_format = fmt; } - - QSize pixelSize() const { return m_pixelSize; } - void setPixelSize(const QSize &sz) { m_pixelSize = sz; } - - int depth() const { return m_depth; } - void setDepth(int depth) { m_depth = depth; } - - int arraySize() const { return m_arraySize; } - void setArraySize(int arraySize) { m_arraySize = arraySize; } - - int arrayRangeStart() const { return m_arrayRangeStart; } - int arrayRangeLength() const { return m_arrayRangeLength; } - void setArrayRange(int startIndex, int count) + QRhiBufferData() = default; + ~QRhiBufferData() { - m_arrayRangeStart = startIndex; - m_arrayRangeLength = count; + if (d && !--d->ref) + delete d; } - - Flags flags() const { return m_flags; } - void setFlags(Flags f) { m_flags = f; } - - int sampleCount() const { return m_sampleCount; } - void setSampleCount(int s) { m_sampleCount = s; } - - virtual bool create() = 0; - virtual NativeTexture nativeTexture(); - virtual bool createFrom(NativeTexture src); - virtual void setNativeLayout(int layout); - -protected: - QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &pixelSize_, int depth_, - int arraySize_, int sampleCount_, Flags flags_); - Format m_format; - QSize m_pixelSize; - int m_depth; - int m_arraySize; - int m_sampleCount; - Flags m_flags; - int m_arrayRangeStart = -1; - int m_arrayRangeLength = -1; + QRhiBufferData(const QRhiBufferData &other) + : d(other.d) + { + if (d) + d->ref += 1; + } + QRhiBufferData &operator=(const QRhiBufferData &other) + { + if (d == other.d) + return *this; + if (other.d) + other.d->ref += 1; + if (d && !--d->ref) + delete d; + d = other.d; + return *this; + } + const char *constData() const + { + return d->size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE ? d->data : d->largeData; + } + quint32 size() const + { + return d->size; + } + void assign(const char *s, quint32 size) + { + if (!d) { + d = new QRhiBufferDataPrivate; + } else if (d->ref != 1) { + d->ref -= 1; + d = new QRhiBufferDataPrivate; + } + d->size = size; + if (size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE) { + memcpy(d->data, s, size); + } else { + if (d->largeAlloc < size) { + delete[] d->largeData; + d->largeAlloc = size; + d->largeData = new char[size]; + } + memcpy(d->largeData, s, size); + } + } +private: + QRhiBufferDataPrivate *d = nullptr; }; -Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiTexture::Flags) +Q_DECLARE_TYPEINFO(QRhiBufferData, Q_RELOCATABLE_TYPE); -class Q_GUI_EXPORT QRhiSampler : public QRhiResource +class QRhiResourceUpdateBatchPrivate { public: - enum Filter { - None, - Nearest, - Linear - }; - - enum AddressMode { - Repeat, - ClampToEdge, - Mirror, - }; - - enum CompareOp { - Never, - Less, - Equal, - LessOrEqual, - Greater, - NotEqual, - GreaterOrEqual, - Always - }; - - QRhiResource::Type resourceType() const override; - - Filter magFilter() const { return m_magFilter; } - void setMagFilter(Filter f) { m_magFilter = f; } - - Filter minFilter() const { return m_minFilter; } - void setMinFilter(Filter f) { m_minFilter = f; } - - Filter mipmapMode() const { return m_mipmapMode; } - void setMipmapMode(Filter f) { m_mipmapMode = f; } - - AddressMode addressU() const { return m_addressU; } - void setAddressU(AddressMode mode) { m_addressU = mode; } - - AddressMode addressV() const { return m_addressV; } - void setAddressV(AddressMode mode) { m_addressV = mode; } - - AddressMode addressW() const { return m_addressW; } - void setAddressW(AddressMode mode) { m_addressW = mode; } - - CompareOp textureCompareOp() const { return m_compareOp; } - void setTextureCompareOp(CompareOp op) { m_compareOp = op; } - - virtual bool create() = 0; + struct BufferOp { + enum Type { + DynamicUpdate, + StaticUpload, + Read + }; + Type type; + QRhiBuffer *buf; + quint32 offset; + QRhiBufferData data; + quint32 readSize; + QRhiReadbackResult *result; + + static BufferOp dynamicUpdate(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data) + { + BufferOp op = {}; + op.type = DynamicUpdate; + op.buf = buf; + op.offset = offset; + const int effectiveSize = size ? size : buf->size(); + op.data.assign(reinterpret_cast<const char *>(data), effectiveSize); + return op; + } -protected: - QRhiSampler(QRhiImplementation *rhi, - Filter magFilter_, Filter minFilter_, Filter mipmapMode_, - AddressMode u_, AddressMode v_, AddressMode w_); - Filter m_magFilter; - Filter m_minFilter; - Filter m_mipmapMode; - AddressMode m_addressU; - AddressMode m_addressV; - AddressMode m_addressW; - CompareOp m_compareOp; -}; + static void changeToDynamicUpdate(BufferOp *op, QRhiBuffer *buf, quint32 offset, quint32 size, const void *data) + { + op->type = DynamicUpdate; + op->buf = buf; + op->offset = offset; + const int effectiveSize = size ? size : buf->size(); + op->data.assign(reinterpret_cast<const char *>(data), effectiveSize); + } -class Q_GUI_EXPORT QRhiRenderBuffer : public QRhiResource -{ -public: - enum Type { - DepthStencil, - Color - }; + static BufferOp staticUpload(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data) + { + BufferOp op = {}; + op.type = StaticUpload; + op.buf = buf; + op.offset = offset; + const int effectiveSize = size ? size : buf->size(); + op.data.assign(reinterpret_cast<const char *>(data), effectiveSize); + return op; + } - enum Flag { - UsedWithSwapChainOnly = 1 << 0 - }; - Q_DECLARE_FLAGS(Flags, Flag) + static void changeToStaticUpload(BufferOp *op, QRhiBuffer *buf, quint32 offset, quint32 size, const void *data) + { + op->type = StaticUpload; + op->buf = buf; + op->offset = offset; + const int effectiveSize = size ? size : buf->size(); + op->data.assign(reinterpret_cast<const char *>(data), effectiveSize); + } - struct NativeRenderBuffer { - quint64 object; + static BufferOp read(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiReadbackResult *result) + { + BufferOp op = {}; + op.type = Read; + op.buf = buf; + op.offset = offset; + op.readSize = size; + op.result = result; + return op; + } }; - QRhiResource::Type resourceType() const override; - - Type type() const { return m_type; } - void setType(Type t) { m_type = t; } - - QSize pixelSize() const { return m_pixelSize; } - void setPixelSize(const QSize &sz) { m_pixelSize = sz; } - - int sampleCount() const { return m_sampleCount; } - void setSampleCount(int s) { m_sampleCount = s; } - - Flags flags() const { return m_flags; } - void setFlags(Flags h) { m_flags = h; } - - virtual bool create() = 0; - virtual bool createFrom(NativeRenderBuffer src); + struct TextureOp { + enum Type { + Upload, + Copy, + Read, + GenMips + }; + Type type; + QRhiTexture *dst; + // Specifying multiple uploads for a subresource must be supported. + // In the backend this can then end up, where applicable, as a + // single, batched copy operation with only one set of barriers. + // This helps when doing for example glyph cache fills. + using MipLevelUploadList = std::array<QVector<QRhiTextureSubresourceUploadDescription>, QRhi::MAX_MIP_LEVELS>; + QVarLengthArray<MipLevelUploadList, 6> subresDesc; + QRhiTexture *src; + QRhiTextureCopyDescription desc; + QRhiReadbackDescription rb; + QRhiReadbackResult *result; + + static TextureOp upload(QRhiTexture *tex, const QRhiTextureUploadDescription &desc) + { + TextureOp op = {}; + op.type = Upload; + op.dst = tex; + int maxLayer = -1; + for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it) { + if (it->layer() > maxLayer) + maxLayer = it->layer(); + } + op.subresDesc.resize(maxLayer + 1); + for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it) + op.subresDesc[it->layer()][it->level()].append(it->description()); + return op; + } - virtual QRhiTexture::Format backingFormat() const = 0; + static TextureOp copy(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc) + { + TextureOp op = {}; + op.type = Copy; + op.dst = dst; + op.src = src; + op.desc = desc; + return op; + } -protected: - QRhiRenderBuffer(QRhiImplementation *rhi, Type type_, const QSize &pixelSize_, - int sampleCount_, Flags flags_, QRhiTexture::Format backingFormatHint_); - Type m_type; - QSize m_pixelSize; - int m_sampleCount; - Flags m_flags; - QRhiTexture::Format m_backingFormatHint; -}; + static TextureOp read(const QRhiReadbackDescription &rb, QRhiReadbackResult *result) + { + TextureOp op = {}; + op.type = Read; + op.rb = rb; + op.result = result; + return op; + } -Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiRenderBuffer::Flags) + static TextureOp genMips(QRhiTexture *tex) + { + TextureOp op = {}; + op.type = GenMips; + op.dst = tex; + return op; + } + }; -class Q_GUI_EXPORT QRhiRenderPassDescriptor : public QRhiResource -{ -public: - QRhiResource::Type resourceType() const override; + int activeBufferOpCount = 0; // this is the real number of used elements in bufferOps, not bufferOps.count() + static const int BUFFER_OPS_STATIC_ALLOC = 1024; + QVarLengthArray<BufferOp, BUFFER_OPS_STATIC_ALLOC> bufferOps; - virtual bool isCompatible(const QRhiRenderPassDescriptor *other) const = 0; - virtual const QRhiNativeHandles *nativeHandles(); + int activeTextureOpCount = 0; // this is the real number of used elements in textureOps, not textureOps.count() + static const int TEXTURE_OPS_STATIC_ALLOC = 256; + QVarLengthArray<TextureOp, TEXTURE_OPS_STATIC_ALLOC> textureOps; - virtual QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const = 0; + QRhiResourceUpdateBatch *q = nullptr; + QRhiImplementation *rhi = nullptr; + int poolIndex = -1; - virtual QVector<quint32> serializedFormat() const = 0; + void free(); + void merge(QRhiResourceUpdateBatchPrivate *other); + bool hasOptimalCapacity() const; + void trimOpLists(); -protected: - QRhiRenderPassDescriptor(QRhiImplementation *rhi); + static QRhiResourceUpdateBatchPrivate *get(QRhiResourceUpdateBatch *b) { return b->d; } }; -class Q_GUI_EXPORT QRhiRenderTarget : public QRhiResource +template<typename T> +struct QRhiBatchedBindings { -public: - virtual QSize pixelSize() const = 0; - virtual float devicePixelRatio() const = 0; - virtual int sampleCount() const = 0; + void feed(int binding, T resource) { // binding must be strictly increasing + if (curBinding == -1 || binding > curBinding + 1) { + finish(); + curBatch.startBinding = binding; + curBatch.resources.clear(); + curBatch.resources.append(resource); + } else { + Q_ASSERT(binding == curBinding + 1); + curBatch.resources.append(resource); + } + curBinding = binding; + } - QRhiRenderPassDescriptor *renderPassDescriptor() const { return m_renderPassDesc; } - void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) { m_renderPassDesc = desc; } + bool finish() { + if (!curBatch.resources.isEmpty()) + batches.append(curBatch); + return !batches.isEmpty(); + } -protected: - QRhiRenderTarget(QRhiImplementation *rhi); - QRhiRenderPassDescriptor *m_renderPassDesc = nullptr; -}; + void clear() { + batches.clear(); + curBatch.resources.clear(); + curBinding = -1; + } -class Q_GUI_EXPORT QRhiSwapChainRenderTarget : public QRhiRenderTarget -{ -public: - QRhiResource::Type resourceType() const override; - QRhiSwapChain *swapChain() const { return m_swapchain; } + struct Batch { + uint startBinding; + QVarLengthArray<T, 4> resources; -protected: - QRhiSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain_); - QRhiSwapChain *m_swapchain; -}; + bool operator==(const Batch &other) const + { + return startBinding == other.startBinding && resources == other.resources; + } -class Q_GUI_EXPORT QRhiTextureRenderTarget : public QRhiRenderTarget -{ -public: - enum Flag { - PreserveColorContents = 1 << 0, - PreserveDepthStencilContents = 1 << 1 + bool operator!=(const Batch &other) const + { + return !operator==(other); + } }; - Q_DECLARE_FLAGS(Flags, Flag) - - QRhiResource::Type resourceType() const override; - QRhiTextureRenderTargetDescription description() const { return m_desc; } - void setDescription(const QRhiTextureRenderTargetDescription &desc) { m_desc = desc; } + QVarLengthArray<Batch, 4> batches; // sorted by startBinding - Flags flags() const { return m_flags; } - void setFlags(Flags f) { m_flags = f; } - - virtual QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() = 0; + bool operator==(const QRhiBatchedBindings<T> &other) const + { + return batches == other.batches; + } - virtual bool create() = 0; + bool operator!=(const QRhiBatchedBindings<T> &other) const + { + return !operator==(other); + } -protected: - QRhiTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc_, Flags flags_); - QRhiTextureRenderTargetDescription m_desc; - Flags m_flags; +private: + Batch curBatch; + int curBinding = -1; }; -Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiTextureRenderTarget::Flags) - -class Q_GUI_EXPORT QRhiShaderResourceBindings : public QRhiResource +class QRhiGlobalObjectIdGenerator { public: - QRhiResource::Type resourceType() const override; - - void setBindings(std::initializer_list<QRhiShaderResourceBinding> list) { m_bindings = list; } - - template<typename InputIterator> - void setBindings(InputIterator first, InputIterator last) - { - m_bindings.clear(); - std::copy(first, last, std::back_inserter(m_bindings)); - } - - const QRhiShaderResourceBinding *cbeginBindings() const { return m_bindings.cbegin(); } - const QRhiShaderResourceBinding *cendBindings() const { return m_bindings.cend(); } - - bool isLayoutCompatible(const QRhiShaderResourceBindings *other) const; - - QVector<quint32> serializedLayoutDescription() const { return m_layoutDesc; } - - virtual bool create() = 0; - - enum UpdateFlag { - BindingsAreSorted = 0x01 - }; - Q_DECLARE_FLAGS(UpdateFlags, UpdateFlag) - - virtual void updateResources(UpdateFlags flags = {}) = 0; - -protected: - static const int BINDING_PREALLOC = 12; - QRhiShaderResourceBindings(QRhiImplementation *rhi); - QVarLengthArray<QRhiShaderResourceBinding, BINDING_PREALLOC> m_bindings; - size_t m_layoutDescHash = 0; - // Intentionally not using QVLA for m_layoutDesc: clients like Qt Quick are much - // better served with an implicitly shared container here, because they will likely - // throw this directly into structs serving as cache keys. - QVector<quint32> m_layoutDesc; - friend class QRhiImplementation; -#ifndef QT_NO_DEBUG_STREAM - friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBindings &); +#ifdef Q_ATOMIC_INT64_IS_SUPPORTED + using Type = quint64; +#else + using Type = quint32; #endif + static Type newId(); }; -Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiShaderResourceBindings::UpdateFlags) - -#ifndef QT_NO_DEBUG_STREAM -Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBindings &); -#endif - -class Q_GUI_EXPORT QRhiGraphicsPipeline : public QRhiResource +class QRhiPassResourceTracker { public: - enum Flag { - UsesBlendConstants = 1 << 0, - UsesStencilRef = 1 << 1, - UsesScissor = 1 << 2, - CompileShadersWithDebugInfo = 1 << 3 - }; - Q_DECLARE_FLAGS(Flags, Flag) - - enum Topology { - Triangles, - TriangleStrip, - TriangleFan, - Lines, - LineStrip, - Points, - Patches - }; - - enum CullMode { - None, - Front, - Back - }; - - enum FrontFace { - CCW, - CW - }; - - enum ColorMaskComponent { - R = 1 << 0, - G = 1 << 1, - B = 1 << 2, - A = 1 << 3 - }; - Q_DECLARE_FLAGS(ColorMask, ColorMaskComponent) - - enum BlendFactor { - Zero, - One, - SrcColor, - OneMinusSrcColor, - DstColor, - OneMinusDstColor, - SrcAlpha, - OneMinusSrcAlpha, - DstAlpha, - OneMinusDstAlpha, - ConstantColor, - OneMinusConstantColor, - ConstantAlpha, - OneMinusConstantAlpha, - SrcAlphaSaturate, - Src1Color, - OneMinusSrc1Color, - Src1Alpha, - OneMinusSrc1Alpha - }; + bool isEmpty() const; + void reset(); - enum BlendOp { - Add, - Subtract, - ReverseSubtract, - Min, - Max - }; - - struct TargetBlend { - ColorMask colorWrite = ColorMask(0xF); // R | G | B | A - bool enable = false; - BlendFactor srcColor = One; - BlendFactor dstColor = OneMinusSrcAlpha; - BlendOp opColor = Add; - BlendFactor srcAlpha = One; - BlendFactor dstAlpha = OneMinusSrcAlpha; - BlendOp opAlpha = Add; - }; - - enum CompareOp { - Never, - Less, - Equal, - LessOrEqual, - Greater, - NotEqual, - GreaterOrEqual, - Always - }; - - enum StencilOp { - StencilZero, - Keep, - Replace, - IncrementAndClamp, - DecrementAndClamp, - Invert, - IncrementAndWrap, - DecrementAndWrap - }; - - struct StencilOpState { - StencilOp failOp = Keep; - StencilOp depthFailOp = Keep; - StencilOp passOp = Keep; - CompareOp compareOp = Always; + struct UsageState { + int layout; + int access; + int stage; }; - enum PolygonMode { - Fill, - Line + enum BufferStage { + BufVertexInputStage, + BufVertexStage, + BufTCStage, + BufTEStage, + BufFragmentStage, + BufComputeStage, + BufGeometryStage }; - QRhiResource::Type resourceType() const override; - - Flags flags() const { return m_flags; } - void setFlags(Flags f) { m_flags = f; } - - Topology topology() const { return m_topology; } - void setTopology(Topology t) { m_topology = t; } - - CullMode cullMode() const { return m_cullMode; } - void setCullMode(CullMode mode) { m_cullMode = mode; } - - FrontFace frontFace() const { return m_frontFace; } - void setFrontFace(FrontFace f) { m_frontFace = f; } - - void setTargetBlends(std::initializer_list<TargetBlend> list) { m_targetBlends = list; } - template<typename InputIterator> - void setTargetBlends(InputIterator first, InputIterator last) - { - m_targetBlends.clear(); - std::copy(first, last, std::back_inserter(m_targetBlends)); - } - const TargetBlend *cbeginTargetBlends() const { return m_targetBlends.cbegin(); } - const TargetBlend *cendTargetBlends() const { return m_targetBlends.cend(); } - - bool hasDepthTest() const { return m_depthTest; } - void setDepthTest(bool enable) { m_depthTest = enable; } - - bool hasDepthWrite() const { return m_depthWrite; } - void setDepthWrite(bool enable) { m_depthWrite = enable; } - - CompareOp depthOp() const { return m_depthOp; } - void setDepthOp(CompareOp op) { m_depthOp = op; } - - bool hasStencilTest() const { return m_stencilTest; } - void setStencilTest(bool enable) { m_stencilTest = enable; } - - StencilOpState stencilFront() const { return m_stencilFront; } - void setStencilFront(const StencilOpState &state) { m_stencilFront = state; } - - StencilOpState stencilBack() const { return m_stencilBack; } - void setStencilBack(const StencilOpState &state) { m_stencilBack = state; } - - quint32 stencilReadMask() const { return m_stencilReadMask; } - void setStencilReadMask(quint32 mask) { m_stencilReadMask = mask; } - - quint32 stencilWriteMask() const { return m_stencilWriteMask; } - void setStencilWriteMask(quint32 mask) { m_stencilWriteMask = mask; } - - int sampleCount() const { return m_sampleCount; } - void setSampleCount(int s) { m_sampleCount = s; } - - float lineWidth() const { return m_lineWidth; } - void setLineWidth(float width) { m_lineWidth = width; } - - int depthBias() const { return m_depthBias; } - void setDepthBias(int bias) { m_depthBias = bias; } - - float slopeScaledDepthBias() const { return m_slopeScaledDepthBias; } - void setSlopeScaledDepthBias(float bias) { m_slopeScaledDepthBias = bias; } - - void setShaderStages(std::initializer_list<QRhiShaderStage> list) { m_shaderStages = list; } - template<typename InputIterator> - void setShaderStages(InputIterator first, InputIterator last) - { - m_shaderStages.clear(); - std::copy(first, last, std::back_inserter(m_shaderStages)); - } - const QRhiShaderStage *cbeginShaderStages() const { return m_shaderStages.cbegin(); } - const QRhiShaderStage *cendShaderStages() const { return m_shaderStages.cend(); } - - QRhiVertexInputLayout vertexInputLayout() const { return m_vertexInputLayout; } - void setVertexInputLayout(const QRhiVertexInputLayout &layout) { m_vertexInputLayout = layout; } - - QRhiShaderResourceBindings *shaderResourceBindings() const { return m_shaderResourceBindings; } - void setShaderResourceBindings(QRhiShaderResourceBindings *srb) { m_shaderResourceBindings = srb; } - - QRhiRenderPassDescriptor *renderPassDescriptor() const { return m_renderPassDesc; } - void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) { m_renderPassDesc = desc; } - - int patchControlPointCount() const { return m_patchControlPointCount; } - void setPatchControlPointCount(int count) { m_patchControlPointCount = count; } - - PolygonMode polygonMode() const {return m_polygonMode; } - void setPolygonMode(PolygonMode mode) {m_polygonMode = mode; } - - virtual bool create() = 0; - -protected: - QRhiGraphicsPipeline(QRhiImplementation *rhi); - Flags m_flags; - Topology m_topology = Triangles; - CullMode m_cullMode = None; - FrontFace m_frontFace = CCW; - QVarLengthArray<TargetBlend, 8> m_targetBlends; - bool m_depthTest = false; - bool m_depthWrite = false; - CompareOp m_depthOp = Less; - bool m_stencilTest = false; - StencilOpState m_stencilFront; - StencilOpState m_stencilBack; - quint32 m_stencilReadMask = 0xFF; - quint32 m_stencilWriteMask = 0xFF; - int m_sampleCount = 1; - float m_lineWidth = 1.0f; - int m_depthBias = 0; - float m_slopeScaledDepthBias = 0.0f; - int m_patchControlPointCount = 3; - PolygonMode m_polygonMode = Fill; - QVarLengthArray<QRhiShaderStage, 4> m_shaderStages; - QRhiVertexInputLayout m_vertexInputLayout; - QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr; - QRhiRenderPassDescriptor *m_renderPassDesc = nullptr; -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiGraphicsPipeline::Flags) -Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiGraphicsPipeline::ColorMask) -Q_DECLARE_TYPEINFO(QRhiGraphicsPipeline::TargetBlend, Q_RELOCATABLE_TYPE); - -struct QRhiSwapChainHdrInfo -{ - bool isHardCodedDefaults; - enum LimitsType { - LuminanceInNits, - ColorComponentValue + enum BufferAccess { + BufVertexInput, + BufIndexRead, + BufUniformRead, + BufStorageLoad, + BufStorageStore, + BufStorageLoadStore }; - LimitsType limitsType; - union { - struct { - float minLuminance; - float maxLuminance; - } luminanceInNits; - struct { - float maxColorComponentValue; - } colorComponentValue; - } limits; -}; -Q_DECLARE_TYPEINFO(QRhiSwapChainHdrInfo, Q_RELOCATABLE_TYPE); + void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage, + const UsageState &state); -#ifndef QT_NO_DEBUG_STREAM -Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiSwapChainHdrInfo &); -#endif - -class Q_GUI_EXPORT QRhiSwapChain : public QRhiResource -{ -public: - enum Flag { - SurfaceHasPreMulAlpha = 1 << 0, - SurfaceHasNonPreMulAlpha = 1 << 1, - sRGB = 1 << 2, - UsedAsTransferSource = 1 << 3, - NoVSync = 1 << 4, - MinimalBufferCount = 1 << 5 + enum TextureStage { + TexVertexStage, + TexTCStage, + TexTEStage, + TexFragmentStage, + TexColorOutputStage, + TexDepthOutputStage, + TexComputeStage, + TexGeometryStage }; - Q_DECLARE_FLAGS(Flags, Flag) - enum Format { - SDR, - HDRExtendedSrgbLinear, - HDR10 + enum TextureAccess { + TexSample, + TexColorOutput, + TexDepthOutput, + TexStorageLoad, + TexStorageStore, + TexStorageLoadStore }; - QRhiResource::Type resourceType() const override; - - QWindow *window() const { return m_window; } - void setWindow(QWindow *window) { m_window = window; } - - Flags flags() const { return m_flags; } - void setFlags(Flags f) { m_flags = f; } - - Format format() const { return m_format; } - void setFormat(Format f) { m_format = f; } - - QRhiRenderBuffer *depthStencil() const { return m_depthStencil; } - void setDepthStencil(QRhiRenderBuffer *ds) { m_depthStencil = ds; } - - int sampleCount() const { return m_sampleCount; } - void setSampleCount(int samples) { m_sampleCount = samples; } - - QRhiRenderPassDescriptor *renderPassDescriptor() const { return m_renderPassDesc; } - void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) { m_renderPassDesc = desc; } - - QSize currentPixelSize() const { return m_currentPixelSize; } - - virtual QRhiCommandBuffer *currentFrameCommandBuffer() = 0; - virtual QRhiRenderTarget *currentFrameRenderTarget() = 0; - virtual QSize surfacePixelSize() = 0; - virtual bool isFormatSupported(Format f) = 0; - virtual QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() = 0; - virtual bool createOrResize() = 0; - virtual QRhiSwapChainHdrInfo hdrInfo(); - -protected: - QRhiSwapChain(QRhiImplementation *rhi); - QWindow *m_window = nullptr; - Flags m_flags; - Format m_format = SDR; - QRhiRenderBuffer *m_depthStencil = nullptr; - int m_sampleCount = 1; - QRhiRenderPassDescriptor *m_renderPassDesc = nullptr; - QSize m_currentPixelSize; -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiSwapChain::Flags) + void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage, + const UsageState &state); -class Q_GUI_EXPORT QRhiComputePipeline : public QRhiResource -{ -public: - enum Flag { - CompileShadersWithDebugInfo = 1 << 0 + struct Buffer { + int slot; + BufferAccess access; + BufferStage stage; + UsageState stateAtPassBegin; }; - Q_DECLARE_FLAGS(Flags, Flag) - - QRhiResource::Type resourceType() const override; - virtual bool create() = 0; - - Flags flags() const { return m_flags; } - void setFlags(Flags f) { m_flags = f; } - - QRhiShaderStage shaderStage() const { return m_shaderStage; } - void setShaderStage(const QRhiShaderStage &stage) { m_shaderStage = stage; } - - QRhiShaderResourceBindings *shaderResourceBindings() const { return m_shaderResourceBindings; } - void setShaderResourceBindings(QRhiShaderResourceBindings *srb) { m_shaderResourceBindings = srb; } - -protected: - QRhiComputePipeline(QRhiImplementation *rhi); - Flags m_flags; - QRhiShaderStage m_shaderStage; - QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr; -}; -Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiComputePipeline::Flags) + using BufferIterator = QHash<QRhiBuffer *, Buffer>::const_iterator; + BufferIterator cbeginBuffers() const { return m_buffers.cbegin(); } + BufferIterator cendBuffers() const { return m_buffers.cend(); } -class Q_GUI_EXPORT QRhiCommandBuffer : public QRhiResource -{ -public: - enum IndexFormat { - IndexUInt16, - IndexUInt32 + struct Texture { + TextureAccess access; + TextureStage stage; + UsageState stateAtPassBegin; }; - enum BeginPassFlag { - ExternalContent = 0x01, - DoNotTrackResourcesForCompute = 0x02 - }; - Q_DECLARE_FLAGS(BeginPassFlags, BeginPassFlag) - - QRhiResource::Type resourceType() const override; - - void resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates); - - void beginPass(QRhiRenderTarget *rt, - const QColor &colorClearValue, - const QRhiDepthStencilClearValue &depthStencilClearValue, - QRhiResourceUpdateBatch *resourceUpdates = nullptr, - BeginPassFlags flags = {}); - void endPass(QRhiResourceUpdateBatch *resourceUpdates = nullptr); - - void setGraphicsPipeline(QRhiGraphicsPipeline *ps); - using DynamicOffset = QPair<int, quint32>; // binding, offset - void setShaderResources(QRhiShaderResourceBindings *srb = nullptr, - int dynamicOffsetCount = 0, - const DynamicOffset *dynamicOffsets = nullptr); - using VertexInput = QPair<QRhiBuffer *, quint32>; // buffer, offset - void setVertexInput(int startBinding, int bindingCount, const VertexInput *bindings, - QRhiBuffer *indexBuf = nullptr, quint32 indexOffset = 0, - IndexFormat indexFormat = IndexUInt16); - - void setViewport(const QRhiViewport &viewport); - void setScissor(const QRhiScissor &scissor); - void setBlendConstants(const QColor &c); - void setStencilRef(quint32 refValue); - - void draw(quint32 vertexCount, - quint32 instanceCount = 1, - quint32 firstVertex = 0, - quint32 firstInstance = 0); - - void drawIndexed(quint32 indexCount, - quint32 instanceCount = 1, - quint32 firstIndex = 0, - qint32 vertexOffset = 0, - quint32 firstInstance = 0); - - void debugMarkBegin(const QByteArray &name); - void debugMarkEnd(); - void debugMarkMsg(const QByteArray &msg); - - void beginComputePass(QRhiResourceUpdateBatch *resourceUpdates = nullptr, BeginPassFlags flags = {}); - void endComputePass(QRhiResourceUpdateBatch *resourceUpdates = nullptr); - void setComputePipeline(QRhiComputePipeline *ps); - void dispatch(int x, int y, int z); - - const QRhiNativeHandles *nativeHandles(); - void beginExternal(); - void endExternal(); - -protected: - QRhiCommandBuffer(QRhiImplementation *rhi); -}; + using TextureIterator = QHash<QRhiTexture *, Texture>::const_iterator; + TextureIterator cbeginTextures() const { return m_textures.cbegin(); } + TextureIterator cendTextures() const { return m_textures.cend(); } -Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiCommandBuffer::BeginPassFlags) + static BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages); + static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages); -struct Q_GUI_EXPORT QRhiReadbackResult -{ - std::function<void()> completed = nullptr; - QRhiTexture::Format format; - QSize pixelSize; - QByteArray data; +private: + QHash<QRhiBuffer *, Buffer> m_buffers; + QHash<QRhiTexture *, Texture> m_textures; }; -struct Q_GUI_EXPORT QRhiBufferReadbackResult -{ - std::function<void()> completed = nullptr; - QByteArray data; -}; +Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Buffer, Q_RELOCATABLE_TYPE); +Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Texture, Q_RELOCATABLE_TYPE); -class Q_GUI_EXPORT QRhiResourceUpdateBatch +template<typename T, int GROW = 1024> +class QRhiBackendCommandList { public: - ~QRhiResourceUpdateBatch(); - - void release(); - - void merge(QRhiResourceUpdateBatch *other); - bool hasOptimalCapacity() const; - - void updateDynamicBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data); - void uploadStaticBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data); - void uploadStaticBuffer(QRhiBuffer *buf, const void *data); - void readBackBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiBufferReadbackResult *result); - void uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc); - void uploadTexture(QRhiTexture *tex, const QImage &image); - void copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc = QRhiTextureCopyDescription()); - void readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result); - void generateMips(QRhiTexture *tex); - + QRhiBackendCommandList() = default; + ~QRhiBackendCommandList() { delete[] v; } + inline void reset() { p = 0; } + inline bool isEmpty() const { return p == 0; } + inline T &get() { + if (p == a) { + a += GROW; + T *nv = new T[a]; + if (v) { + memcpy(nv, v, p * sizeof(T)); + delete[] v; + } + v = nv; + } + return v[p++]; + } + inline void unget() { --p; } + inline T *cbegin() const { return v; } + inline T *cend() const { return v + p; } + inline T *begin() { return v; } + inline T *end() { return v + p; } private: - QRhiResourceUpdateBatch(QRhiImplementation *rhi); - Q_DISABLE_COPY(QRhiResourceUpdateBatch) - QRhiResourceUpdateBatchPrivate *d; - friend class QRhiResourceUpdateBatchPrivate; - friend class QRhi; + Q_DISABLE_COPY(QRhiBackendCommandList) + T *v = nullptr; + int a = 0; + int p = 0; }; -struct Q_GUI_EXPORT QRhiDriverInfo +struct QRhiRenderTargetAttachmentTracker { - enum DeviceType { - UnknownDevice, - IntegratedDevice, - DiscreteDevice, - ExternalDevice, - VirtualDevice, - CpuDevice - }; + struct ResId { quint64 id; uint generation; }; + using ResIdList = QVarLengthArray<ResId, 8 * 2 + 1>; // color, resolve, ds - QByteArray deviceName; - quint64 deviceId = 0; - quint64 vendorId = 0; - DeviceType deviceType = UnknownDevice; -}; - -Q_DECLARE_TYPEINFO(QRhiDriverInfo, Q_RELOCATABLE_TYPE); + template<typename TexType, typename RenderBufferType> + static void updateResIdList(const QRhiTextureRenderTargetDescription &desc, ResIdList *dst); -#ifndef QT_NO_DEBUG_STREAM -Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiDriverInfo &); -#endif - -struct Q_GUI_EXPORT QRhiStats -{ - qint64 totalPipelineCreationTime = 0; - quint32 blockCount = 0; - quint32 allocCount = 0; - quint64 usedBytes = 0; - quint64 unusedBytes = 0; + template<typename TexType, typename RenderBufferType> + static bool isUpToDate(const QRhiTextureRenderTargetDescription &desc, const ResIdList ¤tResIdList); }; -Q_DECLARE_TYPEINFO(QRhiStats, Q_RELOCATABLE_TYPE); - -#ifndef QT_NO_DEBUG_STREAM -Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiStats &); -#endif - -struct Q_GUI_EXPORT QRhiInitParams +inline bool operator==(const QRhiRenderTargetAttachmentTracker::ResId &a, const QRhiRenderTargetAttachmentTracker::ResId &b) { -}; + return a.id == b.id && a.generation == b.generation; +} -class Q_GUI_EXPORT QRhi +inline bool operator!=(const QRhiRenderTargetAttachmentTracker::ResId &a, const QRhiRenderTargetAttachmentTracker::ResId &b) { -public: - enum Implementation { - Null, - Vulkan, - OpenGLES2, - D3D11, - Metal - }; - - enum Flag { - EnableProfiling = 1 << 0, - EnableDebugMarkers = 1 << 1, - PreferSoftwareRenderer = 1 << 2, - EnablePipelineCacheDataSave = 1 << 3 - }; - Q_DECLARE_FLAGS(Flags, Flag) - - enum FrameOpResult { - FrameOpSuccess = 0, - FrameOpError, - FrameOpSwapChainOutOfDate, - FrameOpDeviceLost - }; - - enum Feature { - MultisampleTexture = 1, - MultisampleRenderBuffer, - DebugMarkers, - Timestamps, - Instancing, - CustomInstanceStepRate, - PrimitiveRestart, - NonDynamicUniformBuffers, - NonFourAlignedEffectiveIndexBufferOffset, - NPOTTextureRepeat, - RedOrAlpha8IsRed, - ElementIndexUint, - Compute, - WideLines, - VertexShaderPointSize, - BaseVertex, - BaseInstance, - TriangleFanTopology, - ReadBackNonUniformBuffer, - ReadBackNonBaseMipLevel, - TexelFetch, - RenderToNonBaseMipLevel, - IntAttributes, - ScreenSpaceDerivatives, - ReadBackAnyTextureFormat, - PipelineCacheDataLoadSave, - ImageDataStride, - RenderBufferImport, - ThreeDimensionalTextures, - RenderTo3DTextureSlice, - TextureArrays, - Tessellation, - GeometryShader, - TextureArrayRange, - NonFillPolygonMode - }; - - enum BeginFrameFlag { - }; - Q_DECLARE_FLAGS(BeginFrameFlags, BeginFrameFlag) - - enum EndFrameFlag { - SkipPresent = 1 << 0 - }; - Q_DECLARE_FLAGS(EndFrameFlags, EndFrameFlag) - - enum ResourceLimit { - TextureSizeMin = 1, - TextureSizeMax, - MaxColorAttachments, - FramesInFlight, - MaxAsyncReadbackFrames, - MaxThreadGroupsPerDimension, - MaxThreadsPerThreadGroup, - MaxThreadGroupX, - MaxThreadGroupY, - MaxThreadGroupZ, - TextureArraySizeMax, - MaxUniformBufferRange, - MaxVertexInputs, - MaxVertexOutputs - }; - - ~QRhi(); - - static QRhi *create(Implementation impl, - QRhiInitParams *params, - Flags flags = {}, - QRhiNativeHandles *importDevice = nullptr); - static bool probe(Implementation impl, QRhiInitParams *params); - - Implementation backend() const; - const char *backendName() const; - static const char *backendName(Implementation impl); - QRhiDriverInfo driverInfo() const; - QThread *thread() const; - - using CleanupCallback = std::function<void(QRhi *)>; - void addCleanupCallback(const CleanupCallback &callback); - void runCleanup(); - - using GpuFrameTimeCallback = std::function<void(float t)>; - void addGpuFrameTimeCallback(const GpuFrameTimeCallback &callback); - - QRhiGraphicsPipeline *newGraphicsPipeline(); - QRhiComputePipeline *newComputePipeline(); - QRhiShaderResourceBindings *newShaderResourceBindings(); - - QRhiBuffer *newBuffer(QRhiBuffer::Type type, - QRhiBuffer::UsageFlags usage, - quint32 size); - - QRhiRenderBuffer *newRenderBuffer(QRhiRenderBuffer::Type type, - const QSize &pixelSize, - int sampleCount = 1, - QRhiRenderBuffer::Flags flags = {}, - QRhiTexture::Format backingFormatHint = QRhiTexture::UnknownFormat); - - QRhiTexture *newTexture(QRhiTexture::Format format, - const QSize &pixelSize, - int sampleCount = 1, - QRhiTexture::Flags flags = {}); - - QRhiTexture *newTexture(QRhiTexture::Format format, - int width, int height, int depth, - int sampleCount = 1, - QRhiTexture::Flags flags = {}); + return !(a == b); +} - QRhiTexture *newTextureArray(QRhiTexture::Format format, - int arraySize, - const QSize &pixelSize, - int sampleCount = 1, - QRhiTexture::Flags flags = {}); - - QRhiSampler *newSampler(QRhiSampler::Filter magFilter, - QRhiSampler::Filter minFilter, - QRhiSampler::Filter mipmapMode, - QRhiSampler::AddressMode addressU, - QRhiSampler::AddressMode addressV, - QRhiSampler::AddressMode addressW = QRhiSampler::Repeat); - - QRhiTextureRenderTarget *newTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, - QRhiTextureRenderTarget::Flags flags = {}); - - QRhiSwapChain *newSwapChain(); - FrameOpResult beginFrame(QRhiSwapChain *swapChain, BeginFrameFlags flags = {}); - FrameOpResult endFrame(QRhiSwapChain *swapChain, EndFrameFlags flags = {}); - bool isRecordingFrame() const; - int currentFrameSlot() const; - - FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, BeginFrameFlags flags = {}); - FrameOpResult endOffscreenFrame(EndFrameFlags flags = {}); - - QRhi::FrameOpResult finish(); - - QRhiResourceUpdateBatch *nextResourceUpdateBatch(); - - QList<int> supportedSampleCounts() const; - - int ubufAlignment() const; - int ubufAligned(int v) const; - - int mipLevelsForSize(const QSize &size) const; - QSize sizeForMipLevel(int mipLevel, const QSize &baseLevelSize) const; - - bool isYUpInFramebuffer() const; - bool isYUpInNDC() const; - bool isClipDepthZeroToOne() const; - - QMatrix4x4 clipSpaceCorrMatrix() const; - - bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags = {}) const; - bool isFeatureSupported(QRhi::Feature feature) const; - int resourceLimit(ResourceLimit limit) const; - - const QRhiNativeHandles *nativeHandles(); - bool makeThreadLocalNativeContextCurrent(); - - static const int MAX_MIP_LEVELS = 16; // a width and/or height of 65536 should be enough for everyone - - void releaseCachedResources(); - - bool isDeviceLost() const; - - QByteArray pipelineCacheData(); - void setPipelineCacheData(const QByteArray &data); - - QRhiStats statistics() const; - -protected: - QRhi(); - -private: - Q_DISABLE_COPY(QRhi) - QRhiImplementation *d = nullptr; -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QRhi::Flags) -Q_DECLARE_OPERATORS_FOR_FLAGS(QRhi::BeginFrameFlags) -Q_DECLARE_OPERATORS_FOR_FLAGS(QRhi::EndFrameFlags) +template<typename TexType, typename RenderBufferType> +void QRhiRenderTargetAttachmentTracker::updateResIdList(const QRhiTextureRenderTargetDescription &desc, ResIdList *dst) +{ + const bool hasDepthStencil = desc.depthStencilBuffer() || desc.depthTexture(); + dst->resize(desc.colorAttachmentCount() * 2 + (hasDepthStencil ? 1 : 0)); + int n = 0; + for (auto it = desc.cbeginColorAttachments(), itEnd = desc.cendColorAttachments(); it != itEnd; ++it, ++n) { + const QRhiColorAttachment &colorAtt(*it); + if (colorAtt.texture()) { + TexType *texD = QRHI_RES(TexType, colorAtt.texture()); + (*dst)[n] = { texD->globalResourceId(), texD->generation }; + } else if (colorAtt.renderBuffer()) { + RenderBufferType *rbD = QRHI_RES(RenderBufferType, colorAtt.renderBuffer()); + (*dst)[n] = { rbD->globalResourceId(), rbD->generation }; + } else { + (*dst)[n] = { 0, 0 }; + } + ++n; + if (colorAtt.resolveTexture()) { + TexType *texD = QRHI_RES(TexType, colorAtt.resolveTexture()); + (*dst)[n] = { texD->globalResourceId(), texD->generation }; + } else { + (*dst)[n] = { 0, 0 }; + } + } + if (hasDepthStencil) { + if (desc.depthTexture()) { + TexType *depthTexD = QRHI_RES(TexType, desc.depthTexture()); + (*dst)[n] = { depthTexD->globalResourceId(), depthTexD->generation }; + } else if (desc.depthStencilBuffer()) { + RenderBufferType *depthRbD = QRHI_RES(RenderBufferType, desc.depthStencilBuffer()); + (*dst)[n] = { depthRbD->globalResourceId(), depthRbD->generation }; + } else { + (*dst)[n] = { 0, 0 }; + } + } +} + +template<typename TexType, typename RenderBufferType> +bool QRhiRenderTargetAttachmentTracker::isUpToDate(const QRhiTextureRenderTargetDescription &desc, const ResIdList ¤tResIdList) +{ + // Just as setShaderResources() recognizes if an srb's referenced + // resources have been rebuilt (got a create() since the srb's + // create()), we should do the same for the textures and renderbuffers + // referenced from the rendertarget. It is not uncommon that a texture + // or ds buffer gets resized due to following a window size in some + // form, which involves a create() on them. It is then nice if the + // render target auto-rebuilds in beginPass(). + + ResIdList resIdList; + updateResIdList<TexType, RenderBufferType>(desc, &resIdList); + return resIdList == currentResIdList; +} + +template<typename T> +inline T *qrhi_objectFromProxyData(QRhiSwapChainProxyData *pd, QWindow *window, QRhi::Implementation impl, uint objectIndex) +{ + Q_ASSERT(objectIndex < std::size(pd->reserved)); + if (!pd->reserved[objectIndex]) // // was not set, no other choice, do it here, whatever thread this is + *pd = QRhi::updateSwapChainProxyData(impl, window); + return static_cast<T *>(pd->reserved[objectIndex]); +} QT_END_NAMESPACE |