From 11783743deb4e50fed45e0833e40ae6d920129a5 Mon Sep 17 00:00:00 2001 From: JimmyBinoculars Date: Fri, 20 Feb 2026 21:25:33 +0000 Subject: [PATCH] Dynamic window resizing --- VulkanTest | Bin 103040 -> 110688 bytes cve_pipeline.cpp | 36 ++++++-------- cve_pipeline.hpp | 10 ++-- cve_swap_chain.cpp | 14 +++++- cve_swap_chain.hpp | 4 ++ cve_window.cpp | 9 ++++ cve_window.hpp | 8 +++- first_app.cpp | 117 +++++++++++++++++++++++++++++++++------------ first_app.hpp | 5 +- 9 files changed, 143 insertions(+), 60 deletions(-) diff --git a/VulkanTest b/VulkanTest index 7f9664f1f9e5f6473548989f361d00e26e069a5f..a2d8df6439777c5c9b468dda931b9d30120b2a3b 100755 GIT binary patch literal 110688 zcmeFadtemR`9HjY0ILmbP|&pX678x9=C8V!(^5lDRJwrYDp3^+(p20{@ z#-E+fecv$viMZ^$SAw2_xU*auANskUB+(xGZnw@m%O$#YTqslQyC+q`EH{Xc`TW6^ zFMi|q*ZwGB`>vLg?Wq(nuY}Xa$a3~wEl1uQyg=qVIKKBi>lj&X^Y`T4E=P8;Tza0& zpC0Ia&$9Sw-)(-9M*ihm{B+;5kjBftyUSHu<=pooSG-2gO_(&z1F^IdXR*;Uphd!VeM}o+r8EDFm&C@FCtp&FV<&?JPt3%6Y~gutoXysY)@G}aS!9~SNPjnxux#t z({CJIwQu%Re_cx9^Y5SkPUEYCFDmJJbL%4~HLPxI3;uA}SBKvkxjdy1+55fzn&R;s z*H6m#K}>)6CE#O!_zQjg<4ts|zx-DX=^y`kg8Cmkw*UO^CaAw+X#e?toS@wW7@z&o z`A~xTS0||F3h=VOdMYsx`@~faECJsRB;fP23GC8e z6Yz6d0=fSp0iACppeHGTzFm}{-DeZfzajx2exIP--y|3>lM>J~HbFgA3G}Ba0e@-| z(EmmP`iCaahr1H!;f@6ORSD?P6WGa<6X-*00zM2+Kz|^?INg+ho~ILxi|q;cP@X_f z!U^ack|2L!0y&OUdDyjhW8e7%-H-@M4*pZzow$m`t%d^jgT{vRe77e7ysKRJP1HYDIrP6By-F9DsE z3HZ4nK|QGn^!acC{PF~Pt0&Nh`x4Ysk%0a+3HVc$pq}Og`ae1WAMQ_(KR*He;}hhs zOQ4_K3G{PRf_XnJLAyUsK>w};dVWa)xjd9$JpM8P|DQ>qx84Ny=febY`7S}fUQ58Y zbqVTuBfw)w9FOUuxm+g8s8#Emps5Iz44&bL#5nmNkXS8$)Gfp0dEylCs&Ajg@n1 znnIP0Q%eeK>*rQZEuU3eDbxB*nNwRezp$~gJXCo_&D`1b^F2fqRW^kh>u*#rrS-M7 z#q%oXhMGi%DV3q|jpcQfv%*zXm5ozsZmKLSudSU`UU7p+Rx6wmZmcS=s1$fvp;j|D zB*4Jj8u@TVc}=Ky?K0=Irpm_BdStI`6a^+!h9+13EL_uAIXf^H{hnJIr6rm|_GHrXjWxpFQ9SX$o1R{NCxX}B_6IljEEruN3t#`=cJMwWL9 z+Y|#+SU0cfa&`Hhf(%3ho9!uqC&oxz9aIgGeY2`5t*@_* z^GO*?z)4PWOax|&{;R5m^nwa81SVBBheZ1-=cJm7O2iPJ(wmd$IEL<&ikhaT`bOk} zmh|ctP;3{B6|7<};~bJ?#m8GO9`#|qUySvCpv!W=FQ+J=X98>FLa_Nx}EbR_?gj{`l zBnC?_iCBZp=8oj-w7IZpamIk9h4l?L#)XDzZIgkjDhg)LrW%P+uPAJVLLL}hFblTXlx1y}#x+QgW962evZNGO1c{xD`a*FoT{U$&kYlXURcO1iysqCW zWIMTNp$xezi$;syO$|&5Q{i?|*m-4>XF+6@l~!^YCW^Ag%30;L^igJ&f-Sl6EOVj2f}K;c$|g@? z4d_w!`BEHJHMR7r`jrL*3Li#@VA8}Xp`41)jSZF1j@;SxW%FxhSI#Y#+Ep_K0)?Vf z)Y^5snJD#8s6mcwS1LiGmhF1}J&o1?Abn6fb`#poPJzw~Ynsa7x6EY^p#J4@fS~TF z(6mC~Oa;cPZ1V!O&5H7-5SxU=;-jKaj0#b?APHlvOdTEnp>)Rx z)<80(NDSD^!K*qbi=bn4wmk~Vuu<4p-gqMzQ$u3P<}^2#!5wU>pIZ*6^2V}xS&~9m z$1KqZss9Js7Vmw%)D2tn`!h9@Nwbu-l{+xCY-(0n@stb7N+(V^zl@rQagwX@vb?de z{Km4mm9~kLe62sfAsmv5tm-&eQX-XHbXyJrwCdI|MgP#)?8;DiO)V6nw2?NXv9h|n zsk*G8zP6^~#_Tbuac*TL2P)CUb#>M- ^n1GeP+9~sKH-LGw;M!9S_Ohq65R7?eT za=;yH%;tnDYis9-M(55K#uP^S-&lAl=6{oE4ArEVCa9mGo?R9F^@HKk&|vT6sKRaX{(ZLa^rTktg5~d^8_ZU1O``H zTgs3yQT@Vmo&?m$|~r^$_`?-jvJa@U71~Jcd-{b zJ~2p^J zRF-E#FfgvLZ1kw}N5>z>#GkUA$Mc=X(W7!?ju|sh#h7?e3(U^#m71OHDV#B*U|gUq zd(`=(@_MC>?hWQCIeX{pRY$MZ8ORxc^AiJbwjxQ~B}7aT&d~5aK->q3^uai1k%V&| zGB1A#+Yq0JApaoom*nwUX~&5Bu@>aymrpj#7Qcs*c5U)Wrlz3Yp-6FXq)k%C_GB(! zuN)FL*eYY^k=Ox*K!(F2*rUs;#k%5Y$kMR^;;{tg4i`A^ay17fWE4TR6|zb74k zrDxtKB6%MXfs35mVWrOm{M;|@L!@<>=Ti$eqNWCsycEwD7JQFLKi1P@!7m8d>p2#| zO`tsCAJiaXH`p`M3U(%Wj`ggu@*>$Y?#TU!%%*xyv+`F9*yqWz;Bo;E_58$wZ+z=n z(EB~lBpVj#$9S%`VExui)HlR)y#@dE*&7g99^`4Z;Gc>7$)1P>hedq@J$G4fDDy5v z5(jvG1(=t84h%?f&AeXTk67o!Y<#+f_ge8s8}GHwgQdFgS)a*z(p>m_3!m=7udwhL zE_|tl&vM~sT6ointJ?I;JXXeEkGSx=EWF2}*UrDo%9rZGr(5U2(p>n1cD+`-)vm{D z!FGM5;>Y--j_|U}5kCumHs0o+8^85(*$*hEhi9qmYlng#Wg~IlrQkIMZz}lP75qU3 ze~*GcqTugS@Tpe+NL8DHPgC%BD|kB&4&}5%*&@}BcN5REVfJOmwTb_=jl|uK%M<^A zg16)8#6P0oH(T-{{vic#$Nh=_rGmHP=EOg$;O)3S@eeBa>WNY=jLXX>nb@GDzpv!aQt&@e@VN^9 zhYCJl!P{q&nXD=Jla>6X3jP!YKSRNvs^DiT_;dwdt>8~n@C^$7bOqn6;D4mxTNJ!s z!7o+tXDIk(3jRz5zg)qerQla6_zVTVQo&~`_*Dx2Yz4ns!E-OtzST%;aR@Ht9;Pl==d7btkIg13&Yi_}yF zpR43gQ}B5TK3&0Iq~J3Y{KX1BOTk~F;ByuHSOuT2;4fA1nu7m{f-hC@`3io9f-g|; zGZp+e1z)Y;3l)5Wf-h3=%?iF)!M7;*@d|#af}fz^mnrywf?uxSFH`U<6#PU5zf!>m z75pj%U!vewEBHwYzFomzuHZK-_)-PGRl)yM!S7J;lNJ0f1wTc>n+kraf
  • 1z)M)8x(w%f^Syva}<1wg0EKa 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 q3^-MGNh$w#w9A}6JDd#R4pm0 zDN0mpFChfArP`vZ#L{}Hmh`8KuJiw%d*4f*Y5%XE%zfv3mV55K=bn4teN$6bRxSJ8 zYI)&xie8cUl^_Z!;q_%LHwRQaCdi7%mR)Jj8d`+T1MeZw-ti+F4Niy+$ha@ z)xcWSoGkpiTH~#-> z9i!Je#-9cFObXr{TdVluq$iK3?rZnrx>-HuA6Q+hHCy5n6P<@jsCsfl%HNq5CykT{ zTYldG{K)x+dh*eHB1W%i|y$&atE1BY*Z2+R=_{_;XMD@w$U~O`mdaW^tJ$ zE_0RLfY;O~GWX7p%e}{axy6xw+|y;;iiOv)o?H2yTk+? z=holkW5sxTx^ll3bM9a+e}>oBms@Yi@ebVjOWfu!{Ifon$>-JrA*3g@04raD-LC0zc2dr_aaVZ$UWc_U9gT=2}yD z4Rd*&U3qJs=Exs$GwW>a+k?3zu&4$QV`pz)MaJRxInFB z);i&s8Hi{jaA{SHnEBb5XmmM|B7&p_Qd*qAt)h^o0Vny+dZq{$ z;!}On#CN*X0fTa1D<4l}_pk*}B4PFd8E-CA=*Fw1Z!JaYKgex}&K& zel$=xnh?t#ulu@sY>gbueyiJnJrUeP{cE;dZ&zXP8Abi*T{&pi+OWMcTM=GIt^cZQ z-L*KvwX}Qa_!Z_1O+MSW_Bi(41dG8mrSz zM+?}iE@kQT=R3yxNs^zm$cp-bNmICjue3}Tn9dFQNclRQ*ycvMX*%v7D`L~Y4Z76PPB3Ue$rCpC=VcS#%7mAh@TW|;X2Nq#c!ddHV!|Kl zxPvNQYGPP*Psy!UO?bEocbRZwGNC{DDrm5bIYT(DjK*cm4Z>GR`uG#mnBBx!Mu2`9 zvy$*P4G^U5Ggj4)e#e74db55ERjMPG`QWI_j65*FkIObL5Rc6A)Zc4B;6Yjvg zsk|yoj9QhbBt10YnCMkk>#CkZimSZ*O}L&iIL~Ur^@$|rf4GSeRA~mu$As50;V~w> zt_hDd;lU=nvk4C|;R&rBRV@fLG3+LVFcY3?!i{Bx*h5Tsgh@Wlgx53SV+@?yU*E*Y zFc`oZnD8tU-q3_+oA5>^e6b0SG~szB+y-3qKW5zIFi>Wg@DV0F%Y=_K;n^lU&4e#D;iF7=9&jFi zH2q#QF;G2i;}^(CKwv^hz&!sTaM-i=O92&+wur=`^OgXmPri zzz8pTuovCmi|*w`clV+@deLnK?Wmk~&AbE}dC{R>bf6bq&5Qo0%qs@G=zE-YRL%SE zyacX!(HFhwb6#|b7k$W!-t9$iC)#03Je$1))_Kt@z38Q0^dc{Mo)_9Uwfks|*s23gRMOX8p|GDlJ177sK>xh4| z1K)WGT=SwYdeP^+=n^mbkQcq%i{9?=0ycZm>%8cdUi4BgdXX1B&x@YnMLQ;W0qI`! z2rqiD7v0~B?&U>y_o6#KN;{gieH3Wg%!_X1MTdIPfnIbqFZ!Qrj}Gy#kI-2E?>z!| zntta+U-P0bdeP^+=n^mbkQcq%Ow;|dNG?9O5>_aP8h zQgr9h_Ex@4>40Z?sNEIfh9U&7T_VBj+CTqzJX*wG9uH-70CwkbZ9mz1RMX$?ystI( zK=#K!J#9UC{TBY1S=;W)jP_3fqvfAMA-t+8C|uY6N5(&4+0V9Ydh-vD=k8aU3zB)l z;{@{09ltZb(&O#y{Ij99J>PH#{dEUpV8i5F`NQQSgInI$o*~l>U`-3FGI{1VZgO~) z$;Y|Lp2Fmci=xdR{r!l^>12|*2UL$PfRoxreCRF?5%z+r?3Mh=Dh32MNkB)Qxyt=) zs2lC}sL_Ae{Q;4Vwq&qHmBDMjatE)kuWWM)A?WL@s;(OXn3txLR*iK)mG!f)T2-Q#&!*Css#VWt_-X{wl_)iz=x>r z;V<0b+izDooK6TFwpTiAS@ijg^%e6NCo67u3V~%Fo{QPVa^~Z(ZSacF-*hgauRELVjgm4XPhvN2qB%@nK@! zW;F&k2ni!jokuyl*yDp6IKIQ!Yd7$r$HGdg-yMH{t?tor&6j(W8@*SSq{_~i{ydxt z5KayKoMi87a}WTc=3={RZgiT~Cj<=K#nKE)u($ZfzR;8Drxo*&6b9LsgM&i`kPrRw zA++z)w7$>&85|ZmlZ(#jYn?xgJnw2r+jxXFH{+WOC zYZL!Ag}@G2(YDZs-vjFSxzW}`2^ePWJ3juo(U(C~wYrlw0-b1g9gGgjBdHsB$zXR= zTh%0X>A6N-dc&072ij>}luNFI_wng9)Ne>)$F5!fox1vv#tpSGe7sA!{SRJrs*xNOAtAJ;Q@! zZnRB%4bptjwSGAGq|V9E>h@$qpKnrk-cP*UuNl#PT>F77dp_)y6*t|u4PfC*LF-g?rQb~sQ@g(-y3n8&X z(Mg%2qT}a9Mc-n~gwlZu?%?g!x>B*$f|ObehEhABl+Bf{Yxxv22M{y*Xs0;uXmb#yUXkh}Yx@b=UD+}n*+-gdsvN}mm}B~mVQ$1gu8Y*JbhUUEmKRnR){#?b0@ zHls_mckrRl{lWKH!O%egu`5O0o$j&f!=i(O?x7mzJz4-~&_JPF%AOq7Fgk&fkvo3b zSqg#s+DH{7(SAPHkYnS!> zS66H@W}tmHFYq3C>O|$5cR?x?Ho$8Jz|K491+=YF&xlx z@R4VCb&V$Htd-6kWS@;_BQIs15e=F|kz50Oh@QA`m)A9b={-@bCER7*M~2tvMajh- zuYSr#jtr5r*z}Q+V+&{qH{!$CQV8YWmg~yLwUX~eH~Q<{ShZCrB!Tuf@5k7+k2|bN1L}v7u%EpXjZPOwn?}Mp(v5D$*$3JBxfnu%B z_pB@}B(lD!a>6O9^18O9vdgbiHtxsr(;76%h8=BAm9bc1?1yD~lZv%1F*Km(|48%w$eDv*M;d~r`Jr8ZjJ7t#F?ai2%`4fy?>EbZ19Qk;{f z1rXwzW5?1yq;drPc-YK|)ee%FYmU_cwylzVhlT(la+m^*=29qpqL%qrEzx`;t)p-p z3uAhpG@>4G$44UD==-cCcStkjT_i6sek~!!buF|q?2Z$8Nppw_pQZ{A+0YWIeiRR7 z@2S+6qe;ZB0JJj|4|M8a~G~Xqe<~|Jzf(K};dTVPv=tK7^Ae z$t8FEsVXNsawl`63lJQYBX3!#pwHlIXW^^!m}u?$2+6|^E6oUpur#E~(vP=AcY9en zL{aAoxlifQ9iO0EN+V0$5O=^G|4NmiP5)(RdIF4WAtMfV{GT}Sr)aAWE2f^f`d@9C z&O0L!l3FcHBdt0cIq?@$0m$=Mq) z7K8Bn1o0%5FT{uF$KyOGslL_I$=TfKA!w?}Uvlvc3f>o}liZonmi=Tx8~Pn`+TCq9 z*~@L4+5Te&q zH9TdO$ZYbqST7;}J2Bny|2x5c7+YWY-~_8Nu3<|*bgVSJ)gXILw-><2Xnvbn%kJv7 z2!s|X(YxJ62}+wAhV^)2~`J_TV6k#Dr!`4k#_CB^xjb`{-kcQwGK z=~e0OW^L^)_Rjd8mV%o|k_p`UeeLa=?7{e^_H7HPvM=}70X)F&Zuqmv!1kOU{Izfz ze%Hhp`@$bBxh`EV=Q<7jJ@lj9c~tuaCeh$SB`j@1RKVSDh<8HkS;kxwB9y&1+2#pt z8YPoSSC(d%ue)a2a?Z(Gb98R`L^Mcic#His;lqaIXrbLTFghFuSJN-0xW-uz#qjzr zY3IsV(ZmR4R~h?yViRR)+44yZl#DXgXi~J&r;H^{ic*@Fu~#NFQmU7+*CyGNZ?CiW zCv~+%qFn>*&OdoWT3%;APfDrz10sho?elA_@8m>l0`H{*V|)-8ziKzXVQVHwwB!vs zkRY%t*T}B}`Jm_wz=GLYNcS!N(RN&8*C#h@o(GAc!xM*LfYHdUq=&(+hniAc8|_3P zp8x!YHOc5?X*?0fmU%p?Tz9uIt6 zSn>_KH@%+H;VTv}qqF=C>p7!yC>rHzmFzm4O1*@^_jlgYKKPO?o6%93ewm$`(Y4kU zNCZbOynyKYh6T-xfMTneos=t=*yx!v8&0_>Y)_-!aZQH}K9qLnO|9et+c~E-i_WTF z1HO_2=dLn&Zm<%2iH*pLQa-uJ=4ZX4M1RS?&uXQ-@+AwK)ll)j$U4sIh;QXjoYl9* z3K)mMEcm7^zD)PK(#TKryQoHFrG}rg8?)*uiC?n6XAM^NU1Wo1w^9y%!4}M3CtqYy zbJ{5PK4+^cIVYeO7qXybMwjqet{@8yy0b*=m@JH z3=$6=wb0)b@5$~rvQflc(EcoC(;U%Zznt@U`YpUY{knbO*O@iN1lP*WvF(nQRvHA1c2RdO!Um(g8FR~-^dnz%fS+xa?m83JQ<$}iYdDd^i0A<2twqZd` zy{Tuaq^F|a49!JfvfB&#D3i{z*qjcE|7n(sDysXhUB(UdY@pg zmaxBapI2ThVb3jmF6i1x8kEX2wDTv~;e{_N1;<&lMbA9$cM41=p6jnABenf@oJ6y1 zc6Vwlp1JH@F3~}ILM%U8`u>C|!G3ds?OfDO*>-~6T(nB5Q_SYR)>L`o1l#!9WaZOh z7Q8r5(T=mti$5CL5?|5LUMVG4|!_ed22$L1-Y~P%deOFi3GX{dBV= z?GL03?2f;YE}s9Z9pe!cOdE=EN7z7DT)>?})HNrxCy%foAznpj3oFy$9ocx4%Co~)CdGtlcxg)G-NoytJD7&|$qtf{(Yvz7ZIdO=+;(of% zU~c1)<5r872vD1V_G_=u$BXzdl3B^=s{5eIcq=Y{|Mc>u&nkTmvw=%HD7O!@*O$(Z zUPk@kZutEM^je5$RO6Q@SzOne!AZD&eglhJR+sg7BQzrTfN*~THN%}7UB(q^|Meo9 z@`gLAKQ)}z+mPyH;J)?=7dO`1c86JHUTi?a{ldodgY5adNM+ywHal;8%5Ojy7ES-W zUzhut!L+rauldsf79D%OPSwpn?hDA?WkR&ovheah7=vKpZpTr=-Dqlw%kOMH+-(t1 zXP>BM+yORvS#zZzaewu(mJ{@#IP@ddbLD2`!AI=w%HC1vu<|<(p}=3++g(17?o$rzX9HBH zlD&srQ#UJ@ce6#Sb}C=)hNrPHVl(;(JrEWqqTLMVXXzmUqiuodKW@!%g3Cn zX)khagHo-}?yA7*gXk~$mMe z$sb~b+^PP;a_yOeS%)=UYI}AH)b6g`Z!nv^CP6uxzz(j7i9m1~?uMD}n;d3;uW6~g zypxq*XeaMv5uekib8SlOoDFXtQA&$n@ko|} ze)QKq-^LES6IDGJ=djunTiC64)+u+lvYZY7D0jE8oQ<*J+y7IocndqdF{--n(@<+w zz#eQ|qkL1qmTgK@R=>}_*ko(44QkFKSY928R4ZJ!J8MOg`}5vs)^`(>1_kWdcUx9} z0nc;V+nZU=yTg^g-eou6J*l*Rmu=fTS~;_c)p;*Nd0`XFeJ{Pvg3UD9zK{DAX)xJ& zOnY_{`|G_0O5kReUC^n+!cB;~!VShyozT9(eX@8!h|zi%7>r`=F79bya^7cm3mS#_ zY^3I44otIRlj+(^8wKs!CT4qoWz&u@D)ud1qf@ZM+FT`TNak#0U%%fd@}(3^x4I&& z_$4Dm-Q89J(p>ODYxXV+-;yX7uot%28@zyK(37a?4VWLk))!N(Wp84KwnT=%L6x{u zYuTMXcIN;*+zjx?VZf}X*)Ll>qzi_V6pmLNdoB1ro;uMRZx16XbDOPrqAqbp!{Z&ag&LhF5JtG<{7^TwNJnu zyvSaRB3#_AL7}4ut8Ve!YM}i8iHi`z^gn@cVN{uf8>%`DWpR2{_gEsCXGcQwerst# zXjAP~+W#Ra-F|G2@F?B6B-)C%8Fp9gin%Pk@Ts1Ohyn;)fj|l#?i2WnFib#uP7&UI z>MvS`zr??&kCByByrS6HuECJzm9e1%zHcOn7DuJL$sv5BEG2im1% zZ)9zEHdkI-&z{@aE~XlW*6w=DPWzEN+GSqFZ(9D_Kxyam8=4Kr%4W0eJ0tqkhJQS_ zYU4=&sY+|lYxHX}o8;z3X9@NMSf#f{Db5Mev9#8@YCpquQ+$!v{JxyUf<6pZ-g}$B zIqLdh6J_`sHtNHUO}>R*`2?)MGy(9UIZI2C@9@WCU+om}e*A}7hKHuPyRGhp$@4M1 z&`Q_g<1{|Xn<1kZiMZT!|E=kMJW}GnWsaBUR^lhh7ksU0D^if)fQ^d(;k zaL=FhU_762jF+9P-UdOJy~W9Wd?yQRj8W^6hYCoVp>)|TJ4)hy1&|GbQX_6DBj7}j z-xs0?#UH9zfx_QkN4`IDX#Y@ z`ck@loB2d~9xFW@p**&hJvj7)vgl0~d$@~oU=168xW0031zUVLQu$kD?;lQ34!q6o z9&Y6SwMu=JbD0Gdh5K(^!HFVHxCBu_grhGSXV3ZDKeP5H{;2CNGq%6{9hq^^#YY~U zxt1H{ugnY<#UJ(a0>R=DpdXKE)C{m*5v(F2brwY_u^cIa$6KuP@^xMuXU)knba<>m zCqm$9gyURvS_T>N6`3y7beLxg0H^#2IC=a4uX5RE z-S;$mtb!bJsUqZqOYN@L3OFKS^l{#ujJV0p@~3dx?8+%(>YkQLU&e~}JSY3J`g`Mh zOkj9q9)!6x85>tujz4vqn~dd6EDAkuEm4*^UKgI zAKq!{d3JZ3S)>_EF1h2&Itk5>(RA!xM$A}#plOZwmI_4=YkMHnn#EZ@{6&G?9a4i0 zJYb8p1Ef8wfnF{neVnUwDYfLbN3Ou4?J2b!swi&?LOaDa9ayYf?#9|4Y^cm%#`+zM zQ||3$*#|>A4u*G>q|Gluu&a!9ULIPkm4j(4ibJurFz#PvXAUMQe|2SbJ{hO1>dNMQ z@@J=MZqb7tY!&Efnuf3HMMVIz2~81tS@1hLCeL^!z!Huov^-cuIw|y~e_(W)y~}5K zQl@>7^W@ziOJoAp(;|O+m!p>4zHH0U25mx-5yT3b=q%C3;5jzgc^qx9xl?5n(awR< zweUW{ADywFJ$rC;hNb7@WKFCF+U5^gR&k`fmaQs|a@gG;Mbp&6I(CMSiF+?m`ay$h zAw>$-wNez7n_|QtEoT%~NzRY>QV8e=9ir8aLXEC;%SCanppD0%Qh<$GPfg`!Q{1DY zS?^;Zip9l79J2*{2?cwX63c=mZ1J%M%8A$6=3|kLk|m@---5tw^|vl~xU1znT3*cM zJ0$UK>V>$X@^RRI2?H%k?Cw{yv~75KWq0+HeixVv{+lq z#+1wnt5K7LT~wLfH6W|}I;?3)F7`*sPXX`fqUYDJUrvky1pjr!1}iO(+x_gFYA7~t&&}hO*$RgD2BV2!_Bnni5+N( z{m4H)tDtRcA5E}vDJ7ehzg0dITPv6muZ*FpA9^d zu-Z*pai5@=12%Y-9jWr!9_ZNwrzP zxq1Oqp}j?kmQa(mJr^24o^rAV>whk^UXf1PYM_E#>ada=aqhzoo$KUBc~N5L&$nPr z&bRELb$>v$iLbR$N#F0Ha`5k>JolR@XJDq%|A>YpATr7E@~@G1@myqC8zC=XE!MV^ z=d563@^IYsJJJ|Ry+XX4`D%mx|n$qGs zdQ2&Hu&rN4RIe3{{l;UjvaOfa%k#LdI+yFVo6D|W?h9=Em$BCQkEq^)I8<9VhU$Ph z%=OiJ`BkpEXEs-TdNwV!s6WiwgdZ`RARNLBug?f&8w<&7E4ajh@Dd{y)7SnHfe zG<#-|X3ZtovTD1g^G>|~`D*2*nY`w(>AdD0nJn_lK1$9EcK2$mb=D&WUYfzH-c}C= zKA*-~UH?e=B#Yg+zEAluldUOxLD@W$JuHikh@FOHD?h+VRHh{v$1zyw>^O?)lF8z4 z^j9KgvV}KVD|ctGT{nJr1ck#`-wgASB7cFGI4E&oiu)CRY~7rA$9N(f?-|4GuCe&a zN9AJ_PL$$`oHI4&b3fRft?_zxj(>`)1vXxmnRD?ePfy1?oTsG4wAmkTE%9w9X>o8Z z?$^VzO~Dsjr+7RLzS1A|!KPgs3>taH-!;t_8;-bBt|znynG}ZD#AA&xec5CHLNZ(= zOuUv%zy|Ec%(Zu$R=zq%VBr-a-u>J{H$xxajL}~plPh>UzNfv9Cfi-D2VvVX$G?08 zWy4qSp3zt?&tl3~?w9DHq0t|_BV3Lc?deGn-ol-o<8P-&nJy>jt@yO?q4t~-xqR{z z7I~{)=f_~qXzDAd&D7E%ymF(Zt|#J7X}_RjsHH=TS>oKfEc147Sd6v-Agw^{;f+2E z=|p1O%vR~VWB%*SciuVMy2k$GbY`gB;Y=vQAJHJ(mlR3HrJ9T8h{it zba?r_zwtgcgoS)pM|rnCYw=y<_RH$S-if5>RCpj+THwII663c-2dxH}KpRR+3mk;} zG>N_XT}wx-CCJ|rG{j~JO0`;o(puZGjX<>HO{=yAgM=5Q{2?BPC&#s9v=DEsd8?hg z@i?xeudd)by?8su8&AYCQlzhA8f!Oy;F`nHN4`T=!#*hISO(uDYPHd7BXn*d!5R0r zP50GuO?xO37-V<9LE}QLio1ZA{sG^)JG_d`xzi@*_5?BVH(`K+zjM{TtU4mWPMfj} z_{6eL20I=ix4YB|bh&HK5BM}qQSluy`mzW*Hw9-FvHUCvvx#0>CTRWe5(pt2d)S6f z#-ni#jVwx+m3Hb*-{^Ep$q|_zb5EiYt_D47x z5dt{*qhFAue0x;5ZWdbGPbu!`;cApk4^e&Gg$I^-JX}d-v?V6wNT>tO(b+2@8T64v9|J9+wKOBs1Jq(=uN+X@lN`=%qzr4R%9#g61LS%HgA#b6n;< zp5epq5_R(dwYT`xe&i3I@^iHFj9xGnV>8zwjUQ9K z*+{d}?yAfGM~FLG+ixLrf@d)r9TAt;EkV4OQN)t>Z#{$%HoG@|A1!W@{}AOe+U+9o zn4YX_V_wD@$)i|%13u7v!qaQ{x7o)1vGPO=hQN=Nchm3f$RdMr&u)BPpxjF5yF7KY z*wv2ayV`WVt3_X#HpI7H=9|3McoNbEytHfUFTeP&kbN-=v!DFfSB_OI_LuR`M%o5X zpD=#Zq$o++^Ryx-`>8|x zz!*MWqL5_u%^EWPT{yKyfZW?5*Y|mX{-xd5!71&9EQ0&gr#+s%DAQ1uqAYz5U(&(b z`=lWrPa(=olrjF2v>D}Gl=YrR44_>^YvF5#C`Z@E zKNvOK;|WKIEE?`{c&_5c7yGdl@VVAV3^A7f?@(?-`F)zlgMTPgYB0*fWjNNbmPnJncpbC} zWhwe6e2l~6v0>Y>0mGb)@+8Vy*ss^Y7#%~o2xV|XN%{k2F3QfxNo6P-AthhN69KJ3 z36aQ{n4_yuR-hb%l9uW$>Omyxzfe}7q)^PqMsPGr30tx}lobx#9K=l#c7FcVB*}(- z-awRTD7T@EosJfxOhrlm+(CoJ@MqA^xQ*ou~-EPKu4 zS&X47Tna}pRHbiVtSQWx$MX=Sb-l-vfgvl+_jt~rtat}8ftE`f&;zg=i_!|aX(*#n z=ArCd6E6&6H$o9W#U_j$f~0IST8^@!09}rXv$tRjQE~n@1SKje`v60Rn6Pa}*Q2!V z@Zbm(6`)*|pG8n0DlriKsg#^KFTbVr6`x6 zlrDHY`6$aiN6TTj=u5N+_VO>GYhf?@D@;>Fd)n8KLz(am9Dv=@GV~mRz3c{_$MSJw zyNTdHnSrtlWj@LnM1Sfn7(^-EMg>G8+1^H3gfbShAmI*Lin0`?gxO%#FpW{t|26Rt zW!YVirvXa3&=LHSXFn^+Sys7zt?K@HNJ8taa*c)+m|o3@orG^(#@h^Jpleu^q5HKS59S5GV)2=ezhUFlwn1`xW$!pOu%+Bm zT@obwD;>tGD}&^g%9!!$Q7T(cQ11oFeU!q9>f?1#9-F8xsv{@bqF|-I?lu1>@5sq* znD1v%`u-WN-l-$UKh_l!UvDx0=V>?5ItPqgpsO|h$i30P_Mr4t!_}wj%1xW+rg}Wn z2*|+51*YZrEK;Nt(3j~C!WWRjebd5KM}4`zy1TC2vgQ(Kv?Gm1;p*MGazxFf3`|MX z=c|OPmS8!#T@obXNa7@-A~0XhslKS%5za^x6nHo#LWIpn)7OnogFjx;tL z$t9)KN=N9ecN&BbkZ@+0YH1^fs^!6QyLK%Njn<@*VXlRbVlFhdL31T(28XG=L*zC! zdq8Ox0k=a{M~EC!^JhrZrAC&9s_R4K_?p8Y@f}IL6{=o`M5B+8BMSgX_P`8fbwHqh zVofOqWG?cjJyWd{iqX58sdf*Qdnhr})dit)pPJi{FK>{MJt69)P&s}?0IZIpYO*nN z0<+~DzeT=FeB27fO+FIsUpVcG!aZGteFQ9AeH1$htb+-oP`wH)RaM7@$sPUnf_F&W z7a=!OPlw4-HRr+!50+xz;$Zc+FgdwqXE?DDO1`>Zl$@ZJt(Kn@_0_bao@gmL||R3C%0|2p})s7k1RAN z3;Bw9Kofv(LOL&Scsya4zT+e1hU&ojvaMz=7Ldl&$j^hw)>Addz)W@WY=4k?zCPl! zY>mg$jes3N>Vx`dl$3)-s1^VhS81#cY9Kdnw-sQR~&tpm#*slGFC4GmbeRQ!(^ zzOM(VTN}u6t=gm2K4g11DOJchzKeX8pvg4vlHl)OZ+JYB#2*x-R&OY`=y4MY?WvZI zq+m1T`TONnP}mD+XyLg zfl=C|3$s~D0Jd$ddaj{dPpMd|evh(u^g55{c@p5Zl>ua&bjDyQ90Oi5?tKTqqTu%= zKF!(1;I9IIKJhzQ)xM47rZ0VgF5}6=0tJ1}k~8?X!=6aBha?QH!(0~kzZ0^Y)-Y_fkleXn;5xRU>HZp^x#AI6arqd;qNMJ zHAbU$;okQ_Ep=oQIiy-^%)Qi4)c(=(q`EW|^zX!vDa2z5b<>zy>Yq*IHqAZ)_>VC~ zIwJHa@9PPInn2%R8Fq+_Otqw-Il((I{$yZFP4#@V9N#Pt;7Y^5WH=OMNVezSWX2 zU-urVq7Q<$6{`Ww;h#Tb{dajhpHk3<*C7AG)s4;N2!|bfDb8xwQ@+Qf`>3rub;=$lqwiW6(m$T zYy%dKW_K>}cpfKyZ{cu`@)8#QR7`99C;{*>*m4YnOrn$qiqES#lq&hgU2D1%l z-J%dUzO8B1f$r#XIK=udN-9UCX zLYDVrPopQDf#FGkRv4y$q_08Ij=wkc(wyq*;g)inwp{`CGKOj(Rfc%d1F|)AhJimC zj|Ul4L07e2E4gv2CBViRI`jyrZxSiq3cyt?)p@*CLt60liB;2@W1r@!C)aTN z1*u7}(2cBqie(=H=DghjxD8FsJB0%$lGzTKs^n^?N#O%YP0bP|R;K|qYtL_SWLAd4a->EKz4_i2F`)J%x2qwp^Cqwo%O z^g#~xiA8Rp#84SUy(lqI-Ko&&PCY|iycwH8O4)kkCxK5p>cZ2=Zp42de4d1oDG4DA z^dyuhl2Dp*{9h@^LHU{T_+A+5gMi(SdtV1tlxAMEfQmJ`4073+ecpgzow!6G5D)wzX}Ck4fMOMNT11mmle|TeN4#t#r5mm4*zS+`QT@>@S{2*d&WE=clKqMI(7EJ zZ;=q9+7jedjzYaFUKh&zp9WU2k|&H6z(yUXMiE}2yJg^uZXoQ~hr@n3bEHm`IAV)V)AxMu}z;A3?B znvTyBY-zcU4;jD#heY{@u5WZk_kn_@M?Sg|d_@KMg9N=%6w)LePZ}(M-a7uFjxW*i zK01C=$1mzQJugYp6PW)9RBFM%=Y%9Z0nzomjt?6mXnMk->rEZ+sLt;phslqtZ}pJd zwV&{U;2Q1kkBmxI%XFN!-gFh{_{m}FA3fx@j@;n_H~Pngm?OP^bUaph znvP%7@m;!nC}NfDEFUQV!>^}wyjmK^)%SYJL5Z^kAsJ4*uM7RGe{&{GZNlD!9@V9S?s|0LeOjn5(H7NwUAA;%fmK!+TcOc~RFfT=+@H zFM8pT0iy0cF9|!eWYX1J#~16k5pH93e9~wx=8$MDqD$2oH(wSsEgf|21dg9#@(8Nx zbH6UXMjt6!66iYi|Hz-$a(eXqb78%SBZFn4p2@alD>nBw+*JOh0}WcL>}%@HSNsXnJ;}>#~kpcL3Iq>3cz*p&+_)$_)X*=78Na4v)42nHlUA%AiI3~}So$%w zh%9g$gIn>bfTMKo2F@+gx!L;Y8{FIchu9j^54=UB;;D}8TeF2KodMA`hq!S|z_m*C zC0nd9j)Kd8Q@wd!_3q_1ALuqqX9#J%!IF)B3@)N0mPx8H|El0_5QWs2|5V&K{`o5Z z{ER-6N4JtB8+?$we4yo)d??dfw^p}v!}{Mn_8UvA78V~GM8Cv_zONAC$iMt*3Y@&k zo+;?VI{p&j^doeB^in|FeQ4Yzm*S3mNYERxQ17PpsDNRIXn3$oo!n!a60{>D{%&XvzyZo_0gX(GHxh9Q89eAHl$; zo+T6Y!iAq|}#;-%Jw*@o&fgC(jG@-b~gR={jzmE`XIf z?h;nt=0(IVU8*!ou#f6eKXbODTd3Z?PXta!4|JvLc>ytMwyOFw*^j56?FX~@H$fA0RhlS4PBAyjT9_r?Zbp$sd}TI7hEYFI3*C{XVv-&z~fuVs-86 z5&A$(6u?;>Z>Y-sG3LE=w(W|*=}DiiWt=VV6jCK5r36XFc3H^ashP9m%fTiOi@Z`! z-FkXJeIXS1`4MiDf%ECwa4OwFGj^Ylcuudr#E|g2Y1}3IBG3HS#BE{V`Y1-}-t_=Z zwk!4upsS9rR->Lq%g^d;+irm`)Y%U?yJ2lSc9OQuDR4UXrYoLso^*N|cMS*Ojz-S- z89rm=CK?icuU6izsJuI1+>QE_?oe08d!ml-MIi+>)P1-j0Ap~5>9}{Ao&ubDDB*1( zkDVUBmZ&$V#k+O3cUJyLeJ2&{l18GoiV~qk$4_+q#M#M-k-9TC1l&m!(hwa_(C2Ed zjxW~nSiMmlbbPHUKZCG+pBE9k4Q+jj)0rGyHwF7ou&G6*8wFfX_i45|ij3rmVm&Wj z9)s10y3zRM4jYwDYy~+y zfuofl6M&P|ic$d?-L*wGm->ys={%0EQ^0AB^4=+Z$*Ym$)Hu{8j}pZ=QM@OL{h~N8 zif?%l@hbw0>W|Im<|RKpC?8XQB14OKk-Vb0Xq>cINQLR%oYV2x`2wexb9B{>5%Q&a z0^cKGsjGTp5C&qP&h}nVCvvvDSV(QtrMy?JBZ6H4HvK4Xg1%p~>ONId69>cdR=kK9 z)IxZYS0-FosCzP1NM-XP?vyT7=(Vt12hMxvTcKu*P9ya*)REk-r7-TD7Ls&4LpRq= zuXHDHGMB37v?v`v$IV4V>T^DCi@>pQ;8%b3$a7ecUj&;r$=(~($sBJWW$BMXx|Wp5 z)#Bd*n^$^TFpM^w2TlQ-H&5WkBVb@_;CxZARo=x{-u0=x8(w)gyYg;X<=s1#cl3XE za(j+bbcY(V^{7CO=GPB8F6r&ogGuU!B*v$dzN*oSFS-`!c-ksKf1;24X5dy+LqjtXFJt^7Y&J*nDzB~RvWj;F&`qzPjXLTDgzr=BboQr$Z4BdN z&X!*l#Zpn66vfY?=&3G)1$huJl4oIKLk*Pl)gId(emwxr!|tr0jUj6rC*+HY1WxDY zbm3WbD6D?Wi-=RYly#!u4iJSjOx;ORGev=PP1Jf`j5^$2w>(VRi$gYoKj0%yzfM6rq& zegzP=QMg7N)788me52 zNdhkHK8HJQW7HJFAX`){l<93AUF&r`f0m$ch(h`s_<#MXIlY*qSz-JhvQ3xot0s<= z!vY5B?9MIryf9j})!0)qQGQBRmra%%tDPsyZTIY&EO(IiyfQ_8!)H&|>9S2xH?EgM z)UH`_U3MX??w!oH}_{kLl^@YUEt}|4PflgXwq4 zQ`Jka$oO*TjPcKn8k^Z`^3+~0PkQNPHa@)G9(A5vP1$oNTTYkNc?;z2>a85P@1C`} z@?WxAwn&ard%Y%iRu8@=Z{G99VmU?G^YC@~t?GM@Eth|n)$1$Z&%>p1J=Q0*k(&0V z++oj&H{}XBVC2ZrqcTU0oR&Fi&vUEf;j((`Eqo~kO$kyn$H`syoL?>1Qq;z4<@h}% zYvrcCYS;!@RgbQdgVmkcasy@DxIG_ikYnUM@+Nt>@1C>**(S>=>iqZRCzXsq_2~O@ z+hF?c9$iMc5A$CwtAW>|r8Q(<)wV^p1{p`{M%h74+#% z2lPj`;DFya$TvzH@GD#8d2+Tof2-UsAm1*m<=fT$Tjh>Hg*t7N8LGSu*7XB(<+nAt-MrG=S<8S^EemE;YxL<`goz-?Ee4)@sYCt diff --git a/cve_pipeline.cpp b/cve_pipeline.cpp index b526288..1d2ad9c 100644 --- a/cve_pipeline.cpp +++ b/cve_pipeline.cpp @@ -75,25 +75,18 @@ namespace cve { vertexInputInfo.pVertexBindingDescriptions = bindingDescriptions.data(); vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); - VkPipelineViewportStateCreateInfo viewportInfo{}; - viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportInfo.viewportCount = 1; - viewportInfo.pViewports = &configInfo.viewport; - viewportInfo.scissorCount = 1; - viewportInfo.pScissors = &configInfo.scissor; - VkGraphicsPipelineCreateInfo pipelineInfo{}; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipelineInfo.stageCount = 2; pipelineInfo.pStages = shaderStages; pipelineInfo.pVertexInputState = &vertexInputInfo; pipelineInfo.pInputAssemblyState = &configInfo.inputAssemblyInfo; - pipelineInfo.pViewportState = &viewportInfo; + pipelineInfo.pViewportState = &configInfo.viewportInfo; pipelineInfo.pRasterizationState = &configInfo.rasterizationInfo; pipelineInfo.pMultisampleState = &configInfo.multisampleInfo; pipelineInfo.pColorBlendState = &configInfo.colorBlendInfo; pipelineInfo.pDepthStencilState = &configInfo.depthStencilInfo; - pipelineInfo.pDynamicState = nullptr; + pipelineInfo.pDynamicState = &configInfo.dynamicStateInfo; pipelineInfo.layout = configInfo.pipelineLayout; pipelineInfo.renderPass = configInfo.renderPass; @@ -123,22 +116,16 @@ namespace cve { vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline); } - PipelineConfigInfo CvePipeline::defaultPipelineConfigInfo(uint32_t width, uint32_t height) { - PipelineConfigInfo configInfo{}; - + void CvePipeline::defaultPipelineConfigInfo(PipelineConfigInfo& configInfo) { configInfo.inputAssemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; configInfo.inputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; configInfo.inputAssemblyInfo.primitiveRestartEnable = VK_FALSE; - configInfo.viewport.x = 0.0f; - configInfo.viewport.y = 0.0f; - configInfo.viewport.width = static_cast(width); - configInfo.viewport.height = static_cast(height); - configInfo.viewport.minDepth = 0.0f; - configInfo.viewport.maxDepth = 1.0f; - - configInfo.scissor.offset = {0, 0}; - configInfo.scissor.extent = {width, height}; + configInfo.viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + configInfo.viewportInfo.viewportCount = 1; + configInfo.viewportInfo.pViewports = nullptr; + configInfo.viewportInfo.scissorCount = 1; + configInfo.viewportInfo.pScissors = nullptr; configInfo.rasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; configInfo.rasterizationInfo.depthClampEnable = VK_FALSE; @@ -192,6 +179,11 @@ namespace cve { configInfo.depthStencilInfo.front = {}; // Optional configInfo.depthStencilInfo.back = {}; // Optional - return configInfo; + configInfo.dynamicStateEnables = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; + configInfo.dynamicStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + configInfo.dynamicStateInfo.pDynamicStates = configInfo.dynamicStateEnables.data(); + configInfo.dynamicStateInfo.dynamicStateCount = + static_cast(configInfo.dynamicStateEnables.size()); + configInfo.dynamicStateInfo.flags = 0; } } diff --git a/cve_pipeline.hpp b/cve_pipeline.hpp index b7b02d1..d33bc6e 100644 --- a/cve_pipeline.hpp +++ b/cve_pipeline.hpp @@ -7,14 +7,18 @@ namespace cve { struct PipelineConfigInfo { - VkViewport viewport; - VkRect2D scissor; + PipelineConfigInfo(const PipelineConfigInfo&) = delete; + PipelineConfigInfo& operator=(const PipelineConfigInfo&) = delete; + + VkPipelineViewportStateCreateInfo viewportInfo; VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo; VkPipelineRasterizationStateCreateInfo rasterizationInfo; VkPipelineMultisampleStateCreateInfo multisampleInfo; VkPipelineColorBlendAttachmentState colorBlendAttachment; VkPipelineColorBlendStateCreateInfo colorBlendInfo; VkPipelineDepthStencilStateCreateInfo depthStencilInfo; + std::vector dynamicStateEnables; + VkPipelineDynamicStateCreateInfo dynamicStateInfo; VkPipelineLayout pipelineLayout = nullptr; VkRenderPass renderPass = nullptr; uint32_t subpass = 0; @@ -29,7 +33,7 @@ namespace cve { CvePipeline& operator=(const CvePipeline&) = delete; void bind(VkCommandBuffer commandBuffer); - static PipelineConfigInfo defaultPipelineConfigInfo(uint32_t width, uint32_t height); + static void defaultPipelineConfigInfo(PipelineConfigInfo& configInfo); private: static std::vector readFile(const std::string& filepath); diff --git a/cve_swap_chain.cpp b/cve_swap_chain.cpp index a7e0d22..ec5f3ea 100644 --- a/cve_swap_chain.cpp +++ b/cve_swap_chain.cpp @@ -13,6 +13,18 @@ namespace cve { CveSwapChain::CveSwapChain(CveDevice &deviceRef, VkExtent2D extent) : device{deviceRef}, windowExtent{extent} { + init(); +} + +CveSwapChain::CveSwapChain(CveDevice &deviceRef, VkExtent2D extent, std::shared_ptr previous) + : device{deviceRef}, windowExtent{extent}, oldSwapChain{previous} { + init(); + + // Clean up old swap chain + oldSwapChain = nullptr; +} + +void CveSwapChain::init() { createSwapChain(); createImageViews(); createRenderPass(); @@ -162,7 +174,7 @@ void CveSwapChain::createSwapChain() { createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; - createInfo.oldSwapchain = VK_NULL_HANDLE; + createInfo.oldSwapchain = oldSwapChain ? oldSwapChain->swapChain : VK_NULL_HANDLE; if (vkCreateSwapchainKHR(device.device(), &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); diff --git a/cve_swap_chain.hpp b/cve_swap_chain.hpp index cc10591..346b530 100644 --- a/cve_swap_chain.hpp +++ b/cve_swap_chain.hpp @@ -6,6 +6,7 @@ #include // std lib headers +#include #include #include @@ -16,6 +17,7 @@ class CveSwapChain { static constexpr int MAX_FRAMES_IN_FLIGHT = 2; CveSwapChain(CveDevice &deviceRef, VkExtent2D windowExtent); + CveSwapChain(CveDevice &deviceRef, VkExtent2D windowExtent, std::shared_ptr previous); ~CveSwapChain(); CveSwapChain(const CveSwapChain &) = delete; @@ -39,6 +41,7 @@ class CveSwapChain { VkResult submitCommandBuffers(const VkCommandBuffer *buffers, uint32_t *imageIndex); private: + void init(); void createSwapChain(); void createImageViews(); void createDepthResources(); @@ -69,6 +72,7 @@ class CveSwapChain { VkExtent2D windowExtent; VkSwapchainKHR swapChain; + std::shared_ptr oldSwapChain; std::vector imageAvailableSemaphores; std::vector renderFinishedSemaphores; diff --git a/cve_window.cpp b/cve_window.cpp index a2348fd..4f36cfd 100644 --- a/cve_window.cpp +++ b/cve_window.cpp @@ -20,6 +20,8 @@ namespace cve { window = glfwCreateWindow(width, height, windowName.c_str(), nullptr, nullptr); + glfwSetWindowUserPointer(window, this); + glfwSetFramebufferSizeCallback(window, framebufferResizedCallback); } void CveWindow::createWindowSurface(VkInstance instance, VkSurfaceKHR *surface) { @@ -27,4 +29,11 @@ namespace cve { throw std::runtime_error("Failed to create window surface"); } } + + void CveWindow::framebufferResizedCallback(GLFWwindow *window, int width, int height) { + auto cveWindow = reinterpret_cast(glfwGetWindowUserPointer(window)); + cveWindow->framebufferResized = true; + cveWindow->width = width; + cveWindow->height = height; + } } diff --git a/cve_window.hpp b/cve_window.hpp index 0e08433..7dc5275 100644 --- a/cve_window.hpp +++ b/cve_window.hpp @@ -16,13 +16,17 @@ class CveWindow { bool shouldClose() { return glfwWindowShouldClose(window); }; VkExtent2D getExtent() { return { static_cast(width), static_cast(height) }; }; + bool wasWindowResized() { return framebufferResized; }; + void resetWindowResizedFlag() { framebufferResized = false; }; void createWindowSurface(VkInstance instance, VkSurfaceKHR *surface); private: + static void framebufferResizedCallback(GLFWwindow *window, int width, int height); void initWindow(); - const int width; - const int height; + int width; + int height; + bool framebufferResized = false; std::string windowName; GLFWwindow *window; diff --git a/first_app.cpp b/first_app.cpp index f0d8c72..c540d68 100644 --- a/first_app.cpp +++ b/first_app.cpp @@ -7,7 +7,7 @@ namespace cve { FirstApp::FirstApp() { loadModels(); createPipelineLayout(); - createPipeline(); + recreateSwapChain(); createCommandBuffers(); } @@ -48,8 +48,12 @@ namespace cve { } void FirstApp::createPipeline() { - auto pipelineConfig = CvePipeline::defaultPipelineConfigInfo(cveSwapChain.width(), cveSwapChain.height()); - pipelineConfig.renderPass = cveSwapChain.getRenderPass(); + assert(cveSwapChain != nullptr && "Cannot create pipeline before swap chain"); + assert(pipelineLayout != nullptr && "Cannot create pipeline before pipeline layout"); + + PipelineConfigInfo pipelineConfig{}; + CvePipeline::defaultPipelineConfigInfo(pipelineConfig); + pipelineConfig.renderPass = cveSwapChain->getRenderPass(); pipelineConfig.pipelineLayout = pipelineLayout; cvePipeline = std::make_unique( cveDevice, @@ -59,8 +63,31 @@ namespace cve { ); } + void FirstApp::recreateSwapChain() { + auto extent = cveWindow.getExtent(); + while (extent.width == 0 || extent.height == 0) { + extent = cveWindow.getExtent(); + glfwWaitEvents(); + } + + vkDeviceWaitIdle(cveDevice.device()); + + if (cveSwapChain == nullptr) { + cveSwapChain = std::make_unique(cveDevice, extent); + } else { + cveSwapChain = std::make_unique(cveDevice, extent, std::move(cveSwapChain)); + if (cveSwapChain->imageCount() != commandBuffers.size()) { + freeCommandBuffers(); + createCommandBuffers(); + } + } + + // Check if render pass is compatible + createPipeline(); + } + void FirstApp::createCommandBuffers() { - commandBuffers.resize(cveSwapChain.imageCount()); + commandBuffers.resize(cveSwapChain->imageCount()); VkCommandBufferAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; @@ -72,50 +99,78 @@ namespace cve { VK_SUCCESS) { throw std::runtime_error("Failed to allocate command buffers"); } + } - for (int i=0; i < commandBuffers.size(); i++) { - VkCommandBufferBeginInfo beginInfo{}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + void FirstApp::freeCommandBuffers() { + vkFreeCommandBuffers(cveDevice.device(), cveDevice.getCommandPool(), + static_cast(commandBuffers.size()), commandBuffers.data()); + commandBuffers.clear(); + } - if (vkBeginCommandBuffer(commandBuffers[i], &beginInfo) != VK_SUCCESS) { - throw std::runtime_error("Failed to begin command buffer recording"); - } + void FirstApp::recordCommandBuffer(int imageIndex) { + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - VkRenderPassBeginInfo renderPassInfo{}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = cveSwapChain.getRenderPass(); - renderPassInfo.framebuffer = cveSwapChain.getFrameBuffer(i); + if (vkBeginCommandBuffer(commandBuffers[imageIndex], &beginInfo) != VK_SUCCESS) { + throw std::runtime_error("Failed to begin command buffer recording"); + } - renderPassInfo.renderArea.offset = {0, 0}; - renderPassInfo.renderArea.extent = cveSwapChain.getSwapChainExtent(); + VkRenderPassBeginInfo renderPassInfo{}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = cveSwapChain->getRenderPass(); + renderPassInfo.framebuffer = cveSwapChain->getFrameBuffer(imageIndex); - std::array clearValues{}; - clearValues[0].color = {0.1f, 0.1f, 0.1f, 1.0f}; - clearValues[1].depthStencil = {1.0f, 0}; - renderPassInfo.clearValueCount = static_cast(clearValues.size()); - renderPassInfo.pClearValues = clearValues.data(); + renderPassInfo.renderArea.offset = {0, 0}; + renderPassInfo.renderArea.extent = cveSwapChain->getSwapChainExtent(); - vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + std::array clearValues{}; + clearValues[0].color = {0.1f, 0.1f, 0.1f, 1.0f}; + clearValues[1].depthStencil = {1.0f, 0}; + renderPassInfo.clearValueCount = static_cast(clearValues.size()); + renderPassInfo.pClearValues = clearValues.data(); - cvePipeline->bind(commandBuffers[i]); - cveModel->bind(commandBuffers[i]); - cveModel->draw(commandBuffers[i]); + vkCmdBeginRenderPass(commandBuffers[imageIndex], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - vkCmdEndRenderPass(commandBuffers[i]); - if (vkEndCommandBuffer(commandBuffers[i]) != VK_SUCCESS) { - throw std::runtime_error("Failed to record command buffer!"); - } + VkViewport viewport{}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = static_cast(cveSwapChain->getSwapChainExtent().width); + viewport.height = static_cast(cveSwapChain->getSwapChainExtent().height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + VkRect2D scissor{{0, 0}, cveSwapChain->getSwapChainExtent()}; + vkCmdSetViewport(commandBuffers[imageIndex], 0, 1, &viewport); + vkCmdSetScissor(commandBuffers[imageIndex], 0, 1, &scissor); + + cvePipeline->bind(commandBuffers[imageIndex]); + cveModel->bind(commandBuffers[imageIndex]); + cveModel->draw(commandBuffers[imageIndex]); + + vkCmdEndRenderPass(commandBuffers[imageIndex]); + if (vkEndCommandBuffer(commandBuffers[imageIndex]) != VK_SUCCESS) { + throw std::runtime_error("Failed to record command buffer!"); } } + void FirstApp::drawFrame() { uint32_t imageIndex; - auto result = cveSwapChain.acquireNextImage(&imageIndex); + auto result = cveSwapChain->acquireNextImage(&imageIndex); + if (result == VK_ERROR_OUT_OF_DATE_KHR) { + recreateSwapChain(); + return; + } if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { throw std::runtime_error("Failed to acquire swap chain image!"); } - result = cveSwapChain.submitCommandBuffers(&commandBuffers[imageIndex], &imageIndex); + recordCommandBuffer(imageIndex); + result = cveSwapChain->submitCommandBuffers(&commandBuffers[imageIndex], &imageIndex); + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || cveWindow.wasWindowResized()) { + cveWindow.resetWindowResizedFlag(); + recreateSwapChain(); + return; + } if (result != VK_SUCCESS) { throw std::runtime_error("Failed to present swap chain image!"); } diff --git a/first_app.hpp b/first_app.hpp index 374260c..442cd68 100644 --- a/first_app.hpp +++ b/first_app.hpp @@ -27,11 +27,14 @@ namespace cve { void createPipelineLayout(); void createPipeline(); void createCommandBuffers(); + void freeCommandBuffers(); void drawFrame(); + void recreateSwapChain(); + void recordCommandBuffer(int imageIndex); CveWindow cveWindow{WIDTH, HEIGHT, "Hello Vulkan!"}; CveDevice cveDevice{cveWindow}; - CveSwapChain cveSwapChain{cveDevice, cveWindow.getExtent()}; + std::unique_ptr cveSwapChain; std::unique_ptr cvePipeline; VkPipelineLayout pipelineLayout; std::vector commandBuffers;