From 74bd7a7019451fac10fe0e3db5e278e22ea8aaa3 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 26 Jun 2023 12:51:05 +0200 Subject: [PATCH] rhi: metal: Add support for multiview rendering Some shortcomings and unexpected problems are not unlikely. The basic feature, with 2 views going to a texture array's 0 and 1 elements, seems to be working with macOS, also with MSAA. Instanced drawing has not been verified. (relevant because layered rendering works via instancing in Metal and the QRhi backend has to adjust the instance count in every draw call) Fixes: QTBUG-114774 Change-Id: I3655e0d2c658b88c4cd6b52a32f94134324e4ac9 Reviewed-by: Andy Nichols --- src/gui/rhi/qrhi.cpp | 18 ++- src/gui/rhi/qrhimetal.mm | 119 ++++++++++++++---- src/gui/rhi/qrhimetal_p.h | 2 + tests/manual/rhi/multiview/buildshaders.bat | 8 +- tests/manual/rhi/multiview/multiview.frag.qsb | Bin 2239 -> 2426 bytes tests/manual/rhi/multiview/multiview.vert.qsb | Bin 3234 -> 4199 bytes tests/manual/rhi/multiview/texture.frag.qsb | Bin 3312 -> 4340 bytes tests/manual/rhi/multiview/texture.vert.qsb | Bin 3403 -> 4230 bytes 8 files changed, 114 insertions(+), 33 deletions(-) diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index f7785b7196..78b324c8e6 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -986,7 +986,9 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general") the left and right eyes). Rather, the target of a multiview render pass is always a texture array, automatically rendering to the layer (array element) corresponding to each view. Therefore this feature implies \l TextureArrays - as well. This enum value has been introduced in Qt 6.7. + as well. Multiview rendering is not supported in combination with + tessellation or geometry shaders. See QRhiColorAttachment::setMultiViewCount() + for further details on multiview rendering. This enum value has been introduced in Qt 6.7. */ /*! @@ -2390,17 +2392,18 @@ QRhiColorAttachment::QRhiColorAttachment(QRhiRenderBuffer *renderBuffer) \l{QRhi::isFeatureSupported()}{isFeatureSupported()}. \note For portability, be aware of limitations that exist for multiview - rendering with some of the graphics APIs. For example, OpenGL disallows - tessellation or geometry shaders with multiview. With other APIs, e.g. - Vulkan, some of these are optional features, the actual support depending - on the implementation. It is therefore recommended that multiview render - passes do not rely on any of the features that + rendering with some of the graphics APIs. It is recommended that multiview + render passes do not rely on any of the features that \l{https://registry.khronos.org/OpenGL/extensions/OVR/OVR_multiview.txt}{GL_OVR_multiview} declares as unsupported. The one exception is shader stage outputs other than \c{gl_Position} depending on \c{gl_ViewIndex}: that can be relied on (even with OpenGL) because QRhi never reports multiview as supported without \c{GL_OVR_multiview2} also being present. + \note Multiview rendering is not supported in combination with tessellation + or geometry shaders, even though some implementations of some graphics APIs + may allow this. + \since 6.7 */ @@ -6816,6 +6819,9 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const is reported as supported. The render target must be a 2D texture array, and the color attachment for the render target must have the same \a count set. + See QRhiColorAttachment::setMultiViewCount() for further details on + multiview rendering. + \since 6.7 \sa QRhi::MultiView, QRhiColorAttachment::setMultiViewCount() */ diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index e47ee9118a..1d0e84f871 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -377,6 +377,15 @@ struct QMetalGraphicsPipelineData float slopeScaledDepthBias; QMetalShader vs; QMetalShader fs; + struct ExtraBufferManager { + enum class WorkBufType { + DeviceLocal, + HostVisible + }; + QMetalBuffer *acquireWorkBuffer(QRhiMetal *rhiD, quint32 size, WorkBufType type = WorkBufType::DeviceLocal); + QVector deviceLocalWorkBuffers; + QVector hostVisibleWorkBuffers; + } extraBufMgr; struct Tessellation { QMetalGraphicsPipelineData *q = nullptr; bool enabled = false; @@ -410,13 +419,6 @@ struct QMetalGraphicsPipelineData id vsCompPipeline(QRhiMetal *rhiD, QShader::Variant vertexCompVariant); id tescCompPipeline(QRhiMetal *rhiD); id teseFragRenderPipeline(QRhiMetal *rhiD, QMetalGraphicsPipeline *pipeline); - enum class WorkBufType { - DeviceLocal, - HostVisible - }; - QMetalBuffer *acquireWorkBuffer(QRhiMetal *rhiD, quint32 size, WorkBufType type = WorkBufType::DeviceLocal); - QVector deviceLocalWorkBuffers; - QVector hostVisibleWorkBuffers; } tess; void setupVertexInputDescriptor(MTLVertexDescriptor *desc); void setupStageInputDescriptor(MTLStageInputOutputDescriptor *desc); @@ -580,6 +582,7 @@ bool QRhiMetal::create(QRhi::Flags flags) if (@available(macOS 10.15, *)) caps.isAppleGPU = [d->dev supportsFamily:MTLGPUFamilyApple7]; caps.maxThreadGroupSize = 1024; + caps.multiView = true; #elif defined(Q_OS_TVOS) if ([d->dev supportsFeatureSet: MTLFeatureSet(30003)]) // MTLFeatureSet_tvOS_GPUFamily2_v1 caps.maxTextureSize = 16384; @@ -606,8 +609,10 @@ bool QRhiMetal::create(QRhi::Flags flags) } caps.isAppleGPU = true; if (@available(iOS 13, *)) { - if ([d->dev supportsFamily:MTLGPUFamilyApple4]) + if ([d->dev supportsFamily: MTLGPUFamilyApple4]) caps.maxThreadGroupSize = 1024; + if ([d->dev supportsFamily: MTLGPUFamilyApple5]) + caps.multiView = true; } #endif @@ -834,7 +839,7 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const case QRhi::ThreeDimensionalTextureMipmaps: return true; case QRhi::MultiView: - return false; + return caps.multiView; default: Q_UNREACHABLE(); return false; @@ -1471,11 +1476,11 @@ void QRhiMetal::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline psD->makeActiveForCurrentRenderPassEncoder(cbD); } else { // mark work buffers that can now be safely reused as reusable - for (QMetalBuffer *workBuf : psD->d->tess.deviceLocalWorkBuffers) { + for (QMetalBuffer *workBuf : psD->d->extraBufMgr.deviceLocalWorkBuffers) { if (workBuf && workBuf->lastActiveFrameSlot == currentFrameSlot) workBuf->lastActiveFrameSlot = -1; } - for (QMetalBuffer *workBuf : psD->d->tess.hostVisibleWorkBuffers) { + for (QMetalBuffer *workBuf : psD->d->extraBufMgr.hostVisibleWorkBuffers) { if (workBuf && workBuf->lastActiveFrameSlot == currentFrameSlot) workBuf->lastActiveFrameSlot = -1; } @@ -1967,6 +1972,7 @@ void QRhiMetal::tessellatedDraw(const TessDrawArgs &args) const quint32 vertexOrIndexCount = indexed ? args.drawIndexed.indexCount : args.draw.vertexCount; QMetalGraphicsPipelineData::Tessellation &tess(graphicsPipeline->d->tess); + QMetalGraphicsPipelineData::ExtraBufferManager &extraBufMgr(graphicsPipeline->d->extraBufMgr); const quint32 patchCount = tess.patchCountForDrawCall(vertexOrIndexCount, instanceCount); QMetalBuffer *vertOutBuf = nullptr; QMetalBuffer *tescOutBuf = nullptr; @@ -2000,7 +2006,7 @@ void QRhiMetal::tessellatedDraw(const TessDrawArgs &args) if (outputBufferBinding >= 0) { const quint32 workBufSize = tess.vsCompOutputBufferSize(vertexOrIndexCount, instanceCount); - vertOutBuf = tess.acquireWorkBuffer(this, workBufSize); + vertOutBuf = extraBufMgr.acquireWorkBuffer(this, workBufSize); if (!vertOutBuf) return; [computeEncoder setBuffer: vertOutBuf->d->buf[0] offset: 0 atIndex: outputBufferBinding]; @@ -2048,7 +2054,7 @@ void QRhiMetal::tessellatedDraw(const TessDrawArgs &args) if (outputBufferBinding >= 0) { const quint32 workBufSize = tess.tescCompOutputBufferSize(patchCount); - tescOutBuf = tess.acquireWorkBuffer(this, workBufSize); + tescOutBuf = extraBufMgr.acquireWorkBuffer(this, workBufSize); if (!tescOutBuf) return; [computeEncoder setBuffer: tescOutBuf->d->buf[0] offset: 0 atIndex: outputBufferBinding]; @@ -2056,14 +2062,14 @@ void QRhiMetal::tessellatedDraw(const TessDrawArgs &args) if (patchOutputBufferBinding >= 0) { const quint32 workBufSize = tess.tescCompPatchOutputBufferSize(patchCount); - tescPatchOutBuf = tess.acquireWorkBuffer(this, workBufSize); + tescPatchOutBuf = extraBufMgr.acquireWorkBuffer(this, workBufSize); if (!tescPatchOutBuf) return; [computeEncoder setBuffer: tescPatchOutBuf->d->buf[0] offset: 0 atIndex: patchOutputBufferBinding]; } if (tessFactorBufferBinding >= 0) { - tescFactorBuf = tess.acquireWorkBuffer(this, patchCount * sizeof(MTLQuadTessellationFactorsHalf)); + tescFactorBuf = extraBufMgr.acquireWorkBuffer(this, patchCount * sizeof(MTLQuadTessellationFactorsHalf)); [computeEncoder setBuffer: tescFactorBuf->d->buf[0] offset: 0 atIndex: tessFactorBufferBinding]; } @@ -2072,7 +2078,7 @@ void QRhiMetal::tessellatedDraw(const TessDrawArgs &args) quint32 inControlPointCount; quint32 patchCount; } params; - tescParamsBuf = tess.acquireWorkBuffer(this, sizeof(params), QMetalGraphicsPipelineData::Tessellation::WorkBufType::HostVisible); + tescParamsBuf = extraBufMgr.acquireWorkBuffer(this, sizeof(params), QMetalGraphicsPipelineData::ExtraBufferManager::WorkBufType::HostVisible); if (!tescParamsBuf) return; params.inControlPointCount = tess.inControlPointCount; @@ -2141,6 +2147,39 @@ void QRhiMetal::tessellatedDraw(const TessDrawArgs &args) } } +void QRhiMetal::adjustForMultiViewDraw(quint32 *instanceCount, QRhiCommandBuffer *cb) +{ + QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb); + const int multiViewCount = cbD->currentGraphicsPipeline->m_multiViewCount; + if (multiViewCount <= 1) + return; + + const QMap &ebb(cbD->currentGraphicsPipeline->d->vs.nativeShaderInfo.extraBufferBindings); + const int viewMaskBufBinding = ebb.value(QShaderPrivate::MslMultiViewMaskBufferBinding, -1); + if (viewMaskBufBinding == -1) { + qWarning("No extra buffer for multiview in the vertex shader; was it built with --view-count specified?"); + return; + } + struct { + quint32 viewOffset; + quint32 viewCount; + } multiViewInfo; + multiViewInfo.viewOffset = 0; + multiViewInfo.viewCount = quint32(multiViewCount); + QMetalBuffer *buf = cbD->currentGraphicsPipeline->d->extraBufMgr.acquireWorkBuffer(this, sizeof(multiViewInfo), + QMetalGraphicsPipelineData::ExtraBufferManager::WorkBufType::HostVisible); + if (buf) { + id mtlbuf = buf->d->buf[0]; + char *p = reinterpret_cast([mtlbuf contents]); + memcpy(p, &multiViewInfo, sizeof(multiViewInfo)); + [cbD->d->currentRenderPassEncoder setVertexBuffer: mtlbuf offset: 0 atIndex: viewMaskBufBinding]; + // The instance count is adjusted for layered rendering. The vertex shader is expected to contain something like: + // uint gl_ViewIndex = spvViewMask[0] + (gl_InstanceIndex - gl_BaseInstance) % spvViewMask[1]; + // where spvViewMask is the buffer with multiViewInfo passed in above. + *instanceCount *= multiViewCount; + } +} + void QRhiMetal::draw(QRhiCommandBuffer *cb, quint32 vertexCount, quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) { @@ -2159,6 +2198,8 @@ void QRhiMetal::draw(QRhiCommandBuffer *cb, quint32 vertexCount, return; } + adjustForMultiViewDraw(&instanceCount, cb); + if (caps.baseVertexAndInstance) { [cbD->d->currentRenderPassEncoder drawPrimitives: cbD->currentGraphicsPipeline->d->primitiveType vertexStart: firstVertex vertexCount: vertexCount instanceCount: instanceCount baseInstance: firstInstance]; @@ -2197,6 +2238,8 @@ void QRhiMetal::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount, return; } + adjustForMultiViewDraw(&instanceCount, cb); + if (caps.baseVertexAndInstance) { [cbD->d->currentRenderPassEncoder drawIndexedPrimitives: cbD->currentGraphicsPipeline->d->primitiveType indexCount: indexCount @@ -2904,10 +2947,13 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb, for (auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments(); it != itEnd; ++it) { - if (it->texture()) + if (it->texture()) { QRHI_RES(QMetalTexture, it->texture())->lastActiveFrameSlot = currentFrameSlot; - else if (it->renderBuffer()) + if (it->multiViewCount() >= 2) + cbD->d->currentPassRpDesc.renderTargetArrayLength = NSUInteger(it->multiViewCount()); + } else if (it->renderBuffer()) { QRHI_RES(QMetalRenderBuffer, it->renderBuffer())->lastActiveFrameSlot = currentFrameSlot; + } if (it->resolveTexture()) QRHI_RES(QMetalTexture, it->resolveTexture())->lastActiveFrameSlot = currentFrameSlot; } @@ -4295,10 +4341,10 @@ void QMetalGraphicsPipeline::destroy() d->tess.compTesc.destroy(); d->tess.vertTese.destroy(); - qDeleteAll(d->tess.deviceLocalWorkBuffers); - d->tess.deviceLocalWorkBuffers.clear(); - qDeleteAll(d->tess.hostVisibleWorkBuffers); - d->tess.hostVisibleWorkBuffers.clear(); + qDeleteAll(d->extraBufMgr.deviceLocalWorkBuffers); + d->extraBufMgr.deviceLocalWorkBuffers.clear(); + qDeleteAll(d->extraBufMgr.hostVisibleWorkBuffers); + d->extraBufMgr.hostVisibleWorkBuffers.clear(); delete d->bufferSizeBuffer; d->bufferSizeBuffer = nullptr; @@ -4525,6 +4571,24 @@ static inline MTLPrimitiveType toMetalPrimitiveType(QRhiGraphicsPipeline::Topolo } } +static inline MTLPrimitiveTopologyClass toMetalPrimitiveTopologyClass(QRhiGraphicsPipeline::Topology t) +{ + switch (t) { + case QRhiGraphicsPipeline::Triangles: + case QRhiGraphicsPipeline::TriangleStrip: + case QRhiGraphicsPipeline::TriangleFan: + return MTLPrimitiveTopologyClassTriangle; + case QRhiGraphicsPipeline::Lines: + case QRhiGraphicsPipeline::LineStrip: + return MTLPrimitiveTopologyClassLine; + case QRhiGraphicsPipeline::Points: + return MTLPrimitiveTopologyClassPoint; + default: + Q_UNREACHABLE(); + return MTLPrimitiveTopologyClassTriangle; + } +} + static inline MTLCullMode toMetalCullMode(QRhiGraphicsPipeline::CullMode c) { switch (c) { @@ -4765,6 +4829,7 @@ void QMetalGraphicsPipelineData::setupVertexInputDescriptor(MTLVertexDescriptor desc.attributes[loc].bufferIndex = NSUInteger(firstVertexBinding + it->binding()); } int bindingIndex = 0; + const NSUInteger viewCount = qMax(1, q->multiViewCount()); for (auto it = vertexInputLayout.cbeginBindings(), itEnd = vertexInputLayout.cendBindings(); it != itEnd; ++it, ++bindingIndex) { @@ -4773,6 +4838,8 @@ void QMetalGraphicsPipelineData::setupVertexInputDescriptor(MTLVertexDescriptor it->classification() == QRhiVertexInputBinding::PerInstance ? MTLVertexStepFunctionPerInstance : MTLVertexStepFunctionPerVertex; desc.layouts[layoutIdx].stepRate = NSUInteger(it->instanceStepRate()); + if (desc.layouts[layoutIdx].stepFunction == MTLVertexStepFunctionPerInstance) + desc.layouts[layoutIdx].stepRate *= viewCount; desc.layouts[layoutIdx].stride = it->stride(); } } @@ -4949,6 +5016,9 @@ bool QMetalGraphicsPipeline::createVertexFragmentPipeline() QMetalRenderPassDescriptor *rpD = QRHI_RES(QMetalRenderPassDescriptor, m_renderPassDesc); setupAttachmentsInMetalRenderPassDescriptor(rpDesc, rpD); + if (m_multiViewCount >= 2) + rpDesc.inputPrimitiveTopology = toMetalPrimitiveTopologyClass(m_topology); + rhiD->d->trySeedingRenderPipelineFromBinaryArchive(rpDesc); if (rhiD->rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave)) @@ -5471,7 +5541,7 @@ id QMetalGraphicsPipelineData::Tessellation::teseFragRen return ps; } -QMetalBuffer *QMetalGraphicsPipelineData::Tessellation::acquireWorkBuffer(QRhiMetal *rhiD, quint32 size, WorkBufType type) +QMetalBuffer *QMetalGraphicsPipelineData::ExtraBufferManager::acquireWorkBuffer(QRhiMetal *rhiD, quint32 size, WorkBufType type) { QVector *workBuffers = type == WorkBufType::DeviceLocal ? &deviceLocalWorkBuffers : &hostVisibleWorkBuffers; @@ -5537,6 +5607,9 @@ bool QMetalGraphicsPipeline::createTessellationPipelines(const QShader &tessVert return false; } + if (m_multiViewCount >= 2) + qWarning("Multiview is not supported with tessellation"); + // Now the vertex shader is a compute shader. // It should have three dedicated *VertexAsComputeShader variants. // What the requested variant was (Standard or Batchable) plays no role here. diff --git a/src/gui/rhi/qrhimetal_p.h b/src/gui/rhi/qrhimetal_p.h index 8fb2ce84b0..15f869c3d8 100644 --- a/src/gui/rhi/qrhimetal_p.h +++ b/src/gui/rhi/qrhimetal_p.h @@ -482,6 +482,7 @@ public: }; }; void tessellatedDraw(const TessDrawArgs &args); + void adjustForMultiViewDraw(quint32 *instanceCount, QRhiCommandBuffer *cb); QRhi::Flags rhiFlags; bool importedDevice = false; @@ -499,6 +500,7 @@ public: QVector supportedSampleCounts; bool isAppleGPU = false; int maxThreadGroupSize = 512; + bool multiView = false; } caps; QRhiMetalData *d = nullptr; diff --git a/tests/manual/rhi/multiview/buildshaders.bat b/tests/manual/rhi/multiview/buildshaders.bat index 0499bf032c..c53119bd42 100644 --- a/tests/manual/rhi/multiview/buildshaders.bat +++ b/tests/manual/rhi/multiview/buildshaders.bat @@ -1,4 +1,4 @@ -qsb --view-count 2 --glsl "300 es,330" --hlsl 61 -c multiview.vert -o multiview.vert.qsb -qsb --glsl "300 es,330" --hlsl 61 -c multiview.frag -o multiview.frag.qsb -qsb --glsl "300 es,330" --hlsl 61 -c texture.vert -o texture.vert.qsb -qsb --glsl "300 es,330" --hlsl 61 -c texture.frag -o texture.frag.qsb +qsb --view-count 2 --glsl "300 es,330" --hlsl 61 -c --msl 12 multiview.vert -o multiview.vert.qsb +qsb --glsl "300 es,330" --hlsl 61 -c --msl 12 multiview.frag -o multiview.frag.qsb +qsb --glsl "300 es,330" --hlsl 61 -c --msl 12 texture.vert -o texture.vert.qsb +qsb --glsl "300 es,330" --hlsl 61 -c --msl 12 texture.frag -o texture.frag.qsb diff --git a/tests/manual/rhi/multiview/multiview.frag.qsb b/tests/manual/rhi/multiview/multiview.frag.qsb index ca177058f2918a914a6165e6952d8848fa4bf597..dcaf6c6dff85814bf908677eee703a06a0648c4f 100644 GIT binary patch literal 2426 zcmV-=35E6m01<9@ob6YAP*YbHzsY;#y?hWJ5H%QN9w0PWi%-yq1uRJrLBbjY6;~M( zLV)Z*2uVo!sBH*=ATnJPtq4;Kimlt-omJPFmX5ncab0xOfz?{@qodX0)ahDgcf0HE zbU*HWd4a5U+nw(2?EbNLIQQds&pG$pbMO7}0ss&K0B|TgC{o}8JAet)f@&ysh+t5_ zU%3Llq9C&fPyv;Vpb}_cAc(B zm+WwsC$Ct^pn0i(o9tW|AlS%})EF&RgrgKmpioc`;RNyldkBx=)<9!P&^QvV$%kz$ zv_alce?II9U`s<;0QHd{0k;+nYZCYqj_`DDEaWhxFXHquPG8K$EaLRVT$~7d7LEn% z-cWJBpn~b*b87+4$76_~BxZ8HLpl3Ghzi(T_%RTKQ5?n#!ooQW`PakfQT!2{J;lwV zIM%>bh1}eqp@%fq3&6QN!vSw8=NgqC$GgmSho#m^r!ov}c8F|tv&q5&RhG&s8(mRd zYjmbR1zW5T6jd7=YwMlL>ROZ0iRLnCCW(d!?J}EI&=q!LrM9-Z)}Ai1SP_&;yLOoT zfXG#ADW_3T$|O;k!Tp2WvaV=Ephs|L3ydFh9YHpQar41k zRaC4l-VT#$g#9gWGP@*ChZaJ@f(XdU4%N5e)ZFo=I zkQY|>yo24c2wi8F*gK@7vf@DkkX3+ba>Vc|NIFk@WtunTZfc`ou*Ge}%ih)X#jWps zNj2}oKRk$AxA*0JeKFtDoLQJ7Zyy~>I_$krSyZ?4m1O(kPZ#w2`t;)`-Ee)GeZ=Q9 z_*7NC#wrZ~(F+LC7xRjV)SyZ^L zyGxk3?mVuIOJMkVNytV)n_ikwDF398DqdfP50DoJvP3PD5-=PEnoRSsa1yy`gt>RY zb|I$g&f!O9uauj_j&$tAvpxO!%?|8f-7rr*C{FKh-m|1^iKuVMpZbPd8kgrg#HRcy z3XjCgCTYni-a@O$wQ8Q#>dBHR+OeoaQnFG_OA==pArk+%m!`=5Nk3fnHZ%Owl;?Ye z{5?8~G-Dp7;BJQgl)7X{=qW0oI@)}Oz6#c&r{voPDd2UQHh@yNb6MRODqvb%{ttx2l-d6#163*Sv~0ykf=lude)ja;)mo(bsogo~U6Sjz}L3oWb4_Df&zM z^A~PCsJOk4KBj4ZP_`v;)q&qns}kgW-FJs4+fGdFzfd6Te7?LP*->RIH`@zp%gxnA z{Go`bL*mky?OVJ1Zz@XVr8oL--jc=s_8~Gly8m{A=6Z(CsXw$r-T^cvh*g!aX z>m<`4?AMg^cW!B_L=$uN%%UrU(G^SxtJbQxgk_FtGrO?NOATF48_`S>jk!LXjcBrA zt_Git_C;L^mwwhQy~~7InXr2^(iy!pl{&ZRquA)l*hOcJF%`_N^wX{B?(u~YyAeyU)RaHJatld6ax6fuETuQ?AI0U+V(e2wo`s(C9d#|stw`J+08R?@t z(l17&pD|e3*kJVi!RSkDeajeqF*f>K%c6@$!S!zK>M`x=UbcRBG;Ntx2Y z`wQNw;eTNJZyTM-mR>9iDHM@Jh|L{xKHpI7+ zxSxMjPw?*uKF7b${j>Z_`T5s7%fFhZ_%}S5e`CKL|FXOiN3#4IiTF1%z`q@kf4w@2 zLHyepCi)N3co&nwMRCA z59TJ4Z6{-^63JhrsFjdFjXJ8s)S9(P@!I*uf!u{}3Qnr<1w8?ZeNU*FfYev%$)Xi_ z=gs3QrjD!~KfY4`PV9_IGD%b`=L;lY;MXFJquzF9xKCSGMTteTiS)UGmEnv79=6 seR)9vr`}Poi`3GAHx>AS6!`26`jNzzCqC)f!uuNht9*dJ0ab&9PDHlU00000 literal 2239 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 literal 3234 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 U#Nhc0jlTRp592KV1|O9V>0L%ywEzGB diff --git a/tests/manual/rhi/multiview/texture.frag.qsb b/tests/manual/rhi/multiview/texture.frag.qsb index 1a6be88df7d43289239b7736fc2f4090003a610a..091e9b1cd79b27f174491ec3e34b8b483efaeed6 100644 GIT binary patch literal 4340 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 literal 3312 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 diff --git a/tests/manual/rhi/multiview/texture.vert.qsb b/tests/manual/rhi/multiview/texture.vert.qsb index 78fc8b107298df19d1f8663512f18059ee4f3e19..114fdddb18ae9514f4b9f366ec912fdb9821c035 100644 GIT binary patch literal 4230 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