From fe3a1617afd71e5ea2fced740a69b3d27958e2d7 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 22 Sep 2020 11:01:24 +0200 Subject: [PATCH] rhi: d3d: Fix dynamic offsets with multiple buffers Fixes: QTBUG-86821 Change-Id: I57f86bf0f7e95b92f5b2c5fee587112ecf0fc8e6 Reviewed-by: Andy Nichols --- src/gui/rhi/qrhid3d11.cpp | 47 +++-- src/gui/rhi/qrhid3d11_p_p.h | 3 + src/gui/rhi/qrhigles2_p_p.h | 2 +- tests/auto/gui/rhi/qrhi/data/buildshaders.bat | 2 + tests/auto/gui/rhi/qrhi/data/simple.frag.qsb | Bin 740 -> 719 bytes tests/auto/gui/rhi/qrhi/data/simple.vert.qsb | Bin 786 -> 747 bytes .../gui/rhi/qrhi/data/simpletextured.frag.qsb | Bin 1206 -> 1177 bytes .../gui/rhi/qrhi/data/simpletextured.vert.qsb | Bin 983 -> 918 bytes .../qrhi/data/simpletextured_array.frag.qsb | Bin 1693 -> 1646 bytes .../auto/gui/rhi/qrhi/data/textured.frag.qsb | Bin 1590 -> 1503 bytes .../auto/gui/rhi/qrhi/data/textured.vert.qsb | Bin 1368 -> 1277 bytes .../gui/rhi/qrhi/data/textured_multiubuf.frag | 18 ++ .../rhi/qrhi/data/textured_multiubuf.frag.qsb | Bin 0 -> 1422 bytes .../gui/rhi/qrhi/data/textured_multiubuf.vert | 18 ++ .../rhi/qrhi/data/textured_multiubuf.vert.qsb | Bin 0 -> 1223 bytes tests/auto/gui/rhi/qrhi/tst_qrhi.cpp | 171 ++++++++++++++++++ 16 files changed, 246 insertions(+), 15 deletions(-) create mode 100644 tests/auto/gui/rhi/qrhi/data/textured_multiubuf.frag create mode 100644 tests/auto/gui/rhi/qrhi/data/textured_multiubuf.frag.qsb create mode 100644 tests/auto/gui/rhi/qrhi/data/textured_multiubuf.vert create mode 100644 tests/auto/gui/rhi/qrhi/data/textured_multiubuf.vert.qsb diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index b9829ed263..f3ddc7aac4 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -1903,14 +1903,17 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]) { srbD->vsubufs.clear(); + srbD->vsubuforigbindings.clear(); srbD->vsubufoffsets.clear(); srbD->vsubufsizes.clear(); srbD->fsubufs.clear(); + srbD->fsubuforigbindings.clear(); srbD->fsubufoffsets.clear(); srbD->fsubufsizes.clear(); srbD->csubufs.clear(); + srbD->csubuforigbindings.clear(); srbD->csubufoffsets.clear(); srbD->csubufsizes.clear(); @@ -1927,6 +1930,7 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, struct Stage { struct Buffer { + int binding; // stored and sent along in XXorigbindings just for applyDynamicOffsets() int breg; // b0, b1, ... ID3D11Buffer *buffer; uint offsetInConstants; @@ -1960,9 +1964,12 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, Q_ASSERT(aligned(b->u.ubuf.offset, 256) == b->u.ubuf.offset); bd.ubuf.id = bufD->m_id; bd.ubuf.generation = bufD->generation; - // dynamic ubuf offsets are not considered here, those are baked in + // Dynamic ubuf offsets are not considered here, those are baked in // at a later stage, which is good as vsubufoffsets and friends are - // per-srb, not per-setShaderResources call + // per-srb, not per-setShaderResources call. Other backends (GL, + // Metal) are different in this respect since those do not store + // per-srb vsubufoffsets etc. data so life's a bit easier for them. + // But here we have to defer baking in the dynamic offset. const uint offsetInConstants = uint(b->u.ubuf.offset) / 16; // size must be 16 mult. (in constants, i.e. multiple of 256 bytes). // We can round up if needed since the buffers's actual size @@ -1971,17 +1978,17 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { QPair nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps); if (nativeBinding.first >= 0) - res[RBM_VERTEX].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); + res[RBM_VERTEX].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { QPair nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps); if (nativeBinding.first >= 0) - res[RBM_FRAGMENT].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); + res[RBM_FRAGMENT].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { QPair nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); if (nativeBinding.first >= 0) - res[RBM_COMPUTE].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); + res[RBM_COMPUTE].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); } } break; @@ -2088,28 +2095,34 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, for (const Stage::Buffer &buf : qAsConst(res[RBM_VERTEX].buffers)) { srbD->vsubufs.feed(buf.breg, buf.buffer); + srbD->vsubuforigbindings.feed(buf.breg, UINT(buf.binding)); srbD->vsubufoffsets.feed(buf.breg, buf.offsetInConstants); srbD->vsubufsizes.feed(buf.breg, buf.sizeInConstants); } srbD->vsubufs.finish(); + srbD->vsubuforigbindings.finish(); srbD->vsubufoffsets.finish(); srbD->vsubufsizes.finish(); for (const Stage::Buffer &buf : qAsConst(res[RBM_FRAGMENT].buffers)) { srbD->fsubufs.feed(buf.breg, buf.buffer); + srbD->fsubuforigbindings.feed(buf.breg, UINT(buf.binding)); srbD->fsubufoffsets.feed(buf.breg, buf.offsetInConstants); srbD->fsubufsizes.feed(buf.breg, buf.sizeInConstants); } srbD->fsubufs.finish(); + srbD->fsubuforigbindings.finish(); srbD->fsubufoffsets.finish(); srbD->fsubufsizes.finish(); for (const Stage::Buffer &buf : qAsConst(res[RBM_COMPUTE].buffers)) { srbD->csubufs.feed(buf.breg, buf.buffer); + srbD->csubuforigbindings.feed(buf.breg, UINT(buf.binding)); srbD->csubufoffsets.feed(buf.breg, buf.offsetInConstants); srbD->csubufsizes.feed(buf.breg, buf.sizeInConstants); } srbD->csubufs.finish(); + srbD->csubuforigbindings.finish(); srbD->csubufoffsets.finish(); srbD->csubufsizes.finish(); @@ -2158,17 +2171,20 @@ void QRhiD3D11::executeBufferHostWrites(QD3D11Buffer *bufD) static void applyDynamicOffsets(QVarLengthArray *offsets, int batchIndex, - QRhiBatchedBindings *ubufs, - QRhiBatchedBindings *ubufoffsets, + QRhiBatchedBindings *originalBindings, + QRhiBatchedBindings *staticOffsets, const uint *dynOfsPairs, int dynOfsPairCount) { - const int count = ubufs->batches[batchIndex].resources.count(); - const UINT startBinding = ubufs->batches[batchIndex].startBinding; - *offsets = ubufoffsets->batches[batchIndex].resources; + const int count = staticOffsets->batches[batchIndex].resources.count(); + // Make a copy of the offset list, the entries that have no corresponding + // dynamic offset will continue to use the existing offset value. + *offsets = staticOffsets->batches[batchIndex].resources; for (int b = 0; b < count; ++b) { for (int di = 0; di < dynOfsPairCount; ++di) { const uint binding = dynOfsPairs[2 * di]; - if (binding == startBinding + UINT(b)) { + // binding is the SPIR-V style binding point here, nothing to do + // with the native one. + if (binding == originalBindings->batches[batchIndex].resources[b]) { const uint offsetInConstants = dynOfsPairs[2 * di + 1]; (*offsets)[b] = offsetInConstants; break; @@ -2258,7 +2274,8 @@ void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD, srbD->vsubufsizes.batches[i].resources.constData()); } else { QVarLengthArray offsets; - applyDynamicOffsets(&offsets, i, &srbD->vsubufs, &srbD->vsubufoffsets, dynOfsPairs, dynOfsPairCount); + applyDynamicOffsets(&offsets, i, &srbD->vsubuforigbindings, &srbD->vsubufoffsets, + dynOfsPairs, dynOfsPairCount); context->VSSetConstantBuffers1(srbD->vsubufs.batches[i].startBinding, count, srbD->vsubufs.batches[i].resources.constData(), @@ -2282,7 +2299,8 @@ void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD, srbD->fsubufsizes.batches[i].resources.constData()); } else { QVarLengthArray offsets; - applyDynamicOffsets(&offsets, i, &srbD->fsubufs, &srbD->fsubufoffsets, dynOfsPairs, dynOfsPairCount); + applyDynamicOffsets(&offsets, i, &srbD->fsubuforigbindings, &srbD->fsubufoffsets, + dynOfsPairs, dynOfsPairCount); context->PSSetConstantBuffers1(srbD->fsubufs.batches[i].startBinding, count, srbD->fsubufs.batches[i].resources.constData(), @@ -2306,7 +2324,8 @@ void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD, srbD->csubufsizes.batches[i].resources.constData()); } else { QVarLengthArray offsets; - applyDynamicOffsets(&offsets, i, &srbD->csubufs, &srbD->csubufoffsets, dynOfsPairs, dynOfsPairCount); + applyDynamicOffsets(&offsets, i, &srbD->csubuforigbindings, &srbD->csubufoffsets, + dynOfsPairs, dynOfsPairCount); context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding, count, srbD->csubufs.batches[i].resources.constData(), diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index c6890ca353..a4d5098084 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -238,14 +238,17 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings QVarLengthArray boundResourceData; QRhiBatchedBindings vsubufs; + QRhiBatchedBindings vsubuforigbindings; QRhiBatchedBindings vsubufoffsets; QRhiBatchedBindings vsubufsizes; QRhiBatchedBindings fsubufs; + QRhiBatchedBindings fsubuforigbindings; QRhiBatchedBindings fsubufoffsets; QRhiBatchedBindings fsubufsizes; QRhiBatchedBindings csubufs; + QRhiBatchedBindings csubuforigbindings; QRhiBatchedBindings csubufoffsets; QRhiBatchedBindings csubufsizes; diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index 1f46d424a4..bee9b3249e 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -390,7 +390,7 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer QRhiComputePipeline *maybeComputePs; QRhiShaderResourceBindings *srb; int dynamicOffsetCount; - uint dynamicOffsetPairs[MAX_UBUF_BINDINGS * 2]; // binding, offsetInConstants + uint dynamicOffsetPairs[MAX_UBUF_BINDINGS * 2]; // binding, offset } bindShaderResources; struct { GLbitfield mask; diff --git a/tests/auto/gui/rhi/qrhi/data/buildshaders.bat b/tests/auto/gui/rhi/qrhi/data/buildshaders.bat index f4ebae070b..0102457b8a 100644 --- a/tests/auto/gui/rhi/qrhi/data/buildshaders.bat +++ b/tests/auto/gui/rhi/qrhi/data/buildshaders.bat @@ -44,3 +44,5 @@ qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simpletextured.frag.qsb sim qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 20 -o simpletextured_array.frag.qsb simpletextured_array.frag qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o textured.vert.qsb textured.vert qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o textured.frag.qsb textured.frag +qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o textured_multiubuf.vert.qsb textured_multiubuf.vert +qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o textured_multiubuf.frag.qsb textured_multiubuf.frag diff --git a/tests/auto/gui/rhi/qrhi/data/simple.frag.qsb b/tests/auto/gui/rhi/qrhi/data/simple.frag.qsb index 43edbdffd90541ace686be3142c07ae6f1a98719..d398c81e0ab4e1b7eee4b72ca40fbed54d17f0ea 100644 GIT binary patch literal 719 zcmV;=0xBgi z#9;&x#7oct8x-h56)Z3iZQtUT05}_*6OlDR30|c4blc&U$qKS84QyTIp48*r-hg!s zOL0pl)Z9d+v}bXR^%ZVrveLf95V}Tt)mFMS#Z_AJ4lA=gT`gt`c{#`A@q%KuB)ya* zx(&IDlW4&~BXTU7PS7Ef_?;KpixBmWJ&hM3y0+2S$UClT$Ibt zkwTn98`34nA34%p7x6D+{3y~JXhV^Rzk(cj^*S!M zt)VNL?#)P%b+GYO%dl+LYN70*Lu*$f7MLH@79Oqt$=GCd74En+6RA%zMmcIsOSU;AG( z)08ZPp3zZl`(E|Ko7RKvPoL{w`SI?T*RSU3ct?@Z|E7re9`PgMF=7VwTebRX=q-A% zOv@Dha3Ujqt5zrwy(XSU2JvQS?jCa0wj8VDvdmVNt>Z&wjh>?EHmh3w0XL8-$oT@? zZ>()5g%8n3DCa~8lOnbcF+pb$8&BFz#qR1Z93D2->)Uje$71hU5+XX9e`9l={St=q z`RE;54_1Px2P+j!*J$2tzJ<|~A6IXp29xsN;H>t40KdQfA7N%XIzX5y@_n*r9 BW9k3^ literal 740 zcmVPbf8A;FSvN?L@pshXs%SgSNa0wKoj z?j{-8?1tS<5sQ$M2ah72y-F|Q$q&%a;3w!!Po6{&eQ$R*yNyLD_?F+yyf^RPzL|N1 zkT@Y^lK3P6E|4~{i9$N0L@Z(e>_Fp}AaXjI5}w~iWRFvOy6tewWVt1oQfuI{JzdSS zwyktZmSNciO7|?Tv7W-sbcXIz1~l4btDbr~mzC$4JQ{$_6zB^|F=Mn8ku@9AbCQ+ofpaj*XIbLA^P+WqqC2@EuT0%(H;%qgG9^JGx5_4yv1#I_C0F>^)5oNeA_BY|hhP23Ns);uem> zwb1Kutq9?&wcE8fxF3lpk>fPZ|BFtm{}&3*7b$Wy(v#Rk>I_Coz;{+i&%<9}>}hz6 zIB!7pvyQ7}^Gh=BpA(hDy;;z~=Z*+sBmr}vgEDXqtC&}pPu`uGJf<6m5A{cn72|;h z%C3rhE`l}MU-LZqHNFHZY!wV}8T2vEl*og@m>~Xnqr4#aq>$YJ9(AebeYh6z(<0tH zSfSmF(3uv%^)lo;LBb}8{=S0*-$D_%q_F!5)w$`PU{L!>5?*hlA1Q9C#z52AN>6tc zqXi{4_->Jga)BUms?Izs=roRN4^-Fd0CEeOW6=MwJ4Ko# zYcy1x({iTSgoh87xYyIoh^@aGHIh({SY`WQg>vAs(f;bkI=RE3zOB0h+eEXV7Y%>F3_#dui& diff --git a/tests/auto/gui/rhi/qrhi/data/simple.vert.qsb b/tests/auto/gui/rhi/qrhi/data/simple.vert.qsb index 06af5df492716b57ba270cf613ac172971c2fdf8..c17286c38d947f9161bbc19cacab39f481bbf39f 100644 GIT binary patch literal 747 zcmVlJpM9PN=0_mb5Ax*Qi zOBro%MHZ#co-Ta9?zq z5Amz8U)J@WFPs*4td8w>t%l75t65$5rPpgn-m!#Jth+s_AL$%uukBiLinrSJP1hGv zxDMah>C(1Vo7G>Rw-wG=({5yEN$H8*p0sntys|y8J!v0Cal>6s`Qic%eQC99IMr%- zavtd;&+{Yjg*coF@nq-0K|!Sus(7~Sc@Anq2D%Pa916Tq=MG~Pe?AWB`RJ!KS=9AG z{`|mhL^s1*xS|>4lv4?wO(IeaBc@On)+F#`tewY|?I(+0-`zPiAN=?{_vzJf|Lw## z%<5PR=W7c1Bk&jC3}BnU)ymRx^W3b=;n&cwQ@j%HtCdm-*W17xI0rlto26%>;kmxM zCwZ=#=c{Yx8aMZ?rtR@Xx6>7E*p!Ne5_@W{tly_fWyqJJB(2#jV_QqxiyIr&3hVd# z8-K9T;x@qMi$Telxw^Fd7_d#yGGKj~VOky3PYff_Z$S-DxH0fE1GiP@<*{%rgUH-k z*m@89L@dwvUfExSE~@_*QgeV5YoYcgnHW!Fqzrtn5jqN)W9(sg32FA&P~|id&Gfn zfj&l4@6#ChN(b^3yUfBqBQ{HCov<5l9wtAS_dPnRxkURBlBLOhgzlk{+#p{lpMkq2 zC=W*XcR=vBGf#PD$$kM)BdBYb55_Em#VG0ggb0tqZmT|N)F(9pu?M2~Umgey^dUAd d>rudI2nes^zlx-)7W;P@RB$p5{05ta7t_~(c?|#n literal 786 zcmV+t1MU0(00(M#oV8S2PZL2Dp6$ifMWkrFJmDC4C{b%mfS3S{NV%9GkS-Du(lkqV zDWmOfvpXdu#Gjx~#%EuA>L2h&_~?tjz!#o)A|{IG%${YJCYq4wX{Iyto%5aZ&1Hu% zmS%xz&~mK9T;?;uBs7;ffThrRM#e60SE#olNIOj?Ml)D43%?tL4zq+3F#r_omsgF| zf-kMYEpTMn2aUQn(JpCsp2nn^yTdp%ZKcu#h)E{W5S6OQ>;5aYo2@6HvtOE0saaZ5ZJu zacFlSK0}+9QoJBnM)_0hs#+gY*bL2e!fwHQfb!rTJ)rqDs*U_X@@0rWNPDJ{KS#OH zKMiY3kPb%pDIj=Z=1Aud@#g`}sWS}pV9hcxhAHMJRCuDQuoRs|DkcpT%#RAE(dt?@ zpKaUHY}MiDTVl7YN4PKA)?@rD?3Z=D>kFsJ9kXrw9kXF`#hTG|UwYk!NZ7ngHb-r#RU?5 zX*O+`)oSCEJc`FQ$B!Tv;xH@3#m+&3LMR~!@od@k9E=17I_`T~WupWA5bZ8o8wGhj z<|$1Tbse-E*o|mODBl&95|a;=U92932BpGt#7Y+RXfLBmMW}SXQ~$K!VQgu!f)oFx zAYS~5*iAjIY(HE0_U_)9@#x2w*-x*JdvC|SqpD*qcupsweT4QEzf{0Bpj9i2OR*!lQ>>$Fl)bCG(|Wqlv%HS&I$|l4(b}G6+EQxR^+sFNny%rmJ_Fkhf?C(HYp&N~ ztYfs=P0Py`g>UVnwr6+;wo?~9%gl;yj}X_cik4wJ`l5DU6Sz>fEKHFj7r*OS*`khI z3e6W+1B0ugl3hU)GrfOsPh7$MQ>7z63ZSDtjZU;3sO?^g%s589S=sQ6deQKWy-b-R zt!fW6jVeyba2={)nTBCFwveC_jp4sn89j^7N=2K%GSYtYPU%j%<5$zm*D|Dk0sVsK znSz9TPNLw9vq%CdiFSl1Cpa>g z_~Az+Hi9=&XA{lAIB1a%Bf0|lWsEn0yT<;Lj1#uX@)^eHyeWTp2vvejNL%}jLcERoaPvm>n!6revb=mvxynZ$r>x{LZtST z_qQ06^cUG?HWK5NevEM`&og$B?;DTQDadm^;(wX_NhetT6Hi`IFCX*<3HuPPpTl{P z&4e@Hf8704plo=-*kN(^t-|^5Q-?opU7h{px5p2EeVoy#42LmQ)n%mLk#qzTH$XN^OKbd!RB;{YHKd@UKI3Et*AUZJ95?vM2_`@3=!>mj z^(y=jfIPfyo1WWoYrfF87R4$3E^*w>n14>a-2h64DF1w&QzU)0cglskmLA zTUY*Fuq#LaAUpk*DqEE_fLMV$^9S9?SZQwAKBD_17rJ{t{P~G$La?g%0jwhB4|IpbqD%IOKY-L-g-|zD`Oe%k_SB_mS+L;R z$M?MNIp4i=$3&DMqJB_cFt@0UIR>J~GU&;{ey3@NJTj?Dd2*=+@+8Z%qIxq7kWUuv zflEEdJ30nrmE)0Qe@xjeJ(lF`*S?Rw=+{>khv8AhvVJ5}YF zb*tGh%a#hF<_)9id#$ps>Za{vOK!_IZW{_?r{>s!WUOHfoBrTZRf5GCDLBCQGBJOshQ| z@x7!&A0Pseo7zwymo2)v)}LE`R#tzU>FW!`Ual`{mHi}lplkRL%&v7 zUb!2AiEs4g{gBH?AuwiBQd&@0JC z5O{jmE_-g%-SJgwZCYKwQM{pwyJiI!R^F{QY`(c>vY8n=JUo1-cb|u}_8{b`hwmN#WIM|LUykq$^Qd&y@%4CYD#>ON0zh&)RAx#IXSsdYf|PY55{&kLWF{O2Vf>#hLvnDkDfdk9TJd>M-& ziCu)uJ)M+(7NwWdQtyX|N(Pu~AJ#9)zO(Ks>|;TVI_Ie5;9AE;zbN~0R(w`b!9;+u z)}4)D&vpNRoNPZQKI4%buXb__1@ffm&Pl(C2u@+0lacrf63;dz@*}J~r*}U3&gl7b U{M1q5QgcVx<44*520s(;nYbu)+W-In diff --git a/tests/auto/gui/rhi/qrhi/data/simpletextured.vert.qsb b/tests/auto/gui/rhi/qrhi/data/simpletextured.vert.qsb index c87d4b2fc1e611356bb13ff261e9987caced0a21..22e2c7c3ec49754fd9089a739cdc4576db43b949 100644 GIT binary patch literal 918 zcmV;H18MvK00~8SoXu5ROB+EHo@`>(^^$lOT4aiSNGPO9h$48Q)_5t{Mv_nj5m|TF zxFy*QdkGd1`Ws5=v$T)?fcCLJpwK_kC!hM#+H+>lW;cQr9|}ETc4xlxo!ji331h5> z`69tcF_-D=gsIGepUpJFV^<`sTT-kAJck)zXTZz^EP;v}_%WgPSeyLb#Jf%I(OU~4 ziN~ecUJTI(ziC28APfc_026#~ZdbRnj;m#hb2-!xvv?=5BqIgBab_fo-Y28m4>Sf9$(94udjQkCezl6xc&uxfoljLWZY?D+wViT|)p}f%7V_J_=EoeVR zx*@V3qkW5!ev*8lejfHpqC6PkKLNo5xlDBrQtm6D?WgrJ)i6Q6SHWUZ)aK_pO8hC} z{DSBUA_JD7@0uW2B(d{Z!&Dodrt_ty?kbG~I3f+>a77Mr$7pI#@R2=Uk!8;@%sMxf zrtY*9Rp-KLQI;Lo_EeW+nB0Nox$>#ZL5>=h;ug5q=6iddquc3*rJA|S{{CX9F7kTg zV8?O{*RV|BwP=c@v+J%6GwQj>TcMrey0&rXxqA9qfC6{*6V{>#k>;$b{Tv zJi&WHlN``O2)xxXCil*Cq&1$xc z22Ap~Y@R)@ZoVv017ou;L}JG2olN?8EP~@a4wKsY?pnEADY1)-i!%7yxy4s}5SxOI zcElGpbH`WpRcHUvZ*^;Zw*mScVBUxK>pm7c0MpAW|02O{;wQ%g{t0rGustjnmyV-5nEJ`|T0U_CqAww_&z( skS(@oCsSzXYbpB3zsyZz;YW?^WbXgl$>6^!@<$=$+Wo`W9|h=*OlUaK_y7O^ literal 983 zcmV;|11S6e014%IoXu5RYZFlrKG`I--L@vRwJj)eq&}nwF)6hadcoTCBB&`%kU}YC zo87iYlHIU3Dy86W5b?R_V|~|0e}Ld0@yRD&yv&?4+ua1J^g(dKWarF$b2)ov&oIWa zOpykhXFjvo5o<69el9afpZZ0_Iw{ZEfb*CDKLL^rx(pgFz^9}=U?Ii52=_PYp;&Jc zx|b87<$A)gdHH@x*PX!Uq1Bk;K{%%iTgkq4)NmZvj5O1{?Rdfmr#W2@9bxj8A?(7W zeynq#Amj@PA5XogB%by;I>OlU>+xF}`qx#|VP25slQ_VdMd~x)fP<<%B5nNJ*uretx&`F0?#ILrsDSaxTM>!2bePwI8THUO$v$L}* z#M<~vtTYt3L~<$-E5{PCYR}H!HO8&2uWU8Jz5&P^@O<9OQoG>#EuWWhP@V!A<5(zj zr9Xgk`NowVc?RBKWLqUX>LSeQEoEB-c&)xvf1RisDbsZ(DRw#1E{XpGMg4}9Xcg^! zTAR3nmG#1JoU}ub8Efr_s|lZL&<#b;H;dEvOK87JyHw}UrxE~1Ir^k8UZ{+XFnlLz zxfkr!EFhEEEZ7hqgeYgFU-TgrpP`@vCuvP?@D8FpQHXeXz-p|pnVTe?Td8I17sVN^{CiO;4v!qrfR)L z_%Xu#fb6sC>xud}!{Vz8t2><#cB2`X7N2ifzR}!;c5RBiMLpJgqGjI0zvAJdt_L1Y z0o!OB2!Y+0WH?(vPIDo`64k51P2d<6CXy#>Q9_o{>!6&KfP$g;IxZmB+ FqBUT1_A~$h diff --git a/tests/auto/gui/rhi/qrhi/data/simpletextured_array.frag.qsb b/tests/auto/gui/rhi/qrhi/data/simpletextured_array.frag.qsb index 362e220d25dd6e9f6354f4ed71a9daf1a180396f..b7ae790fd4ae41b637fae31b7e37559b2688e914 100644 GIT binary patch literal 1646 zcmV-!29fyy02D)bob6c6ZxcrppLNKW6G-?9P*NBOlr=HNb`l72;xyO^A|Lu|;M-;{&glcj%tG1c51hr)qwyJ!ySTUSL3)?CKv$57L@BbD5m##Qwa@@<< z0~gZkH&gY=Ux!Zpl>I^fMIU+defSP;hYJVXBWV)aOJMvAZ5Ym@F9G3xdU2_!H6I1D zIOv8G1o#UY>cnEmI|+^B@q(Dp2Fd14hhs&fHmJ4AHKmQVkp~ocSaWH4tjg03We1^6 zw2^Cye5Q>&pvbeZo3gacA=b@w%tyyJn7fUcyHT0D71?`M&aTudn-16Shxqc{%w3+@ zGV-R)Q&}@(`d8051S!qnGdpS zhFvfnFv=`1u2;d}9`HYg_Gur}K0@_RhK0TyYswhovVIc6RCRS8Jn(4EM+b<0G|al< z!>+ywIIp=o-h!~B&LU%9eaG1I)Pv*fHFIT4q`&l;+sirmbv2)^M!K|RdmDI%yk6S} zPJnPk&pYExgAbeD=eHq}1>F7`Y^g6uHbeGFSfb3@!rBX3rvR-@fHm)NCFNS4PPz0C zJ@Wj(R5+%1JvL^QbH#ezHg zsZJ+=)XD&b??7y!DvO^t6Kr$*>9d3y0$CQ}6p6Uzx&##U(JDt8g-x1Jk%SYc#U$3j zgi0oyPAw+!4kn!nsFZ`)9qOA#&6%0$P)dEm-MxfQ_7b)!uEPJG<&|dmHw6|}CgSZy zQD2d5o3QX@l*)SBEmo7VB=03m&vI8_tQS+W5B}~F_b{Y7ChGu{QtWR*C5S*KMJA^N z#vw{?lnt?7k%ibODMgW8fd*%);P)a1jPQ6lPd+4lPNC86j6$y{^ih~oKHWT z5f*z6?F8tfpB|bEhu=Q(jqMccXF=xO6Vyl2rvYyOdel1(_JhnTQsYEpu|@x*Kpzq@ za(U=)h;)&kAeu^pz&lKM8sQ;*gyd*{l*R+}J|i^W0Lf2~?FiwYpjfMTqdxjP*~|Gy z6n|GKHa#TAUVe>9dO}do=cWCWf{*kK!pHfh2&;?mZ_~J!=8Nh z@sxCk;`uq*UnZT9qBBl0mO5e58z&!^h==pWy%eQ2h!6(ug&6S%VMUOhZ0sLb7NwpC>ROiON?0sBhdz9jxY`?7)jzwjClnksbJiLXkonG zrT3jCfAbW#DxvbdVA$ydq5d8;uo_0@A^&0;TYdqRZ?;1a~_rGD_Bd2j6$FB}? s=WP_Y{oT>`aYNt7{ro?0JNJD!G+)f+x4v>YZz-F;kMCyrU+>^J-sP1ohX4Qo literal 1693 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 diff --git a/tests/auto/gui/rhi/qrhi/data/textured.vert.qsb b/tests/auto/gui/rhi/qrhi/data/textured.vert.qsb index d4ba4747772dcc0f69bd0cd82c66498d1760cb1b..22f014ff9170fe5fede92b8d9cbe24dbec9d1d5a 100644 GIT binary patch literal 1277 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 aKSRg=hM*mx9=hZFctsw$&i)_c_;T9mcdLQ` diff --git a/tests/auto/gui/rhi/qrhi/data/textured_multiubuf.frag b/tests/auto/gui/rhi/qrhi/data/textured_multiubuf.frag new file mode 100644 index 0000000000..c1b707a1bb --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/data/textured_multiubuf.frag @@ -0,0 +1,18 @@ +#version 440 + +layout(location = 0) in vec2 uv; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 1) uniform buf { + float opacity; +} fubuf; + +layout(binding = 2) uniform sampler2D tex; + +void main() +{ + vec4 c = texture(tex, uv); + c.a *= fubuf.opacity; + c.rgb *= c.a; + fragColor = c; +} diff --git a/tests/auto/gui/rhi/qrhi/data/textured_multiubuf.frag.qsb b/tests/auto/gui/rhi/qrhi/data/textured_multiubuf.frag.qsb new file mode 100644 index 0000000000000000000000000000000000000000..728ecaf312a964a015de4fc15138d6efd338203e GIT binary patch literal 1422 zcmV;91#$WS01sn$oZVN=ZyQAvf3_1RaX*rlrcEg=)21y>YK#-osv>oyl8?5iC8$mz zP(@~AuboBquC-o=q*YN>i4#)A0dayG7gY6t#F+!)$Qf1q2^=_72=#*C_h#POn>2(V z1P7*io|*T4?{nVFHbm4-L|vemo?EnvIS!)VWzfdKxcyWipDe1kg}nx>m&l=j)+5p`+GZFR0ok;MRa%0GZ>J(72}*#*JFG-7v-s-t zPe0UB>CeBpb}H|F@zsyVer6Xz!qjX6^f4IUfu4XK!PE7b*|~+73FT`sdV$S#BNi|- zF~*FIF>eT@I8e|@&~EYkndohm9@CeSRCsP-v01hU^l+QX&_G1*7n!@nZ?7Ci=r^1zEf^|#4Xfk?>r|-Y|hL6bUYW`kV`duyX5HIic?)_DBW(8Pq7^r%v3Y*TctpuJyW++3PYonwCZH)4lpg( zsd#>!K}vUWglBBYl^LH=xHOQiTK>A@R@JIq8dt4V=6Ft7aro&GaRk|fDyclH1TEhl zpGjkt0eoaq14`NV)o9*$%(ep()t6OqA_wJCc5VHZ8fCC(fyt)RkY{0zr*$*k$}mi< zS8K&N->S}7fps&t#Fmh3Dix_RNtMIm4<+KmJzVr&{L2b=A9{n2VHX}so-g5!W}87d zJ8?G0^1X7GSk_NH`lVnBee47AEyTsp{2sP}6~9&|#7DS4PNoxi&w9s1ei{9GK-R-; zorLCv_=B759Ta;p*=Hj5o`F_e%M&_!ULVAYKLrYO2zZV&DY+>8_DbwbhpCTJBH!Ho z;rBJ=1t0ekMP)Ezu1clexO}bgCCGu#&jMg_oQG4Mel%M2X#J%H;DZq z$%}Q*$bLwCv;JYhCI$Z-bzaLevOh}Z)nxoJsY6m?KSiC-D9g{tx<}&SeMWfaaF%iE ze9f8n1e|Wca-I7`H;+BnYp>KQFLl~4wRj6!J^DNihWS&l*eAS;kaKR&N%VfUo)^U`Oh1v8KAxt1>o@3hn? zCg*b>Hd&q)%*lw2k+zLKy&n}`T58=LIis*fqY?cVMW1CE+5ZO5=S@dPU* zWggG{^Vjx&`Ob3rcXw(QzcTE&rCO_Os|$5Iuxdp-r!{AJD%IgPoqG8t{>iRPp*l^j zfos+6CZe~M*4p8>O)wlvuIRObC~`to5c#xM^L%ylW{Kx?Ze(d`3r)w3D)L!Cqt&$i zbj>Td9VIqcx7~Qc1uerrRQSn>O4-HQvw3N72AZ9X`gKQf_6W} z3}A#UAn6^J6|mxzgrxytyL19$%B$OVCZiRRM#>u1bZ9JtxU)OxC~alio-%&^s;dxN zwsSbTshI8CNZ4g**ks*0AGw*IMsB9++|0B8!p+1nwl5_YQs2UM#5=mE|LHZ|RLqSx cG)_7xi{(5&!@I literal 0 HcmV?d00001 diff --git a/tests/auto/gui/rhi/qrhi/data/textured_multiubuf.vert b/tests/auto/gui/rhi/qrhi/data/textured_multiubuf.vert new file mode 100644 index 0000000000..88dd4e45b6 --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/data/textured_multiubuf.vert @@ -0,0 +1,18 @@ +#version 440 + +layout(location = 0) in vec4 position; +layout(location = 1) in vec2 texcoord; + +layout(location = 0) out vec2 uv; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; +} vubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + uv = texcoord; + gl_Position = vubuf.matrix * position; +} diff --git a/tests/auto/gui/rhi/qrhi/data/textured_multiubuf.vert.qsb b/tests/auto/gui/rhi/qrhi/data/textured_multiubuf.vert.qsb new file mode 100644 index 0000000000000000000000000000000000000000..3cc009d5490e23ba298f7c3d13c096978ff76203 GIT binary patch literal 1223 zcmV;&1UUNu01W+joZVL4ZW~1u9($eC*))mU=BK2gnG%GYQW-l+t4gk;ruk_q6%xf! z6%?Z2*z07Gy&LV1WmM%202K*w%@sEh_dEbR0ThH3cXrNt*QO1W3oaOI zcITY)&3De6nK@n|M4wPCiJlRjFhpBag^iyhYOGH@<0iUWMjQd>3KR28j4bF?V^5M)OFu7>$cM*h-~?ILf5J|ADh;JY#G%# z>9>k{#lwVs-!qiTGul<#c4|F_d3j{JrU&Q5VVgBLGOg?^yY^eM6q`z_gT~$lPk}9P zpHsof>oKxpU8j8@HoP_TxhM8BFKkrjMo@nZ@%u{lq z_yqkI^k1=)o69S!sf5bghn&AVMA!G{GZKChgeeqAcNtxxXVKpbHc+(>Ua~IexsgTIPxIvuQUSq{%u_zrTir*b0d4IA6no);%4Nu(jAj_wQFH|X!0RmXPix+k-n zvvTcW`JpTyR%(VLm+a<|*}$NX&lSXj^8NRgIgT{??HG^7?~xIuPsH>z)-c#w*rKSnz7S7<)0q`S)eBoDGo9BZib z!)zPuV6;G&4D2Z}%KARWhw==+a?9gM5zT{YESXlCQ<&E3p_aVOBD*Yr$%1 zJdP3FS<2G{@Z_hTZ4xroOpW~)Ssq{=*>zrTXxDkY3FaGOzElv0TK^Ew9bukfo;$*8 zB;6R~3mg}5z0LAPUdv_3mzXQ$9u3y0xW{-6qs%=PtTkHK1dl`fB>Nd+{3P#lg6&s1 zF0$Xkz9dCd+erTu8rsJa=kPq|VFA_wmKTAT5bFPXoYzv~b-c#<66b7+{eO-*B)`s> zDdwSgra501+0QiN{y@~XRrL(-NJ>PX3AC!GGp1E-_%%b`X&PRov4^YBF!vYqNbj1> z+B@{f9WJ0OxKseFO4D$UDpf-Uvx+Y$DB(9jS5aXU1(V-Hxr}3}qR5>c-!+_U!>(HS z+1=e@jH;_B?CgY9fIxqtHm$BGIwb@1I+ZEg;~*+uU8urr=m7;3h$wh9%7z}LN%XE) zIWQpY?%t49+k$8XS$RuUF(B})V~ON_wo`mVO6n!~_*lgSDHl{n)5>)hNV1$+BrzkZ llQhFIJm0ZsVpuo(0=Inrdp=&H|6Kmy>p3{x_UF($D2ez-X{G=G literal 0 HcmV?d00001 diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp index a20bea7ace..568e77fd61 100644 --- a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp +++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp @@ -112,6 +112,8 @@ private slots: void renderToTextureTexturedQuadAndUniformBuffer(); void renderToTextureDeferredSrb_data(); void renderToTextureDeferredSrb(); + void renderToTextureMultipleUniformBuffersAndDynamicOffset_data(); + void renderToTextureMultipleUniformBuffersAndDynamicOffset(); void renderToWindowSimple_data(); void renderToWindowSimple(); void finishWithinSwapchainFrame_data(); @@ -2354,6 +2356,175 @@ void tst_QRhi::renderToTextureDeferredSrb() QCOMPARE(result.pixel(4, 227), empty); } +void tst_QRhi::renderToTextureMultipleUniformBuffersAndDynamicOffset_data() +{ + rhiTestData(); +} + +void tst_QRhi::renderToTextureMultipleUniformBuffersAndDynamicOffset() +{ + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + + QScopedPointer rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing rendering"); + + QImage inputImage; + inputImage.load(QLatin1String(":/data/qt256.png")); + QVERIFY(!inputImage.isNull()); + + QScopedPointer texture(rhi->newTexture(QRhiTexture::RGBA8, inputImage.size(), 1, + QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource)); + QVERIFY(texture->create()); + + QScopedPointer rt(rhi->newTextureRenderTarget({ texture.data() })); + QScopedPointer rpDesc(rt->newCompatibleRenderPassDescriptor()); + rt->setRenderPassDescriptor(rpDesc.data()); + QVERIFY(rt->create()); + + QRhiCommandBuffer *cb = nullptr; + QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess); + QVERIFY(cb); + + QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch(); + + static const float verticesUvs[] = { + -1.0f, -1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f + }; + QScopedPointer vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(verticesUvs))); + QVERIFY(vbuf->create()); + updates->uploadStaticBuffer(vbuf.data(), verticesUvs); + + QScopedPointer inputTexture(rhi->newTexture(QRhiTexture::RGBA8, inputImage.size())); + QVERIFY(inputTexture->create()); + updates->uploadTexture(inputTexture.data(), inputImage); + + QScopedPointer sampler(rhi->newSampler(QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None, + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge)); + QVERIFY(sampler->create()); + + const int MATRIX_COUNT = 4; // put 4 mat4s into the buffer, will only use one + const int ubufElemSize = rhi->ubufAligned(64); + QVERIFY(ubufElemSize >= 64); + QScopedPointer ubuf(rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, MATRIX_COUNT * ubufElemSize)); + QVERIFY(ubuf->create()); + + float zeroes[16]; + memset(zeroes, 0, sizeof(zeroes)); + updates->updateDynamicBuffer(ubuf.data(), 0, 64, zeroes); + updates->updateDynamicBuffer(ubuf.data(), ubufElemSize, 64, zeroes); + // the only correct matrix is the third one + QMatrix4x4 matrix; + updates->updateDynamicBuffer(ubuf.data(), ubufElemSize * 2, 64, matrix.constData()); + updates->updateDynamicBuffer(ubuf.data(), ubufElemSize * 3, 64, zeroes); + + const int OPACITY_COUNT = 6; // put 6 floats into the buffer, will only use one + const int ubuf2ElemSize = rhi->ubufAligned(4); + QVERIFY(ubuf2ElemSize >= 4); + QScopedPointer ubuf2(rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, OPACITY_COUNT * ubuf2ElemSize)); + QVERIFY(ubuf2->create()); + + updates->updateDynamicBuffer(ubuf2.data(), 0, 4, &zeroes[0]); + updates->updateDynamicBuffer(ubuf2.data(), ubuf2ElemSize, 4, &zeroes[0]); + updates->updateDynamicBuffer(ubuf2.data(), ubuf2ElemSize * 2, 4, &zeroes[0]); + // the only correct opacity value is the fourth one + float opacity = 0.5f; + updates->updateDynamicBuffer(ubuf2.data(), ubuf2ElemSize * 3, 4, &opacity); + updates->updateDynamicBuffer(ubuf2.data(), ubuf2ElemSize * 4, 4, &zeroes[0]); + updates->updateDynamicBuffer(ubuf2.data(), ubuf2ElemSize * 5, 4, &zeroes[0]); + + const QRhiShaderResourceBinding::StageFlags commonVisibility = QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage; + QScopedPointer srb(rhi->newShaderResourceBindings()); + srb->setBindings({ + QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(0, commonVisibility, ubuf.data(), 64), + QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(1, commonVisibility, ubuf2.data(), 4), + QRhiShaderResourceBinding::sampledTexture(2, QRhiShaderResourceBinding::FragmentStage, inputTexture.data(), sampler.data()) + }); + QVERIFY(srb->create()); + + QScopedPointer pipeline(rhi->newGraphicsPipeline()); + pipeline->setTopology(QRhiGraphicsPipeline::TriangleStrip); + QShader vs = loadShader(":/data/textured_multiubuf.vert.qsb"); + QVERIFY(vs.isValid()); + QShader fs = loadShader(":/data/textured_multiubuf.frag.qsb"); + QVERIFY(fs.isValid()); + pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } }); + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ { 4 * sizeof(float) } }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) } + }); + pipeline->setVertexInputLayout(inputLayout); + pipeline->setShaderResourceBindings(srb.data()); + pipeline->setRenderPassDescriptor(rpDesc.data()); + + QVERIFY(pipeline->create()); + + cb->beginPass(rt.data(), Qt::black, { 1.0f, 0 }, updates); + cb->setGraphicsPipeline(pipeline.data()); + + // Now the magic, expose the 3rd matrix and 4th opacity value to the shader. + // If the handling of dynamic offsets were broken, the shaders would likely + // "see" an all zero matrix and zero opacity, thus leading to different + // rendering output. This way we can verify if using dynamic offsets, and + // more than one at the same time, is functional. + QVarLengthArray, 2> dynamicOffset = { + { 0, quint32(ubufElemSize * 2) }, + { 1, quint32(ubuf2ElemSize * 3) }, + }; + cb->setShaderResources(srb.data(), 2, dynamicOffset.constData()); + + cb->setViewport({ 0, 0, float(texture->pixelSize().width()), float(texture->pixelSize().height()) }); + QRhiCommandBuffer::VertexInput vbindings(vbuf.data(), 0); + cb->setVertexInput(0, 1, &vbindings); + cb->draw(4); + + QRhiReadbackResult readResult; + QImage result; + readResult.completed = [&readResult, &result] { + result = QImage(reinterpret_cast(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + QImage::Format_RGBA8888_Premultiplied); + }; + QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch(); + readbackBatch->readBackTexture({ texture.data() }, &readResult); + cb->endPass(readbackBatch); + + rhi->endOffscreenFrame(); + + QVERIFY(!result.isNull()); + + if (impl == QRhi::Null) + return; + + if (rhi->isYUpInFramebuffer() != rhi->isYUpInNDC()) + result = std::move(result).mirrored(); + + // opacity 0.5 (premultiplied) + static const auto checkSemiWhite = [](const QRgb &c) { + QRgb semiWhite127 = qPremultiply(qRgba(255, 255, 255, 127)); + QRgb semiWhite128 = qPremultiply(qRgba(255, 255, 255, 128)); + return c == semiWhite127 || c == semiWhite128; + }; + QVERIFY(checkSemiWhite(result.pixel(79, 77))); + QVERIFY(checkSemiWhite(result.pixel(124, 81))); + QVERIFY(checkSemiWhite(result.pixel(128, 149))); + QVERIFY(checkSemiWhite(result.pixel(120, 189))); + QVERIFY(checkSemiWhite(result.pixel(116, 185))); + QVERIFY(checkSemiWhite(result.pixel(191, 172))); + + QRgb empty = qRgba(0, 0, 0, 0); + QCOMPARE(result.pixel(11, 45), empty); + QCOMPARE(result.pixel(246, 202), empty); + QCOMPARE(result.pixel(130, 18), empty); + QCOMPARE(result.pixel(4, 227), empty); +} + void tst_QRhi::setWindowType(QWindow *window, QRhi::Implementation impl) { switch (impl) {