├── .gitignore ├── Common ├── Content │ ├── Shaders │ │ ├── HLSL │ │ │ ├── Empty.frag.hlsl │ │ │ ├── SolidColor.frag.hlsl │ │ │ ├── TexturedQuad.frag.hlsl │ │ │ ├── Skybox.frag.hlsl │ │ │ ├── Fullscreen.vert.hlsl │ │ │ ├── CalculateSquares.comp.hlsl │ │ │ ├── FillTexture.comp.hlsl │ │ │ ├── TexturedQuadColor.frag.hlsl │ │ │ ├── TexturedQuad3D.frag.hlsl │ │ │ ├── TexturedQuadWithMultiplyColor.frag.hlsl │ │ │ ├── PositionColor.vert.hlsl │ │ │ ├── TexturedQuad.vert.hlsl │ │ │ ├── Skybox.vert.hlsl │ │ │ ├── PositionColorWithMatrix.vert.hlsl │ │ │ ├── PositionSampler.vert.hlsl │ │ │ ├── TexturedQuadWithMatrix.vert.hlsl │ │ │ ├── GradientTexture.comp.hlsl │ │ │ ├── PositionColorInstanced.vert.hlsl │ │ │ ├── TexturedQuadColorWithMatrix.vert.hlsl │ │ │ ├── TexturedDepthQuad.frag.hlsl │ │ │ ├── RawTriangle.vert.hlsl │ │ │ ├── HotReload.frag.hlsl │ │ │ ├── PullSpriteBatch.vert.hlsl │ │ │ └── SpriteBatch.comp.hlsl │ │ ├── GLSL │ │ │ ├── Empty.frag │ │ │ ├── SolidColor.frag │ │ │ ├── CalculateSquares.comp │ │ │ ├── PositionColor.vert │ │ │ ├── TexturedQuad.frag │ │ │ ├── Skybox.frag │ │ │ ├── TexturedQuad.vert │ │ │ ├── Skybox.vert │ │ │ ├── FillTexture.comp │ │ │ ├── TexturedQuadColor.frag │ │ │ ├── PositionSampler.vert │ │ │ ├── TexturedQuad3D.frag │ │ │ ├── TexturedQuad2DArray.frag │ │ │ ├── PositionColorWithMatrix.vert │ │ │ ├── TexturedQuadWithMatrix.vert │ │ │ ├── TexturedQuadWithMultiplyColor.frag │ │ │ ├── PositionColorInstanced.vert │ │ │ ├── RawTriangle.vert │ │ │ ├── TexturedQuadColorWithMatrix.vert │ │ │ ├── GradientTexture.comp │ │ │ ├── TexturedDepthQuad.frag │ │ │ └── SpriteBatch.comp │ │ └── SPIRV │ │ │ ├── Skybox.frag.spv │ │ │ ├── Skybox.vert.spv │ │ │ ├── SolidColor.frag.spv │ │ │ ├── FillTexture.comp.spv │ │ │ ├── RawTriangle.vert.spv │ │ │ ├── SpriteBatch.comp.spv │ │ │ ├── TexturedQuad.frag.spv │ │ │ ├── TexturedQuad.vert.spv │ │ │ ├── GradientTexture.comp.spv │ │ │ ├── PositionColor.vert.spv │ │ │ ├── PositionSampler.vert.spv │ │ │ ├── PullSpriteBatch.vert.spv │ │ │ ├── TexturedQuad3D.frag.spv │ │ │ ├── CalculateSquares.comp.spv │ │ │ ├── TexturedDepthQuad.frag.spv │ │ │ ├── TexturedQuadColor.frag.spv │ │ │ ├── TexturedQuad2DArray.frag.spv │ │ │ ├── PositionColorInstanced.vert.spv │ │ │ ├── TexturedQuadWithMatrix.vert.spv │ │ │ ├── PositionColorWithMatrix.vert.spv │ │ │ ├── TexturedQuadColorWithMatrix.vert.spv │ │ │ └── TexturedQuadWithMultiplyColor.frag.spv │ ├── Textures │ │ ├── BC1.dds │ │ ├── BC2.dds │ │ ├── BC3.dds │ │ ├── BC7.dds │ │ ├── back.png │ │ ├── front.png │ │ ├── left.png │ │ ├── mip0.png │ │ ├── mip1.png │ │ ├── mip2.png │ │ ├── mip3.png │ │ ├── right.png │ │ ├── top.png │ │ ├── bottom.png │ │ ├── ravioli.png │ │ ├── ravioli.qoi │ │ ├── tex3d_0.png │ │ ├── tex3d_1.png │ │ ├── tex3d_2.png │ │ ├── tex3d_3.png │ │ ├── tex3d_4.png │ │ ├── tex3d_5.png │ │ ├── tex3d_6.png │ │ └── ravioli_atlas.png │ ├── Videos │ │ └── hello.obu │ └── Fonts │ │ ├── SofiaSans.png │ │ └── SofiaSans.ttf ├── UniformTypes.cs ├── VertexTypes.cs └── TestUtils.cs ├── .vscode └── launch.json ├── MoonWorksGraphicsTests.csproj ├── Examples ├── ClearScreenExample.cs ├── Example.cs ├── VideoPlayerExample.cs ├── StoreLoadExample.cs ├── ComputeUniformsExample.cs ├── ClearScreen_MultiWindowExample.cs ├── RenderTexture2DArrayExample.cs ├── TriangleVertexBufferExample.cs ├── WindowResizingExample.cs ├── FontExample.cs ├── VertexSamplerExample.cs ├── RenderTexture2DExample.cs ├── BasicTriangleExample.cs ├── DrawIndirectExample.cs ├── InstancingAndOffsetsExample.cs ├── MSAAExample.cs ├── TextureMipmapsExample.cs ├── CompressedTexturesExample.cs ├── Texture3DExample.cs ├── BasicStencilExample.cs ├── HotReloadShaderExample.cs ├── GetBufferDataExample.cs ├── Texture3DCopyExample.cs ├── CopyTextureExample.cs ├── BasicComputeExample.cs ├── TexturedAnimatedQuadExample.cs ├── CullFaceExample.cs ├── RenderTextureCubeExample.cs ├── RenderTextureMipmapsExample.cs ├── PullSpriteBatchExample.cs ├── ComputeSpriteBatchExample.cs ├── TexturedQuadExample.cs ├── CPUSpriteBatchExample.cs └── DepthMSAAExample.cs ├── CopyMoonlibs.targets ├── MoonWorksGraphicsTests.sln ├── Program.cs └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | .vs/ 4 | *.csproj.user 5 | Properties/ -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/Empty.frag.hlsl: -------------------------------------------------------------------------------- 1 | void main() 2 | { 3 | } 4 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/Empty.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | void main() 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/SolidColor.frag.hlsl: -------------------------------------------------------------------------------- 1 | float4 main(float4 Color : TEXCOORD0) : SV_Target0 2 | { 3 | return Color; 4 | } 5 | -------------------------------------------------------------------------------- /Common/Content/Textures/BC1.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/BC1.dds -------------------------------------------------------------------------------- /Common/Content/Textures/BC2.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/BC2.dds -------------------------------------------------------------------------------- /Common/Content/Textures/BC3.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/BC3.dds -------------------------------------------------------------------------------- /Common/Content/Textures/BC7.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/BC7.dds -------------------------------------------------------------------------------- /Common/Content/Textures/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/back.png -------------------------------------------------------------------------------- /Common/Content/Textures/front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/front.png -------------------------------------------------------------------------------- /Common/Content/Textures/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/left.png -------------------------------------------------------------------------------- /Common/Content/Textures/mip0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/mip0.png -------------------------------------------------------------------------------- /Common/Content/Textures/mip1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/mip1.png -------------------------------------------------------------------------------- /Common/Content/Textures/mip2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/mip2.png -------------------------------------------------------------------------------- /Common/Content/Textures/mip3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/mip3.png -------------------------------------------------------------------------------- /Common/Content/Textures/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/right.png -------------------------------------------------------------------------------- /Common/Content/Textures/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/top.png -------------------------------------------------------------------------------- /Common/Content/Videos/hello.obu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Videos/hello.obu -------------------------------------------------------------------------------- /Common/Content/Fonts/SofiaSans.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Fonts/SofiaSans.png -------------------------------------------------------------------------------- /Common/Content/Fonts/SofiaSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Fonts/SofiaSans.ttf -------------------------------------------------------------------------------- /Common/Content/Textures/bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/bottom.png -------------------------------------------------------------------------------- /Common/Content/Textures/ravioli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/ravioli.png -------------------------------------------------------------------------------- /Common/Content/Textures/ravioli.qoi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/ravioli.qoi -------------------------------------------------------------------------------- /Common/Content/Textures/tex3d_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/tex3d_0.png -------------------------------------------------------------------------------- /Common/Content/Textures/tex3d_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/tex3d_1.png -------------------------------------------------------------------------------- /Common/Content/Textures/tex3d_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/tex3d_2.png -------------------------------------------------------------------------------- /Common/Content/Textures/tex3d_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/tex3d_3.png -------------------------------------------------------------------------------- /Common/Content/Textures/tex3d_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/tex3d_4.png -------------------------------------------------------------------------------- /Common/Content/Textures/tex3d_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/tex3d_5.png -------------------------------------------------------------------------------- /Common/Content/Textures/tex3d_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/tex3d_6.png -------------------------------------------------------------------------------- /Common/Content/Textures/ravioli_atlas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Textures/ravioli_atlas.png -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/Skybox.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/Skybox.frag.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/Skybox.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/Skybox.vert.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/SolidColor.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/SolidColor.frag.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/FillTexture.comp.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/FillTexture.comp.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/RawTriangle.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/RawTriangle.vert.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/SpriteBatch.comp.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/SpriteBatch.comp.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/TexturedQuad.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/TexturedQuad.frag.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/TexturedQuad.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/TexturedQuad.vert.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/GradientTexture.comp.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/GradientTexture.comp.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/PositionColor.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/PositionColor.vert.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/PositionSampler.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/PositionSampler.vert.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/PullSpriteBatch.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/PullSpriteBatch.vert.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/TexturedQuad3D.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/TexturedQuad3D.frag.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/CalculateSquares.comp.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/CalculateSquares.comp.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/TexturedDepthQuad.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/TexturedDepthQuad.frag.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/TexturedQuadColor.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/TexturedQuadColor.frag.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/TexturedQuad2DArray.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/TexturedQuad2DArray.frag.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/PositionColorInstanced.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/PositionColorInstanced.vert.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/TexturedQuadWithMatrix.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/TexturedQuadWithMatrix.vert.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/PositionColorWithMatrix.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/PositionColorWithMatrix.vert.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/TexturedQuadColorWithMatrix.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/TexturedQuadColorWithMatrix.vert.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/SPIRV/TexturedQuadWithMultiplyColor.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoonsideGames/MoonWorksGraphicsTests/HEAD/Common/Content/Shaders/SPIRV/TexturedQuadWithMultiplyColor.frag.spv -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/SolidColor.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec4 Color; 4 | 5 | layout (location = 0) out vec4 FragColor; 6 | 7 | void main() 8 | { 9 | FragColor = Color; 10 | } 11 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/TexturedQuad.frag.hlsl: -------------------------------------------------------------------------------- 1 | Texture2D Texture : register(t0, space2); 2 | SamplerState Sampler : register(s0, space2); 3 | 4 | float4 main(float2 TexCoord : TEXCOORD0) : SV_Target0 5 | { 6 | return Texture.Sample(Sampler, TexCoord); 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [] 7 | } -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/Skybox.frag.hlsl: -------------------------------------------------------------------------------- 1 | TextureCube SkyboxTexture : register(t0, space2); 2 | SamplerState SkyboxSampler : register(s0, space2); 3 | 4 | float4 main(float3 TexCoord : TEXCOORD0) : SV_Target0 5 | { 6 | return SkyboxTexture.Sample(SkyboxSampler, TexCoord); 7 | } 8 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/Fullscreen.vert.hlsl: -------------------------------------------------------------------------------- 1 | float4 main(uint VertexIndex : SV_VertexID) : SV_Position 2 | { 3 | float2 texCoord = float2(float((VertexIndex << 1) & 2), float(VertexIndex & 2)); 4 | return float4((texCoord * float2(2.0f, -2.0f)) + float2(-1.0f, 1.0f), 0.0f, 1.0f); 5 | } 6 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/CalculateSquares.comp.hlsl: -------------------------------------------------------------------------------- 1 | RWByteAddressBuffer NumberBuffer : register(u0, space1); 2 | 3 | [numthreads(8, 1, 1)] 4 | void main(uint3 GlobalInvocationID : SV_DispatchThreadID) 5 | { 6 | uint n = GlobalInvocationID.x; 7 | NumberBuffer.Store(n * 4 + 0, n * n); 8 | } 9 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/CalculateSquares.comp: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (local_size_x = 8) in; 4 | layout (set = 1, binding = 0) writeonly buffer outBuffer 5 | { 6 | uint squares[]; 7 | }; 8 | 9 | void main() 10 | { 11 | uint n = gl_GlobalInvocationID.x; 12 | squares[n] = n * n; 13 | } 14 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/PositionColor.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec3 Position; 4 | layout (location = 1) in vec4 Color; 5 | 6 | layout (location = 0) out vec4 outColor; 7 | 8 | void main() 9 | { 10 | outColor = Color; 11 | gl_Position = vec4(Position, 1); 12 | } 13 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/TexturedQuad.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec2 TexCoord; 4 | 5 | layout (location = 0) out vec4 FragColor; 6 | 7 | layout(set = 2, binding = 0) uniform sampler2D Sampler; 8 | 9 | void main() 10 | { 11 | FragColor = texture(Sampler, TexCoord); 12 | } 13 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/Skybox.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 TexCoord; 4 | layout(location = 0) out vec4 FragColor; 5 | 6 | layout(set = 2, binding = 0) uniform samplerCube SkyboxSampler; 7 | 8 | void main() 9 | { 10 | FragColor = texture(SkyboxSampler, TexCoord); 11 | } 12 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/TexturedQuad.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec3 Position; 4 | layout (location = 1) in vec2 TexCoord; 5 | 6 | layout (location = 0) out vec2 outTexCoord; 7 | 8 | void main() 9 | { 10 | outTexCoord = TexCoord; 11 | gl_Position = vec4(Position, 1); 12 | } 13 | -------------------------------------------------------------------------------- /Common/UniformTypes.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | 3 | namespace MoonWorksGraphicsTests; 4 | 5 | public struct TransformVertexUniform 6 | { 7 | public Matrix4x4 ViewProjection; 8 | 9 | public TransformVertexUniform(Matrix4x4 viewProjection) 10 | { 11 | ViewProjection = viewProjection; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/FillTexture.comp.hlsl: -------------------------------------------------------------------------------- 1 | RWTexture2D outImage : register(u0, space1); 2 | 3 | [numthreads(8, 8, 1)] 4 | void main(uint3 GlobalInvocationID : SV_DispatchThreadID) 5 | { 6 | int2 coord = int2(GlobalInvocationID.xy); 7 | outImage[coord] = float4(1.0f, 1.0f, 0.0f, 1.0f); 8 | } 9 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/Skybox.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 inPos; 4 | layout(location = 0) out vec3 vPos; 5 | 6 | layout(set = 1, binding = 0) uniform UBO 7 | { 8 | mat4 ViewProjection; 9 | } ubo; 10 | 11 | void main() 12 | { 13 | vPos = inPos; 14 | gl_Position = ubo.ViewProjection * vec4(inPos, 1.0); 15 | } 16 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/FillTexture.comp: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; 4 | layout (set = 1, binding = 0, rgba8) uniform writeonly image2D outImage; 5 | 6 | void main() 7 | { 8 | ivec2 coord = ivec2(gl_GlobalInvocationID.xy); 9 | imageStore(outImage, coord, vec4(1.0, 1.0, 0.0, 1.0)); 10 | } 11 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/TexturedQuadColor.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec2 TexCoord; 4 | layout (location = 1) in vec4 Color; 5 | 6 | layout (location = 0) out vec4 FragColor; 7 | 8 | layout(set = 2, binding = 0) uniform sampler2D Sampler; 9 | 10 | void main() 11 | { 12 | FragColor = Color * texture(Sampler, TexCoord); 13 | } 14 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/PositionSampler.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec3 Position; 4 | layout (location = 1) in vec2 TexCoord; 5 | 6 | layout (location = 0) out vec4 outColor; 7 | 8 | layout(set = 0, binding = 0) uniform sampler2D Sampler; 9 | 10 | void main() 11 | { 12 | outColor = texture(Sampler, TexCoord); 13 | gl_Position = vec4(Position, 1); 14 | } 15 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/TexturedQuadColor.frag.hlsl: -------------------------------------------------------------------------------- 1 | Texture2D Texture : register(t0, space2); 2 | SamplerState Sampler : register(s0, space2); 3 | 4 | struct Input 5 | { 6 | float2 TexCoord : TEXCOORD0; 7 | float4 Color : TEXCOORD1; 8 | }; 9 | 10 | float4 main(Input input) : SV_Target0 11 | { 12 | return input.Color * Texture.Sample(Sampler, input.TexCoord); 13 | } 14 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/TexturedQuad3D.frag.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UniformBlock : register(b0, space3) 2 | { 3 | float depth : packoffset(c0); 4 | }; 5 | 6 | Texture3D Texture : register(t0, space2); 7 | SamplerState Sampler : register(s0, space2); 8 | 9 | float4 main(float2 TexCoord : TEXCOORD0) : SV_Target0 10 | { 11 | return Texture.Sample(Sampler, float3(TexCoord, depth)); 12 | } 13 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/TexturedQuad3D.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec2 TexCoord; 4 | 5 | layout (location = 0) out vec4 FragColor; 6 | 7 | layout(set = 2, binding = 0) uniform sampler3D Sampler; 8 | 9 | layout (set = 3, binding = 0) uniform UniformBlock 10 | { 11 | float depth; 12 | }; 13 | 14 | void main() 15 | { 16 | FragColor = texture(Sampler, vec3(TexCoord, depth)); 17 | } 18 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/TexturedQuadWithMultiplyColor.frag.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UniformBlock : register(b0, space3) 2 | { 3 | float4 MultiplyColor : packoffset(c0); 4 | }; 5 | 6 | Texture2D Texture : register(t0, space2); 7 | SamplerState Sampler : register(s0, space2); 8 | 9 | float4 main(float2 TexCoord : TEXCOORD0) : SV_Target0 10 | { 11 | return MultiplyColor * Texture.Sample(Sampler, TexCoord); 12 | } 13 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/TexturedQuad2DArray.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec2 TexCoord; 4 | 5 | layout (location = 0) out vec4 FragColor; 6 | 7 | layout(set = 2, binding = 0) uniform sampler2DArray Sampler; 8 | 9 | layout (set = 3, binding = 0) uniform UniformBlock 10 | { 11 | float depth; 12 | }; 13 | 14 | void main() 15 | { 16 | FragColor = texture(Sampler, vec3(TexCoord, depth)); 17 | } 18 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/PositionColorWithMatrix.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec3 Position; 4 | layout (location = 1) in vec4 Color; 5 | 6 | layout (location = 0) out vec4 outColor; 7 | 8 | layout (set = 1, binding = 0) uniform UniformBlock 9 | { 10 | mat4x4 MatrixTransform; 11 | }; 12 | 13 | void main() 14 | { 15 | outColor = Color; 16 | gl_Position = MatrixTransform * vec4(Position, 1); 17 | } 18 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/TexturedQuadWithMatrix.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec3 Position; 4 | layout (location = 1) in vec2 TexCoord; 5 | 6 | layout (location = 0) out vec2 outTexCoord; 7 | 8 | layout (set = 1, binding = 0) uniform UniformBlock 9 | { 10 | mat4x4 MatrixTransform; 11 | }; 12 | 13 | void main() 14 | { 15 | outTexCoord = TexCoord; 16 | gl_Position = MatrixTransform * vec4(Position, 1); 17 | } 18 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/TexturedQuadWithMultiplyColor.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec2 TexCoord; 4 | 5 | layout (location = 0) out vec4 FragColor; 6 | 7 | layout(set = 2, binding = 0) uniform sampler2D Sampler; 8 | 9 | layout (set = 3, binding = 0) uniform UniformBlock 10 | { 11 | vec4 MultiplyColor; 12 | }; 13 | 14 | void main() 15 | { 16 | FragColor = MultiplyColor * texture(Sampler, TexCoord); 17 | } 18 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/PositionColor.vert.hlsl: -------------------------------------------------------------------------------- 1 | struct Input 2 | { 3 | float3 Position : TEXCOORD0; 4 | float4 Color : TEXCOORD1; 5 | }; 6 | 7 | struct Output 8 | { 9 | float4 Color : TEXCOORD0; 10 | float4 Position : SV_Position; 11 | }; 12 | 13 | Output main(Input input) 14 | { 15 | Output output; 16 | output.Position = float4(input.Position, 1.0f); 17 | output.Color = input.Color; 18 | return output; 19 | } 20 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/PositionColorInstanced.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec3 Position; 4 | layout (location = 1) in vec4 Color; 5 | 6 | layout (location = 0) out vec4 outColor; 7 | 8 | void main() 9 | { 10 | outColor = Color; 11 | 12 | vec3 pos = (Position * 0.25) - vec3(0.75, 0.75, 0); 13 | pos.x += (gl_InstanceIndex % 4) * 0.5; 14 | pos.y += floor(gl_InstanceIndex / 4) * 0.5; 15 | gl_Position = vec4(pos, 1); 16 | } 17 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/TexturedQuad.vert.hlsl: -------------------------------------------------------------------------------- 1 | struct Input 2 | { 3 | float3 Position : TEXCOORD0; 4 | float2 TexCoord : TEXCOORD1; 5 | }; 6 | 7 | struct Output 8 | { 9 | float2 TexCoord : TEXCOORD0; 10 | float4 Position : SV_Position; 11 | }; 12 | 13 | Output main(Input input) 14 | { 15 | Output output; 16 | output.Position = float4(input.Position, 1.0); 17 | output.TexCoord = input.TexCoord; 18 | return output; 19 | } 20 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/RawTriangle.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) out vec4 outColor; 4 | 5 | void main() 6 | { 7 | vec2 pos; 8 | 9 | if (gl_VertexIndex == 0) 10 | { 11 | pos = vec2(-1, -1); 12 | outColor = vec4(1, 0, 0, 1); 13 | } 14 | else if (gl_VertexIndex == 1) 15 | { 16 | pos = vec2(1, -1); 17 | outColor = vec4(0, 1, 0, 1); 18 | } 19 | else if (gl_VertexIndex == 2) 20 | { 21 | pos = vec2(0, 1); 22 | outColor = vec4(0, 0, 1, 1); 23 | } 24 | 25 | gl_Position = vec4(pos, 0, 1); 26 | } 27 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/Skybox.vert.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UBO : register(b0, space1) 2 | { 3 | float4x4 ubo_ViewProjection : packoffset(c0); 4 | }; 5 | 6 | struct Input 7 | { 8 | float3 inPos : TEXCOORD0; 9 | }; 10 | 11 | struct Output 12 | { 13 | float3 vPos : TEXCOORD0; 14 | float4 Position : SV_Position; 15 | }; 16 | 17 | Output main(Input input) 18 | { 19 | Output output; 20 | output.vPos = input.inPos; 21 | output.Position = mul(ubo_ViewProjection, float4(input.inPos, 1.0f)); 22 | return output; 23 | } 24 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/TexturedQuadColorWithMatrix.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec4 Position; 4 | layout (location = 1) in vec2 TexCoord; 5 | layout (location = 2) in vec4 Color; 6 | 7 | layout (location = 0) out vec2 outTexCoord; 8 | layout (location = 1) out vec4 outColor; 9 | 10 | layout (set = 1, binding = 0) uniform UniformBlock 11 | { 12 | mat4x4 MatrixTransform; 13 | }; 14 | 15 | void main() 16 | { 17 | outTexCoord = TexCoord; 18 | outColor = Color; 19 | gl_Position = MatrixTransform * Position; 20 | } 21 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/GradientTexture.comp: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; 4 | layout (set = 1, binding = 0, rgba8) uniform writeonly image2D outImage; 5 | layout (set = 2, binding = 0) uniform UBO 6 | { 7 | float time; 8 | } ubo; 9 | 10 | void main() 11 | { 12 | vec2 size = imageSize(outImage); 13 | vec2 coord = gl_GlobalInvocationID.xy; 14 | vec2 uv = coord / size; 15 | 16 | vec3 col = 0.5 + 0.5*cos(ubo.time + uv.xyx + vec3(0, 2, 4)); 17 | 18 | imageStore(outImage, ivec2(coord), vec4(col, 1.0)); 19 | } 20 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/PositionColorWithMatrix.vert.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UniformBlock : register(b0, space1) 2 | { 3 | float4x4 MatrixTransform : packoffset(c0); 4 | }; 5 | 6 | struct Input 7 | { 8 | float3 Position : TEXCOORD0; 9 | float4 Color : TEXCOORD1; 10 | }; 11 | 12 | struct Output 13 | { 14 | float4 Color : TEXCOORD0; 15 | float4 Position : SV_Position; 16 | }; 17 | 18 | Output main(Input input) 19 | { 20 | Output output; 21 | output.Position = mul(MatrixTransform, float4(input.Position, 1.0f)); 22 | output.Color = input.Color; 23 | return output; 24 | } 25 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/PositionSampler.vert.hlsl: -------------------------------------------------------------------------------- 1 | Texture2D Texture : register(t0, space0); 2 | SamplerState Sampler : register(s0, space0); 3 | 4 | struct Input 5 | { 6 | float3 Position : TEXCOORD0; 7 | float2 TexCoord : TEXCOORD1; 8 | }; 9 | 10 | struct Output 11 | { 12 | float4 Position : SV_Position; 13 | float4 Color : TEXCOORD0; 14 | }; 15 | 16 | Output main(Input input) 17 | { 18 | Output output; 19 | output.Position = float4(input.Position, 1.0f); 20 | output.Color = Texture.SampleLevel(Sampler, input.TexCoord, 0.0f); 21 | return output; 22 | } 23 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/TexturedQuadWithMatrix.vert.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UniformBlock : register(b0, space1) 2 | { 3 | float4x4 MatrixTransform : packoffset(c0); 4 | }; 5 | 6 | struct Input 7 | { 8 | float3 Position : TEXCOORD0; 9 | float2 TexCoord : TEXCOORD1; 10 | }; 11 | 12 | struct Output 13 | { 14 | float4 Position : SV_Position; 15 | float2 TexCoord : TEXCOORD0; 16 | }; 17 | 18 | Output main(Input input) 19 | { 20 | Output output; 21 | output.Position = mul(MatrixTransform, float4(input.Position, 1.0f)); 22 | output.TexCoord = input.TexCoord; 23 | return output; 24 | } 25 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/GradientTexture.comp.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UBO : register(b0, space2) 2 | { 3 | float ubo_time : packoffset(c0); 4 | }; 5 | 6 | RWTexture2D OutImage : register(u0, space1); 7 | 8 | [numthreads(8, 8, 1)] 9 | void main(uint3 GlobalInvocationID : SV_DispatchThreadID) 10 | { 11 | float2 size; 12 | OutImage.GetDimensions(size.x, size.y); 13 | float2 coord = float2(GlobalInvocationID.xy); 14 | float2 uv = coord / size; 15 | float3 col = 0.5f.xxx + (cos((ubo_time.xxx + uv.xyx) + float3(0.0f, 2.0f, 4.0f)) * 0.5f); 16 | OutImage[int2(coord)] = float4(col, 1.0f); 17 | } 18 | -------------------------------------------------------------------------------- /MoonWorksGraphicsTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | true 7 | 8 | 9 | 10 | 11 | Content\%(RecursiveDir)%(Filename)%(Extension) 12 | Always 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/PositionColorInstanced.vert.hlsl: -------------------------------------------------------------------------------- 1 | struct Input 2 | { 3 | float3 Position : TEXCOORD0; 4 | float4 Color : TEXCOORD1; 5 | uint InstanceIndex : SV_InstanceID; 6 | }; 7 | 8 | struct Output 9 | { 10 | float4 Position : SV_Position; 11 | float4 Color : TEXCOORD0; 12 | }; 13 | 14 | Output main(Input input) 15 | { 16 | float3 pos = (input.Position * 0.25f) - float3(0.75f, 0.75f, 0.0f); 17 | pos.x += (float(input.InstanceIndex % 4) * 0.5f); 18 | pos.y += (floor(float(input.InstanceIndex / 4)) * 0.5f); 19 | 20 | Output output; 21 | output.Position = float4(pos, 1.0f); 22 | output.Color = input.Color; 23 | return output; 24 | } 25 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/TexturedQuadColorWithMatrix.vert.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UniformBlock : register(b0, space1) 2 | { 3 | float4x4 MatrixTransform : packoffset(c0); 4 | }; 5 | 6 | struct Input 7 | { 8 | float4 Position : TEXCOORD0; 9 | float2 TexCoord : TEXCOORD1; 10 | float4 Color : TEXCOORD2; 11 | }; 12 | 13 | struct Output 14 | { 15 | float2 TexCoord : TEXCOORD0; 16 | float4 Color : TEXCOORD1; 17 | float4 Position : SV_Position; 18 | }; 19 | 20 | Output main(Input input) 21 | { 22 | Output output; 23 | output.Position = mul(MatrixTransform, input.Position); 24 | output.TexCoord = input.TexCoord; 25 | output.Color = input.Color; 26 | return output; 27 | } 28 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/TexturedDepthQuad.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec2 TexCoord; 4 | layout (location = 0) out vec4 FragColor; 5 | 6 | layout(set = 2, binding = 0) uniform sampler2D Sampler; 7 | 8 | layout (set = 3, binding = 0) uniform UniformBlock 9 | { 10 | float zNear; 11 | float zFar; 12 | }; 13 | 14 | // Calculation taken from http://www.geeks3d.com/20091216/geexlab-how-to-visualize-the-depth-buffer-in-glsl/ 15 | float linearizeDepth(float originalDepth) 16 | { 17 | return (2.0 * zNear) / (zFar + zNear - originalDepth * (zFar - zNear)); 18 | } 19 | 20 | void main() 21 | { 22 | float d = texture(Sampler, TexCoord).r; 23 | d = linearizeDepth(d); 24 | FragColor = vec4(d, d, d, 1.0); 25 | } 26 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/TexturedDepthQuad.frag.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UniformBlock : register(b0, space3) 2 | { 3 | float zNear : packoffset(c0); 4 | float zFar : packoffset(c0.y); 5 | }; 6 | 7 | Texture2D Texture : register(t0, space2); 8 | SamplerState Sampler : register(s0, space2); 9 | 10 | // Calculation taken from http://www.geeks3d.com/20091216/geexlab-how-to-visualize-the-depth-buffer-in-glsl/ 11 | float linearizeDepth(float originalDepth) 12 | { 13 | return (2.0f * zNear) / ((zFar + zNear) - (originalDepth * (zFar - zNear))); 14 | } 15 | 16 | float4 main(float2 TexCoord : TEXCOORD0) : SV_Target0 17 | { 18 | float d = Texture.Sample(Sampler, TexCoord).x; 19 | d = linearizeDepth(d); 20 | return float4(d, d, d, 1.0f); 21 | } 22 | -------------------------------------------------------------------------------- /Examples/ClearScreenExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | 4 | namespace MoonWorksGraphicsTests; 5 | 6 | class ClearScreenExample : Example 7 | { 8 | public override void Init() 9 | { 10 | Window.SetTitle("ClearScreen"); 11 | } 12 | 13 | public override void Update(System.TimeSpan delta) { } 14 | 15 | public override void Draw(double alpha) 16 | { 17 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 18 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 19 | if (swapchainTexture != null) 20 | { 21 | var renderPass = cmdbuf.BeginRenderPass( 22 | new ColorTargetInfo(swapchainTexture, Color.CornflowerBlue) 23 | ); 24 | cmdbuf.EndRenderPass(renderPass); 25 | } 26 | GraphicsDevice.Submit(cmdbuf); 27 | } 28 | 29 | public override void Destroy() 30 | { 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Examples/Example.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MoonWorks; 3 | using MoonWorks.Graphics; 4 | using MoonWorks.Input; 5 | using MoonWorks.Storage; 6 | using MoonWorks.Video; 7 | 8 | namespace MoonWorksGraphicsTests; 9 | 10 | public abstract class Example 11 | { 12 | protected Window Window; 13 | public GraphicsDevice GraphicsDevice; 14 | public Inputs Inputs; 15 | public TitleStorage RootTitleStorage; 16 | public UserStorage UserStorage; 17 | public VideoDevice VideoDevice; 18 | 19 | public void Assign(Game game) 20 | { 21 | Window = game.MainWindow; 22 | GraphicsDevice = game.GraphicsDevice; 23 | Inputs = game.Inputs; 24 | RootTitleStorage = game.RootTitleStorage; 25 | UserStorage = game.UserStorage; 26 | VideoDevice = game.VideoDevice; 27 | } 28 | 29 | public void Start(Game game) 30 | { 31 | Assign(game); 32 | Init(); 33 | } 34 | 35 | public abstract void Init(); 36 | public abstract void Update(TimeSpan delta); 37 | public abstract void Draw(double alpha); 38 | public abstract void Destroy(); 39 | } 40 | -------------------------------------------------------------------------------- /Examples/VideoPlayerExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using MoonWorks.Video; 4 | 5 | namespace MoonWorksGraphicsTests; 6 | 7 | class VideoPlayerExample : Example 8 | { 9 | private VideoAV1 Video; 10 | 11 | public override void Init() 12 | { 13 | Window.SetTitle("VideoPlayer"); 14 | 15 | Video ??= VideoAV1.Create(GraphicsDevice, VideoDevice, RootTitleStorage, TestUtils.GetVideoPath("hello.obu"), 25); 16 | 17 | // Load the video 18 | Video.Load(true); 19 | Video.Play(); 20 | } 21 | 22 | public override void Update(System.TimeSpan delta) 23 | { 24 | Video.Update(delta); 25 | } 26 | 27 | public override void Draw(double alpha) 28 | { 29 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 30 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 31 | if (swapchainTexture != null) 32 | { 33 | cmdbuf.Blit(Video.RenderTexture, swapchainTexture, Filter.Linear); 34 | } 35 | GraphicsDevice.Submit(cmdbuf); 36 | } 37 | 38 | public override void Destroy() 39 | { 40 | Video.Unload(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/RawTriangle.vert.hlsl: -------------------------------------------------------------------------------- 1 | static float4 gl_Position; 2 | static int gl_VertexIndex; 3 | static float4 outColor; 4 | 5 | struct SPIRV_Cross_Input 6 | { 7 | uint gl_VertexIndex : SV_VertexID; 8 | }; 9 | 10 | struct SPIRV_Cross_Output 11 | { 12 | float4 outColor : TEXCOORD0; 13 | float4 gl_Position : SV_Position; 14 | }; 15 | 16 | void vert_main() 17 | { 18 | float2 pos; 19 | if (gl_VertexIndex == 0) 20 | { 21 | pos = (-1.0f).xx; 22 | outColor = float4(1.0f, 0.0f, 0.0f, 1.0f); 23 | } 24 | else 25 | { 26 | if (gl_VertexIndex == 1) 27 | { 28 | pos = float2(1.0f, -1.0f); 29 | outColor = float4(0.0f, 1.0f, 0.0f, 1.0f); 30 | } 31 | else 32 | { 33 | if (gl_VertexIndex == 2) 34 | { 35 | pos = float2(0.0f, 1.0f); 36 | outColor = float4(0.0f, 0.0f, 1.0f, 1.0f); 37 | } 38 | } 39 | } 40 | gl_Position = float4(pos, 0.0f, 1.0f); 41 | } 42 | 43 | SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) 44 | { 45 | gl_VertexIndex = int(stage_input.gl_VertexIndex); 46 | vert_main(); 47 | SPIRV_Cross_Output stage_output; 48 | stage_output.gl_Position = gl_Position; 49 | stage_output.outColor = outColor; 50 | return stage_output; 51 | } 52 | -------------------------------------------------------------------------------- /CopyMoonlibs.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | %(RecursiveDir)%(Filename)%(Extension) 11 | Always 12 | 13 | 14 | 15 | 16 | %(RecursiveDir)%(Filename)%(Extension) 17 | Always 18 | 19 | 20 | 21 | 22 | %(RecursiveDir)%(Filename)%(Extension) 23 | Always 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/HotReload.frag.hlsl: -------------------------------------------------------------------------------- 1 | // Code derived from: https://www.youtube.com/watch?v=f4s1h2YETNY 2 | 3 | cbuffer UniformBlock : register(b0, space3) 4 | { 5 | float2 resolution; 6 | float time; 7 | }; 8 | 9 | float3 palette( float t ) { 10 | float3 a = float3(0.0, 0.5, 1.0); 11 | float3 b = float3(1.0, 0.5, 0.25); 12 | float3 c = float3(1.5, 0.5, 0.0); 13 | float3 d = float3(0.263,0.416,0.557); 14 | 15 | return a + b*cos( 6.28318*(c*t+d) ); 16 | } 17 | 18 | // Thanks IQ 19 | float eqTri(in float2 p, in float r) 20 | { 21 | const float k = sqrt(3.0); 22 | p.x = abs(p.x) - r; 23 | p.x = p.x + r/k; 24 | if( p.x+k*p.y>0.0 ) p = float2(p.x-k*p.y,-k*p.x-p.y)/2.0; 25 | p.x -= clamp( p.x, -2.0*r, 0.0 ); 26 | return -length(p)*sign(p.y); 27 | } 28 | 29 | float4 main(float4 Position : SV_Position) : SV_Target0 30 | { 31 | float2 uv = (Position.xy * 2.0 - resolution) / resolution.y; 32 | float2 uv0 = uv; 33 | float3 finalColor = float3(0.0, 0.0, 0.0); 34 | 35 | for (float i = 0.0; i < 4.0; i++) { 36 | uv = frac(uv * 1.5) - 0.5; 37 | 38 | float d = length(uv) * exp(-length(uv0)); 39 | 40 | float3 col = palette(length(uv0) + i*.4 + time*.4); 41 | 42 | d = sin(d*8. + time)/8.; 43 | d = abs(d); 44 | 45 | d = pow(0.01 / d, 1.2); 46 | 47 | finalColor += col * d; 48 | } 49 | 50 | return float4(finalColor, 1.0); 51 | } 52 | -------------------------------------------------------------------------------- /MoonWorksGraphicsTests.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30717.126 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MoonWorks", "..\MoonWorks\MoonWorks.csproj", "{1695B1D8-4935-490C-A5EC-E2F2AA94B150}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MoonWorksGraphicsTests", "MoonWorksGraphicsTests.csproj", "{8AA61DD7-07CE-45B7-BD1A-52AA0D4DDC92}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {1695B1D8-4935-490C-A5EC-E2F2AA94B150}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {1695B1D8-4935-490C-A5EC-E2F2AA94B150}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {1695B1D8-4935-490C-A5EC-E2F2AA94B150}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {1695B1D8-4935-490C-A5EC-E2F2AA94B150}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {8AA61DD7-07CE-45B7-BD1A-52AA0D4DDC92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {8AA61DD7-07CE-45B7-BD1A-52AA0D4DDC92}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {8AA61DD7-07CE-45B7-BD1A-52AA0D4DDC92}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {8AA61DD7-07CE-45B7-BD1A-52AA0D4DDC92}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {C3D68FAA-3165-43C7-95B3-D845F0DAA918} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/PullSpriteBatch.vert.hlsl: -------------------------------------------------------------------------------- 1 | struct SpriteData 2 | { 3 | float3 Position; 4 | float Rotation; 5 | float2 Scale; 6 | float2 Padding; 7 | float TexU, TexV, TexW, TexH; 8 | float4 Color; 9 | }; 10 | 11 | struct Output 12 | { 13 | float2 Texcoord : TEXCOORD0; 14 | float4 Color : TEXCOORD1; 15 | float4 Position : SV_Position; 16 | }; 17 | 18 | StructuredBuffer DataBuffer : register(t0, space0); 19 | 20 | cbuffer UniformBlock : register(b0, space1) 21 | { 22 | float4x4 ViewProjectionMatrix : packoffset(c0); 23 | }; 24 | 25 | static const uint triangleIndices[6] = {0, 1, 2, 3, 2, 1}; 26 | static const float2 vertexPos[4] = { 27 | {0.0f, 0.0f}, 28 | {1.0f, 0.0f}, 29 | {0.0f, 1.0f}, 30 | {1.0f, 1.0f} 31 | }; 32 | 33 | Output main(uint id : SV_VertexID) 34 | { 35 | uint spriteIndex = id / 6; 36 | uint vert = triangleIndices[id % 6]; 37 | SpriteData sprite = DataBuffer[spriteIndex]; 38 | 39 | float2 texcoord[4] = { 40 | {sprite.TexU, sprite.TexV }, 41 | {sprite.TexU + sprite.TexW, sprite.TexV }, 42 | {sprite.TexU, sprite.TexV + sprite.TexH}, 43 | {sprite.TexU + sprite.TexW, sprite.TexV + sprite.TexH} 44 | }; 45 | 46 | float c = cos(sprite.Rotation); 47 | float s = sin(sprite.Rotation); 48 | 49 | float2 coord = vertexPos[vert]; 50 | coord *= sprite.Scale; 51 | float2x2 rotation = {c, s, -s, c}; 52 | coord = mul(coord, rotation); 53 | 54 | float3 coordWithDepth = float3(coord + sprite.Position.xy, sprite.Position.z); 55 | 56 | Output output; 57 | 58 | output.Position = mul(ViewProjectionMatrix, float4(coordWithDepth, 1.0f)); 59 | output.Texcoord = texcoord[vert]; 60 | output.Color = sprite.Color; 61 | 62 | return output; 63 | } 64 | -------------------------------------------------------------------------------- /Examples/StoreLoadExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MoonWorks; 3 | using MoonWorks.Graphics; 4 | 5 | namespace MoonWorksGraphicsTests; 6 | 7 | class StoreLoadExample : Example 8 | { 9 | private GraphicsPipeline FillPipeline; 10 | 11 | public override void Init() 12 | { 13 | Window.SetTitle("StoreLoad"); 14 | 15 | Shader vertShader = ShaderCross.Create( 16 | GraphicsDevice, 17 | RootTitleStorage, 18 | TestUtils.GetHLSLPath("RawTriangle.vert"), 19 | "main", 20 | ShaderCross.ShaderFormat.HLSL, 21 | ShaderStage.Vertex 22 | ); 23 | 24 | Shader fragShader = ShaderCross.Create( 25 | GraphicsDevice, 26 | RootTitleStorage, 27 | TestUtils.GetHLSLPath("SolidColor.frag"), 28 | "main", 29 | ShaderCross.ShaderFormat.HLSL, 30 | ShaderStage.Fragment 31 | ); 32 | 33 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 34 | Window.SwapchainFormat, 35 | vertShader, 36 | fragShader 37 | ); 38 | FillPipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 39 | } 40 | 41 | public override void Update(TimeSpan delta) 42 | { 43 | 44 | } 45 | 46 | public override void Draw(double alpha) 47 | { 48 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 49 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 50 | if (swapchainTexture != null) 51 | { 52 | var renderPass = cmdbuf.BeginRenderPass( 53 | new ColorTargetInfo(swapchainTexture, Color.Blue) 54 | ); 55 | renderPass.BindGraphicsPipeline(FillPipeline); 56 | renderPass.DrawPrimitives(3, 1, 0, 0); 57 | cmdbuf.EndRenderPass(renderPass); 58 | 59 | renderPass = cmdbuf.BeginRenderPass( 60 | new ColorTargetInfo(swapchainTexture, LoadOp.Load) 61 | ); 62 | cmdbuf.EndRenderPass(renderPass); 63 | } 64 | 65 | GraphicsDevice.Submit(cmdbuf); 66 | } 67 | 68 | public override void Destroy() 69 | { 70 | FillPipeline.Dispose(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Examples/ComputeUniformsExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using MoonWorks.Input; 4 | 5 | namespace MoonWorksGraphicsTests; 6 | 7 | class ComputeUniformsExample : Example 8 | { 9 | private ComputePipeline GradientPipeline; 10 | private Texture RenderTexture; 11 | 12 | record struct GradientTextureComputeUniforms(float Time); 13 | private GradientTextureComputeUniforms Uniforms; 14 | 15 | public override void Init() 16 | { 17 | Window.SetTitle("ComputeUniforms"); 18 | Uniforms.Time = 0; 19 | 20 | // Create the compute pipeline that writes texture data 21 | GradientPipeline = ShaderCross.Create( 22 | GraphicsDevice, 23 | RootTitleStorage, 24 | TestUtils.GetHLSLPath("GradientTexture.comp"), 25 | "main", 26 | ShaderCross.ShaderFormat.HLSL 27 | ); 28 | 29 | RenderTexture = Texture.Create2D( 30 | GraphicsDevice, 31 | Window.Width, 32 | Window.Height, 33 | TextureFormat.R8G8B8A8Unorm, 34 | TextureUsageFlags.ComputeStorageWrite | TextureUsageFlags.Sampler 35 | ); 36 | } 37 | 38 | public override void Update(System.TimeSpan delta) 39 | { 40 | Uniforms.Time += (float) delta.TotalSeconds; 41 | } 42 | 43 | public override void Draw(double alpha) 44 | { 45 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 46 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 47 | if (swapchainTexture != null) 48 | { 49 | var computePass = cmdbuf.BeginComputePass( 50 | new StorageTextureReadWriteBinding(RenderTexture, true) 51 | ); 52 | 53 | cmdbuf.PushComputeUniformData(Uniforms); 54 | 55 | computePass.BindComputePipeline(GradientPipeline); 56 | computePass.Dispatch(RenderTexture.Width / 8, RenderTexture.Height / 8, 1); 57 | cmdbuf.EndComputePass(computePass); 58 | 59 | cmdbuf.Blit(RenderTexture, swapchainTexture, Filter.Linear); 60 | } 61 | 62 | GraphicsDevice.Submit(cmdbuf); 63 | } 64 | 65 | public override void Destroy() 66 | { 67 | GradientPipeline.Dispose(); 68 | RenderTexture.Dispose(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Examples/ClearScreen_MultiWindowExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using MoonWorks.Input; 4 | using SDL3; 5 | 6 | namespace MoonWorksGraphicsTests 7 | { 8 | class ClearScreen_MultiWindowExample : Example 9 | { 10 | private Window SecondaryWindow; 11 | 12 | public override void Init() 13 | { 14 | Window.SetTitle("ClearScreen"); 15 | var (windowX, windowY) = Window.Position; 16 | Window.SetPosition(windowX - 360, windowY); 17 | 18 | SecondaryWindow = new Window( 19 | new WindowCreateInfo("Secondary Window", 640, 480, ScreenMode.Windowed, false, false), 20 | 0 21 | ); 22 | (windowX, windowY) = SecondaryWindow.Position; 23 | SecondaryWindow.SetPosition(windowX + 360, windowY); 24 | 25 | GraphicsDevice.ClaimWindow(SecondaryWindow); 26 | } 27 | 28 | public override void Update(System.TimeSpan delta) { } 29 | 30 | public override void Draw(double alpha) 31 | { 32 | CommandBuffer cmdbuf; 33 | Texture swapchainTexture; 34 | 35 | if (Window.Claimed) 36 | { 37 | cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 38 | swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 39 | if (swapchainTexture != null) 40 | { 41 | var renderPass = cmdbuf.BeginRenderPass( 42 | new ColorTargetInfo(swapchainTexture, Color.CornflowerBlue) 43 | ); 44 | cmdbuf.EndRenderPass(renderPass); 45 | } 46 | GraphicsDevice.Submit(cmdbuf); 47 | } 48 | 49 | if (SecondaryWindow.Claimed) 50 | { 51 | cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 52 | swapchainTexture = cmdbuf.AcquireSwapchainTexture(SecondaryWindow); 53 | if (swapchainTexture != null) 54 | { 55 | var renderPass = cmdbuf.BeginRenderPass( 56 | new ColorTargetInfo(swapchainTexture, Color.Aquamarine) 57 | ); 58 | cmdbuf.EndRenderPass(renderPass); 59 | } 60 | GraphicsDevice.Submit(cmdbuf); 61 | } 62 | } 63 | 64 | public override void Destroy() 65 | { 66 | GraphicsDevice.UnclaimWindow(SecondaryWindow); 67 | SecondaryWindow.Dispose(); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Common/Content/Shaders/GLSL/SpriteBatch.comp: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | struct SpriteComputeData 4 | { 5 | vec3 position; 6 | float rotation; 7 | vec2 scale; 8 | vec4 color; 9 | }; 10 | 11 | struct SpriteVertex 12 | { 13 | vec4 position; 14 | vec2 texcoord; 15 | vec4 color; 16 | }; 17 | 18 | layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in; 19 | layout (std430, set = 0, binding = 0) readonly buffer inBuffer 20 | { 21 | SpriteComputeData computeData[]; 22 | }; 23 | layout (std430, set = 1, binding = 0) writeonly buffer outBuffer 24 | { 25 | SpriteVertex vertexData[]; 26 | }; 27 | 28 | void main() 29 | { 30 | uint n = gl_GlobalInvocationID.x; 31 | 32 | SpriteComputeData currentSpriteData = computeData[n]; 33 | 34 | mat4 Scale = mat4( 35 | currentSpriteData.scale.x, 0, 0, 0, 36 | 0, currentSpriteData.scale.y, 0, 0, 37 | 0, 0, 1, 0, 38 | 0, 0, 0, 1 39 | ); 40 | 41 | float c = cos(currentSpriteData.rotation); 42 | float s = sin(currentSpriteData.rotation); 43 | 44 | mat4 Rotation = mat4( 45 | c, s, 0, 0, 46 | -s, c, 0, 0, 47 | 0, 0, 1, 0, 48 | 0, 0, 0, 1 49 | ); 50 | 51 | mat4 Translation = mat4( 52 | 1, 0, 0, 0, 53 | 0, 1, 0, 0, 54 | 0, 0, 1, 0, 55 | currentSpriteData.position.x, currentSpriteData.position.y, currentSpriteData.position.z, 1 56 | ); 57 | 58 | mat4 Model = Translation * Rotation * Scale; 59 | 60 | vec4 topLeft = vec4(0, 0, 0, 1); 61 | vec4 topRight = vec4(1, 0, 0, 1); 62 | vec4 bottomLeft = vec4(0, 1, 0, 1); 63 | vec4 bottomRight = vec4(1, 1, 0, 1); 64 | 65 | vertexData[n*4] .position = Model * topLeft; 66 | vertexData[n*4+1].position = Model * topRight; 67 | vertexData[n*4+2].position = Model * bottomLeft; 68 | vertexData[n*4+3].position = Model * bottomRight; 69 | 70 | vertexData[n*4] .texcoord = vec2(0, 0); 71 | vertexData[n*4+1].texcoord = vec2(1, 0); 72 | vertexData[n*4+2].texcoord = vec2(0, 1); 73 | vertexData[n*4+3].texcoord = vec2(1, 1); 74 | 75 | vertexData[n*4] .color = currentSpriteData.color; 76 | vertexData[n*4+1].color = currentSpriteData.color; 77 | vertexData[n*4+2].color = currentSpriteData.color; 78 | vertexData[n*4+3].color = currentSpriteData.color; 79 | } 80 | -------------------------------------------------------------------------------- /Examples/RenderTexture2DArrayExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MoonWorks; 3 | using MoonWorks.Graphics; 4 | using MoonWorks.Input; 5 | 6 | namespace MoonWorksGraphicsTests; 7 | 8 | class RenderTexture2DArrayExample : Example 9 | { 10 | private Texture RenderTarget; 11 | 12 | private float t; 13 | private Color[] colors = 14 | [ 15 | Color.Red, 16 | Color.Green, 17 | Color.Blue, 18 | ]; 19 | 20 | public override void Init() 21 | { 22 | Window.SetTitle("RenderTexture2DArray"); 23 | 24 | RenderTarget = Texture.Create2DArray( 25 | GraphicsDevice, 26 | 16, 27 | 16, 28 | (uint) colors.Length, 29 | TextureFormat.R8G8B8A8Unorm, 30 | TextureUsageFlags.ColorTarget | TextureUsageFlags.Sampler 31 | ); 32 | 33 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 34 | 35 | // Clear each depth slice of the RT to a different color 36 | for (uint i = 0; i < colors.Length; i += 1) 37 | { 38 | var renderPass = cmdbuf.BeginRenderPass(new ColorTargetInfo 39 | { 40 | Texture = RenderTarget.Handle, 41 | LayerOrDepthPlane = i, 42 | LoadOp = LoadOp.Clear, 43 | ClearColor = colors[i], 44 | StoreOp = StoreOp.Store 45 | }); 46 | cmdbuf.EndRenderPass(renderPass); 47 | } 48 | 49 | GraphicsDevice.Submit(cmdbuf); 50 | } 51 | 52 | public override void Update(System.TimeSpan delta) 53 | { 54 | t += (float) delta.TotalSeconds; 55 | t %= 3; 56 | } 57 | 58 | public override void Draw(double alpha) 59 | { 60 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 61 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 62 | if (swapchainTexture != null) 63 | { 64 | cmdbuf.Blit(new BlitInfo 65 | { 66 | Source = new BlitRegion 67 | { 68 | Texture = RenderTarget.Handle, 69 | LayerOrDepthPlane = (uint) Math.Floor(t), 70 | W = RenderTarget.Width, 71 | H = RenderTarget.Height 72 | }, 73 | Destination = new BlitRegion(swapchainTexture), 74 | Filter = Filter.Nearest, 75 | LoadOp = LoadOp.DontCare 76 | }); 77 | } 78 | GraphicsDevice.Submit(cmdbuf); 79 | } 80 | 81 | public override void Destroy() 82 | { 83 | RenderTarget.Dispose(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Examples/TriangleVertexBufferExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using MoonWorks.Input; 4 | using System.Numerics; 5 | 6 | namespace MoonWorksGraphicsTests; 7 | 8 | class TriangleVertexBufferExample : Example 9 | { 10 | private GraphicsPipeline Pipeline; 11 | private Buffer VertexBuffer; 12 | 13 | public override void Init() 14 | { 15 | Window.SetTitle("TriangleVertexBuffer"); 16 | 17 | // Load the shaders 18 | Shader vertShader = ShaderCross.Create( 19 | GraphicsDevice, 20 | RootTitleStorage, 21 | TestUtils.GetHLSLPath("PositionColor.vert"), 22 | "main", 23 | ShaderCross.ShaderFormat.HLSL, 24 | ShaderStage.Vertex 25 | ); 26 | Shader fragShader = ShaderCross.Create( 27 | GraphicsDevice, 28 | RootTitleStorage, 29 | TestUtils.GetHLSLPath("SolidColor.frag"), 30 | "main", 31 | ShaderCross.ShaderFormat.HLSL, 32 | ShaderStage.Fragment 33 | ); 34 | 35 | // Create the graphics pipeline 36 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 37 | Window.SwapchainFormat, 38 | vertShader, 39 | fragShader 40 | ); 41 | pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); 42 | Pipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 43 | 44 | // Create and populate the vertex buffer 45 | var resourceUploader = new ResourceUploader(GraphicsDevice); 46 | 47 | VertexBuffer = resourceUploader.CreateBuffer( 48 | [ 49 | new PositionColorVertex(new Vector3(-1, -1, 0), Color.Red), 50 | new PositionColorVertex(new Vector3( 1, -1, 0), Color.Lime), 51 | new PositionColorVertex(new Vector3( 0, 1, 0), Color.Blue), 52 | ], 53 | BufferUsageFlags.Vertex 54 | ); 55 | 56 | resourceUploader.Upload(); 57 | resourceUploader.Dispose(); 58 | } 59 | 60 | public override void Update(System.TimeSpan delta) { } 61 | 62 | public override void Draw(double alpha) 63 | { 64 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 65 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 66 | if (swapchainTexture != null) 67 | { 68 | var renderPass = cmdbuf.BeginRenderPass( 69 | new ColorTargetInfo(swapchainTexture, Color.Black) 70 | ); 71 | renderPass.BindGraphicsPipeline(Pipeline); 72 | renderPass.BindVertexBuffers(VertexBuffer); 73 | renderPass.DrawPrimitives(3, 1, 0, 0); 74 | cmdbuf.EndRenderPass(renderPass); 75 | } 76 | 77 | GraphicsDevice.Submit(cmdbuf); 78 | } 79 | 80 | public override void Destroy() 81 | { 82 | Pipeline.Dispose(); 83 | VertexBuffer.Dispose(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Common/VertexTypes.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using MoonWorks.Graphics; 3 | using System.Numerics; 4 | 5 | namespace MoonWorksGraphicsTests; 6 | 7 | [StructLayout(LayoutKind.Sequential)] 8 | public struct PositionVertex : IVertexType 9 | { 10 | public Vector3 Position; 11 | 12 | public PositionVertex(Vector3 position) 13 | { 14 | Position = position; 15 | } 16 | 17 | public static VertexElementFormat[] Formats { get; } = 18 | [ 19 | VertexElementFormat.Float3 20 | ]; 21 | 22 | public static uint[] Offsets { get; } = [ 0 ]; 23 | 24 | public override string ToString() 25 | { 26 | return Position.ToString(); 27 | } 28 | } 29 | 30 | [StructLayout(LayoutKind.Sequential)] 31 | public struct PositionColorVertex : IVertexType 32 | { 33 | public Vector3 Position; 34 | public Color Color; 35 | 36 | public PositionColorVertex(Vector3 position, Color color) 37 | { 38 | Position = position; 39 | Color = color; 40 | } 41 | 42 | public static VertexElementFormat[] Formats { get; } = 43 | [ 44 | VertexElementFormat.Float3, 45 | VertexElementFormat.Ubyte4Norm 46 | ]; 47 | 48 | public static uint[] Offsets { get; } = 49 | [ 50 | 0, 51 | 12 52 | ]; 53 | 54 | public override string ToString() 55 | { 56 | return Position + " | " + Color; 57 | } 58 | } 59 | 60 | [StructLayout(LayoutKind.Sequential)] 61 | public struct PositionTextureVertex : IVertexType 62 | { 63 | public Vector3 Position; 64 | public Vector2 TexCoord; 65 | 66 | public PositionTextureVertex(Vector3 position, Vector2 texCoord) 67 | { 68 | Position = position; 69 | TexCoord = texCoord; 70 | } 71 | 72 | public static VertexElementFormat[] Formats { get; } = new VertexElementFormat[2] 73 | { 74 | VertexElementFormat.Float3, 75 | VertexElementFormat.Float2 76 | }; 77 | 78 | public static uint[] Offsets { get; } = 79 | [ 80 | 0, 81 | 12 82 | ]; 83 | 84 | public override string ToString() 85 | { 86 | return Position + " | " + TexCoord; 87 | } 88 | } 89 | 90 | [StructLayout(LayoutKind.Explicit, Size = 48)] 91 | struct PositionTextureColorVertex : IVertexType 92 | { 93 | [FieldOffset(0)] 94 | public Vector4 Position; 95 | 96 | [FieldOffset(16)] 97 | public Vector2 TexCoord; 98 | 99 | [FieldOffset(32)] 100 | public Vector4 Color; 101 | 102 | public static VertexElementFormat[] Formats { get; } = 103 | [ 104 | VertexElementFormat.Float4, 105 | VertexElementFormat.Float2, 106 | VertexElementFormat.Float4 107 | ]; 108 | 109 | public static uint[] Offsets { get; } = 110 | [ 111 | 0, 112 | 16, 113 | 32 114 | ]; 115 | } 116 | -------------------------------------------------------------------------------- /Common/Content/Shaders/HLSL/SpriteBatch.comp.hlsl: -------------------------------------------------------------------------------- 1 | struct SpriteComputeData 2 | { 3 | float3 position; 4 | float rotation; 5 | float2 scale; 6 | float4 color; 7 | }; 8 | 9 | struct SpriteVertex 10 | { 11 | float4 position; 12 | float2 texcoord; 13 | float4 color; 14 | }; 15 | 16 | StructuredBuffer ComputeBuffer : register(t0, space0); 17 | RWStructuredBuffer VertexBuffer : register(u0, space1); 18 | 19 | [numthreads(64, 1, 1)] 20 | void main(uint3 GlobalInvocationID : SV_DispatchThreadID) 21 | { 22 | uint n = GlobalInvocationID.x; 23 | 24 | SpriteComputeData currentSpriteData = ComputeBuffer[n]; 25 | 26 | float4x4 Scale = float4x4( 27 | float4(currentSpriteData.scale.x, 0.0f, 0.0f, 0.0f), 28 | float4(0.0f, currentSpriteData.scale.y, 0.0f, 0.0f), 29 | float4(0.0f, 0.0f, 1.0f, 0.0f), 30 | float4(0.0f, 0.0f, 0.0f, 1.0f) 31 | ); 32 | 33 | float c = cos(currentSpriteData.rotation); 34 | float s = sin(currentSpriteData.rotation); 35 | 36 | float4x4 Rotation = float4x4( 37 | float4( c, s, 0.0f, 0.0f), 38 | float4( -s, c, 0.0f, 0.0f), 39 | float4(0.0f, 0.0f, 1.0f, 0.0f), 40 | float4(0.0f, 0.0f, 0.0f, 1.0f) 41 | ); 42 | 43 | float4x4 Translation = float4x4( 44 | float4(1.0f, 0.0f, 0.0f, 0.0f), 45 | float4(0.0f, 1.0f, 0.0f, 0.0f), 46 | float4(0.0f, 0.0f, 1.0f, 0.0f), 47 | float4(currentSpriteData.position.x, currentSpriteData.position.y, currentSpriteData.position.z, 1.0f) 48 | ); 49 | 50 | float4x4 Model = mul(Scale, mul(Rotation, Translation)); 51 | 52 | float4 topLeft = float4(0.0f, 0.0f, 0.0f, 1.0f); 53 | float4 topRight = float4(1.0f, 0.0f, 0.0f, 1.0f); 54 | float4 bottomLeft = float4(0.0f, 1.0f, 0.0f, 1.0f); 55 | float4 bottomRight = float4(1.0f, 1.0f, 0.0f, 1.0f); 56 | 57 | VertexBuffer[n * 4u] .position = mul(topLeft, Model); 58 | VertexBuffer[n * 4u + 1].position = mul(topRight, Model); 59 | VertexBuffer[n * 4u + 2].position = mul(bottomLeft, Model); 60 | VertexBuffer[n * 4u + 3].position = mul(bottomRight, Model); 61 | 62 | VertexBuffer[n * 4u] .texcoord = float2(0.0f, 0.0f); 63 | VertexBuffer[n * 4u + 1].texcoord = float2(1.0f, 0.0f); 64 | VertexBuffer[n * 4u + 2].texcoord = float2(0.0f, 1.0f); 65 | VertexBuffer[n * 4u + 3].texcoord = float2(1.0f, 1.0f); 66 | 67 | VertexBuffer[n * 4u] .color = currentSpriteData.color; 68 | VertexBuffer[n * 4u + 1].color = currentSpriteData.color; 69 | VertexBuffer[n * 4u + 2].color = currentSpriteData.color; 70 | VertexBuffer[n * 4u + 3].color = currentSpriteData.color; 71 | } 72 | -------------------------------------------------------------------------------- /Examples/WindowResizingExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using MoonWorks.Input; 4 | 5 | namespace MoonWorksGraphicsTests; 6 | 7 | class WindowResizingExample : Example 8 | { 9 | private GraphicsPipeline pipeline; 10 | 11 | private int currentResolutionIndex; 12 | private record struct Res(uint Width, uint Height); 13 | private Res[] resolutions = 14 | [ 15 | new Res(640, 480), 16 | new Res(1280, 720), 17 | new Res(1024, 1024), 18 | new Res(1600, 900), 19 | new Res(1920, 1080), 20 | new Res(3200, 1800), 21 | new Res(3840, 2160), 22 | ]; 23 | 24 | public override void Init() 25 | { 26 | Window.SetTitle("WindowResizing"); 27 | 28 | Logger.LogInfo("Press left and right to resize the window!"); 29 | 30 | Shader vertShader = ShaderCross.Create( 31 | GraphicsDevice, 32 | RootTitleStorage, 33 | TestUtils.GetHLSLPath("RawTriangle.vert"), 34 | "main", 35 | ShaderCross.ShaderFormat.HLSL, 36 | ShaderStage.Vertex 37 | ); 38 | 39 | Shader fragShader = ShaderCross.Create( 40 | GraphicsDevice, 41 | RootTitleStorage, 42 | TestUtils.GetHLSLPath("SolidColor.frag"), 43 | "main", 44 | ShaderCross.ShaderFormat.HLSL, 45 | ShaderStage.Fragment 46 | ); 47 | 48 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 49 | Window.SwapchainFormat, 50 | vertShader, 51 | fragShader 52 | ); 53 | pipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 54 | } 55 | 56 | public override void Update(System.TimeSpan delta) 57 | { 58 | int prevResolutionIndex = currentResolutionIndex; 59 | 60 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Left)) 61 | { 62 | currentResolutionIndex -= 1; 63 | if (currentResolutionIndex < 0) 64 | { 65 | currentResolutionIndex = resolutions.Length - 1; 66 | } 67 | } 68 | 69 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Right)) 70 | { 71 | currentResolutionIndex += 1; 72 | if (currentResolutionIndex >= resolutions.Length) 73 | { 74 | currentResolutionIndex = 0; 75 | } 76 | } 77 | 78 | if (prevResolutionIndex != currentResolutionIndex) 79 | { 80 | Logger.LogInfo("Setting resolution to: " + resolutions[currentResolutionIndex]); 81 | Window.SetSize(resolutions[currentResolutionIndex].Width, resolutions[currentResolutionIndex].Height); 82 | Window.SetPositionCentered(); 83 | } 84 | } 85 | 86 | public override void Draw(double alpha) 87 | { 88 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 89 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 90 | if (swapchainTexture != null) 91 | { 92 | var renderPass = cmdbuf.BeginRenderPass( 93 | new ColorTargetInfo(swapchainTexture, Color.Black) 94 | ); 95 | renderPass.BindGraphicsPipeline(pipeline); 96 | renderPass.DrawPrimitives(3, 1, 0, 0); 97 | cmdbuf.EndRenderPass(renderPass); 98 | } 99 | GraphicsDevice.Submit(cmdbuf); 100 | } 101 | 102 | public override void Destroy() 103 | { 104 | pipeline.Dispose(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Examples/FontExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MoonWorks; 3 | using MoonWorks.Graphics; 4 | using MoonWorks.Graphics.Font; 5 | using MoonWorks.Input; 6 | using System.Numerics; 7 | 8 | namespace MoonWorksGraphicsTests; 9 | 10 | class FontExample : Example 11 | { 12 | Font SofiaSans; 13 | TextBatch TextBatch; 14 | GraphicsPipeline FontPipeline; 15 | 16 | float rotation; 17 | 18 | public override void Init() 19 | { 20 | Window.SetTitle("Font"); 21 | 22 | SofiaSans = Font.Load(GraphicsDevice, RootTitleStorage, TestUtils.GetFontPath("SofiaSans.ttf")); 23 | TextBatch = new TextBatch(GraphicsDevice); 24 | 25 | var fontPipelineCreateInfo = new GraphicsPipelineCreateInfo 26 | { 27 | VertexShader = GraphicsDevice.TextVertexShader, 28 | FragmentShader = GraphicsDevice.TextFragmentShader, 29 | VertexInputState = GraphicsDevice.TextVertexInputState, 30 | PrimitiveType = PrimitiveType.TriangleList, 31 | RasterizerState = RasterizerState.CCW_CullNone, 32 | MultisampleState = MultisampleState.None, 33 | DepthStencilState = DepthStencilState.Disable, 34 | TargetInfo = new GraphicsPipelineTargetInfo 35 | { 36 | ColorTargetDescriptions = [ 37 | new ColorTargetDescription 38 | { 39 | Format = Window.SwapchainFormat, 40 | BlendState = ColorTargetBlendState.Opaque 41 | } 42 | ] 43 | } 44 | }; 45 | 46 | FontPipeline = GraphicsPipeline.Create(GraphicsDevice, fontPipelineCreateInfo); 47 | 48 | Logger.LogInfo("Press Left and Right to rotate the text!"); 49 | } 50 | 51 | public override void Update(TimeSpan delta) 52 | { 53 | if (TestUtils.CheckButtonDown(Inputs, TestUtils.ButtonType.Left)) 54 | { 55 | rotation -= (float) delta.TotalSeconds; 56 | } 57 | else if (TestUtils.CheckButtonDown(Inputs, TestUtils.ButtonType.Right)) 58 | { 59 | rotation += (float) delta.TotalSeconds; 60 | } 61 | } 62 | 63 | public override void Draw(double alpha) 64 | { 65 | var cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 66 | var swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 67 | 68 | if (swapchainTexture != null) 69 | { 70 | Matrix4x4 proj = Matrix4x4.CreateOrthographicOffCenter( 71 | 0, 72 | 640, 73 | 480, 74 | 0, 75 | 0, 76 | -1 77 | ); 78 | 79 | Matrix4x4 model = 80 | Matrix4x4.CreateRotationX(rotation) * 81 | Matrix4x4.CreateTranslation(320, 240, 0); 82 | 83 | TextBatch.Start(); 84 | TextBatch.Add( 85 | SofiaSans, 86 | "THIS IS SOME TEXT.", 87 | 64, 88 | model, 89 | Color.White, 90 | HorizontalAlignment.Center, 91 | VerticalAlignment.Middle 92 | ); 93 | TextBatch.UploadBufferData(cmdbuf); 94 | 95 | var renderPass = cmdbuf.BeginRenderPass( 96 | new ColorTargetInfo(swapchainTexture, Color.Black) 97 | ); 98 | 99 | renderPass.BindGraphicsPipeline(FontPipeline); 100 | TextBatch.Render(renderPass, proj); 101 | cmdbuf.EndRenderPass(renderPass); 102 | } 103 | 104 | GraphicsDevice.Submit(cmdbuf); 105 | } 106 | 107 | public override void Destroy() 108 | { 109 | TextBatch.Dispose(); 110 | SofiaSans.Dispose(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Examples/VertexSamplerExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using MoonWorks.Input; 4 | using System.Numerics; 5 | using Buffer = MoonWorks.Graphics.Buffer; 6 | 7 | namespace MoonWorksGraphicsTests; 8 | 9 | class VertexSamplerExample : Example 10 | { 11 | private GraphicsPipeline Pipeline; 12 | private Buffer VertexBuffer; 13 | private Texture Texture; 14 | private Sampler Sampler; 15 | 16 | public override void Init() 17 | { 18 | Window.SetTitle("VertexSampler"); 19 | 20 | // Load the shaders 21 | Shader vertShader = ShaderCross.Create( 22 | GraphicsDevice, 23 | RootTitleStorage, 24 | TestUtils.GetHLSLPath("PositionSampler.vert"), 25 | "main", 26 | ShaderCross.ShaderFormat.HLSL, 27 | ShaderStage.Vertex 28 | ); 29 | 30 | Shader fragShader = ShaderCross.Create( 31 | GraphicsDevice, 32 | RootTitleStorage, 33 | TestUtils.GetHLSLPath("SolidColor.frag"), 34 | "main", 35 | ShaderCross.ShaderFormat.HLSL, 36 | ShaderStage.Fragment 37 | ); 38 | 39 | // Create the graphics pipeline 40 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 41 | Window.SwapchainFormat, 42 | vertShader, 43 | fragShader 44 | ); 45 | pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); 46 | 47 | Pipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 48 | 49 | // Create and populate the GPU resources 50 | Sampler = Sampler.Create(GraphicsDevice, SamplerCreateInfo.PointClamp); 51 | 52 | var resourceUploader = new ResourceUploader(GraphicsDevice); 53 | 54 | VertexBuffer = resourceUploader.CreateBuffer( 55 | [ 56 | new PositionTextureVertex(new Vector3(-1, -1, 0), new Vector2(0, 0)), 57 | new PositionTextureVertex(new Vector3( 1, -1, 0), new Vector2(0.334f, 0)), 58 | new PositionTextureVertex(new Vector3( 0, 1, 0), new Vector2(0.667f, 0)), 59 | ], 60 | BufferUsageFlags.Vertex 61 | ); 62 | 63 | Texture = resourceUploader.CreateTexture2D( 64 | [Color.Yellow, Color.Indigo, Color.HotPink], 65 | TextureFormat.R8G8B8A8Unorm, 66 | TextureUsageFlags.Sampler, 67 | 3, 68 | 1 69 | ); 70 | 71 | resourceUploader.Upload(); 72 | resourceUploader.Dispose(); 73 | } 74 | 75 | public override void Update(System.TimeSpan delta) { } 76 | 77 | public override void Draw(double alpha) 78 | { 79 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 80 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 81 | if (swapchainTexture != null) 82 | { 83 | var renderPass = cmdbuf.BeginRenderPass( 84 | new ColorTargetInfo(swapchainTexture, Color.Black) 85 | ); 86 | renderPass.BindGraphicsPipeline(Pipeline); 87 | renderPass.BindVertexBuffers(VertexBuffer); 88 | renderPass.BindVertexSamplers(new TextureSamplerBinding(Texture, Sampler)); 89 | renderPass.DrawPrimitives(3, 1, 0, 0); 90 | cmdbuf.EndRenderPass(renderPass); 91 | } 92 | GraphicsDevice.Submit(cmdbuf); 93 | } 94 | 95 | public override void Destroy() 96 | { 97 | Pipeline.Dispose(); 98 | VertexBuffer.Dispose(); 99 | Texture.Dispose(); 100 | Sampler.Dispose(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Examples/RenderTexture2DExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | 4 | namespace MoonWorksGraphicsTests; 5 | 6 | class RenderTexture2DExample : Example 7 | { 8 | private Texture[] textures = new Texture[4]; 9 | 10 | public override void Init() 11 | { 12 | Window.SetTitle("RenderTexture2D"); 13 | 14 | for (int i = 0; i < textures.Length; i += 1) 15 | { 16 | textures[i] = Texture.Create2D( 17 | GraphicsDevice, 18 | Window.Width / 4, 19 | Window.Height / 4, 20 | TextureFormat.R8G8B8A8Unorm, 21 | TextureUsageFlags.ColorTarget | TextureUsageFlags.Sampler 22 | ); 23 | } 24 | } 25 | 26 | public override void Update(System.TimeSpan delta) { } 27 | 28 | public override void Draw(double alpha) 29 | { 30 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 31 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 32 | if (swapchainTexture != null) 33 | { 34 | var renderPass = cmdbuf.BeginRenderPass( 35 | new ColorTargetInfo(textures[0], Color.Red) 36 | ); 37 | cmdbuf.EndRenderPass(renderPass); 38 | 39 | renderPass = cmdbuf.BeginRenderPass( 40 | new ColorTargetInfo(textures[1], Color.DodgerBlue) 41 | ); 42 | cmdbuf.EndRenderPass(renderPass); 43 | 44 | renderPass = cmdbuf.BeginRenderPass( 45 | new ColorTargetInfo(textures[2], Color.Green) 46 | ); 47 | cmdbuf.EndRenderPass(renderPass); 48 | 49 | renderPass = cmdbuf.BeginRenderPass( 50 | new ColorTargetInfo(textures[3], Color.DarkGoldenrod) 51 | ); 52 | cmdbuf.EndRenderPass(renderPass); 53 | 54 | cmdbuf.Blit(new BlitInfo 55 | { 56 | Source = new BlitRegion(textures[0]), 57 | Destination = new BlitRegion 58 | { 59 | Texture = swapchainTexture.Handle, 60 | W = swapchainTexture.Width / 2, 61 | H = swapchainTexture.Height / 2, 62 | }, 63 | Filter = Filter.Nearest 64 | }); 65 | 66 | cmdbuf.Blit(new BlitInfo 67 | { 68 | Source = new BlitRegion(textures[1]), 69 | Destination = new BlitRegion 70 | { 71 | Texture = swapchainTexture.Handle, 72 | X = swapchainTexture.Width / 2, 73 | W = swapchainTexture.Width / 2, 74 | H = swapchainTexture.Height / 2, 75 | }, 76 | Filter = Filter.Nearest 77 | }); 78 | 79 | cmdbuf.Blit(new BlitInfo 80 | { 81 | Source = new BlitRegion(textures[2]), 82 | Destination = new BlitRegion 83 | { 84 | Texture = swapchainTexture.Handle, 85 | Y = swapchainTexture.Height / 2, 86 | W = swapchainTexture.Width / 2, 87 | H = swapchainTexture.Height / 2, 88 | }, 89 | Filter = Filter.Nearest 90 | }); 91 | 92 | cmdbuf.Blit(new BlitInfo 93 | { 94 | Source = new BlitRegion(textures[3]), 95 | Destination = new BlitRegion 96 | { 97 | Texture = swapchainTexture.Handle, 98 | X = swapchainTexture.Width / 2, 99 | Y = swapchainTexture.Height / 2, 100 | W = swapchainTexture.Width / 2, 101 | H = swapchainTexture.Height / 2 102 | }, 103 | Filter = Filter.Nearest 104 | }); 105 | } 106 | 107 | GraphicsDevice.Submit(cmdbuf); 108 | } 109 | 110 | public override void Destroy() 111 | { 112 | for (var i = 0; i < 4; i += 1) 113 | { 114 | textures[i].Dispose(); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Examples/BasicTriangleExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using MoonWorks.Input; 4 | 5 | namespace MoonWorksGraphicsTests; 6 | 7 | class BasicTriangleExample : Example 8 | { 9 | private GraphicsPipeline FillPipeline; 10 | private GraphicsPipeline LinePipeline; 11 | 12 | private Viewport SmallViewport = new Viewport(160, 120, 320, 240); 13 | private Rect ScissorRect = new Rect(320, 240, 320, 240); 14 | 15 | private bool UseWireframeMode; 16 | private bool UseSmallViewport; 17 | private bool UseScissorRect; 18 | 19 | public override void Init() 20 | { 21 | Window.SetTitle("BasicTriangle"); 22 | 23 | Logger.LogInfo("Press Left to toggle wireframe mode\nPress Down to toggle small viewport\nPress Right to toggle scissor rect"); 24 | 25 | Shader vertShaderModule = ShaderCross.Create( 26 | GraphicsDevice, 27 | RootTitleStorage, 28 | TestUtils.GetHLSLPath("RawTriangle.vert"), 29 | "main", 30 | ShaderCross.ShaderFormat.HLSL, 31 | ShaderStage.Vertex 32 | ); 33 | 34 | Shader fragShaderModule = ShaderCross.Create( 35 | GraphicsDevice, 36 | RootTitleStorage, 37 | TestUtils.GetHLSLPath("SolidColor.frag"), 38 | "main", 39 | ShaderCross.ShaderFormat.HLSL, 40 | ShaderStage.Fragment 41 | ); 42 | 43 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 44 | Window.SwapchainFormat, 45 | vertShaderModule, 46 | fragShaderModule 47 | ); 48 | FillPipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 49 | 50 | pipelineCreateInfo.RasterizerState.FillMode = FillMode.Line; 51 | LinePipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 52 | } 53 | 54 | public override void Update(System.TimeSpan delta) 55 | { 56 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Left)) 57 | { 58 | UseWireframeMode = !UseWireframeMode; 59 | Logger.LogInfo("Using wireframe mode: " + UseWireframeMode); 60 | } 61 | 62 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Bottom)) 63 | { 64 | UseSmallViewport = !UseSmallViewport; 65 | Logger.LogInfo("Using small viewport: " + UseSmallViewport); 66 | } 67 | 68 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Right)) 69 | { 70 | UseScissorRect = !UseScissorRect; 71 | Logger.LogInfo("Using scissor rect: " + UseScissorRect); 72 | } 73 | } 74 | 75 | public override void Draw(double alpha) 76 | { 77 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 78 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 79 | if (swapchainTexture != null) 80 | { 81 | var renderPass = cmdbuf.BeginRenderPass( 82 | new ColorTargetInfo(swapchainTexture, Color.Black) 83 | ); 84 | 85 | renderPass.BindGraphicsPipeline(UseWireframeMode ? LinePipeline : FillPipeline); 86 | 87 | if (UseSmallViewport) 88 | { 89 | renderPass.SetViewport(SmallViewport); 90 | } 91 | if (UseScissorRect) 92 | { 93 | renderPass.SetScissor(ScissorRect); 94 | } 95 | 96 | renderPass.DrawPrimitives(3, 1, 0, 0); 97 | 98 | cmdbuf.EndRenderPass(renderPass); 99 | } 100 | 101 | GraphicsDevice.Submit(cmdbuf); 102 | } 103 | 104 | public override void Destroy() 105 | { 106 | FillPipeline.Dispose(); 107 | LinePipeline.Dispose(); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Examples/DrawIndirectExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using MoonWorks.Input; 4 | using System.Numerics; 5 | 6 | namespace MoonWorksGraphicsTests; 7 | 8 | class DrawIndirectExample : Example 9 | { 10 | private GraphicsPipeline GraphicsPipeline; 11 | private Buffer VertexBuffer; 12 | private Buffer DrawBuffer; 13 | 14 | public override void Init() 15 | { 16 | Window.SetTitle("DrawIndirect"); 17 | 18 | // Load the shaders 19 | Shader vertShader = ShaderCross.Create( 20 | GraphicsDevice, 21 | RootTitleStorage, 22 | TestUtils.GetHLSLPath("PositionColor.vert"), 23 | "main", 24 | ShaderCross.ShaderFormat.HLSL, 25 | ShaderStage.Vertex 26 | ); 27 | 28 | Shader fragShader = ShaderCross.Create( 29 | GraphicsDevice, 30 | RootTitleStorage, 31 | TestUtils.GetHLSLPath("SolidColor.frag"), 32 | "main", 33 | ShaderCross.ShaderFormat.HLSL, 34 | ShaderStage.Fragment 35 | ); 36 | 37 | // Create the graphics pipeline 38 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 39 | Window.SwapchainFormat, 40 | vertShader, 41 | fragShader 42 | ); 43 | pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); 44 | GraphicsPipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 45 | 46 | // Create and populate the vertex buffer 47 | var resourceUploader = new ResourceUploader(GraphicsDevice); 48 | 49 | VertexBuffer = resourceUploader.CreateBuffer( 50 | "Vertex Buffer", 51 | [ 52 | new PositionColorVertex(new Vector3(-0.5f, 1, 0), Color.Blue), 53 | new PositionColorVertex(new Vector3( -1f, -1, 0), Color.Green), 54 | new PositionColorVertex(new Vector3( 0f, -1, 0), Color.Red), 55 | 56 | new PositionColorVertex(new Vector3(0.5f, 1, 0), Color.Blue), 57 | new PositionColorVertex(new Vector3( 1f, -1, 0), Color.Green), 58 | new PositionColorVertex(new Vector3( 0f, -1, 0), Color.Red), 59 | ], 60 | BufferUsageFlags.Vertex 61 | ); 62 | 63 | DrawBuffer = resourceUploader.CreateBuffer( 64 | "Draw Buffer", 65 | [ 66 | new IndirectDrawCommand 67 | { 68 | NumVertices = 3, 69 | NumInstances = 1, 70 | FirstVertex = 3 71 | }, 72 | new IndirectDrawCommand 73 | { 74 | NumVertices = 3, 75 | NumInstances = 1 76 | } 77 | ], 78 | BufferUsageFlags.Indirect 79 | ); 80 | 81 | resourceUploader.Upload(); 82 | resourceUploader.Dispose(); 83 | } 84 | 85 | public override void Update(System.TimeSpan delta) { } 86 | 87 | public override void Draw(double alpha) 88 | { 89 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 90 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 91 | if (swapchainTexture != null) 92 | { 93 | var renderPass = cmdbuf.BeginRenderPass( 94 | new ColorTargetInfo(swapchainTexture, Color.Black) 95 | ); 96 | renderPass.BindGraphicsPipeline(GraphicsPipeline); 97 | renderPass.BindVertexBuffers(VertexBuffer); 98 | renderPass.DrawPrimitivesIndirect(DrawBuffer, 0, 2); 99 | cmdbuf.EndRenderPass(renderPass); 100 | } 101 | GraphicsDevice.Submit(cmdbuf); 102 | } 103 | 104 | public override void Destroy() 105 | { 106 | GraphicsPipeline.Dispose(); 107 | VertexBuffer.Dispose(); 108 | DrawBuffer.Dispose(); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MoonWorks; 3 | using MoonWorks.Graphics; 4 | 5 | namespace MoonWorksGraphicsTests; 6 | 7 | class Program : Game 8 | { 9 | Example[] Examples = 10 | [ 11 | new ClearScreenExample(), 12 | new ClearScreen_MultiWindowExample(), 13 | new BasicStencilExample(), 14 | new BasicTriangleExample(), 15 | new CompressedTexturesExample(), 16 | new FontExample(), 17 | new BasicComputeExample(), 18 | new ComputeUniformsExample(), 19 | new CopyTextureExample(), 20 | new CullFaceExample(), 21 | new DrawIndirectExample(), 22 | new GetBufferDataExample(), 23 | new InstancingAndOffsetsExample(), 24 | new MSAAExample(), 25 | new DepthMSAAExample(), 26 | new RenderTexture2DArrayExample(), 27 | new RenderTexture2DExample(), 28 | new RenderTextureCubeExample(), 29 | new RenderTextureMipmapsExample(), 30 | new StoreLoadExample(), 31 | new Texture3DCopyExample(), 32 | new Texture3DExample(), 33 | new TexturedQuadExample(), 34 | new TexturedAnimatedQuadExample(), 35 | new TextureMipmapsExample(), 36 | new TriangleVertexBufferExample(), 37 | new VertexSamplerExample(), 38 | new VideoPlayerExample(), 39 | new WindowResizingExample(), 40 | new CPUSpriteBatchExample(), 41 | new ComputeSpriteBatchExample(), 42 | new PullSpriteBatchExample(), 43 | new CubeExample(), 44 | new HotReloadShaderExample() 45 | ]; 46 | 47 | int ExampleIndex = 0; 48 | 49 | public Program( 50 | AppInfo appInfo, 51 | WindowCreateInfo windowCreateInfo, 52 | FramePacingSettings framePacingSettings, 53 | bool debugMode = false 54 | ) : base( 55 | appInfo, 56 | windowCreateInfo, 57 | framePacingSettings, 58 | ShaderFormat.SPIRV | ShaderFormat.DXIL | ShaderFormat.MSL | ShaderFormat.DXBC, 59 | debugMode 60 | ) { 61 | Logger.LogInfo("Welcome to the MoonWorks Graphics Tests program! Press Q and E to cycle through examples!"); 62 | ShaderCross.Initialize(); 63 | Examples[ExampleIndex].Start(this); 64 | } 65 | 66 | protected override void Update(TimeSpan delta) 67 | { 68 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Previous)) 69 | { 70 | Examples[ExampleIndex].Destroy(); 71 | 72 | ExampleIndex -= 1; 73 | if (ExampleIndex < 0) 74 | { 75 | ExampleIndex = Examples.Length - 1; 76 | } 77 | 78 | MainWindow.SetSize(640, 480); 79 | MainWindow.SetPositionCentered(); 80 | Examples[ExampleIndex].Start(this); 81 | } 82 | else if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Next)) 83 | { 84 | Examples[ExampleIndex].Destroy(); 85 | 86 | ExampleIndex = (ExampleIndex + 1) % Examples.Length; 87 | 88 | MainWindow.SetSize(640, 480); 89 | MainWindow.SetPositionCentered(); 90 | Examples[ExampleIndex].Start(this); 91 | } 92 | 93 | Examples[ExampleIndex].Update(delta); 94 | } 95 | 96 | protected override void Draw(double alpha) 97 | { 98 | Examples[ExampleIndex].Draw(alpha); 99 | } 100 | 101 | protected override void Destroy() 102 | { 103 | Examples[ExampleIndex].Destroy(); 104 | } 105 | 106 | static void Main(string[] args) 107 | { 108 | var debugMode = false; 109 | 110 | #if DEBUG 111 | debugMode = true; 112 | #endif 113 | 114 | var windowCreateInfo = new WindowCreateInfo( 115 | "MoonWorksGraphicsTests", 116 | 640, 117 | 480, 118 | ScreenMode.Windowed 119 | ); 120 | 121 | var framePacingSettings = FramePacingSettings.CreateCapped(60, 120); 122 | 123 | var game = new Program( 124 | new AppInfo("MoonsideGames", "MoonWorksGraphicsTests"), 125 | windowCreateInfo, 126 | framePacingSettings, 127 | debugMode 128 | ); 129 | 130 | game.Run(); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /Examples/InstancingAndOffsetsExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using System.Numerics; 4 | 5 | namespace MoonWorksGraphicsTests; 6 | 7 | class InstancingAndOffsetsExample : Example 8 | { 9 | private GraphicsPipeline Pipeline; 10 | private Buffer VertexBuffer; 11 | private Buffer IndexBuffer; 12 | 13 | private bool useVertexOffset; 14 | private bool useIndexOffset; 15 | 16 | public override void Init() 17 | { 18 | Window.SetTitle("InstancingAndOffsets"); 19 | 20 | Logger.LogInfo("Press Left to toggle vertex offset\nPress Right to toggle index offset"); 21 | 22 | // Load the shaders 23 | Shader vertShader = ShaderCross.Create( 24 | GraphicsDevice, 25 | RootTitleStorage, 26 | TestUtils.GetHLSLPath("PositionColorInstanced.vert"), 27 | "main", 28 | ShaderCross.ShaderFormat.HLSL, 29 | ShaderStage.Vertex 30 | ); 31 | 32 | Shader fragShader = ShaderCross.Create( 33 | GraphicsDevice, 34 | RootTitleStorage, 35 | TestUtils.GetHLSLPath("SolidColor.frag"), 36 | "main", 37 | ShaderCross.ShaderFormat.HLSL, 38 | ShaderStage.Fragment 39 | ); 40 | 41 | // Create the graphics pipeline 42 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 43 | Window.SwapchainFormat, 44 | vertShader, 45 | fragShader 46 | ); 47 | pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); 48 | Pipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 49 | 50 | // Create and populate the vertex and index buffers 51 | var resourceUploader = new ResourceUploader(GraphicsDevice); 52 | 53 | VertexBuffer = resourceUploader.CreateBuffer( 54 | [ 55 | new PositionColorVertex(new Vector3(-1, -1, 0), Color.Red), 56 | new PositionColorVertex(new Vector3( 1, -1, 0), Color.Lime), 57 | new PositionColorVertex(new Vector3( 0, 1, 0), Color.Blue), 58 | 59 | new PositionColorVertex(new Vector3(-1, -1, 0), Color.Orange), 60 | new PositionColorVertex(new Vector3( 1, -1, 0), Color.Green), 61 | new PositionColorVertex(new Vector3( 0, 1, 0), Color.Aqua), 62 | 63 | new PositionColorVertex(new Vector3(-1, -1, 0), Color.White), 64 | new PositionColorVertex(new Vector3( 1, -1, 0), Color.White), 65 | new PositionColorVertex(new Vector3( 0, 1, 0), Color.White), 66 | ], 67 | BufferUsageFlags.Vertex 68 | ); 69 | 70 | IndexBuffer = resourceUploader.CreateBuffer( 71 | [ 72 | 0, 1, 2, 73 | 3, 4, 5, 74 | ], 75 | BufferUsageFlags.Index 76 | ); 77 | 78 | resourceUploader.Upload(); 79 | resourceUploader.Dispose(); 80 | } 81 | 82 | public override void Update(System.TimeSpan delta) 83 | { 84 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Left)) 85 | { 86 | useVertexOffset = !useVertexOffset; 87 | Logger.LogInfo("Using vertex offset: " + useVertexOffset); 88 | } 89 | 90 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Right)) 91 | { 92 | useIndexOffset = !useIndexOffset; 93 | Logger.LogInfo("Using index offset: " + useIndexOffset); 94 | } 95 | } 96 | 97 | public override void Draw(double alpha) 98 | { 99 | uint vertexOffset = useVertexOffset ? 3u : 0; 100 | uint indexOffset = useIndexOffset ? 3u : 0; 101 | 102 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 103 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 104 | if (swapchainTexture != null) 105 | { 106 | var renderPass = cmdbuf.BeginRenderPass( 107 | new ColorTargetInfo(swapchainTexture, Color.Black) 108 | ); 109 | renderPass.BindGraphicsPipeline(Pipeline); 110 | renderPass.BindVertexBuffers(VertexBuffer); 111 | renderPass.BindIndexBuffer(IndexBuffer, IndexElementSize.Sixteen); 112 | renderPass.DrawIndexedPrimitives(3, 16, indexOffset, (int) vertexOffset, 0); 113 | cmdbuf.EndRenderPass(renderPass); 114 | } 115 | GraphicsDevice.Submit(cmdbuf); 116 | } 117 | 118 | public override void Destroy() 119 | { 120 | Pipeline.Dispose(); 121 | VertexBuffer.Dispose(); 122 | IndexBuffer.Dispose(); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /Examples/MSAAExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | 4 | namespace MoonWorksGraphicsTests; 5 | 6 | class MSAAExample : Example 7 | { 8 | private GraphicsPipeline[] MsaaPipelines = new GraphicsPipeline[4]; 9 | private Texture[] RenderTargets = new Texture[4]; 10 | private Sampler RTSampler; 11 | 12 | private SampleCount currentSampleCount; 13 | 14 | public override void Init() 15 | { 16 | Window.SetTitle("MSAA"); 17 | 18 | currentSampleCount = SampleCount.Four; 19 | 20 | Logger.LogInfo("Press Left and Right to cycle between sample counts"); 21 | Logger.LogInfo("Setting sample count to: " + currentSampleCount); 22 | 23 | // Create the MSAA pipelines 24 | Shader triangleVertShader = ShaderCross.Create( 25 | GraphicsDevice, 26 | RootTitleStorage, 27 | TestUtils.GetHLSLPath("RawTriangle.vert"), 28 | "main", 29 | ShaderCross.ShaderFormat.HLSL, 30 | ShaderStage.Vertex 31 | ); 32 | 33 | Shader triangleFragShader = ShaderCross.Create( 34 | GraphicsDevice, 35 | RootTitleStorage, 36 | TestUtils.GetHLSLPath("SolidColor.frag"), 37 | "main", 38 | ShaderCross.ShaderFormat.HLSL, 39 | ShaderStage.Fragment 40 | ); 41 | 42 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 43 | Window.SwapchainFormat, 44 | triangleVertShader, 45 | triangleFragShader 46 | ); 47 | for (int i = 0; i < MsaaPipelines.Length; i += 1) 48 | { 49 | pipelineCreateInfo.MultisampleState.SampleCount = (SampleCount) i; 50 | MsaaPipelines[i] = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 51 | } 52 | 53 | // Create the MSAA render textures 54 | for (int i = 0; i < RenderTargets.Length; i += 1) 55 | { 56 | RenderTargets[i] = Texture.Create2D( 57 | GraphicsDevice, 58 | Window.Width, 59 | Window.Height, 60 | Window.SwapchainFormat, 61 | TextureUsageFlags.ColorTarget, 62 | 1, 63 | (SampleCount) i 64 | ); 65 | } 66 | 67 | // Create the sampler 68 | RTSampler = Sampler.Create(GraphicsDevice, SamplerCreateInfo.PointClamp); 69 | } 70 | 71 | public override void Update(System.TimeSpan delta) 72 | { 73 | SampleCount prevSampleCount = currentSampleCount; 74 | 75 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Left)) 76 | { 77 | currentSampleCount -= 1; 78 | if (currentSampleCount < 0) 79 | { 80 | currentSampleCount = SampleCount.Eight; 81 | } 82 | } 83 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Right)) 84 | { 85 | currentSampleCount += 1; 86 | if (currentSampleCount > SampleCount.Eight) 87 | { 88 | currentSampleCount = SampleCount.One; 89 | } 90 | } 91 | 92 | if (prevSampleCount != currentSampleCount) 93 | { 94 | Logger.LogInfo("Setting sample count to: " + currentSampleCount); 95 | } 96 | } 97 | 98 | public override void Draw(double alpha) 99 | { 100 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 101 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 102 | if (swapchainTexture != null) 103 | { 104 | Texture rt = RenderTargets[(int) currentSampleCount]; 105 | 106 | ColorTargetInfo colorTargetInfo; 107 | 108 | if (currentSampleCount == SampleCount.One) 109 | { 110 | colorTargetInfo = new ColorTargetInfo 111 | { 112 | Texture = swapchainTexture.Handle, 113 | LoadOp = LoadOp.Clear, 114 | ClearColor = Color.Black 115 | }; 116 | } 117 | else 118 | { 119 | colorTargetInfo = new ColorTargetInfo 120 | { 121 | Texture = rt.Handle, 122 | LoadOp = LoadOp.Clear, 123 | ClearColor = Color.Black, 124 | Cycle = true, 125 | CycleResolveTexture = true, 126 | ResolveTexture = swapchainTexture.Handle, 127 | StoreOp = StoreOp.Resolve 128 | }; 129 | } 130 | 131 | var renderPass = cmdbuf.BeginRenderPass(colorTargetInfo); 132 | renderPass.BindGraphicsPipeline(MsaaPipelines[(int) currentSampleCount]); 133 | renderPass.DrawPrimitives(3, 1, 0, 0); 134 | cmdbuf.EndRenderPass(renderPass); 135 | } 136 | GraphicsDevice.Submit(cmdbuf); 137 | } 138 | 139 | public override void Destroy() 140 | { 141 | for (var i = 0; i < 4; i += 1) 142 | { 143 | MsaaPipelines[i].Dispose(); 144 | RenderTargets[i].Dispose(); 145 | } 146 | 147 | RTSampler.Dispose(); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /Examples/TextureMipmapsExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using System.Numerics; 4 | 5 | namespace MoonWorksGraphicsTests; 6 | 7 | class TextureMipmapsExample : Example 8 | { 9 | private GraphicsPipeline Pipeline; 10 | private Buffer VertexBuffer; 11 | private Buffer IndexBuffer; 12 | private Texture Texture; 13 | private Sampler Sampler; 14 | 15 | private float scale = 0.5f; 16 | 17 | public override void Init() 18 | { 19 | Window.SetTitle("TextureMipmaps"); 20 | 21 | Logger.LogInfo("Press Left and Right to shrink/expand the scale of the quad"); 22 | 23 | // Load the shaders 24 | Shader vertShaderModule = ShaderCross.Create( 25 | GraphicsDevice, 26 | RootTitleStorage, 27 | TestUtils.GetHLSLPath("TexturedQuadWithMatrix.vert"), 28 | "main", 29 | ShaderCross.ShaderFormat.HLSL, 30 | ShaderStage.Vertex 31 | ); 32 | 33 | Shader fragShaderModule = ShaderCross.Create( 34 | GraphicsDevice, 35 | RootTitleStorage, 36 | TestUtils.GetHLSLPath("TexturedQuad.frag"), 37 | "main", 38 | ShaderCross.ShaderFormat.HLSL, 39 | ShaderStage.Fragment 40 | ); 41 | 42 | // Create the graphics pipeline 43 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 44 | Window.SwapchainFormat, 45 | vertShaderModule, 46 | fragShaderModule 47 | ); 48 | pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); 49 | 50 | Pipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 51 | 52 | Sampler = Sampler.Create(GraphicsDevice, SamplerCreateInfo.PointClamp); 53 | 54 | // Create and populate the GPU resources 55 | Texture = Texture.Create2D( 56 | GraphicsDevice, 57 | 256, 58 | 256, 59 | TextureFormat.R8G8B8A8Unorm, 60 | TextureUsageFlags.Sampler, 61 | 4 62 | ); 63 | 64 | var resourceUploader = new ResourceUploader(GraphicsDevice); 65 | 66 | VertexBuffer = resourceUploader.CreateBuffer( 67 | [ 68 | new PositionTextureVertex(new Vector3(-1, 1, 0), new Vector2(0, 0)), 69 | new PositionTextureVertex(new Vector3( 1, 1, 0), new Vector2(1, 0)), 70 | new PositionTextureVertex(new Vector3( 1, -1, 0), new Vector2(1, 1)), 71 | new PositionTextureVertex(new Vector3(-1, -1, 0), new Vector2(0, 1)), 72 | ], 73 | BufferUsageFlags.Vertex 74 | ); 75 | 76 | IndexBuffer = resourceUploader.CreateBuffer( 77 | [ 78 | 0, 1, 2, 79 | 0, 2, 3 80 | ], 81 | BufferUsageFlags.Index 82 | ); 83 | 84 | // Set the various mip levels 85 | for (uint i = 0; i < Texture.LevelCount; i += 1) 86 | { 87 | var w = Texture.Width >> (int) i; 88 | var h = Texture.Height >> (int) i; 89 | var region = new TextureRegion 90 | { 91 | Texture = Texture.Handle, 92 | MipLevel = i, 93 | W = w, 94 | H = h, 95 | D = 1 96 | }; 97 | 98 | resourceUploader.SetTextureDataFromCompressed( 99 | RootTitleStorage, 100 | TestUtils.GetTexturePath($"mip{i}.png"), 101 | region 102 | ); 103 | } 104 | 105 | resourceUploader.Upload(); 106 | resourceUploader.Dispose(); 107 | } 108 | 109 | public override void Update(System.TimeSpan delta) 110 | { 111 | if (TestUtils.CheckButtonDown(Inputs, TestUtils.ButtonType.Left)) 112 | { 113 | scale = System.MathF.Max(0.01f, scale - 0.01f); 114 | } 115 | 116 | if (TestUtils.CheckButtonDown(Inputs, TestUtils.ButtonType.Right)) 117 | { 118 | scale = System.MathF.Min(1f, scale + 0.01f); 119 | } 120 | } 121 | 122 | public override void Draw(double alpha) 123 | { 124 | TransformVertexUniform vertUniforms = new TransformVertexUniform(Matrix4x4.CreateScale(scale, scale, 1)); 125 | 126 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 127 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 128 | if (swapchainTexture != null) 129 | { 130 | var renderPass = cmdbuf.BeginRenderPass( 131 | new ColorTargetInfo(swapchainTexture, Color.Black) 132 | ); 133 | renderPass.BindGraphicsPipeline(Pipeline); 134 | renderPass.BindVertexBuffers(VertexBuffer); 135 | renderPass.BindIndexBuffer(IndexBuffer, IndexElementSize.Sixteen); 136 | renderPass.BindFragmentSamplers(new TextureSamplerBinding(Texture, Sampler)); 137 | cmdbuf.PushVertexUniformData(vertUniforms); 138 | renderPass.DrawIndexedPrimitives(6, 1, 0, 0, 0); 139 | cmdbuf.EndRenderPass(renderPass); 140 | } 141 | 142 | GraphicsDevice.Submit(cmdbuf); 143 | } 144 | 145 | public override void Destroy() 146 | { 147 | Pipeline.Dispose(); 148 | VertexBuffer.Dispose(); 149 | IndexBuffer.Dispose(); 150 | Texture.Dispose(); 151 | Sampler.Dispose(); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Tests include: 2 | 3 | **ClearScreen** 4 | 5 | Clears the screen to CornflowerBlue. Mostly useful as a smoke test to make sure basic device init and render passes are working as intended. 6 | 7 | **ClearScreen_MultiWindow** 8 | 9 | Similar to above, but with two windows. Useful for testing window claim/unclaim logic and presenting to multiple swapchains. 10 | 11 | **BasicTriangle** 12 | 13 | Sets up a graphics pipeline and draws a triangle without vertex buffers. (The vertices are manually positioned in the vertex shader.) Also tests some basic rasterizer state with custom viewports, scissor rects, and fill/wireframe modes. 14 | 15 | **TriangleVertexBuffer** 16 | 17 | Similar to above, but using a MoonWorks vertex buffer and custom vertex structs. 18 | 19 | **StoreLoad** 20 | 21 | Draws a triangle to the screen in one render pass, stores the attachment, and then loads the attachment again. Tests that load/store operations work as expected. 22 | 23 | **TexturedQuad** 24 | 25 | Draws a textured quad to the screen. Tests texture binding, index buffers, and sampler states. 26 | 27 | **AnimatedTexturedQuad** 28 | 29 | Similar to above, but with rotating and color-blending animations. Tests vertex and fragment uniforms. 30 | 31 | **MSAA** 32 | 33 | Draws a basic triangle with varying MSAA sample counts. 34 | 35 | **CullMode** 36 | 37 | Draws several triangles with various culling modes and winding orders. 38 | 39 | **GetBufferData** 40 | 41 | Sets buffer data, gets the data back from the GPU, and prints the results to the console. 42 | 43 | **Cube** 44 | 45 | Renders a cubemap skybox and a spinning cube. Tests depth textures, sampling from depth textures, depth-only render passes, cube textures, and 32-bit index buffers. 46 | 47 | **BasicCompute** 48 | 49 | Uses compute pipelines to (1) fill a texture with yellow pixels then display it to the screen and (2) calculate the squares of the first 64 integers. Tests compute pipeline creation, compute dispatching, compute textures, and compute buffers. 50 | 51 | **ComputeUniforms** 52 | 53 | Uses a compute pipeline to fill a texture with a color gradient. Tests compute uniforms. 54 | 55 | **DrawIndirect** 56 | 57 | Draws two triangles via indirect commands. Tests DrawPrimitivesIndirect. 58 | 59 | **InstancingAndOffsets** 60 | 61 | Draws 16 instanced triangles. Tests DrawPrimitivesInstanced, vertex offsets, and index offsets. 62 | 63 | **CompressedTextures** 64 | 65 | Loads a series of compressed textures, then displays them for viewing. Tests compressed texture loading. 66 | 67 | **CopyTexture** 68 | 69 | 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 and CopyTextureToBuffer. 70 | 71 | **VideoPlayer** 72 | 73 | Plays a sample Ogg Theora video file. Tests YUV textures and video rendering. 74 | 75 | **Texture3D** 76 | 77 | Displays 2D slices of a 3D texture. Tests creating and drawing 3D textures. 78 | 79 | **TextureMipmaps** 80 | 81 | Displays a quad that can be scaled to reveal various mip levels. The mips are generated from PNGs. Tests SetTextureData for mip levels and rendering mipmaps. 82 | 83 | **VertexSampler** 84 | 85 | Displays a triangle whose colors are driven by sampling a texture in the vertex shader. 86 | 87 | **RenderTexture2D** 88 | 89 | Clears and draws 4 render textures to the screen. Tests binding and sampling 2D render textures. 90 | 91 | **RenderTexture3D** 92 | 93 | Fades through 2D slices of a 3D render texture. Tests binding and sampling 3D render textures. 94 | 95 | **RenderTextureCube** 96 | 97 | Displays a cubemap generated by rendering to a cube render target. Tests binding and sampling cube render textures. 98 | 99 | **RenderTextureMipmaps** 100 | 101 | Displays a quad that can be scaled to reveal various mip levels. The mips are solid colors, generated by clearing various levels of the texture in a render pass. Tests rendering to mipmap levels of a render texture, mip LOD bias, min/max LODs, and mip filter modes. 102 | 103 | **BasicStencil** 104 | 105 | Demonstrates stencil masking using two triangles. Tests stencil buffers and basic stencil operations. 106 | 107 | **DepthMSAA** 108 | 109 | Displays two cubes floating around each other on a multisampled surface. Tests multisampled depth buffers. 110 | 111 | **MSAACube** 112 | 113 | Same as RenderTextureCube, but with MSAA cube RTs. Draws triangles to each cubemap face so there's something to see. Tests cube render target MSAA. 114 | 115 | **WindowResizing** 116 | 117 | Tests resizing the window to various resolutions. 118 | -------------------------------------------------------------------------------- /Examples/CompressedTexturesExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using MoonWorks.Input; 4 | using System.Numerics; 5 | 6 | namespace MoonWorksGraphicsTests; 7 | 8 | class CompressedTexturesExample : Example 9 | { 10 | private GraphicsPipeline Pipeline; 11 | private Buffer VertexBuffer; 12 | private Buffer IndexBuffer; 13 | private Sampler Sampler; 14 | private Texture[] Textures; 15 | private string[] TextureNames = 16 | [ 17 | "BC1", 18 | "BC2", 19 | "BC3", 20 | "BC7" 21 | ]; 22 | 23 | private int CurrentTextureIndex; 24 | 25 | public override void Init() 26 | { 27 | Window.SetTitle("CompressedTextures"); 28 | 29 | Logger.LogInfo("Press Left and Right to cycle between textures"); 30 | Logger.LogInfo("Setting texture to: " + TextureNames[0]); 31 | 32 | // Load the shaders 33 | Shader vertShaderModule = ShaderCross.Create( 34 | GraphicsDevice, 35 | RootTitleStorage, 36 | TestUtils.GetHLSLPath("TexturedQuad.vert"), 37 | "main", 38 | ShaderCross.ShaderFormat.HLSL, 39 | ShaderStage.Vertex 40 | ); 41 | 42 | Shader fragShaderModule = ShaderCross.Create( 43 | GraphicsDevice, 44 | RootTitleStorage, 45 | TestUtils.GetHLSLPath("TexturedQuad.frag"), 46 | "main", 47 | ShaderCross.ShaderFormat.HLSL, 48 | ShaderStage.Fragment 49 | ); 50 | 51 | // Create the graphics pipeline 52 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 53 | Window.SwapchainFormat, 54 | vertShaderModule, 55 | fragShaderModule 56 | ); 57 | pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); 58 | 59 | Pipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 60 | 61 | // Create sampler 62 | Sampler = Sampler.Create(GraphicsDevice, SamplerCreateInfo.LinearWrap); 63 | 64 | // Create texture array 65 | Textures = new Texture[TextureNames.Length]; 66 | 67 | // Create and populate the GPU resources 68 | var resourceUploader = new ResourceUploader(GraphicsDevice); 69 | 70 | VertexBuffer = resourceUploader.CreateBuffer( 71 | [ 72 | new PositionTextureVertex(new Vector3(-1, 1, 0), new Vector2(0, 0)), 73 | new PositionTextureVertex(new Vector3( 1, 1, 0), new Vector2(1, 0)), 74 | new PositionTextureVertex(new Vector3( 1, -1, 0), new Vector2(1, 1)), 75 | new PositionTextureVertex(new Vector3(-1, -1, 0), new Vector2(0, 1)) 76 | ], 77 | BufferUsageFlags.Vertex 78 | ); 79 | 80 | IndexBuffer = resourceUploader.CreateBuffer( 81 | [ 82 | 0, 1, 2, 83 | 0, 2, 3, 84 | ], 85 | BufferUsageFlags.Index 86 | ); 87 | 88 | for (int i = 0; i < TextureNames.Length; i += 1) 89 | { 90 | Textures[i] = resourceUploader.CreateTextureFromDDS(RootTitleStorage, TestUtils.GetTexturePath(TextureNames[i] + ".dds")); 91 | } 92 | 93 | resourceUploader.Upload(); 94 | resourceUploader.Dispose(); 95 | } 96 | 97 | public override void Update(System.TimeSpan delta) 98 | { 99 | int prevSamplerIndex = CurrentTextureIndex; 100 | 101 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Left)) 102 | { 103 | CurrentTextureIndex -= 1; 104 | if (CurrentTextureIndex < 0) 105 | { 106 | CurrentTextureIndex = TextureNames.Length - 1; 107 | } 108 | } 109 | 110 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Right)) 111 | { 112 | CurrentTextureIndex += 1; 113 | if (CurrentTextureIndex >= TextureNames.Length) 114 | { 115 | CurrentTextureIndex = 0; 116 | } 117 | } 118 | 119 | if (prevSamplerIndex != CurrentTextureIndex) 120 | { 121 | Logger.LogInfo("Setting texture to: " + TextureNames[CurrentTextureIndex]); 122 | } 123 | } 124 | 125 | public override void Draw(double alpha) 126 | { 127 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 128 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 129 | if (swapchainTexture != null) 130 | { 131 | var renderPass = cmdbuf.BeginRenderPass( 132 | new ColorTargetInfo(swapchainTexture, LoadOp.DontCare) 133 | ); 134 | renderPass.BindGraphicsPipeline(Pipeline); 135 | renderPass.BindVertexBuffers(VertexBuffer); 136 | renderPass.BindIndexBuffer(IndexBuffer, IndexElementSize.Sixteen); 137 | renderPass.BindFragmentSamplers(new TextureSamplerBinding(Textures[CurrentTextureIndex], Sampler)); 138 | renderPass.DrawIndexedPrimitives(6, 1, 0, 0, 0); 139 | cmdbuf.EndRenderPass(renderPass); 140 | } 141 | GraphicsDevice.Submit(cmdbuf); 142 | } 143 | 144 | public override void Destroy() 145 | { 146 | Pipeline.Dispose(); 147 | VertexBuffer.Dispose(); 148 | IndexBuffer.Dispose(); 149 | Sampler.Dispose(); 150 | 151 | for (int i = 0; i < TextureNames.Length; i += 1) 152 | { 153 | Textures[i].Dispose(); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /Common/TestUtils.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | 4 | namespace MoonWorksGraphicsTests; 5 | 6 | public static class TestUtils 7 | { 8 | public static GraphicsPipelineCreateInfo GetStandardGraphicsPipelineCreateInfo( 9 | TextureFormat swapchainFormat, 10 | Shader vertShader, 11 | Shader fragShader 12 | ) { 13 | return new GraphicsPipelineCreateInfo 14 | { 15 | TargetInfo = new GraphicsPipelineTargetInfo 16 | { 17 | ColorTargetDescriptions = [ 18 | new ColorTargetDescription 19 | { 20 | Format = swapchainFormat, 21 | BlendState = ColorTargetBlendState.Opaque 22 | } 23 | ] 24 | }, 25 | DepthStencilState = DepthStencilState.Disable, 26 | MultisampleState = MultisampleState.None, 27 | PrimitiveType = PrimitiveType.TriangleList, 28 | RasterizerState = RasterizerState.CCW_CullNone, 29 | VertexInputState = VertexInputState.Empty, 30 | VertexShader = vertShader, 31 | FragmentShader = fragShader 32 | }; 33 | } 34 | 35 | public static string GetShaderPath(string shaderName) 36 | { 37 | return "Content/Shaders/Compiled/" + shaderName + ".spv"; 38 | } 39 | 40 | public static string GetHLSLPath(string shaderName) 41 | { 42 | return "Content/Shaders/HLSL/" + shaderName + ".hlsl"; 43 | } 44 | 45 | public static string GetTexturePath(string textureName) 46 | { 47 | return "Content/Textures/" + textureName; 48 | } 49 | 50 | public static string GetVideoPath(string videoName) 51 | { 52 | return "Content/Videos/" + videoName; 53 | } 54 | 55 | public static string GetFontPath(string fontName) 56 | { 57 | return "Content/Fonts/" + fontName; 58 | } 59 | 60 | public enum ButtonType 61 | { 62 | Left, // A/left arrow on keyboard, left d-pad on gamepad 63 | Bottom, // S/down arrow on keyboard, bottom d-pad on gamepad 64 | Right, // D/right arrow on keyboard, right d-pad on gamepad 65 | Previous, // Q on keyboard, left shoulder on gamepad 66 | Next // E on keyboard, right shoulder on gamepad 67 | } 68 | 69 | public static bool CheckButtonPressed(MoonWorks.Input.Inputs inputs, ButtonType buttonType) 70 | { 71 | bool pressed = false; 72 | 73 | if (buttonType == ButtonType.Left) 74 | { 75 | pressed = ( 76 | inputs.GetGamepad(0).DpadLeft.IsPressed || 77 | inputs.Keyboard.IsPressed(MoonWorks.Input.KeyCode.Left) || 78 | inputs.Keyboard.IsPressed(MoonWorks.Input.KeyCode.A) 79 | ); 80 | } 81 | else if (buttonType == ButtonType.Bottom) 82 | { 83 | pressed = ( 84 | inputs.GetGamepad(0).DpadDown.IsPressed || 85 | inputs.Keyboard.IsPressed(MoonWorks.Input.KeyCode.Down) || 86 | inputs.Keyboard.IsPressed(MoonWorks.Input.KeyCode.S) 87 | ); 88 | } 89 | else if (buttonType == ButtonType.Right) 90 | { 91 | pressed = ( 92 | inputs.GetGamepad(0).DpadRight.IsPressed || 93 | inputs.Keyboard.IsPressed(MoonWorks.Input.KeyCode.Right) || 94 | inputs.Keyboard.IsPressed(MoonWorks.Input.KeyCode.D) 95 | ); 96 | } 97 | else if (buttonType == ButtonType.Previous) 98 | { 99 | pressed = ( 100 | inputs.GetGamepad(0).LeftShoulder.IsPressed || 101 | inputs.Keyboard.IsPressed(MoonWorks.Input.KeyCode.Q) 102 | ); 103 | } 104 | else if (buttonType == ButtonType.Next) 105 | { 106 | pressed = ( 107 | inputs.GetGamepad(0).RightShoulder.IsPressed || 108 | inputs.Keyboard.IsPressed(MoonWorks.Input.KeyCode.E) 109 | ); 110 | } 111 | 112 | return pressed; 113 | } 114 | 115 | public static bool CheckButtonDown(MoonWorks.Input.Inputs inputs, ButtonType buttonType) 116 | { 117 | bool down = false; 118 | 119 | if (buttonType == ButtonType.Left) 120 | { 121 | down = ( 122 | inputs.GetGamepad(0).DpadLeft.IsDown || 123 | inputs.Keyboard.IsDown(MoonWorks.Input.KeyCode.Left) || 124 | inputs.Keyboard.IsDown(MoonWorks.Input.KeyCode.A) 125 | ); 126 | } 127 | else if (buttonType == ButtonType.Bottom) 128 | { 129 | down = ( 130 | inputs.GetGamepad(0).DpadDown.IsDown || 131 | inputs.Keyboard.IsDown(MoonWorks.Input.KeyCode.Down) || 132 | inputs.Keyboard.IsDown(MoonWorks.Input.KeyCode.S) 133 | ); 134 | } 135 | else if (buttonType == ButtonType.Right) 136 | { 137 | down = ( 138 | inputs.GetGamepad(0).DpadRight.IsDown || 139 | inputs.Keyboard.IsDown(MoonWorks.Input.KeyCode.Right) || 140 | inputs.Keyboard.IsDown(MoonWorks.Input.KeyCode.D) 141 | ); 142 | } 143 | else if (buttonType == ButtonType.Previous) 144 | { 145 | down = ( 146 | inputs.GetGamepad(0).LeftShoulder.IsDown || 147 | inputs.Keyboard.IsDown(MoonWorks.Input.KeyCode.Q) 148 | ); 149 | } 150 | else if (buttonType == ButtonType.Next) 151 | { 152 | down = ( 153 | inputs.GetGamepad(0).RightShoulder.IsDown || 154 | inputs.Keyboard.IsDown(MoonWorks.Input.KeyCode.E) 155 | ); 156 | } 157 | 158 | return down; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /Examples/Texture3DExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using System.Numerics; 4 | 5 | namespace MoonWorksGraphicsTests; 6 | 7 | class Texture3DExample : Example 8 | { 9 | private GraphicsPipeline Pipeline; 10 | private Buffer VertexBuffer; 11 | private Buffer IndexBuffer; 12 | private Texture Texture; 13 | private Sampler Sampler; 14 | 15 | private int currentDepth = 0; 16 | 17 | readonly record struct FragUniform(float Depth); 18 | 19 | public override void Init() 20 | { 21 | Window.SetTitle("Texture3D"); 22 | 23 | Logger.LogInfo("Press Left and Right to cycle between depth slices"); 24 | 25 | // Load the shaders 26 | Shader vertShader = ShaderCross.Create( 27 | GraphicsDevice, 28 | RootTitleStorage, 29 | TestUtils.GetHLSLPath("TexturedQuad.vert"), 30 | "main", 31 | ShaderCross.ShaderFormat.HLSL, 32 | ShaderStage.Vertex 33 | ); 34 | 35 | Shader fragShader = ShaderCross.Create( 36 | GraphicsDevice, 37 | RootTitleStorage, 38 | TestUtils.GetHLSLPath("TexturedQuad3D.frag"), 39 | "main", 40 | ShaderCross.ShaderFormat.HLSL, 41 | ShaderStage.Fragment 42 | ); 43 | 44 | // Create the graphics pipeline 45 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 46 | Window.SwapchainFormat, 47 | vertShader, 48 | fragShader 49 | ); 50 | pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); 51 | 52 | Pipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 53 | 54 | // Create samplers 55 | Sampler = Sampler.Create(GraphicsDevice, SamplerCreateInfo.PointClamp); 56 | 57 | // Create and populate the GPU resources 58 | var resourceUploader = new ResourceUploader(GraphicsDevice); 59 | 60 | VertexBuffer = resourceUploader.CreateBuffer( 61 | [ 62 | new PositionTextureVertex(new Vector3(-1, -1, 0), new Vector2(0, 0)), 63 | new PositionTextureVertex(new Vector3(1, -1, 0), new Vector2(1, 0)), 64 | new PositionTextureVertex(new Vector3(1, 1, 0), new Vector2(1, 1)), 65 | new PositionTextureVertex(new Vector3(-1, 1, 0), new Vector2(0, 1)) 66 | ], 67 | BufferUsageFlags.Vertex 68 | ); 69 | 70 | IndexBuffer = resourceUploader.CreateBuffer( 71 | [ 72 | 0, 1, 2, 73 | 0, 2, 3, 74 | ], 75 | BufferUsageFlags.Index 76 | ); 77 | 78 | Texture = Texture.Create3D( 79 | GraphicsDevice, 80 | 16, 81 | 16, 82 | 7, 83 | TextureFormat.R8G8B8A8Unorm, 84 | TextureUsageFlags.Sampler 85 | ); 86 | 87 | // Load each depth subimage of the 3D texture 88 | for (uint i = 0; i < Texture.LayerCountOrDepth; i += 1) 89 | { 90 | var region = new TextureRegion 91 | { 92 | Texture = Texture.Handle, 93 | Z = i, 94 | W = Texture.Width, 95 | H = Texture.Height, 96 | D = 1 97 | }; 98 | 99 | resourceUploader.SetTextureDataFromCompressed( 100 | RootTitleStorage, 101 | TestUtils.GetTexturePath($"tex3d_{i}.png"), 102 | region 103 | ); 104 | } 105 | 106 | resourceUploader.Upload(); 107 | resourceUploader.Dispose(); 108 | } 109 | 110 | public override void Update(System.TimeSpan delta) 111 | { 112 | int prevDepth = currentDepth; 113 | 114 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Left)) 115 | { 116 | currentDepth -= 1; 117 | if (currentDepth < 0) 118 | { 119 | currentDepth = (int) Texture.LayerCountOrDepth - 1; 120 | } 121 | } 122 | 123 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Right)) 124 | { 125 | currentDepth += 1; 126 | if (currentDepth >= Texture.LayerCountOrDepth) 127 | { 128 | currentDepth = 0; 129 | } 130 | } 131 | 132 | if (prevDepth != currentDepth) 133 | { 134 | Logger.LogInfo("Setting depth to: " + currentDepth); 135 | } 136 | } 137 | 138 | public override void Draw(double alpha) 139 | { 140 | FragUniform fragUniform = new FragUniform((float)currentDepth / Texture.LayerCountOrDepth + 0.01f); 141 | 142 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 143 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 144 | if (swapchainTexture != null) 145 | { 146 | var renderPass = cmdbuf.BeginRenderPass( 147 | new ColorTargetInfo(swapchainTexture, Color.Black) 148 | ); 149 | renderPass.BindGraphicsPipeline(Pipeline); 150 | renderPass.BindVertexBuffers(VertexBuffer); 151 | renderPass.BindIndexBuffer(IndexBuffer, IndexElementSize.Sixteen); 152 | renderPass.BindFragmentSamplers(new TextureSamplerBinding(Texture, Sampler)); 153 | cmdbuf.PushFragmentUniformData(fragUniform); 154 | renderPass.DrawIndexedPrimitives(6, 1, 0, 0, 0); 155 | cmdbuf.EndRenderPass(renderPass); 156 | } 157 | 158 | GraphicsDevice.Submit(cmdbuf); 159 | } 160 | 161 | public override void Destroy() 162 | { 163 | Pipeline.Dispose(); 164 | VertexBuffer.Dispose(); 165 | IndexBuffer.Dispose(); 166 | Texture.Dispose(); 167 | Sampler.Dispose(); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /Examples/BasicStencilExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using MoonWorks.Input; 4 | using System.Numerics; 5 | 6 | namespace MoonWorksGraphicsTests 7 | { 8 | class BasicStencilExample : Example 9 | { 10 | private GraphicsPipeline MaskerPipeline; 11 | private GraphicsPipeline MaskeePipeline; 12 | private Buffer VertexBuffer; 13 | private Texture DepthStencilTexture; 14 | 15 | public override void Init() 16 | { 17 | Window.SetTitle("BasicStencil"); 18 | 19 | // Load the shaders 20 | Shader vertShaderModule = ShaderCross.Create( 21 | GraphicsDevice, 22 | RootTitleStorage, 23 | TestUtils.GetHLSLPath("PositionColor.vert"), 24 | "main", 25 | ShaderCross.ShaderFormat.HLSL, 26 | ShaderStage.Vertex 27 | ); 28 | 29 | Shader fragShaderModule = ShaderCross.Create( 30 | GraphicsDevice, 31 | RootTitleStorage, 32 | TestUtils.GetHLSLPath("SolidColor.frag"), 33 | "main", 34 | ShaderCross.ShaderFormat.HLSL, 35 | ShaderStage.Fragment 36 | ); 37 | 38 | // Create the graphics pipelines 39 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 40 | Window.SwapchainFormat, 41 | vertShaderModule, 42 | fragShaderModule 43 | ); 44 | pipelineCreateInfo.TargetInfo.HasDepthStencilTarget = true; 45 | pipelineCreateInfo.TargetInfo.DepthStencilFormat = GraphicsDevice.SupportedDepthStencilFormat; 46 | pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(0); 47 | pipelineCreateInfo.DepthStencilState = new DepthStencilState 48 | { 49 | EnableStencilTest = true, 50 | FrontStencilState = new StencilOpState 51 | { 52 | CompareOp = CompareOp.Never, 53 | FailOp = StencilOp.Replace, 54 | PassOp = StencilOp.Keep, 55 | DepthFailOp = StencilOp.Keep 56 | }, 57 | BackStencilState = new StencilOpState 58 | { 59 | CompareOp = CompareOp.Never, 60 | FailOp = StencilOp.Replace, 61 | PassOp = StencilOp.Keep, 62 | DepthFailOp = StencilOp.Keep 63 | }, 64 | WriteMask = 0xFF 65 | }; 66 | MaskerPipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 67 | 68 | pipelineCreateInfo.DepthStencilState = new DepthStencilState 69 | { 70 | EnableStencilTest = true, 71 | FrontStencilState = new StencilOpState 72 | { 73 | CompareOp = CompareOp.Equal, 74 | FailOp = StencilOp.Keep, 75 | PassOp = StencilOp.Keep, 76 | DepthFailOp = StencilOp.Keep 77 | }, 78 | BackStencilState = new StencilOpState 79 | { 80 | CompareOp = CompareOp.Equal, 81 | FailOp = StencilOp.Keep, 82 | PassOp = StencilOp.Keep, 83 | DepthFailOp = StencilOp.Keep 84 | }, 85 | CompareMask = 0xFF, 86 | WriteMask = 0 87 | }; 88 | MaskeePipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 89 | 90 | // Create and populate the GPU resources 91 | DepthStencilTexture = Texture.Create2D( 92 | GraphicsDevice, 93 | Window.Width, 94 | Window.Height, 95 | GraphicsDevice.SupportedDepthStencilFormat, 96 | TextureUsageFlags.DepthStencilTarget 97 | ); 98 | 99 | var resourceUploader = new ResourceUploader(GraphicsDevice); 100 | 101 | VertexBuffer = resourceUploader.CreateBuffer( 102 | [ 103 | new PositionColorVertex(new Vector3(-0.5f, -0.5f, 0), Color.Yellow), 104 | new PositionColorVertex(new Vector3( 0.5f, -0.5f, 0), Color.Yellow), 105 | new PositionColorVertex(new Vector3( 0, 0.5f, 0), Color.Yellow), 106 | 107 | new PositionColorVertex(new Vector3(-1, -1, 0), Color.Red), 108 | new PositionColorVertex(new Vector3( 1, -1, 0), Color.Lime), 109 | new PositionColorVertex(new Vector3( 0, 1, 0), Color.Blue), 110 | ], 111 | BufferUsageFlags.Vertex 112 | ); 113 | 114 | resourceUploader.Upload(); 115 | resourceUploader.Dispose(); 116 | } 117 | 118 | public override void Update(System.TimeSpan delta) { } 119 | 120 | public override void Draw(double alpha) 121 | { 122 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 123 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 124 | if (swapchainTexture != null) 125 | { 126 | var renderPass = cmdbuf.BeginRenderPass( 127 | new DepthStencilTargetInfo(DepthStencilTexture, 0, 0, true), 128 | new ColorTargetInfo(swapchainTexture, Color.Black) 129 | ); 130 | renderPass.BindVertexBuffers(VertexBuffer); 131 | renderPass.SetStencilReference(1); 132 | renderPass.BindGraphicsPipeline(MaskerPipeline); 133 | renderPass.DrawPrimitives(3, 1, 0, 0); 134 | renderPass.SetStencilReference(0); 135 | renderPass.BindGraphicsPipeline(MaskeePipeline); 136 | renderPass.DrawPrimitives(3, 1, 3, 0); 137 | cmdbuf.EndRenderPass(renderPass); 138 | } 139 | GraphicsDevice.Submit(cmdbuf); 140 | } 141 | 142 | public override void Destroy() 143 | { 144 | MaskerPipeline.Dispose(); 145 | MaskeePipeline.Dispose(); 146 | VertexBuffer.Dispose(); 147 | DepthStencilTexture.Dispose(); 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /Examples/HotReloadShaderExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Numerics; 4 | using MoonWorks; 5 | using MoonWorks.Graphics; 6 | using MoonWorks.Input; 7 | 8 | namespace MoonWorksGraphicsTests; 9 | 10 | record struct Uniforms(Vector2 Resolution, float Time); 11 | 12 | class HotReloadShaderExample : Example 13 | { 14 | GraphicsPipeline Pipeline; 15 | Shader VertexShader; 16 | Shader FragmentShader; 17 | float Time; 18 | 19 | FileSystemWatcher Watcher; 20 | bool NeedReload; 21 | 22 | public override void Init() 23 | { 24 | Window.SetTitle("HotReloadShader"); 25 | 26 | VertexShader = ShaderCross.Create( 27 | GraphicsDevice, 28 | RootTitleStorage, 29 | TestUtils.GetHLSLPath("Fullscreen.vert"), 30 | "main", 31 | ShaderCross.ShaderFormat.HLSL, 32 | ShaderStage.Vertex 33 | ); 34 | 35 | LoadPipeline(); 36 | 37 | Logger.LogInfo("Edit HotReload.frag.hlsl in the Content directory to reload the shader!"); 38 | 39 | Watcher = new FileSystemWatcher(Path.Combine(SDL3.SDL.SDL_GetBasePath(), "Content", "Shaders", "HLSL")); 40 | Watcher.Filter = "HotReload.frag.hlsl"; 41 | Watcher.NotifyFilter = NotifyFilters.LastWrite; 42 | Watcher.EnableRaisingEvents = true; 43 | Watcher.Changed += OnChanged; 44 | } 45 | 46 | public override void Update(TimeSpan delta) 47 | { 48 | Time += (float) delta.TotalSeconds; 49 | 50 | if (NeedReload) 51 | { 52 | Logger.LogInfo("File change detected, reloading pipeline..."); 53 | LoadPipeline(); 54 | Logger.LogInfo("Done!"); 55 | 56 | NeedReload = false; 57 | } 58 | } 59 | 60 | public override void Draw(double alpha) 61 | { 62 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 63 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 64 | if (swapchainTexture != null) 65 | { 66 | var renderPass = cmdbuf.BeginRenderPass( 67 | new ColorTargetInfo(swapchainTexture, LoadOp.DontCare) 68 | ); 69 | renderPass.BindGraphicsPipeline(Pipeline); 70 | cmdbuf.PushFragmentUniformData( 71 | new Uniforms( 72 | new Vector2(swapchainTexture.Width, swapchainTexture.Height), 73 | Time 74 | ) 75 | ); 76 | renderPass.DrawPrimitives(3, 1, 0, 0); 77 | cmdbuf.EndRenderPass(renderPass); 78 | } 79 | GraphicsDevice.Submit(cmdbuf); 80 | } 81 | 82 | public override void Destroy() 83 | { 84 | Pipeline.Dispose(); 85 | VertexShader.Dispose(); 86 | FragmentShader.Dispose(); 87 | } 88 | 89 | private void LoadPipeline() 90 | { 91 | var fragmentShader = ShaderCross.Create( 92 | GraphicsDevice, 93 | RootTitleStorage, 94 | TestUtils.GetHLSLPath("HotReload.frag"), 95 | "main", 96 | ShaderCross.ShaderFormat.HLSL, 97 | ShaderStage.Fragment 98 | ); 99 | 100 | if (fragmentShader == null) 101 | { 102 | Logger.LogError("Failed to compile fragment shader!"); 103 | Logger.LogError(SDL3.SDL.SDL_GetError()); 104 | return; 105 | } 106 | 107 | var pipeline = GraphicsPipeline.Create( 108 | GraphicsDevice, 109 | new GraphicsPipelineCreateInfo 110 | { 111 | TargetInfo = new GraphicsPipelineTargetInfo 112 | { 113 | ColorTargetDescriptions = 114 | [ 115 | new ColorTargetDescription 116 | { 117 | Format = Window.SwapchainFormat, 118 | BlendState = ColorTargetBlendState.NoBlend 119 | } 120 | ] 121 | }, 122 | DepthStencilState = DepthStencilState.Disable, 123 | VertexShader = VertexShader, 124 | FragmentShader = fragmentShader, 125 | VertexInputState = VertexInputState.Empty, 126 | RasterizerState = RasterizerState.CCW_CullNone, 127 | PrimitiveType = PrimitiveType.TriangleList, 128 | MultisampleState = MultisampleState.None 129 | } 130 | ); 131 | 132 | if (pipeline == null) 133 | { 134 | Logger.LogError("Failed to compile pipeline!"); 135 | Logger.LogError(SDL3.SDL.SDL_GetError()); 136 | return; 137 | } 138 | 139 | Pipeline?.Dispose(); 140 | FragmentShader?.Dispose(); 141 | 142 | FragmentShader = fragmentShader; 143 | Pipeline = pipeline; 144 | } 145 | 146 | private void OnChanged(object sender, FileSystemEventArgs e) 147 | { 148 | if (e.ChangeType != WatcherChangeTypes.Changed) 149 | { 150 | return; 151 | } 152 | 153 | NeedReload = true; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /Examples/GetBufferDataExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using MoonWorks.Input; 4 | using System.Numerics; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace MoonWorksGraphicsTests; 8 | 9 | class GetBufferDataExample : Example 10 | { 11 | public override void Init() 12 | { 13 | Window.SetTitle("GetBufferData"); 14 | 15 | var vertices = new System.Span( 16 | [ 17 | new PositionVertex(new Vector3(0, 0, 0)), 18 | new PositionVertex(new Vector3(0, 0, 1)), 19 | new PositionVertex(new Vector3(0, 1, 0)), 20 | new PositionVertex(new Vector3(0, 1, 1)), 21 | new PositionVertex(new Vector3(1, 0, 0)), 22 | new PositionVertex(new Vector3(1, 0, 1)), 23 | new PositionVertex(new Vector3(1, 1, 0)), 24 | new PositionVertex(new Vector3(1, 1, 1)), 25 | ]); 26 | 27 | var otherVerts = new System.Span( 28 | [ 29 | new PositionVertex(new Vector3(1, 2, 3)), 30 | new PositionVertex(new Vector3(4, 5, 6)), 31 | new PositionVertex(new Vector3(7, 8, 9)) 32 | ]); 33 | 34 | int vertexSize = Marshal.SizeOf(); 35 | 36 | var resourceUploader = new ResourceUploader(GraphicsDevice); 37 | var vertexBuffer = resourceUploader.CreateBuffer(vertices, BufferUsageFlags.Vertex); 38 | resourceUploader.Upload(); 39 | resourceUploader.Dispose(); 40 | 41 | var uploadBuffer = TransferBuffer.Create( 42 | GraphicsDevice, 43 | TransferBufferUsage.Upload, 44 | vertexBuffer.Size 45 | ); 46 | 47 | var downloadBuffer = TransferBuffer.Create( 48 | GraphicsDevice, 49 | TransferBufferUsage.Download, 50 | vertexBuffer.Size 51 | ); 52 | 53 | // Read back and print out the vertex values 54 | var cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 55 | var copyPass = cmdbuf.BeginCopyPass(); 56 | copyPass.DownloadFromBuffer( 57 | vertexBuffer, 58 | downloadBuffer 59 | ); 60 | cmdbuf.EndCopyPass(copyPass); 61 | var fence = GraphicsDevice.SubmitAndAcquireFence(cmdbuf); 62 | GraphicsDevice.WaitForFence(fence); 63 | GraphicsDevice.ReleaseFence(fence); 64 | 65 | var readbackVertices = downloadBuffer.Map(false); 66 | for (int i = 0; i < readbackVertices.Length; i += 1) 67 | { 68 | Logger.LogInfo(readbackVertices[i].ToString()); 69 | } 70 | 71 | // Change the first three vertices and upload 72 | var uploadVertices = uploadBuffer.Map(false); 73 | readbackVertices.CopyTo(uploadVertices); 74 | otherVerts.CopyTo(uploadVertices); 75 | downloadBuffer.Unmap(); 76 | uploadBuffer.Unmap(); 77 | 78 | cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 79 | copyPass = cmdbuf.BeginCopyPass(); 80 | copyPass.UploadToBuffer(uploadBuffer, vertexBuffer, false); 81 | copyPass.DownloadFromBuffer( 82 | vertexBuffer, 83 | downloadBuffer 84 | ); 85 | cmdbuf.EndCopyPass(copyPass); 86 | fence = GraphicsDevice.SubmitAndAcquireFence(cmdbuf); 87 | GraphicsDevice.WaitForFence(fence); 88 | GraphicsDevice.ReleaseFence(fence); 89 | 90 | // Read the updated buffer 91 | readbackVertices = downloadBuffer.Map(false); 92 | Logger.LogInfo("=== Change first three vertices ==="); 93 | for (int i = 0; i < readbackVertices.Length; i += 1) 94 | { 95 | Logger.LogInfo(readbackVertices[i].ToString()); 96 | } 97 | downloadBuffer.Unmap(); 98 | 99 | // Change the last two vertices and upload 100 | uploadVertices = uploadBuffer.Map(false); 101 | var lastTwoSpan = otherVerts.Slice(1, 2); 102 | lastTwoSpan.CopyTo(uploadVertices.Slice(uploadVertices.Length - 3)); 103 | uploadBuffer.Unmap(); 104 | 105 | cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 106 | copyPass = cmdbuf.BeginCopyPass(); 107 | copyPass.UploadToBuffer( 108 | uploadBuffer, 109 | vertexBuffer, 110 | 0, 111 | (uint)(vertices.Length - 2), 112 | 2, 113 | false 114 | ); 115 | copyPass.DownloadFromBuffer( 116 | vertexBuffer, 117 | downloadBuffer 118 | ); 119 | cmdbuf.EndCopyPass(copyPass); 120 | fence = GraphicsDevice.SubmitAndAcquireFence(cmdbuf); 121 | GraphicsDevice.WaitForFence(fence); 122 | GraphicsDevice.ReleaseFence(fence); 123 | 124 | // Read the updated buffer 125 | readbackVertices = downloadBuffer.Map(false); 126 | Logger.LogInfo("=== Change last two vertices ==="); 127 | for (int i = 0; i < readbackVertices.Length; i += 1) 128 | { 129 | Logger.LogInfo(readbackVertices[i].ToString()); 130 | } 131 | downloadBuffer.Unmap(); 132 | 133 | vertexBuffer.Dispose(); 134 | uploadBuffer.Dispose(); 135 | downloadBuffer.Dispose(); 136 | } 137 | 138 | public override void Update(System.TimeSpan delta) { } 139 | 140 | public override void Draw(double alpha) 141 | { 142 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 143 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 144 | if (swapchainTexture != null) 145 | { 146 | var renderPass = cmdbuf.BeginRenderPass( 147 | new ColorTargetInfo(swapchainTexture, Color.Black) 148 | ); 149 | cmdbuf.EndRenderPass(renderPass); 150 | } 151 | GraphicsDevice.Submit(cmdbuf); 152 | } 153 | 154 | public override void Destroy() 155 | { 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /Examples/Texture3DCopyExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using MoonWorks.Input; 4 | using System.Numerics; 5 | 6 | namespace MoonWorksGraphicsTests; 7 | 8 | class Texture3DCopyExample : Example 9 | { 10 | private GraphicsPipeline Pipeline; 11 | private Buffer VertexBuffer; 12 | private Buffer IndexBuffer; 13 | private Texture RenderTexture; 14 | private Texture Texture3D; 15 | private Sampler Sampler; 16 | 17 | private float t; 18 | private Color[] colors = 19 | [ 20 | Color.Red, 21 | Color.Green, 22 | Color.Blue, 23 | ]; 24 | 25 | struct FragUniform 26 | { 27 | public float Depth; 28 | 29 | public FragUniform(float depth) 30 | { 31 | Depth = depth; 32 | } 33 | } 34 | 35 | public override void Init() 36 | { 37 | Window.SetTitle("Texture3DCopy"); 38 | 39 | // Load the shaders 40 | Shader vertShader = ShaderCross.Create( 41 | GraphicsDevice, 42 | RootTitleStorage, 43 | TestUtils.GetHLSLPath("TexturedQuad.vert"), 44 | "main", 45 | ShaderCross.ShaderFormat.HLSL, 46 | ShaderStage.Vertex 47 | ); 48 | Shader fragShader = ShaderCross.Create( 49 | GraphicsDevice, 50 | RootTitleStorage, 51 | TestUtils.GetHLSLPath("TexturedQuad3D.frag"), 52 | "main", 53 | ShaderCross.ShaderFormat.HLSL, 54 | ShaderStage.Fragment 55 | ); 56 | 57 | // Create the graphics pipeline 58 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 59 | Window.SwapchainFormat, 60 | vertShader, 61 | fragShader 62 | ); 63 | pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); 64 | 65 | Pipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 66 | 67 | // Create samplers 68 | Sampler = Sampler.Create(GraphicsDevice, SamplerCreateInfo.LinearWrap); 69 | 70 | // Create and populate the GPU resources 71 | var resourceUploader = new ResourceUploader(GraphicsDevice); 72 | 73 | VertexBuffer = resourceUploader.CreateBuffer( 74 | [ 75 | new PositionTextureVertex(new Vector3(-1, -1, 0), new Vector2(0, 0)), 76 | new PositionTextureVertex(new Vector3(1, -1, 0), new Vector2(1, 0)), 77 | new PositionTextureVertex(new Vector3(1, 1, 0), new Vector2(1, 1)), 78 | new PositionTextureVertex(new Vector3(-1, 1, 0), new Vector2(0, 1)), 79 | ], 80 | BufferUsageFlags.Vertex 81 | ); 82 | 83 | IndexBuffer = resourceUploader.CreateBuffer( 84 | [ 85 | 0, 1, 2, 86 | 0, 2, 3, 87 | ], 88 | BufferUsageFlags.Index 89 | ); 90 | 91 | resourceUploader.Upload(); 92 | resourceUploader.Dispose(); 93 | 94 | RenderTexture = Texture.Create2DArray( 95 | GraphicsDevice, 96 | 16, 97 | 16, 98 | (uint) colors.Length, 99 | TextureFormat.R8G8B8A8Unorm, 100 | TextureUsageFlags.ColorTarget | TextureUsageFlags.Sampler 101 | ); 102 | 103 | Texture3D = Texture.Create3D( 104 | GraphicsDevice, 105 | 16, 106 | 16, 107 | 3, 108 | TextureFormat.R8G8B8A8Unorm, 109 | TextureUsageFlags.Sampler 110 | ); 111 | 112 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 113 | 114 | // Clear each layer slice of the RT to a different color 115 | for (uint i = 0; i < colors.Length; i += 1) 116 | { 117 | var renderPass = cmdbuf.BeginRenderPass(new ColorTargetInfo 118 | { 119 | Texture = RenderTexture.Handle, 120 | LayerOrDepthPlane = i, 121 | LoadOp = LoadOp.Clear, 122 | ClearColor = colors[i], 123 | StoreOp = StoreOp.Store 124 | }); 125 | cmdbuf.EndRenderPass(renderPass); 126 | } 127 | 128 | // Copy each layer slice to a different 3D depth 129 | var copyPass = cmdbuf.BeginCopyPass(); 130 | for (var i = 0; i < 3; i += 1) 131 | { 132 | copyPass.CopyTextureToTexture( 133 | new TextureLocation 134 | { 135 | Texture = RenderTexture.Handle, 136 | Layer = (uint) i 137 | }, 138 | new TextureLocation 139 | { 140 | Texture = Texture3D.Handle, 141 | Z = (uint) i 142 | }, 143 | 16, 144 | 16, 145 | 1, 146 | false 147 | ); 148 | } 149 | cmdbuf.EndCopyPass(copyPass); 150 | 151 | GraphicsDevice.Submit(cmdbuf); 152 | } 153 | 154 | public override void Update(System.TimeSpan delta) 155 | { 156 | t += (float) delta.TotalSeconds; 157 | } 158 | 159 | public override void Draw(double alpha) 160 | { 161 | FragUniform fragUniform = new FragUniform(t); 162 | 163 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 164 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 165 | if (swapchainTexture != null) 166 | { 167 | var renderPass = cmdbuf.BeginRenderPass( 168 | new ColorTargetInfo(swapchainTexture, Color.Black) 169 | ); 170 | renderPass.BindGraphicsPipeline(Pipeline); 171 | renderPass.BindVertexBuffers(VertexBuffer); 172 | renderPass.BindIndexBuffer(IndexBuffer, IndexElementSize.Sixteen); 173 | renderPass.BindFragmentSamplers(new TextureSamplerBinding(Texture3D, Sampler)); 174 | cmdbuf.PushFragmentUniformData(fragUniform); 175 | renderPass.DrawIndexedPrimitives(6, 1, 0, 0, 0); 176 | cmdbuf.EndRenderPass(renderPass); 177 | } 178 | GraphicsDevice.Submit(cmdbuf); 179 | } 180 | 181 | public override void Destroy() 182 | { 183 | Pipeline.Dispose(); 184 | VertexBuffer.Dispose(); 185 | IndexBuffer.Dispose(); 186 | RenderTexture.Dispose(); 187 | Texture3D.Dispose(); 188 | Sampler.Dispose(); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /Examples/CopyTextureExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | 4 | namespace MoonWorksGraphicsTests 5 | { 6 | class CopyTextureExample : Example 7 | { 8 | private Texture OriginalTexture; 9 | private Texture TextureCopy; 10 | private Texture TextureSmall; 11 | 12 | public override unsafe void Init() 13 | { 14 | Window.SetTitle("CopyTexture"); 15 | 16 | // Create and populate the GPU resources 17 | var resourceUploader = new ResourceUploader(GraphicsDevice); 18 | 19 | OriginalTexture = resourceUploader.CreateTexture2DFromCompressed( 20 | RootTitleStorage, 21 | TestUtils.GetTexturePath("ravioli.png"), 22 | TextureFormat.R8G8B8A8Unorm, 23 | TextureUsageFlags.Sampler 24 | ); 25 | 26 | resourceUploader.Upload(); 27 | resourceUploader.Dispose(); 28 | 29 | // Load the texture bytes so we can compare them. 30 | var pixels = ImageUtils.GetPixelDataFromFile( 31 | RootTitleStorage, 32 | TestUtils.GetTexturePath("ravioli.png"), 33 | out var width, 34 | out var height, 35 | out var byteCount 36 | ); 37 | 38 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 39 | 40 | var textureCreateInfo = new TextureCreateInfo 41 | { 42 | Type = OriginalTexture.Type, 43 | Format = OriginalTexture.Format, 44 | Usage = OriginalTexture.UsageFlags, 45 | Width = OriginalTexture.Width, 46 | Height = OriginalTexture.Height, 47 | LayerCountOrDepth = OriginalTexture.LayerCountOrDepth, 48 | NumLevels = OriginalTexture.LevelCount, 49 | SampleCount = OriginalTexture.SampleCount 50 | }; 51 | 52 | // Create a 1:1 copy of the texture 53 | TextureCopy = Texture.Create(GraphicsDevice, textureCreateInfo); 54 | 55 | // Create a download transfer buffer 56 | TransferBuffer compareBuffer = TransferBuffer.Create( 57 | GraphicsDevice, 58 | TransferBufferUsage.Download, 59 | byteCount 60 | ); 61 | 62 | var copyPass = cmdbuf.BeginCopyPass(); 63 | copyPass.CopyTextureToTexture( 64 | new TextureLocation(OriginalTexture), 65 | new TextureLocation(TextureCopy), 66 | OriginalTexture.Width, 67 | OriginalTexture.Height, 68 | 1, 69 | false 70 | ); 71 | cmdbuf.EndCopyPass(copyPass); 72 | 73 | // Create a half-sized copy of this texture 74 | textureCreateInfo.Width /= 2; 75 | textureCreateInfo.Height /= 2; 76 | textureCreateInfo.Usage |= TextureUsageFlags.ColorTarget; 77 | TextureSmall = Texture.Create(GraphicsDevice, textureCreateInfo); 78 | 79 | // Render the half-size copy 80 | cmdbuf.Blit(OriginalTexture, TextureSmall, Filter.Linear); 81 | 82 | // Copy the texture to a transfer buffer 83 | copyPass = cmdbuf.BeginCopyPass(); 84 | copyPass.DownloadFromTexture( 85 | new TextureRegion(TextureCopy), 86 | new TextureTransferInfo(compareBuffer) 87 | ); 88 | cmdbuf.EndCopyPass(copyPass); 89 | 90 | var fence = GraphicsDevice.SubmitAndAcquireFence(cmdbuf); 91 | GraphicsDevice.WaitForFence(fence); 92 | GraphicsDevice.ReleaseFence(fence); 93 | 94 | // Compare the original bytes to the copied bytes. 95 | var copiedSpan = compareBuffer.Map(false); 96 | var originalSpan = new System.Span(pixels, (int)byteCount); 97 | 98 | if (System.MemoryExtensions.SequenceEqual(originalSpan, copiedSpan)) 99 | { 100 | Logger.LogInfo("SUCCESS! Original texture bytes and the downloaded bytes match!"); 101 | 102 | } 103 | else 104 | { 105 | Logger.LogError("FAIL! Original texture bytes do not match downloaded bytes!"); 106 | } 107 | compareBuffer.Unmap(); 108 | 109 | ImageUtils.FreePixelData(pixels); 110 | } 111 | 112 | public override void Update(System.TimeSpan delta) { } 113 | 114 | public override void Draw(double alpha) 115 | { 116 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 117 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 118 | if (swapchainTexture != null) 119 | { 120 | var clearPass = cmdbuf.BeginRenderPass( 121 | new ColorTargetInfo(swapchainTexture, Color.Black) 122 | ); 123 | cmdbuf.EndRenderPass(clearPass); 124 | 125 | cmdbuf.Blit(new BlitInfo 126 | { 127 | Source = new BlitRegion(OriginalTexture), 128 | Destination = new BlitRegion 129 | { 130 | Texture = swapchainTexture.Handle, 131 | W = swapchainTexture.Width / 2, 132 | H = swapchainTexture.Height / 2 133 | }, 134 | Filter = Filter.Nearest 135 | }); 136 | 137 | cmdbuf.Blit(new BlitInfo 138 | { 139 | Source = new BlitRegion(TextureCopy), 140 | Destination = new BlitRegion 141 | { 142 | Texture = swapchainTexture.Handle, 143 | X = swapchainTexture.Width / 2, 144 | W = swapchainTexture.Width / 2, 145 | H = swapchainTexture.Height / 2, 146 | }, 147 | Filter = Filter.Nearest 148 | }); 149 | 150 | cmdbuf.Blit(new BlitInfo 151 | { 152 | Source = new BlitRegion(TextureSmall), 153 | Destination = new BlitRegion 154 | { 155 | Texture = swapchainTexture.Handle, 156 | X = swapchainTexture.Width / 4, 157 | Y = swapchainTexture.Height / 2, 158 | W = swapchainTexture.Width / 2, 159 | H = swapchainTexture.Height / 2 160 | }, 161 | Filter = Filter.Nearest 162 | }); 163 | } 164 | 165 | GraphicsDevice.Submit(cmdbuf); 166 | } 167 | 168 | public override void Destroy() 169 | { 170 | OriginalTexture.Dispose(); 171 | TextureCopy.Dispose(); 172 | TextureSmall.Dispose(); 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /Examples/BasicComputeExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using MoonWorks.Input; 4 | using System.Numerics; 5 | 6 | namespace MoonWorksGraphicsTests; 7 | 8 | class BasicComputeExample : Example 9 | { 10 | private GraphicsPipeline DrawPipeline; 11 | private Texture Texture; 12 | private Sampler Sampler; 13 | private Buffer VertexBuffer; 14 | 15 | public override void Init() 16 | { 17 | Window.SetTitle("BasicCompute"); 18 | 19 | // Create the compute pipeline that writes texture data 20 | ComputePipeline fillTextureComputePipeline = ShaderCross.Create( 21 | GraphicsDevice, 22 | RootTitleStorage, 23 | TestUtils.GetHLSLPath("FillTexture.comp"), 24 | "main", 25 | ShaderCross.ShaderFormat.HLSL 26 | ); 27 | 28 | // Create the compute pipeline that calculates squares of numbers 29 | ComputePipeline calculateSquaresComputePipeline = ShaderCross.Create( 30 | GraphicsDevice, 31 | RootTitleStorage, 32 | TestUtils.GetHLSLPath("CalculateSquares.comp"), 33 | "main", 34 | ShaderCross.ShaderFormat.HLSL 35 | ); 36 | 37 | // Create the graphics pipeline 38 | Shader vertShader = ShaderCross.Create( 39 | GraphicsDevice, 40 | RootTitleStorage, 41 | TestUtils.GetHLSLPath("TexturedQuad.vert"), 42 | "main", 43 | ShaderCross.ShaderFormat.HLSL, 44 | ShaderStage.Vertex 45 | ); 46 | 47 | Shader fragShader = ShaderCross.Create( 48 | GraphicsDevice, 49 | RootTitleStorage, 50 | TestUtils.GetHLSLPath("TexturedQuad.frag"), 51 | "main", 52 | ShaderCross.ShaderFormat.HLSL, 53 | ShaderStage.Fragment 54 | ); 55 | 56 | GraphicsPipelineCreateInfo drawPipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 57 | Window.SwapchainFormat, 58 | vertShader, 59 | fragShader 60 | ); 61 | drawPipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(0); 62 | 63 | DrawPipeline = GraphicsPipeline.Create( 64 | GraphicsDevice, 65 | drawPipelineCreateInfo 66 | ); 67 | 68 | // Create buffers and textures 69 | uint[] squares = new uint[64]; 70 | Buffer squaresBuffer = Buffer.Create( 71 | GraphicsDevice, 72 | BufferUsageFlags.ComputeStorageWrite, 73 | (uint) squares.Length 74 | ); 75 | 76 | TransferBuffer transferBuffer = TransferBuffer.Create( 77 | GraphicsDevice, 78 | TransferBufferUsage.Download, 79 | (uint) squares.Length 80 | ); 81 | 82 | Texture = Texture.Create2D( 83 | GraphicsDevice, 84 | Window.Width, 85 | Window.Height, 86 | TextureFormat.R8G8B8A8Unorm, 87 | TextureUsageFlags.ComputeStorageWrite | TextureUsageFlags.Sampler 88 | ); 89 | 90 | Sampler = Sampler.Create(GraphicsDevice, new SamplerCreateInfo()); 91 | 92 | // Upload GPU resources and dispatch compute work 93 | var resourceUploader = new ResourceUploader(GraphicsDevice); 94 | VertexBuffer = resourceUploader.CreateBuffer( 95 | [ 96 | new PositionTextureVertex(new Vector3(-1, -1, 0), new Vector2(0, 0)), 97 | new PositionTextureVertex(new Vector3(1, -1, 0), new Vector2(1, 0)), 98 | new PositionTextureVertex(new Vector3(1, 1, 0), new Vector2(1, 1)), 99 | new PositionTextureVertex(new Vector3(-1, -1, 0), new Vector2(0, 0)), 100 | new PositionTextureVertex(new Vector3(1, 1, 0), new Vector2(1, 1)), 101 | new PositionTextureVertex(new Vector3(-1, 1, 0), new Vector2(0, 1)), 102 | ], 103 | BufferUsageFlags.Vertex 104 | ); 105 | 106 | resourceUploader.Upload(); 107 | resourceUploader.Dispose(); 108 | 109 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 110 | 111 | // This should result in a bright yellow texture! 112 | var computePass = cmdbuf.BeginComputePass(new StorageTextureReadWriteBinding(Texture)); 113 | computePass.BindComputePipeline(fillTextureComputePipeline); 114 | computePass.Dispatch(Texture.Width / 8, Texture.Height / 8, 1); 115 | cmdbuf.EndComputePass(computePass); 116 | 117 | // This calculates the squares of the first N integers! 118 | computePass = cmdbuf.BeginComputePass(new StorageBufferReadWriteBinding(squaresBuffer)); 119 | computePass.BindComputePipeline(calculateSquaresComputePipeline); 120 | computePass.Dispatch((uint) squares.Length / 8, 1, 1); 121 | cmdbuf.EndComputePass(computePass); 122 | 123 | var copyPass = cmdbuf.BeginCopyPass(); 124 | copyPass.DownloadFromBuffer(squaresBuffer, transferBuffer); 125 | cmdbuf.EndCopyPass(copyPass); 126 | 127 | var fence = GraphicsDevice.SubmitAndAcquireFence(cmdbuf); 128 | GraphicsDevice.WaitForFence(fence); 129 | GraphicsDevice.ReleaseFence(fence); 130 | 131 | // Print the squares! 132 | var transferSpan = transferBuffer.Map(false); 133 | transferSpan.CopyTo(squares); 134 | transferBuffer.Unmap(); 135 | Logger.LogInfo("Squares of the first " + squares.Length + " integers: " + string.Join(", ", squares)); 136 | } 137 | 138 | public override void Update(System.TimeSpan delta) { } 139 | 140 | public override void Draw(double alpha) 141 | { 142 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 143 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 144 | if (swapchainTexture != null) 145 | { 146 | var renderPass = cmdbuf.BeginRenderPass(new ColorTargetInfo 147 | { 148 | Texture = swapchainTexture, 149 | LoadOp = LoadOp.Clear, 150 | ClearColor = Color.CornflowerBlue 151 | }); 152 | renderPass.BindGraphicsPipeline(DrawPipeline); 153 | renderPass.BindFragmentSamplers(new TextureSamplerBinding(Texture, Sampler)); 154 | renderPass.BindVertexBuffers(VertexBuffer); 155 | renderPass.DrawPrimitives(6, 1, 0, 0); 156 | cmdbuf.EndRenderPass(renderPass); 157 | } 158 | GraphicsDevice.Submit(cmdbuf); 159 | } 160 | 161 | public override void Destroy() 162 | { 163 | DrawPipeline.Dispose(); 164 | Texture.Dispose(); 165 | Sampler.Dispose(); 166 | VertexBuffer.Dispose(); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /Examples/TexturedAnimatedQuadExample.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using MoonWorks; 3 | using MoonWorks.Graphics; 4 | using MoonWorks.Input; 5 | using System.Numerics; 6 | 7 | namespace MoonWorksGraphicsTests; 8 | 9 | class TexturedAnimatedQuadExample : Example 10 | { 11 | private GraphicsPipeline Pipeline; 12 | private Buffer VertexBuffer; 13 | private Buffer IndexBuffer; 14 | private Texture Texture; 15 | private Sampler Sampler; 16 | 17 | private float t; 18 | 19 | [StructLayout(LayoutKind.Sequential)] 20 | private struct FragmentUniforms 21 | { 22 | public Vector4 MultiplyColor; 23 | 24 | public FragmentUniforms(Vector4 multiplyColor) 25 | { 26 | MultiplyColor = multiplyColor; 27 | } 28 | } 29 | 30 | public override void Init() 31 | { 32 | Window.SetTitle("TexturedAnimatedQuad"); 33 | 34 | // Load the shaders 35 | Shader vertShader = ShaderCross.Create( 36 | GraphicsDevice, 37 | RootTitleStorage, 38 | TestUtils.GetHLSLPath("TexturedQuadWithMatrix.vert"), 39 | "main", 40 | ShaderCross.ShaderFormat.HLSL, 41 | ShaderStage.Vertex 42 | ); 43 | 44 | Shader fragShader = ShaderCross.Create( 45 | GraphicsDevice, 46 | RootTitleStorage, 47 | TestUtils.GetHLSLPath("TexturedQuadWithMultiplyColor.frag"), 48 | "main", 49 | ShaderCross.ShaderFormat.HLSL, 50 | ShaderStage.Fragment 51 | ); 52 | 53 | // Create the graphics pipeline 54 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 55 | Window.SwapchainFormat, 56 | vertShader, 57 | fragShader 58 | ); 59 | pipelineCreateInfo.TargetInfo.ColorTargetDescriptions[0].BlendState = ColorTargetBlendState.PremultipliedAlphaBlend; 60 | pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); 61 | 62 | Pipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 63 | 64 | Sampler = Sampler.Create(GraphicsDevice, SamplerCreateInfo.PointClamp); 65 | 66 | // Create and populate the GPU resources 67 | var resourceUploader = new ResourceUploader(GraphicsDevice); 68 | 69 | VertexBuffer = resourceUploader.CreateBuffer( 70 | [ 71 | new PositionTextureVertex(new Vector3(-0.5f, -0.5f, 0), new Vector2(0, 0)), 72 | new PositionTextureVertex(new Vector3(0.5f, -0.5f, 0), new Vector2(1, 0)), 73 | new PositionTextureVertex(new Vector3(0.5f, 0.5f, 0), new Vector2(1, 1)), 74 | new PositionTextureVertex(new Vector3(-0.5f, 0.5f, 0), new Vector2(0, 1)), 75 | ], 76 | BufferUsageFlags.Vertex 77 | ); 78 | 79 | IndexBuffer = resourceUploader.CreateBuffer( 80 | [ 81 | 0, 1, 2, 82 | 0, 2, 3, 83 | ], 84 | BufferUsageFlags.Index 85 | ); 86 | 87 | Texture = resourceUploader.CreateTexture2DFromCompressed( 88 | RootTitleStorage, 89 | TestUtils.GetTexturePath("ravioli.png"), 90 | TextureFormat.R8G8B8A8Unorm, 91 | TextureUsageFlags.Sampler 92 | ); 93 | 94 | resourceUploader.Upload(); 95 | resourceUploader.Dispose(); 96 | } 97 | 98 | public override void Update(System.TimeSpan delta) 99 | { 100 | t += (float) delta.TotalSeconds; 101 | } 102 | 103 | public override void Draw(double alpha) 104 | { 105 | TransformVertexUniform vertUniforms; 106 | FragmentUniforms fragUniforms; 107 | 108 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 109 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 110 | if (swapchainTexture != null) 111 | { 112 | var renderPass = cmdbuf.BeginRenderPass( 113 | new ColorTargetInfo(swapchainTexture, Color.Black) 114 | ); 115 | renderPass.BindGraphicsPipeline(Pipeline); 116 | renderPass.BindVertexBuffers(VertexBuffer); 117 | renderPass.BindIndexBuffer(IndexBuffer, IndexElementSize.Sixteen); 118 | renderPass.BindFragmentSamplers(new TextureSamplerBinding(Texture, Sampler)); 119 | 120 | // Top-left 121 | vertUniforms = new TransformVertexUniform(Matrix4x4.CreateRotationZ(t) * Matrix4x4.CreateTranslation(new Vector3(-0.5f, -0.5f, 0))); 122 | fragUniforms = new FragmentUniforms(new Vector4(1f, 0.5f + System.MathF.Sin(t) * 0.5f, 1f, 1f)); 123 | cmdbuf.PushVertexUniformData(vertUniforms); 124 | cmdbuf.PushFragmentUniformData(fragUniforms); 125 | renderPass.DrawIndexedPrimitives(6, 1, 0, 0, 0); 126 | 127 | // Top-right 128 | vertUniforms = new TransformVertexUniform(Matrix4x4.CreateRotationZ((2 * System.MathF.PI) - t) * Matrix4x4.CreateTranslation(new Vector3(0.5f, -0.5f, 0))); 129 | fragUniforms = new FragmentUniforms(new Vector4(1f, 0.5f + System.MathF.Cos(t) * 0.5f, 1f, 1f)); 130 | cmdbuf.PushVertexUniformData(vertUniforms); 131 | cmdbuf.PushFragmentUniformData(fragUniforms); 132 | renderPass.DrawIndexedPrimitives(6, 1, 0, 0, 0); 133 | 134 | // Bottom-left 135 | vertUniforms = new TransformVertexUniform(Matrix4x4.CreateRotationZ(t) * Matrix4x4.CreateTranslation(new Vector3(-0.5f, 0.5f, 0))); 136 | fragUniforms = new FragmentUniforms(new Vector4(1f, 0.5f + System.MathF.Sin(t) * 0.2f, 1f, 1f)); 137 | cmdbuf.PushVertexUniformData(vertUniforms); 138 | cmdbuf.PushFragmentUniformData(fragUniforms); 139 | renderPass.DrawIndexedPrimitives(6, 1, 0, 0, 0); 140 | 141 | // Bottom-right 142 | vertUniforms = new TransformVertexUniform(Matrix4x4.CreateRotationZ(t) * Matrix4x4.CreateTranslation(new Vector3(0.5f, 0.5f, 0))); 143 | fragUniforms = new FragmentUniforms(new Vector4(1f, 0.5f + System.MathF.Cos(t) * 1f, 1f, 1f)); 144 | cmdbuf.PushVertexUniformData(vertUniforms); 145 | cmdbuf.PushFragmentUniformData(fragUniforms); 146 | renderPass.DrawIndexedPrimitives(6, 1, 0, 0, 0); 147 | 148 | cmdbuf.EndRenderPass(renderPass); 149 | } 150 | 151 | GraphicsDevice.Submit(cmdbuf); 152 | } 153 | 154 | public override void Destroy() 155 | { 156 | Pipeline.Dispose(); 157 | VertexBuffer.Dispose(); 158 | IndexBuffer.Dispose(); 159 | Texture.Dispose(); 160 | Sampler.Dispose(); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /Examples/CullFaceExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using System.Numerics; 4 | 5 | namespace MoonWorksGraphicsTests; 6 | 7 | class CullFaceExample : Example 8 | { 9 | private GraphicsPipeline CW_CullNonePipeline; 10 | private GraphicsPipeline CW_CullFrontPipeline; 11 | private GraphicsPipeline CW_CullBackPipeline; 12 | private GraphicsPipeline CCW_CullNonePipeline; 13 | private GraphicsPipeline CCW_CullFrontPipeline; 14 | private GraphicsPipeline CCW_CullBackPipeline; 15 | private Buffer CW_VertexBuffer; 16 | private Buffer CCW_VertexBuffer; 17 | 18 | private bool UseClockwiseWinding; 19 | 20 | public override void Init() 21 | { 22 | Window.SetTitle("CullFace"); 23 | 24 | Logger.LogInfo("Press Down to toggle the winding order of the triangles (default is counter-clockwise)"); 25 | 26 | // Load the shaders 27 | Shader vertShader = ShaderCross.Create( 28 | GraphicsDevice, 29 | RootTitleStorage, 30 | TestUtils.GetHLSLPath("PositionColor.vert"), 31 | "main", 32 | ShaderCross.ShaderFormat.HLSL, 33 | ShaderStage.Vertex 34 | ); 35 | 36 | Shader fragShader = ShaderCross.Create( 37 | GraphicsDevice, 38 | RootTitleStorage, 39 | TestUtils.GetHLSLPath("SolidColor.frag"), 40 | "main", 41 | ShaderCross.ShaderFormat.HLSL, 42 | ShaderStage.Fragment 43 | ); 44 | 45 | // Create the graphics pipelines 46 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 47 | Window.SwapchainFormat, 48 | vertShader, 49 | fragShader 50 | ); 51 | pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); 52 | 53 | pipelineCreateInfo.RasterizerState = RasterizerState.CW_CullNone; 54 | CW_CullNonePipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 55 | 56 | pipelineCreateInfo.RasterizerState = RasterizerState.CW_CullFront; 57 | CW_CullFrontPipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 58 | 59 | pipelineCreateInfo.RasterizerState = RasterizerState.CW_CullBack; 60 | CW_CullBackPipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 61 | 62 | pipelineCreateInfo.RasterizerState = RasterizerState.CCW_CullNone; 63 | CCW_CullNonePipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 64 | 65 | pipelineCreateInfo.RasterizerState = RasterizerState.CCW_CullFront; 66 | CCW_CullFrontPipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 67 | 68 | pipelineCreateInfo.RasterizerState = RasterizerState.CCW_CullBack; 69 | CCW_CullBackPipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 70 | 71 | // Create and populate the vertex buffers 72 | var resourceUploader = new ResourceUploader(GraphicsDevice); 73 | 74 | CW_VertexBuffer = resourceUploader.CreateBuffer( 75 | [ 76 | new PositionColorVertex(new Vector3( 0, 1, 0), Color.Blue), 77 | new PositionColorVertex(new Vector3( 1, -1, 0), Color.Green), 78 | new PositionColorVertex(new Vector3(-1, -1, 0), Color.Red), 79 | ], 80 | BufferUsageFlags.Vertex 81 | ); 82 | 83 | CCW_VertexBuffer = resourceUploader.CreateBuffer( 84 | [ 85 | new PositionColorVertex(new Vector3(-1, -1, 0), Color.Red), 86 | new PositionColorVertex(new Vector3( 1, -1, 0), Color.Green), 87 | new PositionColorVertex(new Vector3( 0, 1, 0), Color.Blue) 88 | ], 89 | BufferUsageFlags.Vertex 90 | ); 91 | 92 | resourceUploader.Upload(); 93 | resourceUploader.Dispose(); 94 | } 95 | 96 | public override void Update(System.TimeSpan delta) 97 | { 98 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Bottom)) 99 | { 100 | UseClockwiseWinding = !UseClockwiseWinding; 101 | Logger.LogInfo("Using clockwise winding: " + UseClockwiseWinding); 102 | } 103 | } 104 | 105 | public override void Draw(double alpha) 106 | { 107 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 108 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 109 | if (swapchainTexture != null) 110 | { 111 | var renderPass = cmdbuf.BeginRenderPass( 112 | new ColorTargetInfo(swapchainTexture, Color.Black) 113 | ); 114 | 115 | // Need to bind a pipeline before binding vertex buffers 116 | renderPass.BindGraphicsPipeline(CW_CullNonePipeline); 117 | if (UseClockwiseWinding) 118 | { 119 | renderPass.BindVertexBuffers(CW_VertexBuffer); 120 | } 121 | else 122 | { 123 | renderPass.BindVertexBuffers(CCW_VertexBuffer); 124 | } 125 | 126 | renderPass.SetViewport(new Viewport(0, 0, 213, 240)); 127 | renderPass.DrawPrimitives(3, 1, 0, 0); 128 | 129 | renderPass.SetViewport(new Viewport(213, 0, 213, 240)); 130 | renderPass.BindGraphicsPipeline(CW_CullFrontPipeline); 131 | renderPass.DrawPrimitives(3, 1, 0, 0); 132 | 133 | renderPass.SetViewport(new Viewport(426, 0, 213, 240)); 134 | renderPass.BindGraphicsPipeline(CW_CullBackPipeline); 135 | renderPass.DrawPrimitives(3, 1, 0, 0); 136 | 137 | renderPass.SetViewport(new Viewport(0, 240, 213, 240)); 138 | renderPass.BindGraphicsPipeline(CCW_CullNonePipeline); 139 | renderPass.DrawPrimitives(3, 1, 0, 0); 140 | 141 | renderPass.SetViewport(new Viewport(213, 240, 213, 240)); 142 | renderPass.BindGraphicsPipeline(CCW_CullFrontPipeline); 143 | renderPass.DrawPrimitives(3, 1, 0, 0); 144 | 145 | renderPass.SetViewport(new Viewport(426, 240, 213, 240)); 146 | renderPass.BindGraphicsPipeline(CCW_CullBackPipeline); 147 | renderPass.DrawPrimitives(3, 1, 0, 0); 148 | 149 | cmdbuf.EndRenderPass(renderPass); 150 | } 151 | 152 | GraphicsDevice.Submit(cmdbuf); 153 | } 154 | 155 | public override void Destroy() 156 | { 157 | CW_CullNonePipeline.Dispose(); 158 | CW_CullFrontPipeline.Dispose(); 159 | CW_CullBackPipeline.Dispose(); 160 | CCW_CullNonePipeline.Dispose(); 161 | CCW_CullFrontPipeline.Dispose(); 162 | CCW_CullBackPipeline.Dispose(); 163 | CW_VertexBuffer.Dispose(); 164 | CCW_VertexBuffer.Dispose(); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /Examples/RenderTextureCubeExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks.Graphics; 2 | using System.Numerics; 3 | using MoonWorks; 4 | using MoonWorks.Input; 5 | 6 | namespace MoonWorksGraphicsTests; 7 | 8 | class RenderTextureCubeExample : Example 9 | { 10 | private GraphicsPipeline pipeline; 11 | private Buffer vertexBuffer; 12 | private Buffer indexBuffer; 13 | private Texture cubemap; 14 | private Sampler sampler; 15 | 16 | private Vector3 camPos = new Vector3(0, 0, 4f); 17 | 18 | private Color[] colors = new Color[] 19 | { 20 | Color.Red, 21 | Color.Green, 22 | Color.Blue, 23 | Color.Orange, 24 | Color.Yellow, 25 | Color.Purple, 26 | }; 27 | 28 | public override void Init() 29 | { 30 | Window.SetTitle("RenderTextureCube"); 31 | 32 | Logger.LogInfo("Press Down to view the other side of the cubemap"); 33 | 34 | // Load the shaders 35 | Shader vertShader = ShaderCross.Create( 36 | GraphicsDevice, 37 | RootTitleStorage, 38 | TestUtils.GetHLSLPath("Skybox.vert"), 39 | "main", 40 | ShaderCross.ShaderFormat.HLSL, 41 | ShaderStage.Vertex 42 | ); 43 | 44 | Shader fragShader = ShaderCross.Create( 45 | GraphicsDevice, 46 | RootTitleStorage, 47 | TestUtils.GetHLSLPath("Skybox.frag"), 48 | "main", 49 | ShaderCross.ShaderFormat.HLSL, 50 | ShaderStage.Fragment 51 | ); 52 | 53 | // Create the graphics pipeline 54 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 55 | Window.SwapchainFormat, 56 | vertShader, 57 | fragShader 58 | ); 59 | pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); 60 | 61 | pipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 62 | 63 | // Create samplers 64 | sampler = Sampler.Create(GraphicsDevice, SamplerCreateInfo.PointClamp); 65 | 66 | // Create and populate the GPU resources 67 | var resourceUploader = new ResourceUploader(GraphicsDevice); 68 | 69 | vertexBuffer = resourceUploader.CreateBuffer( 70 | [ 71 | new PositionVertex(new Vector3(-10, -10, -10)), 72 | new PositionVertex(new Vector3(10, -10, -10)), 73 | new PositionVertex(new Vector3(10, 10, -10)), 74 | new PositionVertex(new Vector3(-10, 10, -10)), 75 | 76 | new PositionVertex(new Vector3(-10, -10, 10)), 77 | new PositionVertex(new Vector3(10, -10, 10)), 78 | new PositionVertex(new Vector3(10, 10, 10)), 79 | new PositionVertex(new Vector3(-10, 10, 10)), 80 | 81 | new PositionVertex(new Vector3(-10, -10, -10)), 82 | new PositionVertex(new Vector3(-10, 10, -10)), 83 | new PositionVertex(new Vector3(-10, 10, 10)), 84 | new PositionVertex(new Vector3(-10, -10, 10)), 85 | 86 | new PositionVertex(new Vector3(10, -10, -10)), 87 | new PositionVertex(new Vector3(10, 10, -10)), 88 | new PositionVertex(new Vector3(10, 10, 10)), 89 | new PositionVertex(new Vector3(10, -10, 10)), 90 | 91 | new PositionVertex(new Vector3(-10, -10, -10)), 92 | new PositionVertex(new Vector3(-10, -10, 10)), 93 | new PositionVertex(new Vector3(10, -10, 10)), 94 | new PositionVertex(new Vector3(10, -10, -10)), 95 | 96 | new PositionVertex(new Vector3(-10, 10, -10)), 97 | new PositionVertex(new Vector3(-10, 10, 10)), 98 | new PositionVertex(new Vector3(10, 10, 10)), 99 | new PositionVertex(new Vector3(10, 10, -10)) 100 | ], 101 | BufferUsageFlags.Vertex 102 | ); 103 | 104 | indexBuffer = resourceUploader.CreateBuffer( 105 | [ 106 | 0, 1, 2, 0, 2, 3, 107 | 6, 5, 4, 7, 6, 4, 108 | 8, 9, 10, 8, 10, 11, 109 | 14, 13, 12, 15, 14, 12, 110 | 16, 17, 18, 16, 18, 19, 111 | 22, 21, 20, 23, 22, 20 112 | ], 113 | BufferUsageFlags.Index 114 | ); 115 | 116 | resourceUploader.Upload(); 117 | resourceUploader.Dispose(); 118 | 119 | cubemap = Texture.CreateCube( 120 | GraphicsDevice, 121 | 16, 122 | TextureFormat.R8G8B8A8Unorm, 123 | TextureUsageFlags.ColorTarget | TextureUsageFlags.Sampler 124 | ); 125 | 126 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 127 | 128 | // Clear each slice of the cubemap to a different color 129 | for (uint i = 0; i < 6; i += 1) 130 | { 131 | var renderPass = cmdbuf.BeginRenderPass(new ColorTargetInfo 132 | { 133 | Texture = cubemap.Handle, 134 | LayerOrDepthPlane = i, 135 | LoadOp = LoadOp.Clear, 136 | ClearColor = colors[i], 137 | StoreOp = StoreOp.Store 138 | }); 139 | cmdbuf.EndRenderPass(renderPass); 140 | } 141 | 142 | GraphicsDevice.Submit(cmdbuf); 143 | } 144 | 145 | public override void Update(System.TimeSpan delta) 146 | { 147 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Bottom)) 148 | { 149 | camPos.Z *= -1; 150 | } 151 | } 152 | 153 | public override void Draw(double alpha) 154 | { 155 | Matrix4x4 proj = Matrix4x4.CreatePerspectiveFieldOfView( 156 | float.DegreesToRadians(75f), 157 | (float) Window.Width / Window.Height, 158 | 0.01f, 159 | 100f 160 | ); 161 | Matrix4x4 view = Matrix4x4.CreateLookAt( 162 | camPos, 163 | Vector3.Zero, 164 | Vector3.UnitY 165 | ); 166 | TransformVertexUniform vertUniforms = new TransformVertexUniform(view * proj); 167 | 168 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 169 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 170 | if (swapchainTexture != null) 171 | { 172 | var renderPass = cmdbuf.BeginRenderPass( 173 | new ColorTargetInfo(swapchainTexture, Color.Black) 174 | ); 175 | renderPass.BindGraphicsPipeline(pipeline); 176 | renderPass.BindVertexBuffers(vertexBuffer); 177 | renderPass.BindIndexBuffer(indexBuffer, IndexElementSize.Sixteen); 178 | renderPass.BindFragmentSamplers(new TextureSamplerBinding(cubemap, sampler)); 179 | cmdbuf.PushVertexUniformData(vertUniforms); 180 | renderPass.DrawIndexedPrimitives(36, 1, 0, 0, 0); 181 | cmdbuf.EndRenderPass(renderPass); 182 | } 183 | GraphicsDevice.Submit(cmdbuf); 184 | } 185 | 186 | public override void Destroy() 187 | { 188 | 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /Examples/RenderTextureMipmapsExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using MoonWorks.Graphics; 3 | using MoonWorks.Input; 4 | using System.Numerics; 5 | 6 | namespace MoonWorksGraphicsTests; 7 | 8 | class RenderTextureMipmapsExample : Example 9 | { 10 | private GraphicsPipeline Pipeline; 11 | private Buffer VertexBuffer; 12 | private Buffer IndexBuffer; 13 | private Texture Texture; 14 | 15 | private Sampler[] Samplers = new Sampler[5]; 16 | 17 | private float scale = 0.5f; 18 | private int currentSamplerIndex = 0; 19 | private Color[] colors = 20 | [ 21 | Color.Red, 22 | Color.Green, 23 | Color.Blue, 24 | Color.Yellow, 25 | ]; 26 | 27 | private string GetSamplerString(int index) 28 | { 29 | switch (index) 30 | { 31 | case 0: 32 | return "PointClamp"; 33 | case 1: 34 | return "LinearClamp"; 35 | case 2: 36 | return "PointClamp with Mip LOD Bias = 0.25"; 37 | case 3: 38 | return "PointClamp with Min LOD = 1"; 39 | case 4: 40 | return "PointClamp with Max LOD = 1"; 41 | default: 42 | throw new System.Exception("Unknown sampler!"); 43 | } 44 | } 45 | 46 | public override void Init() 47 | { 48 | Window.SetTitle("RenderTextureMipmaps"); 49 | 50 | Logger.LogInfo("Press Left and Right to shrink/expand the scale of the quad"); 51 | Logger.LogInfo("Press Down to cycle through sampler states"); 52 | Logger.LogInfo(GetSamplerString(currentSamplerIndex)); 53 | 54 | // Load the shaders 55 | Shader vertShaderModule = ShaderCross.Create( 56 | GraphicsDevice, 57 | RootTitleStorage, 58 | TestUtils.GetHLSLPath("TexturedQuadWithMatrix.vert"), 59 | "main", 60 | ShaderCross.ShaderFormat.HLSL, 61 | ShaderStage.Vertex 62 | ); 63 | 64 | Shader fragShaderModule = ShaderCross.Create( 65 | GraphicsDevice, 66 | RootTitleStorage, 67 | TestUtils.GetHLSLPath("TexturedQuad.frag"), 68 | "main", 69 | ShaderCross.ShaderFormat.HLSL, 70 | ShaderStage.Fragment 71 | ); 72 | 73 | // Create the graphics pipeline 74 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 75 | Window.SwapchainFormat, 76 | vertShaderModule, 77 | fragShaderModule 78 | ); 79 | pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); 80 | 81 | Pipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 82 | 83 | // Create samplers 84 | SamplerCreateInfo samplerCreateInfo = SamplerCreateInfo.PointClamp; 85 | Samplers[0] = Sampler.Create(GraphicsDevice, samplerCreateInfo); 86 | 87 | samplerCreateInfo = SamplerCreateInfo.LinearClamp; 88 | Samplers[1] = Sampler.Create(GraphicsDevice, samplerCreateInfo); 89 | 90 | samplerCreateInfo = SamplerCreateInfo.PointClamp; 91 | samplerCreateInfo.MipLodBias = 0.25f; 92 | Samplers[2] = Sampler.Create(GraphicsDevice, samplerCreateInfo); 93 | 94 | samplerCreateInfo = SamplerCreateInfo.PointClamp; 95 | samplerCreateInfo.MinLod = 1; 96 | Samplers[3] = Sampler.Create(GraphicsDevice, samplerCreateInfo); 97 | 98 | samplerCreateInfo = SamplerCreateInfo.PointClamp; 99 | samplerCreateInfo.MaxLod = 1; 100 | Samplers[4] = Sampler.Create(GraphicsDevice, samplerCreateInfo); 101 | 102 | // Create and populate the GPU resources 103 | var resourceUploader = new ResourceUploader(GraphicsDevice); 104 | 105 | VertexBuffer = resourceUploader.CreateBuffer( 106 | [ 107 | new PositionTextureVertex(new Vector3(-1, -1, 0), new Vector2(0, 0)), 108 | new PositionTextureVertex(new Vector3(1, -1, 0), new Vector2(1, 0)), 109 | new PositionTextureVertex(new Vector3(1, 1, 0), new Vector2(1, 1)), 110 | new PositionTextureVertex(new Vector3(-1, 1, 0), new Vector2(0, 1)), 111 | ], 112 | BufferUsageFlags.Vertex 113 | ); 114 | 115 | IndexBuffer = resourceUploader.CreateBuffer( 116 | [ 117 | 0, 1, 2, 118 | 0, 2, 3, 119 | ], 120 | BufferUsageFlags.Index 121 | ); 122 | 123 | resourceUploader.Upload(); 124 | resourceUploader.Dispose(); 125 | 126 | Texture = Texture.Create2D( 127 | GraphicsDevice, 128 | Window.Width, 129 | Window.Height, 130 | TextureFormat.R8G8B8A8Unorm, 131 | TextureUsageFlags.ColorTarget | TextureUsageFlags.Sampler, 132 | 4 133 | ); 134 | 135 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 136 | 137 | // Clear each mip level to a different color 138 | for (uint i = 0; i < Texture.LevelCount; i += 1) 139 | { 140 | var renderPass = cmdbuf.BeginRenderPass(new ColorTargetInfo 141 | { 142 | Texture = Texture.Handle, 143 | MipLevel = i, 144 | LoadOp = LoadOp.Clear, 145 | ClearColor = colors[i], 146 | StoreOp = StoreOp.Store 147 | }); 148 | cmdbuf.EndRenderPass(renderPass); 149 | } 150 | 151 | GraphicsDevice.Submit(cmdbuf); 152 | } 153 | 154 | public override void Update(System.TimeSpan delta) 155 | { 156 | if (TestUtils.CheckButtonDown(Inputs, TestUtils.ButtonType.Left)) 157 | { 158 | scale = System.MathF.Max(0.01f, scale - 0.01f); 159 | } 160 | 161 | if (TestUtils.CheckButtonDown(Inputs, TestUtils.ButtonType.Right)) 162 | { 163 | scale = System.MathF.Min(1f, scale + 0.01f); 164 | } 165 | 166 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Bottom)) 167 | { 168 | currentSamplerIndex = (currentSamplerIndex + 1) % Samplers.Length; 169 | Logger.LogInfo(GetSamplerString(currentSamplerIndex)); 170 | } 171 | } 172 | 173 | public override void Draw(double alpha) 174 | { 175 | TransformVertexUniform vertUniforms = new TransformVertexUniform(Matrix4x4.CreateScale(scale, scale, 1)); 176 | 177 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 178 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 179 | if (swapchainTexture != null) 180 | { 181 | var renderPass = cmdbuf.BeginRenderPass( 182 | new ColorTargetInfo(swapchainTexture, Color.Black) 183 | ); 184 | renderPass.BindGraphicsPipeline(Pipeline); 185 | renderPass.BindVertexBuffers(VertexBuffer); 186 | renderPass.BindIndexBuffer(IndexBuffer, IndexElementSize.Sixteen); 187 | renderPass.BindFragmentSamplers(new TextureSamplerBinding(Texture, Samplers[currentSamplerIndex])); 188 | cmdbuf.PushVertexUniformData(vertUniforms); 189 | renderPass.DrawIndexedPrimitives(6, 1, 0, 0, 0); 190 | cmdbuf.EndRenderPass(renderPass); 191 | } 192 | 193 | GraphicsDevice.Submit(cmdbuf); 194 | } 195 | 196 | public override void Destroy() 197 | { 198 | Pipeline.Dispose(); 199 | VertexBuffer.Dispose(); 200 | IndexBuffer.Dispose(); 201 | Texture.Dispose(); 202 | 203 | for (var i = 0; i < 5; i += 1) 204 | { 205 | Samplers[i].Dispose(); 206 | } 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /Examples/PullSpriteBatchExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using MoonWorks; 4 | using MoonWorks.Graphics; 5 | using MoonWorks.Input; 6 | using System.Numerics; 7 | using Buffer = MoonWorks.Graphics.Buffer; 8 | 9 | namespace MoonWorksGraphicsTests; 10 | 11 | class PullSpriteBatchExample : Example 12 | { 13 | GraphicsPipeline RenderPipeline; 14 | Sampler Sampler; 15 | Texture SpriteAtlasTexture; 16 | TransferBuffer SpriteDataTransferBuffer; 17 | Buffer SpriteDataBuffer; 18 | 19 | const int MAX_SPRITE_COUNT = 8192; 20 | 21 | Random Random = new Random(); 22 | 23 | [StructLayout(LayoutKind.Explicit, Size = 64)] 24 | struct SpriteInstance 25 | { 26 | [FieldOffset(0)] 27 | public Vector3 Position; 28 | 29 | [FieldOffset(12)] 30 | public float Rotation; 31 | 32 | [FieldOffset(16)] 33 | public Vector2 Size; 34 | 35 | [FieldOffset(24)] 36 | public Vector2 Padding; 37 | 38 | [FieldOffset(32)] 39 | public float TexU; 40 | 41 | [FieldOffset(36)] 42 | public float TexV; 43 | 44 | [FieldOffset(40)] 45 | public float TexW; 46 | 47 | [FieldOffset(44)] 48 | public float TexH; 49 | 50 | [FieldOffset(48)] 51 | public Vector4 Color; 52 | } 53 | 54 | public override unsafe void Init() 55 | { 56 | Window.SetTitle("PullSpriteBatch"); 57 | 58 | Shader vertShader = ShaderCross.Create( 59 | GraphicsDevice, 60 | RootTitleStorage, 61 | TestUtils.GetHLSLPath("PullSpriteBatch.vert"), 62 | "main", 63 | ShaderCross.ShaderFormat.HLSL, 64 | ShaderStage.Vertex 65 | ); 66 | 67 | Shader fragShader = ShaderCross.Create( 68 | GraphicsDevice, 69 | RootTitleStorage, 70 | TestUtils.GetHLSLPath("TexturedQuadColor.frag"), 71 | "main", 72 | ShaderCross.ShaderFormat.HLSL, 73 | ShaderStage.Fragment 74 | ); 75 | 76 | var renderPipelineCreateInfo = new GraphicsPipelineCreateInfo 77 | { 78 | TargetInfo = new GraphicsPipelineTargetInfo 79 | { 80 | ColorTargetDescriptions = [ 81 | new ColorTargetDescription 82 | { 83 | Format = Window.SwapchainFormat, 84 | BlendState = ColorTargetBlendState.NonPremultipliedAlphaBlend 85 | } 86 | ] 87 | }, 88 | DepthStencilState = DepthStencilState.Disable, 89 | MultisampleState = MultisampleState.None, 90 | PrimitiveType = PrimitiveType.TriangleList, 91 | RasterizerState = RasterizerState.CCW_CullNone, 92 | VertexInputState = VertexInputState.Empty, 93 | VertexShader = vertShader, 94 | FragmentShader = fragShader 95 | }; 96 | 97 | RenderPipeline = GraphicsPipeline.Create(GraphicsDevice, renderPipelineCreateInfo); 98 | 99 | Sampler = Sampler.Create(GraphicsDevice, SamplerCreateInfo.PointClamp); 100 | 101 | var resourceUploader = new ResourceUploader(GraphicsDevice); 102 | 103 | SpriteAtlasTexture = resourceUploader.CreateTexture2DFromCompressed( 104 | RootTitleStorage, 105 | TestUtils.GetTexturePath("ravioli_atlas.png"), 106 | TextureFormat.R8G8B8A8Unorm, 107 | TextureUsageFlags.Sampler 108 | ); 109 | 110 | resourceUploader.Upload(); 111 | resourceUploader.Dispose(); 112 | 113 | SpriteDataTransferBuffer = TransferBuffer.Create( 114 | GraphicsDevice, 115 | TransferBufferUsage.Upload, 116 | MAX_SPRITE_COUNT 117 | ); 118 | 119 | SpriteDataBuffer = Buffer.Create( 120 | GraphicsDevice, 121 | BufferUsageFlags.GraphicsStorageRead, 122 | MAX_SPRITE_COUNT 123 | ); 124 | } 125 | 126 | public override void Update(TimeSpan delta) 127 | { 128 | 129 | } 130 | 131 | public override unsafe void Draw(double alpha) 132 | { 133 | Matrix4x4 cameraMatrix = 134 | Matrix4x4.CreateOrthographicOffCenter( 135 | 0, 136 | 640, 137 | 480, 138 | 0, 139 | 0, 140 | -1f 141 | ); 142 | 143 | float[] uCoords = [ 0.0f, 0.5f, 0.0f, 0.5f ]; 144 | float[] vCoords = [ 0.0f, 0.0f, 0.5f, 0.5f ]; 145 | 146 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 147 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 148 | if (swapchainTexture != null) 149 | { 150 | // Build sprite data transfer 151 | var data = SpriteDataTransferBuffer.Map(true); 152 | for (var i = 0; i < MAX_SPRITE_COUNT; i += 1) 153 | { 154 | int ravioli = Random.Next(4); 155 | data[i].Position = new Vector3(Random.Next(640), Random.Next(480), 0); 156 | data[i].Rotation = 0; 157 | data[i].Size = new Vector2(32, 32); 158 | data[i].TexU = uCoords[ravioli]; 159 | data[i].TexV = vCoords[ravioli]; 160 | data[i].TexW = 0.5f; 161 | data[i].TexH = 0.5f; 162 | data[i].Color = new Vector4(1f, 1f, 1f, 1f); 163 | } 164 | SpriteDataTransferBuffer.Unmap(); 165 | 166 | // Upload sprite data to buffer 167 | var copyPass = cmdbuf.BeginCopyPass(); 168 | copyPass.UploadToBuffer(SpriteDataTransferBuffer, SpriteDataBuffer, true); 169 | cmdbuf.EndCopyPass(copyPass); 170 | 171 | var renderPass = cmdbuf.BeginRenderPass( 172 | new ColorTargetInfo(swapchainTexture, Color.Black) 173 | ); 174 | 175 | cmdbuf.PushVertexUniformData(cameraMatrix); 176 | 177 | renderPass.BindGraphicsPipeline(RenderPipeline); 178 | renderPass.BindFragmentSamplers(new TextureSamplerBinding(SpriteAtlasTexture, Sampler)); 179 | renderPass.BindVertexStorageBuffers(SpriteDataBuffer); 180 | renderPass.DrawPrimitives(MAX_SPRITE_COUNT * 6, 1, 0, 0); 181 | 182 | cmdbuf.EndRenderPass(renderPass); 183 | } 184 | 185 | GraphicsDevice.Submit(cmdbuf); 186 | } 187 | 188 | public override void Destroy() 189 | { 190 | RenderPipeline.Dispose(); 191 | Sampler.Dispose(); 192 | SpriteAtlasTexture.Dispose(); 193 | SpriteDataTransferBuffer.Dispose(); 194 | SpriteDataBuffer.Dispose(); 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /Examples/ComputeSpriteBatchExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using MoonWorks; 4 | using MoonWorks.Graphics; 5 | using MoonWorks.Input; 6 | using System.Numerics; 7 | using Buffer = MoonWorks.Graphics.Buffer; 8 | 9 | namespace MoonWorksGraphicsTests; 10 | 11 | /* 12 | * This example builds the sprite batch using a compute shader. 13 | * Compare with CPUSpriteBatchExample. 14 | * This example should be MUCH faster. 15 | * 16 | * For speed comparisons, make sure to set the framerate to Uncapped 17 | * and present mode to Immediate. 18 | */ 19 | class ComputeSpriteBatchExample : Example 20 | { 21 | ComputePipeline ComputePipeline; 22 | GraphicsPipeline RenderPipeline; 23 | Sampler Sampler; 24 | Texture SpriteTexture; 25 | TransferBuffer SpriteComputeTransferBuffer; 26 | Buffer SpriteComputeBuffer; 27 | Buffer SpriteVertexBuffer; 28 | Buffer SpriteIndexBuffer; 29 | 30 | const int MAX_SPRITE_COUNT = 8192; 31 | 32 | Random Random = new Random(); 33 | 34 | [StructLayout(LayoutKind.Explicit, Size = 48)] 35 | struct ComputeSpriteData 36 | { 37 | [FieldOffset(0)] 38 | public Vector3 Position; 39 | 40 | [FieldOffset(12)] 41 | public float Rotation; 42 | 43 | [FieldOffset(16)] 44 | public Vector2 Size; 45 | 46 | [FieldOffset(32)] 47 | public Vector4 Color; 48 | } 49 | 50 | public override unsafe void Init() 51 | { 52 | Window.SetTitle("ComputeSpriteBatch"); 53 | 54 | Shader vertShader = ShaderCross.Create( 55 | GraphicsDevice, 56 | RootTitleStorage, 57 | TestUtils.GetHLSLPath("TexturedQuadColorWithMatrix.vert"), 58 | "main", 59 | ShaderCross.ShaderFormat.HLSL, 60 | ShaderStage.Vertex 61 | ); 62 | 63 | Shader fragShader = ShaderCross.Create( 64 | GraphicsDevice, 65 | RootTitleStorage, 66 | TestUtils.GetHLSLPath("TexturedQuadColor.frag"), 67 | "main", 68 | ShaderCross.ShaderFormat.HLSL, 69 | ShaderStage.Fragment 70 | ); 71 | 72 | GraphicsPipelineCreateInfo renderPipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 73 | Window.SwapchainFormat, 74 | vertShader, 75 | fragShader 76 | ); 77 | renderPipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); 78 | 79 | RenderPipeline = GraphicsPipeline.Create(GraphicsDevice, renderPipelineCreateInfo); 80 | 81 | ComputePipeline = ShaderCross.Create( 82 | GraphicsDevice, 83 | RootTitleStorage, 84 | TestUtils.GetHLSLPath("SpriteBatch.comp"), 85 | "main", 86 | ShaderCross.ShaderFormat.HLSL 87 | ); 88 | 89 | Sampler = Sampler.Create(GraphicsDevice, SamplerCreateInfo.PointClamp); 90 | 91 | // Create and populate the sprite texture 92 | var resourceUploader = new ResourceUploader(GraphicsDevice); 93 | 94 | SpriteTexture = resourceUploader.CreateTexture2DFromCompressed( 95 | RootTitleStorage, 96 | TestUtils.GetTexturePath("ravioli.png"), 97 | TextureFormat.R8G8B8A8Unorm, 98 | TextureUsageFlags.Sampler 99 | ); 100 | 101 | resourceUploader.Upload(); 102 | resourceUploader.Dispose(); 103 | 104 | SpriteComputeTransferBuffer = TransferBuffer.Create( 105 | GraphicsDevice, 106 | TransferBufferUsage.Upload, 107 | MAX_SPRITE_COUNT 108 | ); 109 | 110 | SpriteComputeBuffer = Buffer.Create( 111 | GraphicsDevice, 112 | BufferUsageFlags.ComputeStorageRead, 113 | MAX_SPRITE_COUNT 114 | ); 115 | 116 | SpriteVertexBuffer = Buffer.Create( 117 | GraphicsDevice, 118 | BufferUsageFlags.ComputeStorageWrite | BufferUsageFlags.Vertex, 119 | MAX_SPRITE_COUNT * 4 120 | ); 121 | 122 | SpriteIndexBuffer = Buffer.Create( 123 | GraphicsDevice, 124 | BufferUsageFlags.Index, 125 | MAX_SPRITE_COUNT * 6 126 | ); 127 | 128 | TransferBuffer spriteIndexTransferBuffer = TransferBuffer.Create( 129 | GraphicsDevice, 130 | TransferBufferUsage.Upload, 131 | MAX_SPRITE_COUNT * 6 132 | ); 133 | 134 | var indexSpan = spriteIndexTransferBuffer.Map(false); 135 | 136 | for (int i = 0, j = 0; i < MAX_SPRITE_COUNT * 6; i += 6, j += 4) 137 | { 138 | indexSpan[i] = (uint) j; 139 | indexSpan[i + 1] = (uint) j + 1; 140 | indexSpan[i + 2] = (uint) j + 2; 141 | indexSpan[i + 3] = (uint) j + 3; 142 | indexSpan[i + 4] = (uint) j + 2; 143 | indexSpan[i + 5] = (uint) j + 1; 144 | } 145 | spriteIndexTransferBuffer.Unmap(); 146 | 147 | var cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 148 | var copyPass = cmdbuf.BeginCopyPass(); 149 | copyPass.UploadToBuffer(spriteIndexTransferBuffer, SpriteIndexBuffer, false); 150 | cmdbuf.EndCopyPass(copyPass); 151 | GraphicsDevice.Submit(cmdbuf); 152 | } 153 | 154 | public override void Update(TimeSpan delta) 155 | { 156 | 157 | } 158 | 159 | public override unsafe void Draw(double alpha) 160 | { 161 | Matrix4x4 cameraMatrix = 162 | Matrix4x4.CreateOrthographicOffCenter( 163 | 0, 164 | 640, 165 | 480, 166 | 0, 167 | 0, 168 | -1f 169 | ); 170 | 171 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 172 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 173 | if (swapchainTexture != null) 174 | { 175 | // Build sprite compute transfer 176 | var data = SpriteComputeTransferBuffer.Map(true); 177 | for (var i = 0; i < MAX_SPRITE_COUNT; i += 1) 178 | { 179 | data[i].Position = new Vector3(Random.Next(640), Random.Next(480), 0); 180 | data[i].Rotation = (float) (Random.NextDouble() * System.Math.PI * 2); 181 | data[i].Size = new Vector2(32, 32); 182 | data[i].Color = new Vector4(1f, 1f, 1f, 1f); 183 | } 184 | SpriteComputeTransferBuffer.Unmap(); 185 | 186 | // Upload compute data to buffer 187 | var copyPass = cmdbuf.BeginCopyPass(); 188 | copyPass.UploadToBuffer(SpriteComputeTransferBuffer, SpriteComputeBuffer, true); 189 | cmdbuf.EndCopyPass(copyPass); 190 | 191 | // Set up compute pass to build sprite vertex buffer 192 | var computePass = cmdbuf.BeginComputePass( 193 | new StorageBufferReadWriteBinding(SpriteVertexBuffer, true) 194 | ); 195 | 196 | computePass.BindComputePipeline(ComputePipeline); 197 | computePass.BindStorageBuffers(SpriteComputeBuffer); 198 | computePass.Dispatch(MAX_SPRITE_COUNT / 64, 1, 1); 199 | 200 | cmdbuf.EndComputePass(computePass); 201 | 202 | // Render sprites using vertex buffer 203 | var renderPass = cmdbuf.BeginRenderPass( 204 | new ColorTargetInfo(swapchainTexture, Color.Black) 205 | ); 206 | 207 | cmdbuf.PushVertexUniformData(cameraMatrix); 208 | 209 | renderPass.BindGraphicsPipeline(RenderPipeline); 210 | renderPass.BindVertexBuffers(SpriteVertexBuffer); 211 | renderPass.BindIndexBuffer(SpriteIndexBuffer, IndexElementSize.ThirtyTwo); 212 | renderPass.BindFragmentSamplers(new TextureSamplerBinding(SpriteTexture, Sampler)); 213 | renderPass.DrawIndexedPrimitives(MAX_SPRITE_COUNT * 6, 1, 0, 0, 0); 214 | 215 | cmdbuf.EndRenderPass(renderPass); 216 | } 217 | 218 | GraphicsDevice.Submit(cmdbuf); 219 | } 220 | 221 | public override void Destroy() 222 | { 223 | ComputePipeline.Dispose(); 224 | RenderPipeline.Dispose(); 225 | Sampler.Dispose(); 226 | SpriteTexture.Dispose(); 227 | SpriteComputeTransferBuffer.Dispose(); 228 | SpriteComputeBuffer.Dispose(); 229 | SpriteVertexBuffer.Dispose(); 230 | SpriteIndexBuffer.Dispose(); 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /Examples/TexturedQuadExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MoonWorks; 3 | using MoonWorks.Graphics; 4 | using System.Numerics; 5 | using Buffer = MoonWorks.Graphics.Buffer; 6 | using System.Runtime.InteropServices; 7 | 8 | namespace MoonWorksGraphicsTests; 9 | 10 | class TexturedQuadExample : Example 11 | { 12 | private GraphicsPipeline pipeline; 13 | private Buffer vertexBuffer; 14 | private Buffer indexBuffer; 15 | private Sampler[] samplers = new Sampler[6]; 16 | private string[] samplerNames = 17 | [ 18 | "PointClamp", 19 | "PointWrap", 20 | "LinearClamp", 21 | "LinearWrap", 22 | "AnisotropicClamp", 23 | "AnisotropicWrap" 24 | ]; 25 | 26 | private int currentSamplerIndex; 27 | 28 | private Texture[] textures = new Texture[4]; 29 | private string[] imageLoadFormatNames = 30 | [ 31 | "PNG from file", 32 | "PNG from memory", 33 | "QOI from file", 34 | "QOI from memory" 35 | ]; 36 | 37 | private int currentTextureIndex; 38 | 39 | private System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); 40 | 41 | public override unsafe void Init() 42 | { 43 | Window.SetTitle("TexturedQuad"); 44 | 45 | Logger.LogInfo("Press Left and Right to cycle between sampler states"); 46 | Logger.LogInfo("Setting sampler state to: " + samplerNames[0]); 47 | 48 | Logger.LogInfo("Press Down to cycle between image load formats"); 49 | Logger.LogInfo("Setting image format to: " + imageLoadFormatNames[0]); 50 | 51 | var pngPath = TestUtils.GetTexturePath("ravioli.png"); 52 | var qoiPath = TestUtils.GetTexturePath("ravioli.qoi"); 53 | 54 | RootTitleStorage.GetFileSize(pngPath, out var pngSize); 55 | RootTitleStorage.GetFileSize(qoiPath, out var qoiSize); 56 | 57 | var pngBytes = NativeMemory.Alloc((nuint) pngSize); 58 | var pngSpan = new Span(pngBytes, (int) pngSize); 59 | 60 | var qoiBytes = NativeMemory.Alloc((nuint) qoiSize); 61 | var qoiSpan = new Span(qoiBytes, (int) qoiSize); 62 | 63 | RootTitleStorage.ReadFile(pngPath, pngSpan); 64 | RootTitleStorage.ReadFile(qoiPath, qoiSpan); 65 | 66 | Logger.LogInfo(pngSpan.Length.ToString()); 67 | Logger.LogInfo(qoiSpan.Length.ToString()); 68 | 69 | // Load the shaders 70 | Shader vertShader = ShaderCross.Create( 71 | GraphicsDevice, 72 | RootTitleStorage, 73 | TestUtils.GetHLSLPath("TexturedQuad.vert"), 74 | "main", 75 | ShaderCross.ShaderFormat.HLSL, 76 | ShaderStage.Vertex 77 | ); 78 | 79 | Shader fragShader = ShaderCross.Create( 80 | GraphicsDevice, 81 | RootTitleStorage, 82 | TestUtils.GetHLSLPath("TexturedQuad.frag"), 83 | "main", 84 | ShaderCross.ShaderFormat.HLSL, 85 | ShaderStage.Fragment 86 | ); 87 | 88 | // Create the graphics pipeline 89 | GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 90 | Window.SwapchainFormat, 91 | vertShader, 92 | fragShader 93 | ); 94 | pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); 95 | 96 | pipeline = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 97 | 98 | // Create samplers 99 | samplers[0] = Sampler.Create(GraphicsDevice, SamplerCreateInfo.PointClamp); 100 | samplers[1] = Sampler.Create(GraphicsDevice, SamplerCreateInfo.PointWrap); 101 | samplers[2] = Sampler.Create(GraphicsDevice, SamplerCreateInfo.LinearClamp); 102 | samplers[3] = Sampler.Create(GraphicsDevice, SamplerCreateInfo.LinearWrap); 103 | samplers[4] = Sampler.Create(GraphicsDevice, SamplerCreateInfo.AnisotropicClamp); 104 | samplers[5] = Sampler.Create(GraphicsDevice, SamplerCreateInfo.AnisotropicWrap); 105 | 106 | ReadOnlySpan vertexData = [ 107 | new PositionTextureVertex(new Vector3(-1, 1, 0), new Vector2(0, 0)), 108 | new PositionTextureVertex(new Vector3( 1, 1, 0), new Vector2(4, 0)), 109 | new PositionTextureVertex(new Vector3( 1, -1, 0), new Vector2(4, 4)), 110 | new PositionTextureVertex(new Vector3(-1, -1, 0), new Vector2(0, 4)), 111 | ]; 112 | 113 | ReadOnlySpan indexData = [ 114 | 0, 1, 2, 115 | 0, 2, 3, 116 | ]; 117 | 118 | // Create and populate the GPU resources 119 | 120 | var resourceUploader = new ResourceUploader(GraphicsDevice); 121 | 122 | vertexBuffer = resourceUploader.CreateBuffer(vertexData, BufferUsageFlags.Vertex); 123 | indexBuffer = resourceUploader.CreateBuffer(indexData, BufferUsageFlags.Index); 124 | 125 | textures[0] = resourceUploader.CreateTexture2DFromCompressed(RootTitleStorage, TestUtils.GetTexturePath("ravioli.png"), TextureFormat.R8G8B8A8Unorm, TextureUsageFlags.Sampler); 126 | textures[1] = resourceUploader.CreateTexture2DFromCompressed(pngSpan, TextureFormat.R8G8B8A8Unorm, TextureUsageFlags.Sampler); 127 | textures[2] = resourceUploader.CreateTexture2DFromCompressed(RootTitleStorage, TestUtils.GetTexturePath("ravioli.qoi"), TextureFormat.R8G8B8A8Unorm, TextureUsageFlags.Sampler); 128 | textures[3] = resourceUploader.CreateTexture2DFromCompressed(qoiSpan, TextureFormat.R8G8B8A8Unorm, TextureUsageFlags.Sampler); 129 | 130 | resourceUploader.Upload(); 131 | resourceUploader.Dispose(); 132 | 133 | NativeMemory.Free(pngBytes); 134 | NativeMemory.Free(qoiBytes); 135 | } 136 | 137 | public override void Update(System.TimeSpan delta) 138 | { 139 | int prevSamplerIndex = currentSamplerIndex; 140 | 141 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Left)) 142 | { 143 | currentSamplerIndex -= 1; 144 | if (currentSamplerIndex < 0) 145 | { 146 | currentSamplerIndex = samplers.Length - 1; 147 | } 148 | } 149 | 150 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Right)) 151 | { 152 | currentSamplerIndex += 1; 153 | if (currentSamplerIndex >= samplers.Length) 154 | { 155 | currentSamplerIndex = 0; 156 | } 157 | } 158 | 159 | if (prevSamplerIndex != currentSamplerIndex) 160 | { 161 | Logger.LogInfo("Setting sampler state to: " + samplerNames[currentSamplerIndex]); 162 | } 163 | 164 | int prevTextureIndex = currentTextureIndex; 165 | 166 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Bottom)) 167 | { 168 | currentTextureIndex = (currentTextureIndex + 1) % imageLoadFormatNames.Length; 169 | } 170 | 171 | if (prevTextureIndex != currentTextureIndex) 172 | { 173 | Logger.LogInfo("Setting texture format to: " + imageLoadFormatNames[currentTextureIndex]); 174 | } 175 | } 176 | 177 | public override void Draw(double alpha) 178 | { 179 | var cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 180 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 181 | if (swapchainTexture != null) 182 | { 183 | var renderPass = cmdbuf.BeginRenderPass( 184 | new ColorTargetInfo(swapchainTexture, Color.Black) 185 | ); 186 | renderPass.BindGraphicsPipeline(pipeline); 187 | renderPass.BindVertexBuffers(vertexBuffer); 188 | renderPass.BindIndexBuffer(indexBuffer, IndexElementSize.Sixteen); 189 | renderPass.BindFragmentSamplers(new TextureSamplerBinding(textures[currentTextureIndex], samplers[currentSamplerIndex])); 190 | renderPass.DrawIndexedPrimitives(6, 1, 0, 0, 0); 191 | cmdbuf.EndRenderPass(renderPass); 192 | } 193 | GraphicsDevice.Submit(cmdbuf); 194 | } 195 | 196 | public override void Destroy() 197 | { 198 | pipeline.Dispose(); 199 | vertexBuffer.Dispose(); 200 | indexBuffer.Dispose(); 201 | 202 | for (var i = 0; i < samplers.Length; i += 1) 203 | { 204 | samplers[i].Dispose(); 205 | } 206 | 207 | for (var i = 0; i < textures.Length; i += 1) 208 | { 209 | textures[i].Dispose(); 210 | } 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /Examples/CPUSpriteBatchExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MoonWorks; 3 | using MoonWorks.Graphics; 4 | using MoonWorks.Input; 5 | using System.Numerics; 6 | using Buffer = MoonWorks.Graphics.Buffer; 7 | 8 | namespace MoonWorksGraphicsTests; 9 | 10 | /* 11 | * This example builds the sprite batch on the CPU. 12 | * Compare with ComputeSpriteBatchExample. 13 | * This example should be MUCH slower. 14 | * 15 | * For speed comparisons, make sure to set the framerate to Uncapped 16 | * and present mode to Immediate. 17 | */ 18 | class CPUSpriteBatchExample : Example 19 | { 20 | GraphicsPipeline RenderPipeline; 21 | Sampler Sampler; 22 | Texture SpriteTexture; 23 | TransferBuffer SpriteVertexTransferBuffer; 24 | Buffer SpriteVertexBuffer; 25 | Buffer SpriteIndexBuffer; 26 | 27 | const int SPRITE_COUNT = 8192; 28 | 29 | struct SpriteInstanceData 30 | { 31 | public Vector3 Position; 32 | public float Rotation; 33 | public Vector2 Size; 34 | public Vector4 Color; 35 | } 36 | 37 | SpriteInstanceData[] InstanceData = new SpriteInstanceData[SPRITE_COUNT]; 38 | 39 | Random Random = new Random(); 40 | 41 | public override unsafe void Init() 42 | { 43 | Window.SetTitle("CPUSpriteBatch"); 44 | 45 | Shader vertShader = ShaderCross.Create( 46 | GraphicsDevice, 47 | RootTitleStorage, 48 | TestUtils.GetHLSLPath("TexturedQuadColorWithMatrix.vert"), 49 | "main", 50 | ShaderCross.ShaderFormat.HLSL, 51 | ShaderStage.Vertex 52 | ); 53 | 54 | Shader fragShader = ShaderCross.Create( 55 | GraphicsDevice, 56 | RootTitleStorage, 57 | TestUtils.GetHLSLPath("TexturedQuadColor.frag"), 58 | "main", 59 | ShaderCross.ShaderFormat.HLSL, 60 | ShaderStage.Fragment 61 | ); 62 | 63 | GraphicsPipelineCreateInfo renderPipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( 64 | Window.SwapchainFormat, 65 | vertShader, 66 | fragShader 67 | ); 68 | renderPipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); 69 | 70 | RenderPipeline = GraphicsPipeline.Create(GraphicsDevice, renderPipelineCreateInfo); 71 | 72 | Sampler = Sampler.Create(GraphicsDevice, SamplerCreateInfo.PointClamp); 73 | 74 | // Create and populate the sprite texture 75 | var resourceUploader = new ResourceUploader(GraphicsDevice); 76 | 77 | SpriteTexture = resourceUploader.CreateTexture2DFromCompressed( 78 | RootTitleStorage, 79 | TestUtils.GetTexturePath("ravioli.png"), 80 | TextureFormat.R8G8B8A8Unorm, 81 | TextureUsageFlags.Sampler 82 | ); 83 | 84 | resourceUploader.Upload(); 85 | resourceUploader.Dispose(); 86 | 87 | SpriteVertexBuffer = Buffer.Create( 88 | GraphicsDevice, 89 | BufferUsageFlags.Vertex, 90 | SPRITE_COUNT * 4 91 | ); 92 | 93 | SpriteIndexBuffer = Buffer.Create( 94 | GraphicsDevice, 95 | BufferUsageFlags.Index, 96 | SPRITE_COUNT * 6 97 | ); 98 | 99 | SpriteVertexTransferBuffer = TransferBuffer.Create( 100 | GraphicsDevice, 101 | TransferBufferUsage.Upload, 102 | SPRITE_COUNT * 4 103 | ); 104 | 105 | TransferBuffer spriteIndexTransferBuffer = TransferBuffer.Create( 106 | GraphicsDevice, 107 | TransferBufferUsage.Upload, 108 | SPRITE_COUNT * 6 109 | ); 110 | 111 | var indexSpan = spriteIndexTransferBuffer.Map(false); 112 | for (int i = 0, j = 0; i < SPRITE_COUNT * 6; i += 6, j += 4) 113 | { 114 | indexSpan[i] = (uint) j; 115 | indexSpan[i + 1] = (uint) j + 1; 116 | indexSpan[i + 2] = (uint) j + 2; 117 | indexSpan[i + 3] = (uint) j + 3; 118 | indexSpan[i + 4] = (uint) j + 2; 119 | indexSpan[i + 5] = (uint) j + 1; 120 | } 121 | spriteIndexTransferBuffer.Unmap(); 122 | 123 | var cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 124 | var copyPass = cmdbuf.BeginCopyPass(); 125 | copyPass.UploadToBuffer(spriteIndexTransferBuffer, SpriteIndexBuffer, false); 126 | cmdbuf.EndCopyPass(copyPass); 127 | GraphicsDevice.Submit(cmdbuf); 128 | } 129 | 130 | public override void Update(TimeSpan delta) 131 | { 132 | 133 | } 134 | 135 | public override unsafe void Draw(double alpha) 136 | { 137 | Matrix4x4 cameraMatrix = 138 | Matrix4x4.CreateOrthographicOffCenter( 139 | 0, 140 | 640, 141 | 480, 142 | 0, 143 | 0, 144 | -1f 145 | ); 146 | 147 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 148 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 149 | if (swapchainTexture != null) 150 | { 151 | // generate sprite instance data 152 | for (var i = 0; i < SPRITE_COUNT; i += 1) 153 | { 154 | InstanceData[i] = new SpriteInstanceData 155 | { 156 | Position = new Vector3(Random.Next(640), Random.Next(480), 0), 157 | Rotation = (float) (Random.NextDouble() * System.Math.PI * 2), 158 | Size = new Vector2(32, 32), 159 | Color = new Vector4(1f, 1f, 1f, 1f) 160 | }; 161 | } 162 | 163 | // transform vertex data 164 | var dataSpan = SpriteVertexTransferBuffer.Map(true); 165 | for (var i = 0; i < SPRITE_COUNT; i += 1) 166 | { 167 | var transform = 168 | Matrix4x4.CreateScale(InstanceData[i].Size.X, InstanceData[i].Size.Y, 1) * 169 | Matrix4x4.CreateRotationZ(InstanceData[i].Rotation) * 170 | Matrix4x4.CreateTranslation(InstanceData[i].Position); 171 | 172 | dataSpan[i*4] = new PositionTextureColorVertex 173 | { 174 | Position = new Vector4(Vector3.Transform(new Vector3(0, 0, 0), transform), 1), 175 | TexCoord = new Vector2(0, 0), 176 | Color = InstanceData[i].Color 177 | }; 178 | 179 | dataSpan[i*4 + 1] = new PositionTextureColorVertex 180 | { 181 | Position = new Vector4(Vector3.Transform(new Vector3(1, 0, 0), transform), 1), 182 | TexCoord = new Vector2(1, 0), 183 | Color = InstanceData[i].Color 184 | }; 185 | 186 | dataSpan[i*4 + 2] = new PositionTextureColorVertex 187 | { 188 | Position = new Vector4(Vector3.Transform(new Vector3(0, 1, 0), transform), 1), 189 | TexCoord = new Vector2(0, 1), 190 | Color = InstanceData[i].Color 191 | }; 192 | 193 | dataSpan[i*4 + 3] = new PositionTextureColorVertex 194 | { 195 | Position = new Vector4(Vector3.Transform(new Vector3(1, 1, 0), transform), 1), 196 | TexCoord = new Vector2(1, 1), 197 | Color = InstanceData[i].Color 198 | }; 199 | } 200 | SpriteVertexTransferBuffer.Unmap(); 201 | 202 | // Upload vertex data 203 | var copyPass = cmdbuf.BeginCopyPass(); 204 | copyPass.UploadToBuffer(SpriteVertexTransferBuffer, SpriteVertexBuffer, true); 205 | cmdbuf.EndCopyPass(copyPass); 206 | 207 | // Render sprites using vertex buffer 208 | var renderPass = cmdbuf.BeginRenderPass( 209 | new ColorTargetInfo(swapchainTexture, Color.Black) 210 | ); 211 | 212 | renderPass.BindGraphicsPipeline(RenderPipeline); 213 | renderPass.BindVertexBuffers(SpriteVertexBuffer); 214 | renderPass.BindIndexBuffer(SpriteIndexBuffer, IndexElementSize.ThirtyTwo); 215 | renderPass.BindFragmentSamplers(new TextureSamplerBinding(SpriteTexture, Sampler)); 216 | cmdbuf.PushVertexUniformData(cameraMatrix); 217 | renderPass.DrawIndexedPrimitives(SPRITE_COUNT * 6, 1, 0, 0, 0); 218 | 219 | cmdbuf.EndRenderPass(renderPass); 220 | } 221 | 222 | GraphicsDevice.Submit(cmdbuf); 223 | } 224 | 225 | public override void Destroy() 226 | { 227 | RenderPipeline.Dispose(); 228 | Sampler.Dispose(); 229 | SpriteTexture.Dispose(); 230 | SpriteVertexTransferBuffer.Dispose(); 231 | SpriteVertexBuffer.Dispose(); 232 | SpriteIndexBuffer.Dispose(); 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /Examples/DepthMSAAExample.cs: -------------------------------------------------------------------------------- 1 | using MoonWorks; 2 | using System.Numerics; 3 | using MoonWorks.Graphics; 4 | using MoonWorks.Input; 5 | 6 | namespace MoonWorksGraphicsTests; 7 | 8 | class DepthMSAAExample : Example 9 | { 10 | private GraphicsPipeline[] CubePipelines = new GraphicsPipeline[4]; 11 | private Texture[] RenderTargets = new Texture[4]; 12 | private Texture[] DepthRTs = new Texture[4]; 13 | private Texture ResolveTarget; 14 | private Buffer CubeVertexBuffer1; 15 | private Buffer CubeVertexBuffer2; 16 | private Buffer CubeIndexBuffer; 17 | 18 | private float cubeTimer; 19 | private Quaternion cubeRotation; 20 | private Quaternion previousCubeRotation; 21 | private Vector3 camPos; 22 | private SampleCount currentSampleCount; 23 | 24 | public override void Init() 25 | { 26 | Window.SetTitle("DepthMSAA"); 27 | 28 | cubeTimer = 0; 29 | cubeRotation = Quaternion.Identity; 30 | previousCubeRotation = Quaternion.Identity; 31 | camPos = new Vector3(0, 1.5f, 4); 32 | currentSampleCount = SampleCount.Four; 33 | 34 | Logger.LogInfo("Press Left and Right to cycle between sample counts"); 35 | Logger.LogInfo("Setting sample count to: " + currentSampleCount); 36 | 37 | // Create the cube pipelines 38 | Shader cubeVertShader = ShaderCross.Create( 39 | GraphicsDevice, 40 | RootTitleStorage, 41 | TestUtils.GetHLSLPath("PositionColorWithMatrix.vert"), 42 | "main", 43 | ShaderCross.ShaderFormat.HLSL, 44 | ShaderStage.Vertex 45 | ); 46 | 47 | Shader cubeFragShader = ShaderCross.Create( 48 | GraphicsDevice, 49 | RootTitleStorage, 50 | TestUtils.GetHLSLPath("SolidColor.frag"), 51 | "main", 52 | ShaderCross.ShaderFormat.HLSL, 53 | ShaderStage.Fragment 54 | ); 55 | 56 | GraphicsPipelineCreateInfo pipelineCreateInfo = new GraphicsPipelineCreateInfo 57 | { 58 | TargetInfo = new GraphicsPipelineTargetInfo 59 | { 60 | ColorTargetDescriptions = [ 61 | new ColorTargetDescription 62 | { 63 | Format = Window.SwapchainFormat, 64 | BlendState = ColorTargetBlendState.Opaque 65 | } 66 | ], 67 | HasDepthStencilTarget = true, 68 | DepthStencilFormat = GraphicsDevice.SupportedDepthFormat 69 | }, 70 | DepthStencilState = new DepthStencilState 71 | { 72 | EnableDepthTest = true, 73 | EnableDepthWrite = true, 74 | CompareOp = CompareOp.LessOrEqual 75 | }, 76 | VertexInputState = VertexInputState.CreateSingleBinding(), 77 | PrimitiveType = PrimitiveType.TriangleList, 78 | RasterizerState = RasterizerState.CW_CullBack, 79 | MultisampleState = MultisampleState.None, 80 | VertexShader = cubeVertShader, 81 | FragmentShader = cubeFragShader 82 | }; 83 | 84 | for (int i = 0; i < CubePipelines.Length; i += 1) 85 | { 86 | pipelineCreateInfo.MultisampleState.SampleCount = (SampleCount) i; 87 | CubePipelines[i] = GraphicsPipeline.Create(GraphicsDevice, pipelineCreateInfo); 88 | } 89 | 90 | // Create the MSAA render textures and depth textures 91 | for (int i = 0; i < RenderTargets.Length; i += 1) 92 | { 93 | RenderTargets[i] = Texture.Create2D( 94 | GraphicsDevice, 95 | Window.Width, 96 | Window.Height, 97 | Window.SwapchainFormat, 98 | TextureUsageFlags.ColorTarget, 99 | 1, 100 | (SampleCount) i 101 | ); 102 | 103 | DepthRTs[i] = Texture.Create2D( 104 | GraphicsDevice, 105 | Window.Width, 106 | Window.Height, 107 | GraphicsDevice.SupportedDepthFormat, 108 | TextureUsageFlags.DepthStencilTarget, 109 | 1, 110 | (SampleCount) i 111 | ); 112 | } 113 | 114 | ResolveTarget = Texture.Create2D( 115 | GraphicsDevice, 116 | Window.Width, 117 | Window.Height, 118 | Window.SwapchainFormat, 119 | TextureUsageFlags.ColorTarget | TextureUsageFlags.Sampler 120 | ); 121 | 122 | // Create the buffers 123 | var resourceUploader = new ResourceUploader(GraphicsDevice); 124 | 125 | var cubeVertexData = new System.Span( 126 | [ 127 | new PositionColorVertex(new Vector3(-1, -1, -1), new Color(1f, 0f, 0f)), 128 | new PositionColorVertex(new Vector3(1, -1, -1), new Color(1f, 0f, 0f)), 129 | new PositionColorVertex(new Vector3(1, 1, -1), new Color(1f, 0f, 0f)), 130 | new PositionColorVertex(new Vector3(-1, 1, -1), new Color(1f, 0f, 0f)), 131 | 132 | new PositionColorVertex(new Vector3(-1, -1, 1), new Color(0f, 1f, 0f)), 133 | new PositionColorVertex(new Vector3(1, -1, 1), new Color(0f, 1f, 0f)), 134 | new PositionColorVertex(new Vector3(1, 1, 1), new Color(0f, 1f, 0f)), 135 | new PositionColorVertex(new Vector3(-1, 1, 1), new Color(0f, 1f, 0f)), 136 | 137 | new PositionColorVertex(new Vector3(-1, -1, -1), new Color(0f, 0f, 1f)), 138 | new PositionColorVertex(new Vector3(-1, 1, -1), new Color(0f, 0f, 1f)), 139 | new PositionColorVertex(new Vector3(-1, 1, 1), new Color(0f, 0f, 1f)), 140 | new PositionColorVertex(new Vector3(-1, -1, 1), new Color(0f, 0f, 1f)), 141 | 142 | new PositionColorVertex(new Vector3(1, -1, -1), new Color(1f, 0.5f, 0f)), 143 | new PositionColorVertex(new Vector3(1, 1, -1), new Color(1f, 0.5f, 0f)), 144 | new PositionColorVertex(new Vector3(1, 1, 1), new Color(1f, 0.5f, 0f)), 145 | new PositionColorVertex(new Vector3(1, -1, 1), new Color(1f, 0.5f, 0f)), 146 | 147 | new PositionColorVertex(new Vector3(-1, -1, -1), new Color(1f, 0f, 0.5f)), 148 | new PositionColorVertex(new Vector3(-1, -1, 1), new Color(1f, 0f, 0.5f)), 149 | new PositionColorVertex(new Vector3(1, -1, 1), new Color(1f, 0f, 0.5f)), 150 | new PositionColorVertex(new Vector3(1, -1, -1), new Color(1f, 0f, 0.5f)), 151 | 152 | new PositionColorVertex(new Vector3(-1, 1, -1), new Color(0f, 0.5f, 0f)), 153 | new PositionColorVertex(new Vector3(-1, 1, 1), new Color(0f, 0.5f, 0f)), 154 | new PositionColorVertex(new Vector3(1, 1, 1), new Color(0f, 0.5f, 0f)), 155 | new PositionColorVertex(new Vector3(1, 1, -1), new Color(0f, 0.5f, 0f)) 156 | ]); 157 | 158 | CubeVertexBuffer1 = resourceUploader.CreateBuffer( 159 | cubeVertexData, 160 | BufferUsageFlags.Vertex 161 | ); 162 | 163 | // Scoot all the verts slightly for the second cube... 164 | for (int i = 0; i < cubeVertexData.Length; i += 1) 165 | { 166 | cubeVertexData[i].Position.Z += 3; 167 | } 168 | 169 | CubeVertexBuffer2 = resourceUploader.CreateBuffer( 170 | cubeVertexData, 171 | BufferUsageFlags.Vertex 172 | ); 173 | 174 | CubeIndexBuffer = resourceUploader.CreateBuffer( 175 | [ 176 | 0, 1, 2, 0, 2, 3, 177 | 6, 5, 4, 7, 6, 4, 178 | 8, 9, 10, 8, 10, 11, 179 | 14, 13, 12, 15, 14, 12, 180 | 16, 17, 18, 16, 18, 19, 181 | 22, 21, 20, 23, 22, 20 182 | ], 183 | BufferUsageFlags.Index 184 | ); 185 | 186 | resourceUploader.Upload(); 187 | resourceUploader.Dispose(); 188 | } 189 | 190 | public override void Update(System.TimeSpan delta) 191 | { 192 | SampleCount prevSampleCount = currentSampleCount; 193 | 194 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Left)) 195 | { 196 | currentSampleCount -= 1; 197 | if (currentSampleCount < 0) 198 | { 199 | currentSampleCount = SampleCount.Eight; 200 | } 201 | } 202 | if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Right)) 203 | { 204 | currentSampleCount += 1; 205 | if (currentSampleCount > SampleCount.Eight) 206 | { 207 | currentSampleCount = SampleCount.One; 208 | } 209 | } 210 | 211 | if (prevSampleCount != currentSampleCount) 212 | { 213 | Logger.LogInfo("Setting sample count to: " + currentSampleCount); 214 | } 215 | 216 | // Rotate the cube 217 | cubeTimer += (float) delta.TotalSeconds; 218 | previousCubeRotation = cubeRotation; 219 | cubeRotation = Quaternion.CreateFromYawPitchRoll(cubeTimer * 2f, 0, cubeTimer * 2f); 220 | } 221 | 222 | public override void Draw(double alpha) 223 | { 224 | CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); 225 | Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window); 226 | if (swapchainTexture != null) 227 | { 228 | // Set up cube model-view-projection matrix 229 | Matrix4x4 proj = Matrix4x4.CreatePerspectiveFieldOfView( 230 | float.DegreesToRadians(75f), 231 | (float) Window.Width / Window.Height, 232 | 0.01f, 233 | 100f 234 | ); 235 | Matrix4x4 view = Matrix4x4.CreateLookAt(camPos, Vector3.Zero, Vector3.UnitY); 236 | Matrix4x4 model = Matrix4x4.CreateFromQuaternion( 237 | Quaternion.Slerp( 238 | previousCubeRotation, 239 | cubeRotation, 240 | (float) alpha 241 | ) 242 | ); 243 | TransformVertexUniform cubeUniforms = new TransformVertexUniform(model * view * proj); 244 | 245 | int index = (int) currentSampleCount; 246 | 247 | ColorTargetInfo colorTargetInfo; 248 | 249 | if (currentSampleCount == SampleCount.One) 250 | { 251 | colorTargetInfo = new ColorTargetInfo(swapchainTexture, Color.Black); 252 | } 253 | else 254 | { 255 | colorTargetInfo = new ColorTargetInfo 256 | { 257 | Texture = RenderTargets[index].Handle, 258 | LoadOp = LoadOp.Clear, 259 | ClearColor = Color.Black, 260 | StoreOp = StoreOp.Resolve, 261 | ResolveTexture = swapchainTexture.Handle 262 | }; 263 | } 264 | 265 | // Begin the MSAA RT pass 266 | var renderPass = cmdbuf.BeginRenderPass( 267 | new DepthStencilTargetInfo(DepthRTs[index], 1, true), 268 | colorTargetInfo 269 | ); 270 | renderPass.BindGraphicsPipeline(CubePipelines[index]); 271 | 272 | cmdbuf.PushVertexUniformData(cubeUniforms); 273 | 274 | // Draw the first cube 275 | renderPass.BindVertexBuffers(CubeVertexBuffer1); 276 | renderPass.BindIndexBuffer(CubeIndexBuffer, IndexElementSize.ThirtyTwo); 277 | renderPass.DrawIndexedPrimitives(36, 1, 0, 0, 0); 278 | 279 | // Draw the second cube 280 | renderPass.BindVertexBuffers(CubeVertexBuffer2); 281 | renderPass.BindIndexBuffer(CubeIndexBuffer, IndexElementSize.ThirtyTwo); 282 | renderPass.DrawIndexedPrimitives(36, 1, 0, 0, 0); 283 | 284 | cmdbuf.EndRenderPass(renderPass); 285 | } 286 | GraphicsDevice.Submit(cmdbuf); 287 | } 288 | 289 | public override void Destroy() 290 | { 291 | for (var i = 0; i < 4; i += 1) 292 | { 293 | CubePipelines[i].Dispose(); 294 | RenderTargets[i].Dispose(); 295 | DepthRTs[i].Dispose(); 296 | } 297 | ResolveTarget.Dispose(); 298 | CubeVertexBuffer1.Dispose(); 299 | CubeVertexBuffer2.Dispose(); 300 | CubeIndexBuffer.Dispose(); 301 | } 302 | } 303 | --------------------------------------------------------------------------------