From 041b52ed44f4a281013595beebd24a9f5b0025cd Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Tue, 11 Jun 2024 17:20:47 -0700 Subject: [PATCH] compute sprite batch --- .../Compiled/CalculateSquares.comp.spv | Bin 844 -> 932 bytes .../Shaders/Compiled/SpriteBatch.comp.spv | Bin 0 -> 5208 bytes .../Compiled/TexturedQuadColor.frag.spv | Bin 0 -> 736 bytes .../TexturedQuadColorWithMatrix.vert.spv | Bin 0 -> 1400 bytes .../Shaders/Source/CalculateSquares.comp | 2 +- .../Content/Shaders/Source/SpriteBatch.comp | 79 ++++++ .../Shaders/Source/TexturedQuadColor.frag | 13 + .../Source/TexturedQuadColorWithMatrix.vert | 20 ++ Common/VertexTypes.cs | 53 +++- Examples/ComputeSpriteBatchExample.cs | 244 ++++++++++++++++++ MoonWorksGraphicsTests.csproj | 39 --- Program.cs | 3 +- 12 files changed, 406 insertions(+), 47 deletions(-) create mode 100644 Common/Content/Shaders/Compiled/SpriteBatch.comp.spv create mode 100644 Common/Content/Shaders/Compiled/TexturedQuadColor.frag.spv create mode 100644 Common/Content/Shaders/Compiled/TexturedQuadColorWithMatrix.vert.spv create mode 100644 Common/Content/Shaders/Source/SpriteBatch.comp create mode 100644 Common/Content/Shaders/Source/TexturedQuadColor.frag create mode 100644 Common/Content/Shaders/Source/TexturedQuadColorWithMatrix.vert create mode 100644 Examples/ComputeSpriteBatchExample.cs diff --git a/Common/Content/Shaders/Compiled/CalculateSquares.comp.spv b/Common/Content/Shaders/Compiled/CalculateSquares.comp.spv index ede2b14d007ded3bfa735bf1b38e29e6943d60ac..dce77365fa85d0eece933aff8f10d60faa9109ee 100644 GIT binary patch delta 111 zcmX@ZwuGIVnMs+Qfq{{Mn}K&CccD8A0~dq4PrSRozq^lXd~!iSd~r!-PHKEkW?pK1 sN@h`Na!F=cDgy%x0|%12%)I2B(i9{G6RRh4voHuUK!D_CPDW=Y07R`FF8}}l delta 27 jcmZ3&euj;knMs+Qfq{{Mn}K5@cj3e%lQyR@+A#qDN!JD% diff --git a/Common/Content/Shaders/Compiled/SpriteBatch.comp.spv b/Common/Content/Shaders/Compiled/SpriteBatch.comp.spv new file mode 100644 index 0000000000000000000000000000000000000000..1b4ee940249ea2a390868c537b6048c484854cdc GIT binary patch literal 5208 zcmZ{mXLnRp6oxN^3D`vxI|fm)Aa=kW6b)z;CH9tt$pl6xnK-#Yv4Oq!-h1!8`@vu3 z7uWK6?!8-&v-D=|b@u!2efD|JKIh&^&+H|0vuswjQ?^U?TUI{vv)M2iTyHTB3=R!0 zpU%gYpLo)-X6%~v6p7~SMox`!4mL5`oHVc#wmZDse5@ZcSL@+#HskMrIoXccz~Jz} z`t<{Y=M2}UriQ2Ut*ypzt2x;i9&2_Q^}M;IVcxtXuQ^$7&5Wf9H8RrmYpgMkH560B zQ_rT>@Ib4*akRB=a!b2Dnm5~%>(&(Ux!InKLsOk*-Z;BGF*TDn){N$(aJ~E)^O}1fvdtyl(A=~+ z$1S+)88^1`yggB*6`b=+u1u}5BM-0a>t&5j-nbc9?6Wvj{O+F0+f!2O?RIAjw>VFE zd-~6L*0L#ZdnW(8f!+~0pDo2|KAEWj6VeG|xao2+5Oy#W|IMy3LpPY4^?^z#=`2=2E!eV~(F6LV^`X(3JqGxh_ zn6=uBskZ2s>su#q)K;5ZPc`2@s?FY5PaN9Bzk=Y-ov*(aIj-M_`SgML z7#1eKH+Tm|edie8k#QC#e`A2thf zkKzL{ALk#$SZXfu60myI5c!AUJKy}JjKG|$>cS%l_Wq4`VSkrm zzHxt(Qta=Mcs0B5o3Jb9cf)VR>FmKfxf>>b20M0t;)pH6ms?Gy?^_?{JL-FA%sk)i z#aJJ9G3(4{JQ$PnaqT6HhhX;0xvnKP&pEy;hhol|g*j&_NpXLn$bHopH#&nZ&i}# zow7gXos1c~h|^HRshD$DBo?vLD$Y3(kJ#x67w#z|2$qZZ1^E3~^yor-Yg(tfx9j1Y@0{+~MG4p4_luL5^U}U= z0K2BOtzoYFT+3)I?#(6m_RDu8yq_1ugl?$Mc$Q3p1kE`&FML({_ zkNvE`*CKXJh0}P%uB~F`M?7NJ!KqtKu4mks_iz|0}jT>Ig7&zL&R8^z=TZ^XA} zPw~DQuVd!ON6r|&_c?MJ_~yyG#t5UF{y5{N%HPb`tbD(pH&lL$aRRe`FXJ>e54#5q z;+cxe8AHPs{E-STV7v))ttYE*&&~Me$gid+TN!V`I+$l~O-D7#n;+}nil4538(7Zu zw^y2O$CqD;g{C|3M=GqQZJ2uwP22I!kq=FG;)f<{h9>##SZKNnKh<hnVia%0e zH9dxT2SU^1_~yumrYG=2lQlz=y!oN&N&HmPQ(!qYS?d|bXR)Yd{4mUWApbNLwVuOI zYdsH^OZWEzSl)XO^3Sc7<U@4<4Zh9AK4<++v` degt=G_z6xvH2jPo8mti-UR zUO02-oO|B;@fPxzduBPSTFp*ub6S>{V$w=!biJ`RSgmJ+>zgYabt|MsJPj*bQ4!21 z;ey1zP!*1Zro80TM1KWUHv7@VqE*cGe0MZ*y(fRVT>7i^R}}bBxCs1Nm;}>x_z~bM zXMEve8okf521kx;Z^xXp|8p{V8^%$bs2?8Y$?~T7crsr`L882q&iWF34&ykPDP^wi zu*W$>2Tlz*d&8-5A+Xbq_w~<#v;XdXTP}S4^c6ODI{Gh3>j_=?c_TRc^zvn6nZp@mwZnn%Lvywg25@W=5OB;;O$EWjRdiwO)6C$=v zy9^{|M^Q*edNr{r=W9~f9qFF*SUQll^|fSwE3soXO)w6Fv$J6QK8$9wa9;dK;xMsk z98PT>M}_?!6SvWbvuTtprp*9P5zV_jC zis_X7I>OWZhvL5_;iowN66Zy{B(7WWobhFITi7fWyI#h#my)+>ac+NV3UXFH=9h1j z*x5TfFD7Xe*FLt2Z;>Rm&(qG>A3{GTvY%7?HOsHwCRua|Pi=VQE(); + + RenderPipeline = new GraphicsPipeline(GraphicsDevice, renderPipelineCreateInfo); + + ComputePipeline = new ComputePipeline( + GraphicsDevice, + TestUtils.GetShaderPath("SpriteBatch.comp"), + "main", + new ComputePipelineCreateInfo + { + ShaderFormat = ShaderFormat.SPIRV, + ReadOnlyStorageBufferCount = 1, + ReadWriteStorageBufferCount = 1, + ThreadCountX = 64, + ThreadCountY = 1, + ThreadCountZ = 1 + } + ); + + Sampler = new Sampler(GraphicsDevice, SamplerCreateInfo.PointClamp); + + // Create and populate the sprite texture + var resourceUploader = new ResourceUploader(GraphicsDevice); + + SpriteTexture = resourceUploader.CreateTexture2DFromCompressed(TestUtils.GetTexturePath("ravioli.png")); + + resourceUploader.Upload(); + resourceUploader.Dispose(); + + SpriteComputeTransferBuffer = TransferBuffer.Create( + GraphicsDevice, + TransferUsage.Buffer, + TransferBufferMapFlags.Write, + MAX_SPRITE_COUNT + ); + + SpriteComputeBuffer = Buffer.Create( + GraphicsDevice, + BufferUsageFlags.ComputeStorageRead, + MAX_SPRITE_COUNT + ); + + SpriteVertexBuffer = Buffer.Create( + GraphicsDevice, + BufferUsageFlags.ComputeStorageWrite | BufferUsageFlags.Vertex, + MAX_SPRITE_COUNT * 4 + ); + + SpriteIndexBuffer = Buffer.Create( + GraphicsDevice, + BufferUsageFlags.Index, + MAX_SPRITE_COUNT * 6 + ); + + TransferBuffer spriteIndexTransferBuffer = TransferBuffer.Create( + GraphicsDevice, + TransferUsage.Buffer, + TransferBufferMapFlags.Write, + MAX_SPRITE_COUNT * 6 + ); + + spriteIndexTransferBuffer.Map(false, out byte* mapPointer); + uint *indexPointer = (uint*) mapPointer; + + for (uint i = 0, j = 0; i < MAX_SPRITE_COUNT * 6; i += 6, j += 4) + { + indexPointer[i] = j; + indexPointer[i + 1] = j + 1; + indexPointer[i + 2] = j + 2; + indexPointer[i + 3] = j + 3; + indexPointer[i + 4] = j + 2; + indexPointer[i + 5] = j + 1; + } + spriteIndexTransferBuffer.Unmap(); + + var cmdbuf = GraphicsDevice.AcquireCommandBuffer(); + var copyPass = cmdbuf.BeginCopyPass(); + copyPass.UploadToBuffer(spriteIndexTransferBuffer, SpriteIndexBuffer, false); + cmdbuf.EndCopyPass(copyPass); + GraphicsDevice.Submit(cmdbuf); + } + + public override void Update(TimeSpan delta) + { + + } + + public override unsafe void Draw(double alpha) + { + Matrix4x4 cameraMatrix = + Matrix4x4.CreateOrthographicOffCenter( + 0, + 640, + 480, + 0, + 0, + -1f + ); + + CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); + Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); + if (swapchainTexture != null) + { + // Build sprite compute transfer + SpriteComputeTransferBuffer.Map(true, out byte* mapPointer); + ComputeSpriteData *dataPointer = (ComputeSpriteData*) mapPointer; + + for (var i = 0; i < MAX_SPRITE_COUNT; i += 1) + { + dataPointer[i] = new ComputeSpriteData + { + Position = new Vector3(Random.Next(640), Random.Next(480), 0), + Rotation = (float) (Random.NextDouble() * System.Math.PI * 2), + Size = new Vector2(32, 32), + Color = new Vector4(1f, 1f, 1f, 1f) + }; + } + SpriteComputeTransferBuffer.Unmap(); + + // Upload compute data to buffer + var copyPass = cmdbuf.BeginCopyPass(); + copyPass.UploadToBuffer(SpriteComputeTransferBuffer, SpriteComputeBuffer, true); + cmdbuf.EndCopyPass(copyPass); + + // Set up compute pass to build sprite vertex buffer + var computePass = cmdbuf.BeginComputePass(new StorageBufferReadWriteBinding + { + Buffer = SpriteVertexBuffer, + Cycle = true + }); + + computePass.BindComputePipeline(ComputePipeline); + computePass.BindStorageBuffer(SpriteComputeBuffer); + computePass.Dispatch(MAX_SPRITE_COUNT / 64, 1, 1); + + cmdbuf.EndComputePass(computePass); + + // Render sprites using vertex buffer + var renderPass = cmdbuf.BeginRenderPass( + new ColorAttachmentInfo(swapchainTexture, false, Color.Black) + ); + + renderPass.BindGraphicsPipeline(RenderPipeline); + renderPass.BindVertexBuffer(SpriteVertexBuffer); + renderPass.BindIndexBuffer(SpriteIndexBuffer, IndexElementSize.ThirtyTwo); + renderPass.BindFragmentSampler(new TextureSamplerBinding(SpriteTexture, Sampler)); + renderPass.PushVertexUniformData(cameraMatrix); + renderPass.DrawIndexedPrimitives(0, 0, MAX_SPRITE_COUNT * 2); + + cmdbuf.EndRenderPass(renderPass); + } + + GraphicsDevice.Submit(cmdbuf); + } + + public override void Destroy() + { + ComputePipeline.Dispose(); + RenderPipeline.Dispose(); + Sampler.Dispose(); + SpriteTexture.Dispose(); + SpriteComputeTransferBuffer.Dispose(); + SpriteComputeBuffer.Dispose(); + SpriteVertexBuffer.Dispose(); + SpriteIndexBuffer.Dispose(); + } +} diff --git a/MoonWorksGraphicsTests.csproj b/MoonWorksGraphicsTests.csproj index b0a6d00..a2c7b04 100644 --- a/MoonWorksGraphicsTests.csproj +++ b/MoonWorksGraphicsTests.csproj @@ -17,45 +17,6 @@ - - - $(DefaultItemExcludes);Examples\**\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Program.cs b/Program.cs index 347f978..55bb91c 100644 --- a/Program.cs +++ b/Program.cs @@ -37,7 +37,8 @@ class Program : Game new TriangleVertexBufferExample(), new VertexSamplerExample(), new VideoPlayerExample(), - new WindowResizingExample() + new WindowResizingExample(), + new ComputeSpriteBatchExample() ]; int ExampleIndex = 0;