Add CopyTexture test

pull/1/head
Caleb Cornett 2023-01-07 18:03:12 -05:00
parent efac8a0108
commit 28e0e1efb0
4 changed files with 207 additions and 0 deletions

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\..\MoonWorks\MoonWorks.csproj" />
<ProjectReference Include="..\MoonWorks.Test.Common\MoonWorks.Test.Common.csproj" />
</ItemGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<Platforms>x64</Platforms>
</PropertyGroup>
<Import Project="$(SolutionDir)NativeAOT_Console.targets" Condition="Exists('$(SolutionDir)NativeAOT_Console.targets')" />
</Project>

View File

@ -0,0 +1,180 @@
using MoonWorks;
using MoonWorks.Graphics;
using MoonWorks.Math.Float;
namespace MoonWorks.Test
{
class CopyTextureGame : Game
{
private GraphicsPipeline pipeline;
private Buffer vertexBuffer;
private Buffer indexBuffer;
private Texture originalTexture;
private Texture textureCopy;
private Texture textureSmallCopy;
private Sampler sampler;
public CopyTextureGame() : base(TestUtils.GetStandardWindowCreateInfo(), TestUtils.GetStandardFrameLimiterSettings(), 60, true)
{
// Load the shaders
ShaderModule vertShaderModule = new ShaderModule(GraphicsDevice, TestUtils.GetShaderPath("TexturedQuadVert.spv"));
ShaderModule fragShaderModule = new ShaderModule(GraphicsDevice, TestUtils.GetShaderPath("TexturedQuadFrag.spv"));
// Create the graphics pipeline
GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo(
MainWindow.SwapchainFormat,
vertShaderModule,
fragShaderModule
);
pipelineCreateInfo.AttachmentInfo.ColorAttachmentDescriptions[0].BlendState = ColorAttachmentBlendState.AlphaBlend;
pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding<PositionTextureVertex>();
pipelineCreateInfo.FragmentShaderInfo.SamplerBindingCount = 1;
pipeline = new GraphicsPipeline(GraphicsDevice, pipelineCreateInfo);
// Create sampler
sampler = new Sampler(GraphicsDevice, SamplerCreateInfo.PointClamp);
// Create and populate the GPU resources
vertexBuffer = Buffer.Create<PositionTextureVertex>(GraphicsDevice, BufferUsageFlags.Vertex, 12);
indexBuffer = Buffer.Create<ushort>(GraphicsDevice, BufferUsageFlags.Index, 12);
CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer();
cmdbuf.SetBufferData(
vertexBuffer,
new PositionTextureVertex[]
{
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))
}
);
cmdbuf.SetBufferData(
indexBuffer,
new ushort[]
{
0, 1, 2,
0, 2, 3,
// For testing index offsets
8, 9, 10,
8, 10, 11,
}
);
// Load the texture. Copy-pasted from Texture.LoadPNG,
// but with the texture bytes stored.
var pixels = RefreshCS.Refresh.Refresh_Image_Load(
TestUtils.GetTexturePath("ravioli.png"),
out var width,
out var height,
out var channels
);
var byteCount = (uint)(width * height * channels);
TextureCreateInfo textureCreateInfo;
textureCreateInfo.Width = (uint)width;
textureCreateInfo.Height = (uint)height;
textureCreateInfo.Depth = 1;
textureCreateInfo.Format = TextureFormat.R8G8B8A8;
textureCreateInfo.IsCube = false;
textureCreateInfo.LevelCount = 1;
textureCreateInfo.UsageFlags = TextureUsageFlags.Sampler;
originalTexture = new Texture(GraphicsDevice, textureCreateInfo);
cmdbuf.SetTextureData(originalTexture, pixels, byteCount);
byte[] textureBytes = new byte[byteCount];
System.Runtime.InteropServices.Marshal.Copy(pixels, textureBytes, 0, (int) byteCount);
RefreshCS.Refresh.Refresh_Image_Free(pixels);
// Create a 1:1 copy of the texture
textureCopy = new Texture(GraphicsDevice, textureCreateInfo);
cmdbuf.CopyTextureToTexture(
new TextureSlice(originalTexture),
new TextureSlice(textureCopy),
Filter.Linear
);
// Create a half-sized copy of this texture
textureCreateInfo.Width /= 2;
textureCreateInfo.Height /= 2;
textureSmallCopy = new Texture(GraphicsDevice, textureCreateInfo);
cmdbuf.CopyTextureToTexture(
new TextureSlice(originalTexture),
new TextureSlice(
textureSmallCopy,
new Rect(
(int) textureCreateInfo.Width,
(int) textureCreateInfo.Height
)
),
Filter.Linear
);
// Copy the texture to a buffer
Buffer compareBuffer = Buffer.Create<byte>(GraphicsDevice, 0, (uint) textureBytes.Length);
cmdbuf.CopyTextureToBuffer(new TextureSlice(originalTexture), compareBuffer);
GraphicsDevice.Submit(cmdbuf);
GraphicsDevice.Wait();
// Compare the original bytes to the copied bytes.
// Doing a manual equality check per byte because I can't find a way to memcmp in C#.
byte[] copiedBytes = new byte[textureBytes.Length];
compareBuffer.GetData<byte>(copiedBytes, (uint) copiedBytes.Length);
for (int i = 0; i < copiedBytes.Length; i += 1)
{
if (textureBytes[i] != copiedBytes[i])
{
Logger.LogError("FAIL! Original texture bytes do not match bytes from CopyTextureToBuffer!");
return;
}
}
Logger.LogError("SUCCESS! Original texture bytes and the bytes from CopyTextureToBuffer match!");
}
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, Color.Black));
cmdbuf.BindGraphicsPipeline(pipeline);
cmdbuf.BindVertexBuffers(vertexBuffer);
cmdbuf.BindIndexBuffer(indexBuffer, IndexElementSize.Sixteen);
cmdbuf.BindFragmentSamplers(new TextureSamplerBinding(originalTexture, sampler));
cmdbuf.DrawIndexedPrimitives(0, 0, 2, 0, 0);
cmdbuf.BindFragmentSamplers(new TextureSamplerBinding(textureCopy, sampler));
cmdbuf.DrawIndexedPrimitives(4, 0, 2, 0, 0);
cmdbuf.BindFragmentSamplers(new TextureSamplerBinding(textureSmallCopy, sampler));
cmdbuf.DrawIndexedPrimitives(0, 6, 2, 0, 0);
cmdbuf.EndRenderPass();
}
GraphicsDevice.Submit(cmdbuf);
}
public static void Main(string[] args)
{
CopyTextureGame game = new CopyTextureGame();
game.Run();
}
}
}

