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 QRHIMETAL_P_H
38 #define QRHIMETAL_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 "qrhimetal_p.h"
52 #include "qrhi_p_p.h"
53 #include <QWindow>
54 
55 QT_BEGIN_NAMESPACE
56 
57 static const int QMTL_FRAMES_IN_FLIGHT = 2;
58 
59 // have to hide the ObjC stuff, this header cannot contain MTL* at all
60 struct QMetalBufferData;
61 
62 struct QMetalBuffer : public QRhiBuffer
63 {
64     QMetalBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size);
65     ~QMetalBuffer();
66     void release() override;
67     bool build() override;
68     QRhiBuffer::NativeBuffer nativeBuffer() override;
69 
70     QMetalBufferData *d;
71     uint generation = 0;
72     int lastActiveFrameSlot = -1;
73     friend class QRhiMetal;
74     friend struct QMetalShaderResourceBindings;
75 };
76 
77 struct QMetalRenderBufferData;
78 
79 struct QMetalRenderBuffer : public QRhiRenderBuffer
80 {
81     QMetalRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
82                        int sampleCount, QRhiRenderBuffer::Flags flags);
83     ~QMetalRenderBuffer();
84     void release() override;
85     bool build() override;
86     QRhiTexture::Format backingFormat() const override;
87 
88     QMetalRenderBufferData *d;
89     int samples = 1;
90     uint generation = 0;
91     int lastActiveFrameSlot = -1;
92     friend class QRhiMetal;
93 };
94 
95 struct QMetalTextureData;
96 
97 struct QMetalTexture : public QRhiTexture
98 {
99     QMetalTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize,
100                   int sampleCount, Flags flags);
101     ~QMetalTexture();
102     void release() override;
103     bool build() override;
104     bool buildFrom(NativeTexture src) override;
105     NativeTexture nativeTexture() override;
106 
107     bool prepareBuild(QSize *adjustedSize = nullptr);
108 
109     QMetalTextureData *d;
110     int mipLevelCount = 0;
111     int samples = 1;
112     uint generation = 0;
113     int lastActiveFrameSlot = -1;
114     friend class QRhiMetal;
115     friend struct QMetalShaderResourceBindings;
116     friend struct QMetalTextureData;
117 };
118 
119 struct QMetalSamplerData;
120 
121 struct QMetalSampler : public QRhiSampler
122 {
123     QMetalSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
124                   AddressMode u, AddressMode v, AddressMode w);
125     ~QMetalSampler();
126     void release() override;
127     bool build() override;
128 
129     QMetalSamplerData *d;
130     uint generation = 0;
131     int lastActiveFrameSlot = -1;
132     friend class QRhiMetal;
133     friend struct QMetalShaderResourceBindings;
134 };
135 
136 struct QMetalRenderPassDescriptor : public QRhiRenderPassDescriptor
137 {
138     QMetalRenderPassDescriptor(QRhiImplementation *rhi);
139     ~QMetalRenderPassDescriptor();
140     void release() override;
141     bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
142 
143     // there is no MTLRenderPassDescriptor here as one will be created for each pass in beginPass()
144 
145     // but the things needed for the render pipeline descriptor have to be provided
146     static const int MAX_COLOR_ATTACHMENTS = 8;
147     int colorAttachmentCount = 0;
148     bool hasDepthStencil = false;
149     int colorFormat[MAX_COLOR_ATTACHMENTS];
150     int dsFormat;
151 };
152 
153 struct QMetalRenderTargetData;
154 
155 struct QMetalReferenceRenderTarget : public QRhiRenderTarget
156 {
157     QMetalReferenceRenderTarget(QRhiImplementation *rhi);
158     ~QMetalReferenceRenderTarget();
159     void release() override;
160 
161     QSize pixelSize() const override;
162     float devicePixelRatio() const override;
163     int sampleCount() const override;
164 
165     QMetalRenderTargetData *d;
166 };
167 
168 struct QMetalTextureRenderTarget : public QRhiTextureRenderTarget
169 {
170     QMetalTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
171     ~QMetalTextureRenderTarget();
172     void release() override;
173 
174     QSize pixelSize() const override;
175     float devicePixelRatio() const override;
176     int sampleCount() const override;
177 
178     QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
179     bool build() override;
180 
181     QMetalRenderTargetData *d;
182     friend class QRhiMetal;
183 };
184 
185 struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
186 {
187     QMetalShaderResourceBindings(QRhiImplementation *rhi);
188     ~QMetalShaderResourceBindings();
189     void release() override;
190     bool build() override;
191 
192     QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
193     int maxBinding = -1;
194 
195     struct BoundUniformBufferData {
196         quint64 id;
197         uint generation;
198     };
199     struct BoundSampledTextureData {
200         int count;
201         struct {
202             quint64 texId;
203             uint texGeneration;
204             quint64 samplerId;
205             uint samplerGeneration;
206         } d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE];
207     };
208     struct BoundStorageImageData {
209         quint64 id;
210         uint generation;
211     };
212     struct BoundStorageBufferData {
213         quint64 id;
214         uint generation;
215     };
216     struct BoundResourceData {
217         union {
218             BoundUniformBufferData ubuf;
219             BoundSampledTextureData stex;
220             BoundStorageImageData simage;
221             BoundStorageBufferData sbuf;
222         };
223     };
224     QVarLengthArray<BoundResourceData, 8> boundResourceData;
225 
226     uint generation = 0;
227     friend class QRhiMetal;
228 };
229 
230 struct QMetalGraphicsPipelineData;
231 
232 struct QMetalGraphicsPipeline : public QRhiGraphicsPipeline
233 {
234     QMetalGraphicsPipeline(QRhiImplementation *rhi);
235     ~QMetalGraphicsPipeline();
236     void release() override;
237     bool build() override;
238 
239     QMetalGraphicsPipelineData *d;
240     uint generation = 0;
241     int lastActiveFrameSlot = -1;
242     friend class QRhiMetal;
243 };
244 
245 struct QMetalComputePipelineData;
246 
247 struct QMetalComputePipeline : public QRhiComputePipeline
248 {
249     QMetalComputePipeline(QRhiImplementation *rhi);
250     ~QMetalComputePipeline();
251     void release() override;
252     bool build() override;
253 
254     QMetalComputePipelineData *d;
255     uint generation = 0;
256     int lastActiveFrameSlot = -1;
257     friend class QRhiMetal;
258 };
259 
260 struct QMetalCommandBufferData;
261 struct QMetalSwapChain;
262 
263 struct QMetalCommandBuffer : public QRhiCommandBuffer
264 {
265     QMetalCommandBuffer(QRhiImplementation *rhi);
266     ~QMetalCommandBuffer();
267     void release() override;
268 
269     QMetalCommandBufferData *d = nullptr;
270     QRhiMetalCommandBufferNativeHandles nativeHandlesStruct;
271 
272     enum PassType {
273         NoPass,
274         RenderPass,
275         ComputePass
276     };
277 
278     // per-pass (render or compute command encoder) persistent state
279     PassType recordingPass;
280     QRhiRenderTarget *currentTarget;
281 
282     // per-pass (render or compute command encoder) volatile (cached) state
283     QRhiGraphicsPipeline *currentGraphicsPipeline;
284     QRhiComputePipeline *currentComputePipeline;
285     uint currentPipelineGeneration;
286     QRhiShaderResourceBindings *currentGraphicsSrb;
287     QRhiShaderResourceBindings *currentComputeSrb;
288     uint currentSrbGeneration;
289     int currentResSlot;
290     QRhiBuffer *currentIndexBuffer;
291     quint32 currentIndexOffset;
292     QRhiCommandBuffer::IndexFormat currentIndexFormat;
293     int currentCullMode;
294     int currentFrontFaceWinding;
295     QPair<float, float> currentDepthBiasValues;
296 
297     const QRhiNativeHandles *nativeHandles();
298     void resetState();
299     void resetPerPassState();
300     void resetPerPassCachedState();
301 };
302 
303 struct QMetalSwapChainData;
304 
305 struct QMetalSwapChain : public QRhiSwapChain
306 {
307     QMetalSwapChain(QRhiImplementation *rhi);
308     ~QMetalSwapChain();
309     void release() override;
310 
311     QRhiCommandBuffer *currentFrameCommandBuffer() override;
312     QRhiRenderTarget *currentFrameRenderTarget() override;
313     QSize surfacePixelSize() override;
314 
315     QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
316 
317     bool buildOrResize() override;
318 
319     void chooseFormats();
320 
321     QWindow *window = nullptr;
322     QSize pixelSize;
323     int currentFrameSlot = 0; // 0..QMTL_FRAMES_IN_FLIGHT-1
324     int frameCount = 0;
325     int samples = 1;
326     QMetalReferenceRenderTarget rtWrapper;
327     QMetalCommandBuffer cbWrapper;
328     QMetalRenderBuffer *ds = nullptr;
329     QMetalSwapChainData *d = nullptr;
330 };
331 
332 struct QRhiMetalData;
333 
334 class QRhiMetal : public QRhiImplementation
335 {
336 public:
337     QRhiMetal(QRhiMetalInitParams *params, QRhiMetalNativeHandles *importDevice = nullptr);
338     ~QRhiMetal();
339 
340     bool create(QRhi::Flags flags) override;
341     void destroy() override;
342 
343     QRhiGraphicsPipeline *createGraphicsPipeline() override;
344     QRhiComputePipeline *createComputePipeline() override;
345     QRhiShaderResourceBindings *createShaderResourceBindings() override;
346     QRhiBuffer *createBuffer(QRhiBuffer::Type type,
347                              QRhiBuffer::UsageFlags usage,
348                              int size) override;
349     QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
350                                          const QSize &pixelSize,
351                                          int sampleCount,
352                                          QRhiRenderBuffer::Flags flags) override;
353     QRhiTexture *createTexture(QRhiTexture::Format format,
354                                const QSize &pixelSize,
355                                int sampleCount,
356                                QRhiTexture::Flags flags) override;
357     QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
358                                QRhiSampler::Filter minFilter,
359                                QRhiSampler::Filter mipmapMode,
360                                QRhiSampler:: AddressMode u,
361                                QRhiSampler::AddressMode v,
362                                QRhiSampler::AddressMode w) override;
363 
364     QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
365                                                        QRhiTextureRenderTarget::Flags flags) override;
366 
367     QRhiSwapChain *createSwapChain() override;
368     QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
369     QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
370     QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
371     QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
372     QRhi::FrameOpResult finish() override;
373 
374     void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
375 
376     void beginPass(QRhiCommandBuffer *cb,
377                    QRhiRenderTarget *rt,
378                    const QColor &colorClearValue,
379                    const QRhiDepthStencilClearValue &depthStencilClearValue,
380                    QRhiResourceUpdateBatch *resourceUpdates) override;
381     void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
382 
383     void setGraphicsPipeline(QRhiCommandBuffer *cb,
384                              QRhiGraphicsPipeline *ps) override;
385 
386     void setShaderResources(QRhiCommandBuffer *cb,
387                             QRhiShaderResourceBindings *srb,
388                             int dynamicOffsetCount,
389                             const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
390 
391     void setVertexInput(QRhiCommandBuffer *cb,
392                         int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
393                         QRhiBuffer *indexBuf, quint32 indexOffset,
394                         QRhiCommandBuffer::IndexFormat indexFormat) override;
395 
396     void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
397     void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
398     void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
399     void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
400 
401     void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
402               quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
403 
404     void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
405                      quint32 instanceCount, quint32 firstIndex,
406                      qint32 vertexOffset, quint32 firstInstance) override;
407 
408     void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
409     void debugMarkEnd(QRhiCommandBuffer *cb) override;
410     void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
411 
412     void beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
413     void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
414     void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
415     void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
416 
417     const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
418     void beginExternal(QRhiCommandBuffer *cb) override;
419     void endExternal(QRhiCommandBuffer *cb) override;
420 
421     QVector<int> supportedSampleCounts() const override;
422     int ubufAlignment() const override;
423     bool isYUpInFramebuffer() const override;
424     bool isYUpInNDC() const override;
425     bool isClipDepthZeroToOne() const override;
426     QMatrix4x4 clipSpaceCorrMatrix() const override;
427     bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
428     bool isFeatureSupported(QRhi::Feature feature) const override;
429     int resourceLimit(QRhi::ResourceLimit limit) const override;
430     const QRhiNativeHandles *nativeHandles() override;
431     void sendVMemStatsToProfiler() override;
432     bool makeThreadLocalNativeContextCurrent() override;
433     void releaseCachedResources() override;
434     bool isDeviceLost() const override;
435 
436     void executeDeferredReleases(bool forced = false);
437     void finishActiveReadbacks(bool forced = false);
438     qsizetype subresUploadByteSize(const QRhiTextureSubresourceUploadDescription &subresDesc) const;
439     void enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEncPtr,
440                              int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc,
441                              qsizetype *curOfs);
442     void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
443     void executeBufferHostWritesForSlot(QMetalBuffer *bufD, int slot);
444     void executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD);
445     static const int SUPPORTED_STAGES = 3;
446     void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD,
447                                        QMetalCommandBuffer *cbD,
448                                        int dynamicOffsetCount,
449                                        const QRhiCommandBuffer::DynamicOffset *dynamicOffsets,
450                                        bool offsetOnlyChange,
451                                        const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[SUPPORTED_STAGES]);
452     int effectiveSampleCount(int sampleCount) const;
453 
454     bool importedDevice = false;
455     bool importedCmdQueue = false;
456     QMetalSwapChain *currentSwapChain = nullptr;
457     QSet<QMetalSwapChain *> swapchains;
458     QRhiMetalNativeHandles nativeHandlesStruct;
459 
460     struct {
461         int maxTextureSize = 4096;
462     } caps;
463 
464     QRhiMetalData *d = nullptr;
465 };
466 
467 QT_END_NAMESPACE
468 
469 #endif
470