diff --git a/Examples/CopyTextureExample.cs b/Examples/CopyTextureExample.cs new file mode 100644 index 0000000..7b78b81 --- /dev/null +++ b/Examples/CopyTextureExample.cs @@ -0,0 +1,184 @@ +using System.Runtime.InteropServices; +using MoonWorks; +using MoonWorks.Graphics; +using MoonWorks.Input; +using MoonWorks.Math.Float; + +namespace MoonWorksGraphicsTests +{ + class CopyTextureExample : Example + { + private Texture OriginalTexture; + private Texture TextureCopy; + private Texture TextureSmall; + + public override unsafe void Init(Window window, GraphicsDevice graphicsDevice, Inputs inputs) + { + Window = window; + GraphicsDevice = graphicsDevice; + + Window.SetTitle("CopyTexture"); + + // Create and populate the GPU resources + var resourceUploader = new ResourceUploader(GraphicsDevice); + + OriginalTexture = resourceUploader.CreateTexture2DFromCompressed( + TestUtils.GetTexturePath("ravioli.png") + ); + + resourceUploader.Upload(); + resourceUploader.Dispose(); + + // Load the texture bytes so we can compare them. + var pixels = ImageUtils.GetPixelDataFromFile( + TestUtils.GetTexturePath("ravioli.png"), + out var width, + out var height, + out var byteCount + ); + + CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); + + var textureCreateInfo = new TextureCreateInfo + { + Width = OriginalTexture.Width, + Height = OriginalTexture.Height, + Depth = OriginalTexture.Depth, + IsCube = OriginalTexture.IsCube, + LayerCount = OriginalTexture.LayerCount, + LevelCount = OriginalTexture.LevelCount, + SampleCount = OriginalTexture.SampleCount, + Format = OriginalTexture.Format, + UsageFlags = OriginalTexture.UsageFlags + }; + + // Create a 1:1 copy of the texture + TextureCopy = new Texture(GraphicsDevice, textureCreateInfo); + + // Create a download transfer buffer + TransferBuffer compareBuffer = new TransferBuffer( + GraphicsDevice, + TransferUsage.Texture, + TransferBufferMapFlags.Read, + byteCount + ); + + var copyPass = cmdbuf.BeginCopyPass(); + copyPass.CopyTextureToTexture( + OriginalTexture, + TextureCopy, + false + ); + cmdbuf.EndCopyPass(copyPass); + + // Create a half-sized copy of this texture + textureCreateInfo.Width /= 2; + textureCreateInfo.Height /= 2; + textureCreateInfo.UsageFlags |= TextureUsageFlags.ColorTarget; + TextureSmall = new Texture(GraphicsDevice, textureCreateInfo); + + // Render the half-size copy + cmdbuf.Blit(OriginalTexture, TextureSmall, Filter.Linear, false); + + // Copy the texture to a transfer buffer + copyPass = cmdbuf.BeginCopyPass(); + copyPass.DownloadFromTexture( + TextureCopy, + compareBuffer, + new BufferImageCopy(0, 0, 0) + ); + cmdbuf.EndCopyPass(copyPass); + + var fence = GraphicsDevice.SubmitAndAcquireFence(cmdbuf); + GraphicsDevice.WaitForFence(fence); + GraphicsDevice.ReleaseFence(fence); + + // Compare the original bytes to the copied bytes. + var copiedBytes = NativeMemory.Alloc(byteCount); + var copiedSpan = new System.Span(copiedBytes, (int) byteCount); + compareBuffer.GetData(copiedSpan); + + var originalSpan = new System.Span(pixels, (int)byteCount); + + if (System.MemoryExtensions.SequenceEqual(originalSpan, copiedSpan)) + { + Logger.LogInfo("SUCCESS! Original texture bytes and the downloaded bytes match!"); + + } + else + { + Logger.LogError("FAIL! Original texture bytes do not match downloaded bytes!"); + } + + RefreshCS.Refresh.Refresh_Image_Free(pixels); + NativeMemory.Free(copiedBytes); + } + + public override void Update(System.TimeSpan delta) { } + + public override void Draw(double alpha) + { + CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); + Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); + if (swapchainTexture != null) + { + var clearPass = cmdbuf.BeginRenderPass( + new ColorAttachmentInfo(swapchainTexture, false, Color.Black) + ); + cmdbuf.EndRenderPass(clearPass); + + cmdbuf.Blit( + OriginalTexture, + new TextureRegion + { + TextureSlice = swapchainTexture, + Width = swapchainTexture.Width / 2, + Height = swapchainTexture.Height / 2, + Depth = 1 + }, + Filter.Nearest, + false + ); + + cmdbuf.Blit( + TextureCopy, + new TextureRegion + { + TextureSlice = swapchainTexture, + X = swapchainTexture.Width / 2, + Y = 0, + Width = swapchainTexture.Width / 2, + Height = swapchainTexture.Height / 2, + Depth = 1 + }, + Filter.Nearest, + false + ); + + cmdbuf.Blit( + TextureSmall, + new TextureRegion + { + TextureSlice = swapchainTexture, + X = swapchainTexture.Width / 4, + Y = swapchainTexture.Height / 2, + Width = swapchainTexture.Width / 2, + Height = swapchainTexture.Height / 2, + Depth = 1 + }, + Filter.Nearest, + false + ); + } + + GraphicsDevice.Submit(cmdbuf); + } + + public override void Destroy() + { + OriginalTexture.Dispose(); + TextureCopy.Dispose(); + TextureSmall.Dispose(); + } + } +} diff --git a/Examples/CopyTextureGame.cs b/Examples/CopyTextureGame.cs deleted file mode 100644 index 8f5a35a..0000000 --- a/Examples/CopyTextureGame.cs +++ /dev/null @@ -1,181 +0,0 @@ -using System.Runtime.InteropServices; -using MoonWorks.Graphics; -using MoonWorks.Math.Float; - -namespace MoonWorksGraphicsTests -{ - class CopyTextureGame : Game - { - private GraphicsPipeline pipeline; - private GpuBuffer vertexBuffer; - private GpuBuffer indexBuffer; - private Texture originalTexture; - private Texture textureCopy; - private Texture textureSmallCopy; - private Sampler sampler; - - public unsafe CopyTextureGame() : base(TestUtils.GetStandardWindowCreateInfo(), TestUtils.GetStandardFrameLimiterSettings(), TestUtils.PreferredBackends, 60, true) - { - // Load the shaders - ShaderModule vertShaderModule = new ShaderModule(GraphicsDevice, TestUtils.GetShaderPath("TexturedQuad.vert")); - ShaderModule fragShaderModule = new ShaderModule(GraphicsDevice, TestUtils.GetShaderPath("TexturedQuad.frag")); - - // Create the graphics pipeline - GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( - MainWindow.SwapchainFormat, - vertShaderModule, - fragShaderModule - ); - pipelineCreateInfo.AttachmentInfo.ColorAttachmentDescriptions[0].BlendState = ColorAttachmentBlendState.AlphaBlend; - pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); - pipelineCreateInfo.FragmentShaderInfo.SamplerBindingCount = 1; - pipeline = new GraphicsPipeline(GraphicsDevice, pipelineCreateInfo); - - // Create sampler - sampler = new Sampler(GraphicsDevice, SamplerCreateInfo.PointClamp); - - // Create and populate the GPU resources - var resourceUploader = new ResourceUploader(GraphicsDevice); - - vertexBuffer = resourceUploader.CreateBuffer( - [ - new PositionTextureVertex(new Vector3(-1f, 0f, 0), new Vector2(0, 0)), - new PositionTextureVertex(new Vector3( 0f, 0f, 0), new Vector2(1, 0)), - new PositionTextureVertex(new Vector3( 0f, 1f, 0), new Vector2(1, 1)), - new PositionTextureVertex(new Vector3(-1f, 1f, 0), new Vector2(0, 1)), - - new PositionTextureVertex(new Vector3(0f, 0f, 0), new Vector2(0, 0)), - new PositionTextureVertex(new Vector3(1f, 0f, 0), new Vector2(1, 0)), - new PositionTextureVertex(new Vector3(1f, 1f, 0), new Vector2(1, 1)), - new PositionTextureVertex(new Vector3(0f, 1f, 0), new Vector2(0, 1)), - - new PositionTextureVertex(new Vector3(-0.5f, -1f, 0), new Vector2(0, 0)), - new PositionTextureVertex(new Vector3( 0.5f, -1f, 0), new Vector2(1, 0)), - new PositionTextureVertex(new Vector3( 0.5f, 0f, 0), new Vector2(1, 1)), - new PositionTextureVertex(new Vector3(-0.5f, 0f, 0), new Vector2(0, 1)) - ], - BufferUsageFlags.Vertex - ); - - indexBuffer = resourceUploader.CreateBuffer( - [ - 0, 1, 2, - 0, 2, 3, - ], - BufferUsageFlags.Index - ); - - originalTexture = resourceUploader.CreateTexture2DFromCompressed( - TestUtils.GetTexturePath("ravioli.png") - ); - - resourceUploader.Upload(); - resourceUploader.Dispose(); - - // Load the texture bytes so we can compare them. - var pixels = ImageUtils.GetPixelDataFromFile( - TestUtils.GetTexturePath("ravioli.png"), - out var width, - out var height, - out var byteCount - ); - - CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); - - var textureCreateInfo = new TextureCreateInfo - { - Width = originalTexture.Width, - Height = originalTexture.Height, - Depth = originalTexture.Depth, - IsCube = originalTexture.IsCube, - LayerCount = originalTexture.LayerCount, - LevelCount = originalTexture.LevelCount, - SampleCount = originalTexture.SampleCount, - Format = originalTexture.Format, - UsageFlags = originalTexture.UsageFlags - }; - - // Create a 1:1 copy of the texture - textureCopy = new Texture(GraphicsDevice, textureCreateInfo); - - cmdbuf.BeginCopyPass(); - cmdbuf.CopyTextureToTexture( - originalTexture, - textureCopy, - WriteOptions.Unsafe - ); - cmdbuf.EndCopyPass(); - - // Create a half-sized copy of this texture - textureCreateInfo.Width /= 2; - textureCreateInfo.Height /= 2; - textureCreateInfo.UsageFlags |= TextureUsageFlags.ColorTarget; - textureSmallCopy = new Texture(GraphicsDevice, textureCreateInfo); - - // Render the half-size copy - cmdbuf.Blit(originalTexture, textureSmallCopy, Filter.Linear, WriteOptions.Unsafe); - - var fence = GraphicsDevice.SubmitAndAcquireFence(cmdbuf); - GraphicsDevice.WaitForFences(fence); - GraphicsDevice.ReleaseFence(fence); - - // Copy the texture to a transfer buffer - TransferBuffer compareBuffer = new TransferBuffer(GraphicsDevice, TransferUsage.Texture, byteCount); - - GraphicsDevice.DownloadFromTexture( - textureCopy, - compareBuffer, - TransferOptions.Unsafe - ); - - // Compare the original bytes to the copied bytes. - var copiedBytes = NativeMemory.Alloc(byteCount); - var copiedSpan = new System.Span(copiedBytes, (int) byteCount); - compareBuffer.GetData(copiedSpan); - - var originalSpan = new System.Span((void*) pixels, (int)byteCount); - - if (System.MemoryExtensions.SequenceEqual(originalSpan, copiedSpan)) - { - Logger.LogInfo("SUCCESS! Original texture bytes and the downloaded bytes match!"); - - } - else - { - Logger.LogError("FAIL! Original texture bytes do not match downloaded bytes!"); - } - - RefreshCS.Refresh.Refresh_Image_Free(pixels); - NativeMemory.Free(copiedBytes); - } - - protected override void Update(System.TimeSpan delta) { } - - protected override void Draw(double alpha) - { - CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); - Texture? backbuffer = cmdbuf.AcquireSwapchainTexture(MainWindow); - if (backbuffer != null) - { - cmdbuf.BeginRenderPass(new ColorAttachmentInfo(backbuffer, WriteOptions.Cycle, Color.Black)); - cmdbuf.BindGraphicsPipeline(pipeline); - cmdbuf.BindVertexBuffers(vertexBuffer); - cmdbuf.BindIndexBuffer(indexBuffer, IndexElementSize.Sixteen); - cmdbuf.BindFragmentSamplers(new TextureSamplerBinding(originalTexture, sampler)); - cmdbuf.DrawIndexedPrimitives(0, 0, 2); - cmdbuf.BindFragmentSamplers(new TextureSamplerBinding(textureCopy, sampler)); - cmdbuf.DrawIndexedPrimitives(4, 0, 2); - cmdbuf.BindFragmentSamplers(new TextureSamplerBinding(textureSmallCopy, sampler)); - cmdbuf.DrawIndexedPrimitives(8, 0, 2); - cmdbuf.EndRenderPass(); - } - GraphicsDevice.Submit(cmdbuf); - } - - public static void Main(string[] args) - { - CopyTextureGame game = new CopyTextureGame(); - game.Run(); - } - } -} diff --git a/MoonWorksGraphicsTests.csproj b/MoonWorksGraphicsTests.csproj index 272ad80..362e738 100644 --- a/MoonWorksGraphicsTests.csproj +++ b/MoonWorksGraphicsTests.csproj @@ -31,6 +31,7 @@ + diff --git a/Program.cs b/Program.cs index 00d6fb0..602486a 100644 --- a/Program.cs +++ b/Program.cs @@ -14,7 +14,8 @@ class Program : Game new BasicTriangleExample(), new CompressedTexturesExample(), new BasicComputeExample(), - new ComputeUniformsExample() + new ComputeUniformsExample(), + new CopyTextureExample() ]; int ExampleIndex = 0;