View File

@ -35,6 +35,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DrawIndirect", "DrawIndirec
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompressedTextures", "CompressedTextures\CompressedTextures.csproj", "{E90D236C-BD0F-4420-ADD0-867D21F4DCA5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CopyTexture", "CopyTexture\CopyTexture.csproj", "{CF25A5A2-A0BD-4C9B-BB07-19CCD97C1C4E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@ -105,6 +107,10 @@ Global
{E90D236C-BD0F-4420-ADD0-867D21F4DCA5}.Debug|x64.Build.0 = Debug|x64
{E90D236C-BD0F-4420-ADD0-867D21F4DCA5}.Release|x64.ActiveCfg = Release|Any CPU
{E90D236C-BD0F-4420-ADD0-867D21F4DCA5}.Release|x64.Build.0 = Release|Any CPU
{CF25A5A2-A0BD-4C9B-BB07-19CCD97C1C4E}.Debug|x64.ActiveCfg = Debug|x64
{CF25A5A2-A0BD-4C9B-BB07-19CCD97C1C4E}.Debug|x64.Build.0 = Debug|x64
{CF25A5A2-A0BD-4C9B-BB07-19CCD97C1C4E}.Release|x64.ActiveCfg = Release|Any CPU
{CF25A5A2-A0BD-4C9B-BB07-19CCD97C1C4E}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -55,3 +55,7 @@ Draws two triangles via indirect commands. Tests DrawPrimitivesIndirect.
**CompressedTextures**
Loads a series of compressed textures, then displays them for viewing. Tests compressed texture loading.
**CopyTexture**
Loads an image, then makes three copies of the image. One is a 1:1 scale image, another is a half-sized image (to test linear/nearest blitting), and the final copy is to a buffer. The buffer bytes are then compared with the original texture bytes to verify the copy's correctness. Tests CopyTextureToTexture, CopyTextureToBuffer, vertex offsets, and index offsets.