From e324e47896b8425accce91f543b53180bf1979e0 Mon Sep 17 00:00:00 2001 From: matthew Date: Mon, 4 Aug 2025 19:06:32 +1000 Subject: [PATCH] added better transparency to the pbr shader --- assets/shaders/full_screen_triangle.vert.spv | Bin 0 -> 1152 bytes assets/shaders/gradient.comp.spv | Bin 4096 -> 4388 bytes assets/shaders/gui.frag.spv | Bin 2868 -> 3160 bytes assets/shaders/gui.vert.spv | Bin 5356 -> 5648 bytes assets/shaders/oit.frag.spv | Bin 0 -> 9180 bytes assets/shaders/pbr.frag.spv | Bin 6156 -> 9380 bytes assets/shaders/pbr.vert.spv | Bin 4336 -> 4628 bytes assets/shaders/triangle.frag.spv | Bin 2816 -> 3108 bytes assets/shaders/triangle.vert.spv | Bin 3708 -> 4000 bytes src/gears/game.d | 44 +++++ src/gears/main.d | 1 + src/gears/renderer.d | 37 +++- src/gears/vulkan.d | 190 ++++++++++++++++--- src/gears/vulkan_funcs.d | 2 + src/shaders/full_screen_triangle.vert.glsl | 7 + src/shaders/oit.frag.glsl | 84 ++++++++ src/shaders/pbr.frag.glsl | 37 +++- src/shaders/structures.layout | 16 ++ 18 files changed, 382 insertions(+), 36 deletions(-) create mode 100644 assets/shaders/full_screen_triangle.vert.spv create mode 100644 assets/shaders/oit.frag.spv create mode 100644 src/shaders/full_screen_triangle.vert.glsl create mode 100644 src/shaders/oit.frag.glsl diff --git a/assets/shaders/full_screen_triangle.vert.spv b/assets/shaders/full_screen_triangle.vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..c353e8c0a2c0bbbe786c20f6197933bbe77c9a68 GIT binary patch literal 1152 zcmYk4TWb?h6oq$lt&MH1wXK)hCdL~I#RnBZyrD7*fd&e`4ka1nz&II_sZ{Yn5Pz8u zzW9TD5nSKQIb}}R*?Xd|3|`>tynaQqr<~!^fsR4dAumTq)D8*EQzOX zo=gh&IYGBv)46Pto=oe4wiNYRZPhrZ8u@HtZS_m-k7@iNnHS0F`)rz=TFDP8ew@s! zl%UidgXid(@oeD=H_OC!OP={k-etv+`>O7Erphswa<5aDzj2G=IGZGAIkrRYBu&q9 z^vO;*ktU$ep6p(Un`J%je5YyRV^5oU184?Pz!PsP>d5zH zJ5uom!RY(?UzUf%wuDzozN$+;^Z@_VW9FeR^lM%(XZJl`S4^p2ORjn zV%qZD#ZLIn&_45bttw{jUs7@R1sNQDev^hhY{=k$O9Q^>IW)O6%(dzHpVEN0JjafH zcy7n@>?zd0teE3y;9%o_l}Hrz~0e=(frfb@I>|>D7suQ literal 0 HcmV?d00001 diff --git a/assets/shaders/gradient.comp.spv b/assets/shaders/gradient.comp.spv index 18575bcb9069e4e18141c323c255d4f462b2a4a2..035a46b8fc6c04cefef26165ed9c05b911341caa 100644 GIT binary patch delta 1157 zcmYk5&2G~`5XaXavD*Yhs|cZ}YLhmn3J{9aN}$4_fYc!104i4!H*p%1#Lb5zdO?9l zhrFR7u@d6P3uOGL<1F z>!WmSEGrFTWBGc2vn@zR^jvfx8eV-lGzX4qi~VZko%_en=e?dk6;~DH2RFgzml;Ox zsec*Gr~WL%`eMBGB7YiqLoi2j!4PkB7WiS5VDWFWTp?nL&c=RcKJ@f%j&fB$-nO=k ze*8rLf3T|CFdb?P$9=CACA(^DP1sATD(ox$e{I#p{$o`il2a0$^@A`7{TWSW{oE2; z*OHa<4dP?Fe3zDAT!gd83!{YXs$m@1TROrtM_$wly5v|YTz$8H84F7f?Vbcrl&$Su zvF)6{CpK~-NenXMV#6)yn5|x85L-o$Uzp7mG;0M=P>R9>}iI@yKYipEsf;+T2HZN#+J31VsA1mp19?A z^uXOv`&5);^FH%qz-J7cf-!Jw*iGSLBlOH^hp|ye?iG}(h>ooOx}VJjZ9vY;&3J6p zN&_EdJ(3OZ+bLF2>&g?G8jLwF)S&5_w`fb6I{^6q~Yj~0P=OfAd$BsQCalZDU3z;?uELhnUsnq5Y+azEhk@xv6mFFw2r VQQpr3`F{AK#wjNFYEk-T{{!)1eZK$z delta 819 zcmYjPyH4X!5WRjRP6*3_3J4M;Zogji0Q&Iu)1PH?J||f3`Ikw*=f~{N;nzak@e;omdL3eUVzOeni)0M=aTo;s z*awqW-6pX3+&}7fydF}Z4o-O1jM0);>UnR?A%9l+o60}cbIPs(U$y6^d3TBTw8JQj z{FrjmH+OBfPR*GnGSnF$ZvKwq#EX)&+Yy0$v}dNsQ0Ff%IS7y0ZHe~a-F`8?*=pnp zNZOW2>nd^{*g_+PaG<6dyWzMSM99|Q;~9gPEES#FjEl-s&52npw#h#JtAV zhcHKD-!n|U>KlrhX=V)Kh{m>uFs_jrb~8*?3hoA1I6OD&Dx6brZZ3^^6FXr}qh?MP z$Zo+k0*P%H!Qj4dVana&qt2@ip;H@$2F@#XI6X z@%!R^F#$gjzp9wTSQQ8QThaQv4%IemrauTD|9Bi`c~)h~I4`E*&sCHr<0LMmzkt5~ z^l5+aI2_Jq;k^7Mjl(p_;&7A{@vuzJ;zgXsF3E;zHS!HQisav+qq}pDyeh+S5uJv^ zJe6oV`r~d%29g&w*46oq>8JTgl>Shkac&f$#<4j|;^*NsDvRV?=$f^s=CdOIi8JPz z)8e;k_0+)A6JimQ7f6%SN!c93`EZA5dXmJM(=6k47Cud3@=WpCHdj}=BA)AZfql2W zWNNUf^=J}};^M`7fkU%28pe}6m4Wr;y^qAyiFbcgM9;sQMyGlL8;?FXil(zPE}q1Z zGL|(?Z&^pUp4Ge1Pq1)6L zbsr_;aW#)^J+Y(K^I1Hs(#Ynfp5W9uN>AcZ9+q{=x}NC#T013gi;h~mcuUWvFZGVn z*(CCm&X*Zza!#W8(!lB0&^K@F8_==jrf(OyeFNbx#sy;7{4W~Nv&5js=aVGU7|kiN ztKCKCrV%ruisNm#uE&V$YjsJi=r|jKF?3JbTE# zZNDQlZ`GM>h|l+h`ys#V2ZrCTVt0n1!G7~F`VPB4JdD_2e|i`_2KJYjnrvv@7DG0u!kOd8rvQ3r-&9{IcD*?H(O@ zH}%Q7Et{ahu4_mAdg2?3MSf&z-_s{G!xsFDMy6(9=&2QXogSH5f!&n;Qlldt@i`aq z@khSW$ee3S-$wKaK8}eCF;RmA&AKRhE_0oz$fzViizpI zi?Jm)GBXVkqoj>B(m5NGTq(~qY!9Frzsg_bxVh6#hOV-th z58x9}*|6+_Pe5YBf#${LVNF3ys1S)Ho2I;y|85vp(W z_aC`7k1uzTRr!}^**BGw|P+}d0ABlqOU%B8xNR~ zzyD2cdBm z?EfEJ>I9u9co-+46ZWvX;B=IZ7 X4#Z9+&@zfF*f*RF*?@7Z8q1@rHuicz?Tk0_GHY2K@pZPx89I8Vd5;-Q;l#rzJKhvGd=O+ z+d1H)Bujhkq(e`LXmXUK`>dTFWdAw#v)^vD`bR0aP~=*wn#^@wEiN%f&2#p$^f>GH z7*|Hzj=F-lL$!$i6Z8II{(q?kn7`&-4QfqRInOGcS1%G+_RjfShewth>75{68Uazd zFZa{VUN^~lZ8IHb80ptREXUJ4c;gLxvzQt}H_;@QbQQ{W9lnM)WmEWOSuU1~V{Bl2 z%J}B7${c`x3TyEo^h<+%vr4ZFu!R!2{vO4cH!08d?tyPWSDYW#hmu<>aBP&^O~>hp ztq@wzE$4wPS?*4OV+XA8z;Rke@qpVtXFU&{2X?`7PYN8b!U|8J9F$in4o=L$ITM%2 z+wi@GSa&Bbk$bSXVp_fANVA;L^k?)~4cITEi!$Gq67Q_zE$jxqK+LmJ>LL>FVOfJ` zC<<$^>lNgDunxwu1~JbK2~ClqmX*f(N8lm!I+SS|mO`Fs#JoCXSzN@CcPksapMbbt mm-QKMew;kBh`BOy%fMX80hCSiD_>zFD0#*ckEg#YrSKo%?}uOj delta 842 zcmYjPT}vB56rD}>!>!R6qJp({IVC zBY)-8UUJPmJU$PjFbZN0Y33;)PxnIP+++34DX%D0Z@xrvBBLZ@dqSyS&T87R(7ljJ zCp_btyqHY?I^T0Ab}Ga=nzRFv)f>pU-~dE(&DM+GrT<2Y-zPln#<=#5{HAkv(=&;P5JJDfqb=gQ8CUJ3#B;UQ>etmY=_-uyl=c_)n5Os#Kzj#53x7vN#jZ zxUp`A_&KF*m3VW#SnJ&0zJ5o!LoG#>g}sC){?o;~%f-Zh&j0k^-Mc)gmvV;>`M0<> z$s5b-i*c!EAs!8{MqfuZ{K^&ajQ(pC?~1B%Uc~^J+X7)eep}SND{f?|``*%SzU}! zua^drwuXC7yBkONrQK~!`t42nm!)@?%atDSjLtCUac41qhNiK>!^zz45?-y9D{;O* zs_w!!%}NpL(U5EoS~@L759|$wMNOt*~1o|BQtVt zv2l(p-*Dt`EN3Yy4)jHV(PCSMYxYIeVF$C1!S2s*=#bUBN$s&=?a)EEEh^O-u`LNEv+FPS#KqxjoaDt{ z|I>G`mRumtJm0i!8}wdim3epQhwnqXY`hoj*O~raN>o+!OkzW44f+0r*gOmx7Dvr6 z4!t=JjJTZ0;;0?Qp*P2Y5jQBZ9#S6LA7Gpz{O%7ha)Uh-V4N4Q$3?8k0r55w!}OyX zYO+SWBU2MwDtS|8dOvXDs6iZh7{^9f9J0kB6Gy+qp%2HUllNe*Yz+2@JI@+0cf0@e z&mf+=Pd>3BJ{=uH|cJ$EB8-blcJUVtU>8YVRPk-DQhV^F{FqoYq z{OAX)Rb+nj0JbE+Y+siLnC}?Msl_(e@YyA zy7IFots=%@(#Z>keUZ1b9y!q*>8t}jV6Dt{^0n}_A)s2xF^&@hlpWKh+&@i94&4> z*qAr{F7mkP%cL`=$(yrg>ywi_%Im~!@;bFPOQsftKfOnyM{b(G*7Tjyx8Jd4o$0%z z-_#xr+4-Ac?YP&RZuYYD>#v)YLuU?k5ySLB$;`+6uafNCU=ol2)gsOS>v@ehJ(>PR z$;^Rx`u~zRy@R9QDb8G3?=@cMn*m0?{o>>!ex~$$67D29?Zw#Sn*nA-9*92ni>UDp zapLb4Q3L&e$CwlSeN&Vb;r}gfqpsP1C^_eK@ZX6T$7?p!dqe~l(k%7&dtu~dKH;FB zHWBsy;0^fFANpe+V-5Z+nHeZBOVTNa^A@KA8){yoQdw6zu#i?*e1CyiSyi-x80Z%Ts-X(ccmPx@crxicCz*+16N7RRSzg8-i_?&cV zt&+@~!KsDL`wTW$I`8N`lF5(%8tG#tgX53R-%nsG^p+6EzBAaHr-ZQY_;Q!{oyUDb z=l#2@Nx!>Ef1pW!Fwl9=9u9Q!J=&xn40PUHe$!a}-UKch4hKep`f%e7q6g@tDPZSGvXJBwO75lCfFb_auW|p`9bo_eJCaryuqR z44M6*H*(?o0}*zM{gKCbkId)Cl8G~)pGd|Je4T2t4?h*L204+%{Y)~r&FANmZ9d^T z{6aW3o6j#LgIT>_NhTNgpr7MIlIa7R_3&%S^kBJ}-)}_V7WZ4p4~f8856&kTGH3G< z5&iR4{!zp`iO%=rPa^VnXOCR;q=Sag20q5Cg^;*(^R*3U3NMvySNavreoTbAwy2<7A^( z>tnohuuVQ58(6pxtP%0Nu@hyZ9<}&)7j(-#Su$&mjdu)vwNB7zVN)be5hn(l>~5#Et5=7(#q_+cUj_L<%ex4vdcCWq;>C5LC@aOwDfb2iYY zi^xqaWQ(06*>cTP&AHO)l|Ffk(Rm-{$<`{FIT2%bnETWw9UC#c*XXuRM@e2FA97)% zE_LQf2D7z6XTHpx9^uyG(UR%W_ISQzFxz8nVBvZ)SF5#9vdw9MWb|jm6pPEXi~<9uxwfwNazyly!=rH46pNCzXQ z`JCf@?2UbqbZUTGjTcJ>H=lDQ<3m2`qT^#ZUm}^h7XMPo^k(trNhTgY;?eQp4B6Vi z(K%nN72NW_OmaA{^QD8?oyP`7yq#Ij6FT>Vd~nP6a><-YyL)-bV3rRX81Z)ZxF_K| z!8w~DVoVe9PD~Y_E~4IH;=Bc5-6Hmm`oz6Lgx?+h40U-d66XxX;tb9ZwjNPIL|$ae z(<_-gS1Av9`$S+nMXWP*!I%d*i6@W6Um%(IeLlV@8Eluxa+V~6_lx+OhdKiyJ)6nD zhhQ&@tRA+o9(AqWg_7y%IrV{TZ|+RVb3}~UBGz)2_~9aYK0@5qvL>0eH2vZx{Zg-U z_E`JfBJ$Kl*2f-?(=++dSNk>CE17)-w;UHqwj9Ku<7f6)dV5aXYFr{29DjO5w;HdK zObu|$@oLG`$cczS$ItBhBx4^GS&hpigX7P<(XGbilBof1Ij)dwIfy~Wk9_RGmEO+& zAlv?omfR*{%oW-G92v;1lG&@H#I4?ICF66o$a;RAWbn)VdcR)sRU&Zf<66nBqOJOu zz-z?cAOeFJqeS#{t#V+0qX-{zS&lbJrncpHvt%%cVLA5s9B&bZ54o)Ww@M}lXNTVl zoc*_n@MW-u_<&i=+a(i|6IskVBojkTV(91?*GVRZc@l#Un8jQ#nV4{G z-z6Q~*7n_!SzB<6dynK+Q5g4L>EKuTIlfOavEUZ>e#y=CJ|GNypO5>XWH90_?n9C- zj(MQt7rv#;ae;_&w8+lad@s)vKSsp)S}4xlpCx{S$le0<8=Lgon)KVf&Kb!{{;-I= z6QpteKO$m}aw2T>OAT;4S09xOhK+jY+&SVuCYmDxw^%S+i;qhtHeCBpNC&t4pY%R< zZa*a*3}Vn9>t$#ECdv4a$LicHnL6RQ{j_v^8T5t^n8n;8nV6i&&fsSx6GKg6@By=! zTO|`SD6*K(N+yOLiNOcV=Jz?t>?=0*2id HJ6q2K_Rp;g literal 0 HcmV?d00001 diff --git a/assets/shaders/pbr.frag.spv b/assets/shaders/pbr.frag.spv index 4f0dc6384393ae06ac739025201b204e0dc9e18f..36729ed2ad622f2b2e1fc94520c58078888a82e0 100644 GIT binary patch literal 9380 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 RA9qT|2mC*}i|E|*{{m&nS;YVV diff --git a/assets/shaders/pbr.vert.spv b/assets/shaders/pbr.vert.spv index 09f599096fedc900708294420b8dcd787218c646..c0ddc20ecc2e16bb74f2e3a16fc0ddedaa58f8d0 100644 GIT binary patch delta 1000 zcmYjPyG|QX5WV{}CUzcL$O=Ueh|{=;B1;q?a6te;q@;*Mq&zXZ_%6GW4anFM4N9GY z!n*tf1qJd~q|O&mrihgMLC(3mSJ|;<=bm$B#&c))&(hWNreilM!neddQ5TuW?UAsB zg(Kt3BDThJP3!S^vpxF>%vX2>m+&KadVAS+Hhn?ubw4_i8?Q!5A_suN!;kqnKRP!Y z>-XgOa5Ru-hKtpm6EtH&Sk#X*c{~(8I*{W`-7HB)XA+z*Vm0rE^HdyW_hQ*S=?wFh z0(u1*@7yO=torU#JTLY6TAzRD=P$PbzV1e z>N{u0ox_t}o|8^4yleZLqZbe&X$MJM#uD5u;b%D0b}%xRVsd$AuBSCuYyWdyy=>|< z_U3TZEsY($9(xL47cFA7QOUPRxdDG@6hyn=77eGyQ$afh;-Ji4HVPsKBDYfF{DNCI zoVqJIZ~|s;83nOgaJwaLy5QazPPMARHfP}W*MSEMehTk9w0_=+Jbn1*L720dw&ST1(>QX&YYM$tB84da_pKQTJQ>- QIx&|)&fs*?zCW@50rmrN;Q#;t delta 723 zcmYk3%}PR15XaB`@-s70kdREX7A~UP6(-b57X?KGm6qLWR}#$152#(QAh%a&(NcVZ z9zlA79w4YU=>NaoQ;z(dGryU0oEcwMzq5;)n)3^vBEljf8e(cOp$cV~&nt=HaVb&- ztV1Sbjb2NdW{9d2)8nNY$bs3nyDhVgqwonskkQOrt7Uike@p?pZZ(^Oo(<*`HOJJG zO3iuFQ%k&~|KF+i?Z^J0%enySM*1@9CVC3rU+y_#kgOXyd>^^z2P3)7SLXOi`~HT# z8u+kp*wR&2KkH~bfx zcl2OP{09i}=%3)9;K4t^qX!e`^L8KfzB{A9GZmkh*IQ}Q7; z!$*e}BX=t~OhykGIq8RD%^Idef~+^at}jcI%>lbE{2qW`u|PoqngE z3~AE#b53+qOC{0Bt(XL#%%;Gf{Jhl1bt_C3g@6J}@To7tK9W^@1U;%&_-wS3`8Q57R%SrjrZ zN<#L-P>%M$hm|>ii_rGN)jt`P1>+ydY2NE58SBgV&BK0;^Q4=`hr~Q$>bVrOnUT=F zbbr5>CCGTXx&$mcNq+SX<1SpFKHg|LlX70I>*uahhkvI1YwiEm&p%EJ_+O`9WA7^a z9HgDJlVn_{n7rZ!A$PVrF~dD0*e}POERQ>RQSFOJ9l4Ve%y7@6IRBaMvDy*s$6NPF zesDGACX$pbQN%Ow`N9?oxd;huYuYbfux@F$fR5RWsUp@Gz#RC*K3Ys|`bCGb$*kH8 ztY@&b0n9hphQ(Chbf}ojw#~o}8*FC);~BZbH;bufbl?dGc{3(&awTsbt>EoyA0aMK z+#ymcLxGGGt|6nx-Ju& zE~$hsNW_({TVC{2Z_4`1*d+(sHEYjliaj>=SEsg5t+J{0`I9d@y>ma$4}^#iRGOTdZu3L)9Kp(*e!F2U~%B`y7)u4>7LxIP@8`4NqugGv_$t3 zzikku)>TQp5W5&%maAK2(KT6}Bm$N!d}e`=)r%_S+P)P7YC|Gkiro`!h*IHI!hur( zpU(klsN3?7xGwK~cq1NDO|#yLO&{Q7;WIt3hWJe9u_(9Zl=rgpR^Y_r_m}=^-TDLJ Chi|z6 delta 815 zcmYk4xlY4C5Qf)R4j_P)B0?btq;eSv5K^FsfH)9L1F0jU7!eV3B#xAhijpGQijION zWt1o25hy8n2s#Spw|Bu~jd$nUo!yz=el7j1uW4!}$r1`%WEpnGA~TuFl!;|2=Hz@k z-5_{E?#y1Ms%EeTf6%h~Hi#Q|gPz+*R)QG}4CeZmJ?}R7V+yfu@9Jta^oS*x&EK`0 zV)IWeUqFujpVJAvaWEQSUyAmbdWrT`^*p_uaPEiiXT3sX7S2EPoP|@Ca7zFF+NIH; zC#+diI25eKO(R=qQ3Uhvx?aEIyTPD0MvNX>yl!L_XWlj}^+soCegkV{HWi9^lN>GC zObc69Y2J*rU!fQ#8TNv$#u#$I%98PVDiRf9U}a0L&}ay@8)FH<_9WvIaY9P09Lg0M z(}Fc)Y(cP7$@o_)`zWPE4Hx9-8dAnpKnxYo1yq2bkqUY^r!cG;3P`b&#H0d};SQMG zM@r3y>8ZxwGUY1DKOirXm#K&&8e!ly5#w{fifo1cmhVihjRw(z%sQrdR9cjU80CW% Z=@gW*Lk`h!3&em};J5{`Gk;pnE5FeLTG0Ri diff --git a/src/gears/game.d b/src/gears/game.d index 21e2a74..12f6c34 100644 --- a/src/gears/game.d +++ b/src/gears/game.d @@ -3,15 +3,18 @@ import includes; import renderer : Destroy; import renderer; import util; +import alloc; import platform; import math; import core.stdc.math : cosf, sinf; +import std.algorithm.sorting; f32 g_DELTA; struct Game { Renderer rd; + Arena frame_arena; PlatformWindow* window; @@ -19,6 +22,7 @@ struct Game Pipeline triangle_pipeline; Pipeline compute_pipeline; Pipeline ui_pipeline; + Pipeline oit_pipeline; GlobalUniforms globals; PushConst pc; @@ -36,6 +40,7 @@ InitGame(PlatformWindow* window) { Game g = { rd: InitRenderer(window), + frame_arena: CreateArena(MB(16)), window: window, timer: CreateTimer(), globals: { @@ -76,13 +81,23 @@ InitGame(PlatformWindow* window) ] }; + GfxPipelineInfo oit_info = { + vertex_shader: "shaders/full_screen_triangle.vert.spv", + frag_shader: "shaders/oit.frag.spv", + }; + CompPipelineInfo gradient_info = { shader: "shaders/gradient.comp.spv", }; + Logf("pbr"); g.pbr_pipeline = BuildGfxPipeline(&g.rd, &pbr_info); + Logf("triangle"); g.triangle_pipeline = BuildGfxPipeline(&g.rd, &triangle_info); + Logf("ui"); g.ui_pipeline = BuildGfxPipeline(&g.rd, &ui_info); + Logf("oit"); + g.oit_pipeline = BuildGfxPipeline(&g.rd, &oit_info); g.compute_pipeline = BuildCompPipeline(&g.rd, &gradient_info); PrintShader(&g.rd, &g.pbr_pipeline, VK_SHADER_STAGE_VERTEX_BIT); @@ -107,8 +122,12 @@ Cycle(Game* g) { g_DELTA = DeltaTime(&g.timer); + Reset(&g.frame_arena); + ProcessInputs(g, &g.camera); + //Sort(g, g.camera.pos, &g.model); + //Update(g, &g.camera); Update(&g.camera); @@ -234,3 +253,28 @@ Update(Camera* cam) Vec4 pos = rotation * Vec4(cam.velocity * 0.5 * g_DELTA, 0.0); cam.pos += pos.xyz; } + +void +Sort(Game* g, Vec3 pos, Model* model) +{ + f32[] lengths = AllocArray!(f32)(&g.frame_arena, model.positions.length); + + foreach(i; 0 .. lengths.length) + { + model.pos_indices[i] = cast(u32)i; + lengths.ptr[i] = fabs(Norm(&pos) - Norm(model.positions.ptr + i)); + } + + makeIndex!("a < b")(lengths, model.pos_indices); + + Logf("%s", model.positions.length); + + foreach(i, v; model.pos_indices) + { + model.indices[i+0] = cast(u32)((3*v)+0); + model.indices[i+1] = cast(u32)((3*v)+1); + model.indices[i+2] = cast(u32)((3*v)+2); + } + + UpdateIndexBuffer(&g.rd, model); +} diff --git a/src/gears/main.d b/src/gears/main.d index c2edf1e..0683ddc 100644 --- a/src/gears/main.d +++ b/src/gears/main.d @@ -14,6 +14,7 @@ import core.stdc.string : memcpy; // 2. Set up VK_AMD_shader_info // 3. Determine how to better handle inputs // 4. Make assets loaded from the disk in debug mode +// 5. Set up multisampling void main(string[] argv) { diff --git a/src/gears/renderer.d b/src/gears/renderer.d index e089c93..aa476e9 100644 --- a/src/gears/renderer.d +++ b/src/gears/renderer.d @@ -4,7 +4,7 @@ import assets; import util; import alloc; import vulkan; -import vulkan : Destroy, Init, Draw, DrawIndexed, Bind, BindUIBuffers, BeginRender, SetUniform, PrepComputeDrawImage, Dispatch, FinishFrame, BeginFrame, WaitIdle, PushConstants, BindBuffers, SetClearColor; +import vulkan : Destroy, Init, Draw, DrawIndexed, Bind, BindUIBuffers, BeginRender, SetUniform, PrepComputeDrawImage, Dispatch, FinishFrame, BeginFrame, WaitIdle, PushConstants, BindBuffers, SetClearColor, ImageBarrier; import assets; import std.math.traits : isNaN; import util : Logf; @@ -33,6 +33,8 @@ enum Format : VkFormat RGB_F32 = VK_FORMAT_R32G32B32_SFLOAT, RGBA_F32 = VK_FORMAT_R32G32B32A32_SFLOAT, RGBA_UINT = VK_FORMAT_B8G8R8A8_UINT, + R_U32 = VK_FORMAT_R32_UINT, + RG_U32 = VK_FORMAT_R32G32_UINT, RGBA_UNORM = VK_FORMAT_R8G8B8A8_UNORM, RGBA_SRGB = VK_FORMAT_R8G8B8A8_SRGB, } @@ -47,6 +49,7 @@ enum BufferType : int Uniform = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, Storage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, Staging = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + BufferView = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, } alias BT = BufferType; @@ -161,6 +164,10 @@ struct Model Buffer[] materials; ImageView[] textures; + + Vec3[] positions; + u32[] pos_indices; + u32[] indices; } Renderer @@ -260,6 +267,12 @@ Bind(Renderer* rd, Pipeline* pipeline) Bind(&rd.vk, pipeline); } +void +UpdateIndexBuffer(Renderer* rd, Model* model) +{ + assert(Transfer(&rd.vk, &model.index_buffer, model.indices), "UpdateIndexBuffer failure"); +} + void DrawRect(Renderer* rd, f32 p0_x, f32 p0_y, f32 p1_x, f32 p1_y, Vec4 col) { @@ -345,7 +358,6 @@ LoadModel(Renderer* rd, string name) u32[] tex_lookup = AllocArray!(u32)(&rd.temp_arena, m3d.numtexture); model.textures = AllocArray!(ImageView)(&rd.arena, m3d.numtexture); - Logf("numtexture %s", m3d.numtexture); foreach(i; 0 .. m3d.numtexture) { u32 w = m3d.texture[i].w; u32 h = m3d.texture[i].h; u32 ch = m3d.texture[i].f; @@ -360,7 +372,6 @@ LoadModel(Renderer* rd, string name) Material[] mats = AllocArray!(Material)(&rd.temp_arena, m3d.nummaterial); u32[] mat_lookup = AllocArray!(u32)(&rd.temp_arena, m3d.nummaterial); model.materials = AllocArray!(Buffer)(&rd.arena, m3d.nummaterial); - Logf("nummaterial %s", m3d.nummaterial); foreach(i; 0 .. m3d.nummaterial) { const(char)[] mat_name = m3d.material[i].name[0 .. strlen(m3d.material[i].name)]; @@ -391,7 +402,6 @@ LoadModel(Renderer* rd, string name) } break; case m3dp_map_D: { - Logf("alpha %s", i); mats[i].alpha_texture = tex_lookup[m3d.material[i].prop[j].value.textureid]; mats[i].alpha_has_texture = true; } break; @@ -447,8 +457,10 @@ LoadModel(Renderer* rd, string name) m3dv_t* vertex; - u32[] indices = AllocArray!(u32)(&rd.temp_arena, m3d.numface * 3); + u32[] indices = AllocArray!(u32)(&rd.arena, m3d.numface * 3); Vertex[] vertices = AllocArray!(Vertex)(&rd.temp_arena, m3d.numface * 3); + Vec3[] positions = AllocArray!(Vec3)(&rd.arena, m3d.numface); + u32[] pos_indices = AllocArray!(u32)(&rd.arena, m3d.numface); foreach(i; 0 .. m3d.numface) { @@ -484,6 +496,11 @@ LoadModel(Renderer* rd, string name) indices[i0] = i0; indices[i1] = i1; indices[i2] = i2; + + Vec3 center = (vertices[i0].pos + vertices[i1].pos + vertices[i2].pos) / 3.0; + + positions[i] = center; + pos_indices[i] = i; } for(u64 i = 0; i < indices.length; i += 3) @@ -529,6 +546,10 @@ LoadModel(Renderer* rd, string name) WriteDescriptors(&rd.vk, DT.Material, model.materials, mat_lookup); WriteDescriptors(&rd.vk, DT.SampledImage, model.textures, tex_lookup); + model.positions = positions; + model.indices = indices; + model.pos_indices = pos_indices; + Reset(&rd.temp_arena); return model; @@ -618,6 +639,12 @@ ClearColorEnabled(Renderer* rd, bool enabled) rd.vk.enable_clear_color = enabled; } +void +ImageBarrier(Renderer* rd) +{ + ImageBarrier(&rd.vk); +} + void Destroy(Renderer* rd, Model* model) { diff --git a/src/gears/vulkan.d b/src/gears/vulkan.d index 9d673bc..be4026b 100644 --- a/src/gears/vulkan.d +++ b/src/gears/vulkan.d @@ -80,6 +80,10 @@ const VkImageUsageFlags VK_DRAW_IMAGE_USAGE_FLAGS = VK_IMAGE_USAGE_TRANSFER_SRC_ VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; +const VkImageUsageFlags TEXTURE_IMAGE_USAGE = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; +const VkImageUsageFlags CONVERT_IMAGE_USAGE = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; +const VkImageUsageFlags OIT_IMAGE_USAGE = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + enum StepInitialized : u32 { Renderer = 1, @@ -117,6 +121,14 @@ struct Image VkImageLayout layout; } +struct BufferView +{ + Buffer base; + VkBufferView view; + + alias base this; +} + struct ImageView { Image base; @@ -199,6 +211,7 @@ struct Vulkan DescBindings[DT.max] desc_bindings; VkSampler nearest_sampler; + VkSampler oit_sampler; VkPipeline[FRAME_OVERLAP] last_pipeline; VkPipelineLayout pipeline_layout; @@ -224,6 +237,9 @@ struct Vulkan bool enable_clear_color; VkClearColorValue clear_color; + BufferView a_buffer_view; + ImageView aux_image; + alias queues this; } @@ -755,7 +771,7 @@ TransferAssets(Vulkan* vk) pragma(inline): void CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, u32 ch, u8[] data) { - CreateImageView(vk, view, w, h); + CreateImageView(vk, view, w, h, FMT.RGBA_UNORM, TEXTURE_IMAGE_USAGE); if (ch == 4) { @@ -768,7 +784,7 @@ CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, u32 ch, u8[] data) assert(Transfer(vk, &buf, data), "CreateImageView failure: Buffer Transfer error"); ImageView conv_view; - CreateImageView(vk, &conv_view, w, h, FMT.RGBA_F32); + CreateImageView(vk, &conv_view, w, h, FMT.RGBA_F32, CONVERT_IMAGE_USAGE); WriteConvDescriptor(vk, &buf); WriteConvDescriptor(vk, &conv_view); @@ -872,7 +888,25 @@ FinishComputePass(Vulkan* vk) } pragma(inline): void -CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, Format format = FMT.RGBA_UNORM) +CreateBufferView(Vulkan* vk, BufferView* view, u64 size, Format format) +{ + CreateBuffer(vk, &view.base, BT.BufferView, size, false); + + VkBufferViewCreateInfo info = { + sType: VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, + buffer: view.buffer, + format: format, + range: size, + }; + + VkResult result = vkCreateBufferView(vk.device, &info, null, &view.view); + VkCheckA("CreateBufferView failure: vkCreateBufferView failed", result); + + view.size = size; +} + +pragma(inline): void +CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, Format format = FMT.RGBA_UNORM, VkImageUsageFlags usage) { VmaAllocationCreateInfo alloc_info = { usage: VMA_MEMORY_USAGE_GPU_ONLY, @@ -887,7 +921,7 @@ CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, Format format = FMT.R format: format, tiling: VK_IMAGE_TILING_OPTIMAL, initialLayout: VK_IMAGE_LAYOUT_UNDEFINED, - usage: format == FMT.RGBA_F32 ? (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT) : (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT), + usage: usage, samples: VK_SAMPLE_COUNT_1_BIT, extent: { width: w, @@ -996,6 +1030,27 @@ PushConstants(Vulkan* vk, PushConst* pc) ); } +void +ImageBarrier(Vulkan* vk) +{ + VkMemoryBarrier2 barrier = { + sType: VK_STRUCTURE_TYPE_MEMORY_BARRIER_2, + srcStageMask: VK_PIPELINE_STAGE_2_TRANSFER_BIT, + srcAccessMask: VK_ACCESS_2_TRANSFER_WRITE_BIT, + dstStageMask: VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, + dstAccessMask: VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT, + }; + + VkDependencyInfo dependency = { + sType: VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + dependencyFlags: VK_DEPENDENCY_BY_REGION_BIT, + memoryBarrierCount: 1, + pMemoryBarriers: &barrier, + }; + + vkCmdPipelineBarrier2(vk.cmds[vk.frame_index], &dependency); +} + bool Transfer(T)(Vulkan* vk, Buffer* buf, T[] data) { @@ -1323,7 +1378,7 @@ CreateGraphicsPipeline(Vulkan* vk, GfxPipelineInfo* build_info) VkPipelineDepthStencilStateCreateInfo depth_info = { sType: VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, depthTestEnable: VK_TRUE, - depthWriteEnable: VK_TRUE, + depthWriteEnable: VK_FALSE, depthCompareOp: VK_COMPARE_OP_GREATER_OR_EQUAL, depthBoundsTestEnable: VK_FALSE, stencilTestEnable: VK_FALSE, @@ -1380,36 +1435,36 @@ CreateGraphicsPipeline(Vulkan* vk, GfxPipelineInfo* build_info) VkPipelineShaderStageCreateInfo[] shader_info = [ { sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - stage: VK_SHADER_STAGE_VERTEX_BIT, - pName: "main", + stage: VK_SHADER_STAGE_FRAGMENT_BIT, + pName: "main", }, { sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - stage: VK_SHADER_STAGE_FRAGMENT_BIT, + stage: VK_SHADER_STAGE_VERTEX_BIT, pName: "main", }, ]; Arena* arena = &vk.frame_arenas[0]; - u8[] vert_bytes = LoadAssetData(arena, build_info.vertex_shader); u8[] frag_bytes = LoadAssetData(arena, build_info.frag_shader); + u8[] vert_bytes = LoadAssetData(arena, build_info.vertex_shader); assert(vert_bytes && frag_bytes, "Unable to load shaders"); - Result!(Shader) vert_module = BuildShader(vk, vert_bytes); Result!(Shader) frag_module = BuildShader(vk, frag_bytes); + Result!(Shader) vert_module = BuildShader(vk, vert_bytes); assert(vert_module.ok && frag_module.ok, "Unable to build vulkan shaders"); scope(exit) { - Destroy(vk, vert_module.value); Destroy(vk, frag_module.value); + Destroy(vk, vert_module.value); } - __traits(getMember, shader_info.ptr + 0, "module") = vert_module.value; - __traits(getMember, shader_info.ptr + 1, "module") = frag_module.value; + __traits(getMember, shader_info.ptr + 0, "module") = frag_module.value; + __traits(getMember, shader_info.ptr + 1, "module") = vert_module.value; VkSpecializationInfo vert_spec_info = { dataSize: build_info.vert_spec.size, @@ -1652,6 +1707,7 @@ InitDescriptors(Vulkan* vk) { type: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, descriptorCount: 4096 }, { type: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: 4096 }, { type: VK_DESCRIPTOR_TYPE_SAMPLER, descriptorCount: 4096 }, + { type: VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, descriptorCount: 4096 }, ]; VkDescriptorPoolCreateInfo pool_info = { @@ -1667,7 +1723,17 @@ InitDescriptors(Vulkan* vk) if (success) { - VkDescriptorBindingFlags[4] shared_binding_flags; + VkDescriptorSetLayoutBinding[] shared_bindings = [ + { binding: 0, descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, + { binding: 1, descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, + { binding: 2, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, + { binding: 3, descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, + { binding: 4, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, + { binding: 5, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, + { binding: 6, descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, + ]; + + VkDescriptorBindingFlags[] shared_binding_flags = AllocArray!(VkDescriptorBindingFlags)(&vk.frame_arenas[0], shared_bindings.length); shared_binding_flags[] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT; VkDescriptorSetLayoutBindingFlagsCreateInfo shared_flag_info = { @@ -1676,13 +1742,6 @@ InitDescriptors(Vulkan* vk) pBindingFlags: shared_binding_flags.ptr, }; - VkDescriptorSetLayoutBinding[] shared_bindings = [ - { binding: 0, descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, - { binding: 1, descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, - { binding: 2, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, - { binding: 3, descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, - ]; - VkDescriptorSetLayoutCreateInfo shared_set_info = { sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, pNext: &shared_flag_info, @@ -1814,20 +1873,89 @@ InitDescriptors(Vulkan* vk) if (success) { + VkSamplerCreateInfo sampler_info = { + sType: VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + magFilter: VK_FILTER_LINEAR, + minFilter: VK_FILTER_LINEAR, + addressModeU: VK_SAMPLER_ADDRESS_MODE_REPEAT, + addressModeV: VK_SAMPLER_ADDRESS_MODE_REPEAT, + addressModeW: VK_SAMPLER_ADDRESS_MODE_REPEAT, + anisotropyEnable: VK_FALSE, + compareEnable: VK_FALSE, + borderColor: VK_BORDER_COLOR_INT_OPAQUE_BLACK, + mipmapMode: VK_SAMPLER_MIPMAP_MODE_NEAREST, + unnormalizedCoordinates: VK_FALSE, + }; + + result = vkCreateSampler(vk.device, &sampler_info, null, &vk.oit_sampler); + success = VkCheck("vkCreateSampler failure", result); + } + + if (success) + { + // TODO: move this elsewhere later + // Also add samples/supersampling scaling + + CreateBufferView(vk, &vk.a_buffer_view, (u32.sizeof * 2) * vk.swapchain_extent.width * vk.swapchain_extent.height, FMT.RG_U32); + CreateImageView(vk, &vk.aux_image, vk.swapchain_extent.width, vk.swapchain_extent.height, FMT.R_U32, OIT_IMAGE_USAGE); + + VkDescriptorBufferInfo a_buffer_info = { + buffer: vk.a_buffer_view.buffer, + offset: 0, + range: VK_WHOLE_SIZE, + }; + + VkDescriptorImageInfo aux_info = { + sampler: vk.oit_sampler, + imageView: vk.aux_image.view, + imageLayout: VK_IMAGE_LAYOUT_GENERAL, + }; + VkDescriptorImageInfo sampler_info = { sampler: vk.nearest_sampler, }; - VkWriteDescriptorSet write = { - sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - dstSet: vk.desc_sets[DT.Shared], - dstBinding: 3, - descriptorCount: 1, - descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, - pImageInfo: &sampler_info, + VkDescriptorImageInfo oit_sample_info = { + sampler: vk.oit_sampler, }; - vkUpdateDescriptorSets(vk.device, 1, &write, 0, null); + VkWriteDescriptorSet[] writes = [ + { + sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: vk.desc_sets[DT.Shared], + dstBinding: 3, + descriptorCount: 1, + descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, + pImageInfo: &sampler_info, + }, + { + sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: vk.desc_sets[DT.Shared], + dstBinding: 4, + descriptorCount: 1, + descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, + pBufferInfo: &a_buffer_info, + pTexelBufferView: &vk.a_buffer_view.view, + }, + { + sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: vk.desc_sets[DT.Shared], + dstBinding: 5, + descriptorCount: 1, + descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + pImageInfo: &aux_info, + }, + { + sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: vk.desc_sets[DT.Shared], + dstBinding: 6, + descriptorCount: 1, + descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, + pImageInfo: &oit_sample_info, + }, + ]; + + vkUpdateDescriptorSets(vk.device, cast(u32)writes.length, writes.ptr, 0, null); WriteDrawImageDesc(vk); } @@ -2467,6 +2595,7 @@ InitDevice(Vulkan* vk) descriptorBindingSampledImageUpdateAfterBind: VK_TRUE, descriptorBindingStorageImageUpdateAfterBind: VK_TRUE, descriptorBindingStorageBufferUpdateAfterBind: VK_TRUE, + descriptorBindingStorageTexelBufferUpdateAfterBind: VK_TRUE, descriptorBindingPartiallyBound: VK_TRUE, shaderSampledImageArrayNonUniformIndexing: VK_TRUE, shaderUniformBufferArrayNonUniformIndexing: VK_TRUE, @@ -2488,6 +2617,7 @@ InitDevice(Vulkan* vk) shaderStorageBufferArrayDynamicIndexing: VK_TRUE, shaderStorageImageArrayDynamicIndexing: VK_TRUE, samplerAnisotropy: VK_TRUE, + fragmentStoresAndAtomics: VK_TRUE, }, }; @@ -2557,6 +2687,7 @@ CheckDeviceFeatures(VkPhysicalDevice device) VkPhysicalDeviceFeatures features = features2.features; bool result = true; + result &= cast(bool)features.fragmentStoresAndAtomics; result &= cast(bool)features.shaderUniformBufferArrayDynamicIndexing; result &= cast(bool)features.shaderSampledImageArrayDynamicIndexing; result &= cast(bool)features.shaderStorageBufferArrayDynamicIndexing; @@ -2566,6 +2697,7 @@ CheckDeviceFeatures(VkPhysicalDevice device) result &= cast(bool)features_12.descriptorIndexing; result &= cast(bool)features_12.bufferDeviceAddress; result &= cast(bool)features_12.descriptorBindingUniformBufferUpdateAfterBind; + result &= cast(bool)features_12.descriptorBindingStorageTexelBufferUpdateAfterBind; result &= cast(bool)features_12.descriptorBindingSampledImageUpdateAfterBind; result &= cast(bool)features_12.descriptorBindingStorageImageUpdateAfterBind; result &= cast(bool)features_12.descriptorBindingStorageBufferUpdateAfterBind; diff --git a/src/gears/vulkan_funcs.d b/src/gears/vulkan_funcs.d index 282195e..af4be1e 100644 --- a/src/gears/vulkan_funcs.d +++ b/src/gears/vulkan_funcs.d @@ -58,6 +58,7 @@ version(AMD_GPU) PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR = null; PFN_vkCreateImage vkCreateImage = null; PFN_vkCreateImageView vkCreateImageView = null; +PFN_vkCreateBufferView vkCreateBufferView = null; PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR = null; PFN_vkGetDeviceQueue vkGetDeviceQueue = null; PFN_vkCreateSemaphore vkCreateSemaphore = null; @@ -154,6 +155,7 @@ LoadDeviceFunctions(Vulkan* vk) vkCreateSwapchainKHR = cast(PFN_vkCreateSwapchainKHR)vkGetDeviceProcAddr(vk.device, "vkCreateSwapchainKHR"); vkCreateImage = cast(PFN_vkCreateImage)vkGetDeviceProcAddr(vk.device, "vkCreateImage"); vkCreateImageView = cast(PFN_vkCreateImageView)vkGetDeviceProcAddr(vk.device, "vkCreateImageView"); + vkCreateBufferView = cast(PFN_vkCreateBufferView)vkGetDeviceProcAddr(vk.device, "vkCreateBufferView"); vkGetSwapchainImagesKHR = cast(PFN_vkGetSwapchainImagesKHR)vkGetDeviceProcAddr(vk.device, "vkGetSwapchainImagesKHR"); vkGetDeviceQueue = cast(PFN_vkGetDeviceQueue)vkGetDeviceProcAddr(vk.device, "vkGetDeviceQueue"); vkCreateSemaphore = cast(PFN_vkCreateSemaphore)vkGetDeviceProcAddr(vk.device, "vkCreateSemaphore"); diff --git a/src/shaders/full_screen_triangle.vert.glsl b/src/shaders/full_screen_triangle.vert.glsl new file mode 100644 index 0000000..001d5b1 --- /dev/null +++ b/src/shaders/full_screen_triangle.vert.glsl @@ -0,0 +1,7 @@ +#version 460 + +void main() +{ + vec4 pos = vec4((float((gl_VertexIndex >> 1U) & 1U)) * 4.0 - 1.0, (float(gl_VertexIndex & 1U)) * 4.0 - 1.0, 0, 1.0); + gl_Position = pos; +} diff --git a/src/shaders/oit.frag.glsl b/src/shaders/oit.frag.glsl new file mode 100644 index 0000000..d9b84d5 --- /dev/null +++ b/src/shaders/oit.frag.glsl @@ -0,0 +1,84 @@ +#version 460 + +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_nonuniform_qualifier : require + +#define COMPOSITE_PASS + +#include "structures.layout" + +layout (location = 0) out vec4 FragColor; + +void BubbleSort(inout uvec2 array[OIT_LAYERS], int n) +{ + for(int i = (n - 2); i >= 0; --i) + { + for(int j = 0; j <= i; ++j) + { + if(uintBitsToFloat(array[j].g) >= uintBitsToFloat(array[j+1].g)) + { + uvec2 temp = array[j+1]; + array[j+1] = array[j]; + array[j] = temp; + } + } + } +} + +float UnPreMultSRGBToLinear(float col) +{ + return col < 0.04045f ? col / 12.92f : pow((col + 0.055f) / 1.055f, 2.4f); +} + +vec4 UnPreMultSRGBToLinear(vec4 col) +{ + col.r = UnPreMultSRGBToLinear(col.r); + col.g = UnPreMultSRGBToLinear(col.g); + col.b = UnPreMultSRGBToLinear(col.b); + return col; +} + +void DoBlend(inout vec4 color, vec4 base_color) +{ + color.rgb += (1 - color.a) * base_color.rgb; + color.a += (1 - color.a) * base_color.a; +} + +void DoBlendPacked(inout vec4 color, uint fragment) +{ + vec4 unpacked_color = unpackUnorm4x8(fragment); + unpacked_color = UnPreMultSRGBToLinear(unpacked_color); + unpacked_color.rgb *= unpacked_color.a; + DoBlend(color, unpacked_color); +} + +void main() +{ + ivec2 coord = ivec2(gl_FragCoord.xy); + int store_mask = 0; + int view_size = int(G.res.x) * int(G.res.y); + int sample_id = 0; + int list_pos = view_size * OIT_LAYERS * sample_id + coord.y * int(G.res.x) + coord.x; + uvec2 array[OIT_LAYERS]; + + vec4 color = vec4(0.0); + + int fragments = int(imageLoad(ImageAux, coord).r); + fragments = min(OIT_LAYERS, fragments); + + for (int i = 0; i < fragments; i++) + { + array[i] = imageLoad(ImageABuffer, list_pos + i * view_size).rg; + } + + BubbleSort(array, fragments); + + vec4 color_sum = vec4(0.0); + + for(int i = 0; i < fragments; i++) + { + DoBlendPacked(color_sum, array[i].x); + } + + FragColor = color_sum; +} diff --git a/src/shaders/pbr.frag.glsl b/src/shaders/pbr.frag.glsl index d1170ed..e47f671 100644 --- a/src/shaders/pbr.frag.glsl +++ b/src/shaders/pbr.frag.glsl @@ -10,7 +10,7 @@ layout (location = 0) in struct FragDataIn { vec2 uv; } FragData; -layout (location = 0) out vec4 FragColor; +layout (location = 0, index = 0) out vec4 FragColor; vec4 CalculateDirectionalLight(vec4 diff_col, vec4 diff_samp, vec4 light_col, vec3 dir, vec3 normal) { @@ -25,8 +25,27 @@ vec4 CalculateDirectionalLight(vec4 diff_col, vec4 diff_samp, vec4 light_col, ve return (ambient + diffuse); } +float UnPreMultLinearToSRGB(float col) +{ + return col < 0.0031308f ? col * 12.92f : (pow(col, 1.0f / 2.4f) * 1.055f) - 0.055f; +} + +vec4 UnPreMultLinearToSRGB(vec4 col) +{ + col.r = UnPreMultLinearToSRGB(col.x); + col.g = UnPreMultLinearToSRGB(col.x); + col.b = UnPreMultLinearToSRGB(col.x); + return col; +} + void main() { + ivec2 coord = ivec2(gl_FragCoord.xy); + int store_mask = 0; + int view_size = int(G.res.x) * int(G.res.y); + int sample_id = 0; + int list_pos = view_size * OIT_LAYERS * sample_id + coord.y * int(G.res.x) + coord.x; + vec4 col = Materials[nonuniformEXT(PC.mat_id)].diffuse; vec4 tex_col = texture(sampler2D(Textures[nonuniformEXT(Materials[nonuniformEXT(PC.mat_id)].albedo_texture)], SamplerNearest), FragData.uv); @@ -39,5 +58,19 @@ void main() out_col.a = alpha_col.a; } - FragColor = out_col; + vec4 srgb_col = UnPreMultLinearToSRGB(out_col); + + uvec4 store_value = uvec4(packUnorm4x8(srgb_col), floatBitsToUint(gl_FragCoord.z), store_mask, 0); + + uint old_counter = imageAtomicAdd(ImageAux, coord, 1u); + if (old_counter < OIT_LAYERS) + { + imageStore(ImageABuffer, list_pos + int(old_counter) * view_size, store_value); + + FragColor = vec4(0.0); + } + else + { + FragColor = vec4(out_col.rgb * out_col.a, out_col.a); // Change to vec4(0.0) to disable tail blending + } } diff --git a/src/shaders/structures.layout b/src/shaders/structures.layout index ca31899..b150455 100644 --- a/src/shaders/structures.layout +++ b/src/shaders/structures.layout @@ -2,6 +2,8 @@ // **** STRUCTS MUST BE PACKED IN OPTIMAL PACKING ORDER TO MATCH D STRUCTS **** // **************************************************************************** +#define OIT_LAYERS 64 + layout (set = 0, binding = 0) uniform GlobalUniforms { mat4 view_matrix; mat4 projection_matrix; @@ -20,6 +22,20 @@ layout (rgba16f, set = 0, binding = 2) uniform image2D DrawImage; layout (set = 0, binding = 3) uniform sampler SamplerNearest; +#ifdef COMPOSITE_PASS + +layout (set = 0, binding = 4, rg32ui) uniform restrict readonly uimageBuffer ImageABuffer; + +layout (set = 0, binding = 5, r32ui) uniform restrict readonly uimage2D ImageAux; + +#else + +layout (set = 0, binding = 4, rg32ui) uniform coherent uimageBuffer ImageABuffer; + +layout (set = 0, binding = 5, r32ui) uniform coherent uimage2D ImageAux; + +#endif + layout (set = 1, binding = 0) uniform texture2D Textures[]; layout (set = 2, binding = 0) uniform Material {