/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Gui module ** ** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPLv3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or later as published by the Free ** Software Foundation and appearing in the file LICENSE.GPL included in ** the packaging of this file. Please review the following information to ** ensure the GNU General Public License version 2.0 requirements will be ** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QRHIMETAL_P_H #define QRHIMETAL_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include "qrhimetal_p.h" #include "qrhi_p_p.h" #include QT_BEGIN_NAMESPACE static const int QMTL_FRAMES_IN_FLIGHT = 2; // have to hide the ObjC stuff, this header cannot contain MTL* at all struct QMetalBufferData; struct QMetalBuffer : public QRhiBuffer { QMetalBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size); ~QMetalBuffer(); void release() override; bool build() override; QMetalBufferData *d; uint generation = 0; int lastActiveFrameSlot = -1; friend class QRhiMetal; friend struct QMetalShaderResourceBindings; }; struct QMetalRenderBufferData; struct QMetalRenderBuffer : public QRhiRenderBuffer { QMetalRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags); ~QMetalRenderBuffer(); void release() override; bool build() override; QRhiTexture::Format backingFormat() const override; QMetalRenderBufferData *d; int samples = 1; uint generation = 0; int lastActiveFrameSlot = -1; friend class QRhiMetal; }; struct QMetalTextureData; struct QMetalTexture : public QRhiTexture { QMetalTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int sampleCount, Flags flags); ~QMetalTexture(); void release() override; bool build() override; bool buildFrom(NativeTexture src) override; NativeTexture nativeTexture() override; bool prepareBuild(QSize *adjustedSize = nullptr); QMetalTextureData *d; int mipLevelCount = 0; int samples = 1; uint generation = 0; int lastActiveFrameSlot = -1; friend class QRhiMetal; friend struct QMetalShaderResourceBindings; friend struct QMetalTextureData; }; struct QMetalSamplerData; struct QMetalSampler : public QRhiSampler { QMetalSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode, AddressMode u, AddressMode v); ~QMetalSampler(); void release() override; bool build() override; QMetalSamplerData *d; uint generation = 0; int lastActiveFrameSlot = -1; friend class QRhiMetal; friend struct QMetalShaderResourceBindings; }; struct QMetalRenderPassDescriptor : public QRhiRenderPassDescriptor { QMetalRenderPassDescriptor(QRhiImplementation *rhi); ~QMetalRenderPassDescriptor(); void release() override; bool isCompatible(const QRhiRenderPassDescriptor *other) const override; // there is no MTLRenderPassDescriptor here as one will be created for each pass in beginPass() // but the things needed for the render pipeline descriptor have to be provided static const int MAX_COLOR_ATTACHMENTS = 8; int colorAttachmentCount = 0; bool hasDepthStencil = false; int colorFormat[MAX_COLOR_ATTACHMENTS]; int dsFormat; }; struct QMetalRenderTargetData; struct QMetalReferenceRenderTarget : public QRhiRenderTarget { QMetalReferenceRenderTarget(QRhiImplementation *rhi); ~QMetalReferenceRenderTarget(); void release() override; QSize pixelSize() const override; float devicePixelRatio() const override; int sampleCount() const override; QMetalRenderTargetData *d; }; struct QMetalTextureRenderTarget : public QRhiTextureRenderTarget { QMetalTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags); ~QMetalTextureRenderTarget(); void release() override; QSize pixelSize() const override; float devicePixelRatio() const override; int sampleCount() const override; QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override; bool build() override; QMetalRenderTargetData *d; friend class QRhiMetal; }; struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings { QMetalShaderResourceBindings(QRhiImplementation *rhi); ~QMetalShaderResourceBindings(); void release() override; bool build() override; QVarLengthArray sortedBindings; int maxBinding = -1; struct BoundUniformBufferData { quint64 id; uint generation; }; struct BoundSampledTextureData { quint64 texId; uint texGeneration; quint64 samplerId; uint samplerGeneration; }; struct BoundStorageImageData { quint64 id; uint generation; }; struct BoundStorageBufferData { quint64 id; uint generation; }; struct BoundResourceData { union { BoundUniformBufferData ubuf; BoundSampledTextureData stex; BoundStorageImageData simage; BoundStorageBufferData sbuf; }; }; QVarLengthArray boundResourceData; uint generation = 0; friend class QRhiMetal; }; struct QMetalGraphicsPipelineData; struct QMetalGraphicsPipeline : public QRhiGraphicsPipeline { QMetalGraphicsPipeline(QRhiImplementation *rhi); ~QMetalGraphicsPipeline(); void release() override; bool build() override; QMetalGraphicsPipelineData *d; uint generation = 0; int lastActiveFrameSlot = -1; friend class QRhiMetal; }; struct QMetalComputePipelineData; struct QMetalComputePipeline : public QRhiComputePipeline { QMetalComputePipeline(QRhiImplementation *rhi); ~QMetalComputePipeline(); void release() override; bool build() override; QMetalComputePipelineData *d; uint generation = 0; int lastActiveFrameSlot = -1; friend class QRhiMetal; }; struct QMetalCommandBufferData; struct QMetalSwapChain; struct QMetalCommandBuffer : public QRhiCommandBuffer { QMetalCommandBuffer(QRhiImplementation *rhi); ~QMetalCommandBuffer(); void release() override; QMetalCommandBufferData *d = nullptr; QRhiMetalCommandBufferNativeHandles nativeHandlesStruct; enum PassType { NoPass, RenderPass, ComputePass }; // per-pass (render or compute command encoder) persistent state PassType recordingPass; QRhiRenderTarget *currentTarget; // per-pass (render or compute command encoder) volatile (cached) state QRhiGraphicsPipeline *currentGraphicsPipeline; QRhiComputePipeline *currentComputePipeline; uint currentPipelineGeneration; QRhiShaderResourceBindings *currentGraphicsSrb; QRhiShaderResourceBindings *currentComputeSrb; uint currentSrbGeneration; int currentResSlot; QRhiBuffer *currentIndexBuffer; quint32 currentIndexOffset; QRhiCommandBuffer::IndexFormat currentIndexFormat; int currentCullMode; int currentFrontFaceWinding; const QRhiNativeHandles *nativeHandles(); void resetState(); void resetPerPassState(); void resetPerPassCachedState(); }; struct QMetalSwapChainData; struct QMetalSwapChain : public QRhiSwapChain { QMetalSwapChain(QRhiImplementation *rhi); ~QMetalSwapChain(); void release() override; QRhiCommandBuffer *currentFrameCommandBuffer() override; QRhiRenderTarget *currentFrameRenderTarget() override; QSize surfacePixelSize() override; QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override; bool buildOrResize() override; void chooseFormats(); QWindow *window = nullptr; QSize pixelSize; int currentFrameSlot = 0; // 0..QMTL_FRAMES_IN_FLIGHT-1 int frameCount = 0; int samples = 1; QMetalReferenceRenderTarget rtWrapper; QMetalCommandBuffer cbWrapper; QMetalRenderBuffer *ds = nullptr; QMetalSwapChainData *d = nullptr; }; struct QRhiMetalData; class QRhiMetal : public QRhiImplementation { public: QRhiMetal(QRhiMetalInitParams *params, QRhiMetalNativeHandles *importDevice = nullptr); ~QRhiMetal(); bool create(QRhi::Flags flags) override; void destroy() override; QRhiGraphicsPipeline *createGraphicsPipeline() override; QRhiComputePipeline *createComputePipeline() override; QRhiShaderResourceBindings *createShaderResourceBindings() override; QRhiBuffer *createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, int size) override; QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags) override; QRhiTexture *createTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount, QRhiTexture::Flags flags) override; QRhiSampler *createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter, QRhiSampler::Filter mipmapMode, QRhiSampler:: AddressMode u, QRhiSampler::AddressMode v) override; QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, QRhiTextureRenderTarget::Flags flags) override; QRhiSwapChain *createSwapChain() override; QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override; QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override; QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override; QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override; QRhi::FrameOpResult finish() override; void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override; void beginPass(QRhiCommandBuffer *cb, QRhiRenderTarget *rt, const QColor &colorClearValue, const QRhiDepthStencilClearValue &depthStencilClearValue, QRhiResourceUpdateBatch *resourceUpdates) override; void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override; void setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps) override; void setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb, int dynamicOffsetCount, const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override; void setVertexInput(QRhiCommandBuffer *cb, int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings, QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat) override; void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override; void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override; void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override; void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override; void draw(QRhiCommandBuffer *cb, quint32 vertexCount, quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override; void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount, quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance) override; void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override; void debugMarkEnd(QRhiCommandBuffer *cb) override; void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override; void beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override; void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override; void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override; void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override; const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override; void beginExternal(QRhiCommandBuffer *cb) override; void endExternal(QRhiCommandBuffer *cb) override; QVector supportedSampleCounts() const override; int ubufAlignment() const override; bool isYUpInFramebuffer() const override; bool isYUpInNDC() const override; bool isClipDepthZeroToOne() const override; QMatrix4x4 clipSpaceCorrMatrix() const override; bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override; bool isFeatureSupported(QRhi::Feature feature) const override; int resourceLimit(QRhi::ResourceLimit limit) const override; const QRhiNativeHandles *nativeHandles() override; void sendVMemStatsToProfiler() override; bool makeThreadLocalNativeContextCurrent() override; void releaseCachedResources() override; bool isDeviceLost() const override; void executeDeferredReleases(bool forced = false); void finishActiveReadbacks(bool forced = false); qsizetype subresUploadByteSize(const QRhiTextureSubresourceUploadDescription &subresDesc) const; void enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEncPtr, int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc, qsizetype *curOfs); void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates); void executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD); static const int SUPPORTED_STAGES = 3; void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, QMetalCommandBuffer *cbD, int dynamicOffsetCount, const QRhiCommandBuffer::DynamicOffset *dynamicOffsets, bool offsetOnlyChange, const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[SUPPORTED_STAGES]); int effectiveSampleCount(int sampleCount) const; bool importedDevice = false; bool importedCmdQueue = false; QMetalSwapChain *currentSwapChain = nullptr; QSet swapchains; QRhiMetalNativeHandles nativeHandlesStruct; struct { int maxTextureSize = 4096; } caps; QRhiMetalData *d = nullptr; }; QT_END_NAMESPACE #endif