public unsafe void Copy_1DTo2D() { if (!GD.Features.Texture1D) { return; } Texture tex1D = RF.CreateTexture( TextureDescription.Texture1D(100, 1, 1, PixelFormat.R16_UNorm, TextureUsage.Staging)); Texture tex2D = RF.CreateTexture( TextureDescription.Texture2D(100, 10, 1, 1, PixelFormat.R16_UNorm, TextureUsage.Staging)); MappedResourceView <ushort> writeView = GD.Map <ushort>(tex1D, MapMode.Write); Assert.Equal(tex1D.Width, (uint)writeView.Count); for (int i = 0; i < writeView.Count; i++) { writeView[i] = (ushort)(i * 2); } GD.Unmap(tex1D); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.CopyTexture( tex1D, 0, 0, 0, 0, 0, tex2D, 0, 5, 0, 0, 0, tex1D.Width, 1, 1, 1); cl.End(); GD.SubmitCommands(cl); GD.DisposeWhenIdle(cl); GD.WaitForIdle(); MappedResourceView <ushort> readView = GD.Map <ushort>(tex2D, MapMode.Read); for (int i = 0; i < tex2D.Width; i++) { Assert.Equal((ushort)(i * 2), readView[i, 5]); } GD.Unmap(tex2D); }
private DeviceBuffer GetReadback(DeviceBuffer buffer) { DeviceBuffer readback; if ((buffer.Usage & BufferUsage.Staging) != 0) { readback = buffer; } else { readback = CreateBuffer(buffer.SizeInBytes, BufferUsage.Staging); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.CopyBuffer(buffer, 0, readback, 0, buffer.SizeInBytes); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); } return(readback); }
public void Copy_ArrayToNonArray() { Texture src = RF.CreateTexture(TextureDescription.Texture2D( 10, 10, 1, 10, PixelFormat.R8_G8_B8_A8_UNorm, TextureUsage.Staging)); Texture dst = RF.CreateTexture(TextureDescription.Texture2D( 10, 10, 1, 1, PixelFormat.R8_G8_B8_A8_UNorm, TextureUsage.Staging)); MappedResourceView <RgbaByte> writeView = GD.Map <RgbaByte>(src, MapMode.Write, 5); for (int y = 0; y < src.Height; y++) { for (int x = 0; x < src.Width; x++) { writeView[x, y] = new RgbaByte((byte)x, (byte)y, 0, 1); } } GD.Unmap(src, 5); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.CopyTexture( src, 0, 0, 0, 0, 5, dst, 0, 0, 0, 0, 0, 10, 10, 1, 1); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); MappedResourceView <RgbaByte> readView = GD.Map <RgbaByte>(dst, MapMode.Read); for (int y = 0; y < dst.Height; y++) { for (int x = 0; x < dst.Width; x++) { Assert.Equal(new RgbaByte((byte)x, (byte)y, 0, 1), readView[x, y]); } } GD.Unmap(dst); }
public void ResourceSet_InvalidSlot_Fails() { DeviceBuffer infoBuffer = RF.CreateBuffer(new BufferDescription(16, BufferUsage.UniformBuffer)); DeviceBuffer orthoBuffer = RF.CreateBuffer(new BufferDescription(64, BufferUsage.UniformBuffer)); ShaderSetDescription shaderSet = new ShaderSetDescription( new VertexLayoutDescription[] { new VertexLayoutDescription( new VertexElementDescription("Position", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float2), new VertexElementDescription("Color_UInt", VertexElementSemantic.TextureCoordinate, VertexElementFormat.UInt4)) }, TestShaders.LoadVertexFragment(RF, "UIntVertexAttribs")); ResourceLayout layout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("InfoBuffer", ResourceKind.UniformBuffer, ShaderStages.Vertex), new ResourceLayoutElementDescription("Ortho", ResourceKind.UniformBuffer, ShaderStages.Vertex))); ResourceSet set = RF.CreateResourceSet(new ResourceSetDescription(layout, infoBuffer, orthoBuffer)); GraphicsPipelineDescription gpd = new GraphicsPipelineDescription( BlendStateDescription.SingleOverrideBlend, DepthStencilStateDescription.Disabled, RasterizerStateDescription.Default, PrimitiveTopology.PointList, shaderSet, layout, new OutputDescription(null, new OutputAttachmentDescription(PixelFormat.B8_G8_R8_A8_UNorm))); Pipeline pipeline = RF.CreateGraphicsPipeline(ref gpd); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.SetPipeline(pipeline); Assert.Throws <VeldridException>(() => cl.SetGraphicsResourceSet(1, set)); Assert.Throws <VeldridException>(() => cl.SetGraphicsResourceSet(2, set)); Assert.Throws <VeldridException>(() => cl.SetGraphicsResourceSet(3, set)); cl.End(); }
public void CommandList_Update_Staging() { DeviceBuffer staging = RF.CreateBuffer( new BufferDescription(1024, BufferUsage.Staging)); byte[] data = Enumerable.Range(0, 1024).Select(i => (byte)i).ToArray(); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.UpdateBuffer(staging, 0, data); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); MappedResourceView <byte> readView = GD.Map <byte>(staging, MapMode.Read); for (uint i = 0; i < staging.SizeInBytes; i++) { Assert.Equal((byte)i, readView[i]); } }
public unsafe void UpdateBuffer_ZeroSize(BufferUsage usage, bool useCommandListUpdate) { DeviceBuffer buffer = CreateBuffer(1024, usage); byte[] initialData = Enumerable.Range(0, 1024).Select(i => (byte)i).ToArray(); byte[] otherData = Enumerable.Range(0, 1024).Select(i => (byte)(i + 10)).ToArray(); GD.UpdateBuffer(buffer, 0, initialData); if (useCommandListUpdate) { CommandList cl = RF.CreateCommandList(); cl.Begin(); fixed(byte *dataPtr = otherData) { cl.UpdateBuffer(buffer, 0, (IntPtr)dataPtr, 0); } cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); } else { fixed(byte *dataPtr = otherData) { GD.UpdateBuffer(buffer, 0, (IntPtr)dataPtr, 0); } } DeviceBuffer readback = GetReadback(buffer); MappedResourceView <byte> readMap = GD.Map <byte>(readback, MapMode.Read); for (int i = 0; i < 1024; i++) { Assert.Equal((byte)i, readMap[i]); } GD.Unmap(readback); }
public unsafe void Copy_BC3_Unorm() { Texture copySrc = RF.CreateTexture(TextureDescription.Texture2D( 64, 64, 1, 1, PixelFormat.BC3_UNorm, TextureUsage.Staging)); Texture copyDst = RF.CreateTexture(TextureDescription.Texture2D( 64, 64, 1, 1, PixelFormat.BC3_UNorm, TextureUsage.Staging)); uint totalDataSize = copySrc.Width * copySrc.Height; byte[] data = new byte[totalDataSize]; for (int i = 0; i < data.Length; i++) { data[i] = (byte)i; } fixed(byte *dataPtr = data) { GD.UpdateTexture(copySrc, (IntPtr)dataPtr, totalDataSize, 0, 0, 0, copySrc.Width, copySrc.Height, 1, 0, 0); } CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.CopyTexture( copySrc, 0, 0, 0, 0, 0, copyDst, 0, 0, 0, 0, 0, copySrc.Width, copySrc.Height, 1, 1); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); MappedResourceView <byte> view = GD.Map <byte>(copyDst, MapMode.Read); for (int i = 0; i < data.Length; i++) { Assert.Equal(view[i], data[i]); } }
public void Update_Dynamic_NonZeroOffset() { DeviceBuffer dynamic = RF.CreateBuffer( new BufferDescription(1024, BufferUsage.Dynamic | BufferUsage.UniformBuffer)); byte[] initialData = Enumerable.Range(0, 1024).Select(i => (byte)i).ToArray(); GD.UpdateBuffer(dynamic, 0, initialData); byte[] replacementData = Enumerable.Repeat((byte)255, 512).ToArray(); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.UpdateBuffer(dynamic, 512, replacementData); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); DeviceBuffer dst = RF.CreateBuffer( new BufferDescription(1024, BufferUsage.Staging)); cl.Begin(); cl.CopyBuffer(dynamic, 0, dst, 0, dynamic.SizeInBytes); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); MappedResourceView <byte> readView = GD.Map <byte>(dst, MapMode.Read); for (uint i = 0; i < 512; i++) { Assert.Equal((byte)i, readView[i]); } for (uint i = 512; i < 1024; i++) { Assert.Equal((byte)255, readView[i]); } }
public void UpdateUniform_Offset_CommandList(BufferUsage usage) { DeviceBuffer buffer = CreateBuffer(128, usage); CommandList cl = RF.CreateCommandList(); cl.Begin(); Matrix4x4 mat1 = new Matrix4x4(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); cl.UpdateBuffer(buffer, 0, ref mat1); Matrix4x4 mat2 = new Matrix4x4(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); cl.UpdateBuffer(buffer, 64, ref mat2); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); DeviceBuffer readback = GetReadback(buffer); MappedResourceView <Matrix4x4> readView = GD.Map <Matrix4x4>(readback, MapMode.Read); Assert.Equal(mat1, readView[0]); Assert.Equal(mat2, readView[1]); GD.Unmap(readback); }
public void CommandList_UpdateNonStaging_Unaligned(BufferUsage usage, uint bufferSize, uint dataSize, uint offset) { DeviceBuffer buffer = CreateBuffer(bufferSize, usage); byte[] data = Enumerable.Range(0, (int)dataSize).Select(i => (byte)i).ToArray(); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.UpdateBuffer(buffer, offset, data); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); DeviceBuffer readback = GetReadback(buffer); MappedResourceView <byte> readView = GD.Map <byte>(readback, MapMode.Read); for (uint i = 0; i < dataSize; i++) { byte expected = data[i]; byte actual = readView[i + offset]; Assert.Equal(expected, actual); } GD.Unmap(readback); }
public unsafe void UnusualSize() { DeviceBuffer src = RF.CreateBuffer( new BufferDescription(208, BufferUsage.UniformBuffer)); DeviceBuffer dst = RF.CreateBuffer( new BufferDescription(208, BufferUsage.Staging)); byte[] data = Enumerable.Range(0, 208).Select(i => (byte)(i * 150)).ToArray(); GD.UpdateBuffer(src, 0, data); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.CopyBuffer(src, 0, dst, 0, src.SizeInBytes); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); MappedResource readMap = GD.Map(dst, MapMode.Read); for (int i = 0; i < readMap.SizeInBytes; i++) { Assert.Equal((byte)(i * 150), ((byte *)readMap.Data)[i]); } }
public void FillBuffer_WithOffsets(uint srcSetMultiple, uint srcBindingMultiple, uint dstSetMultiple, uint dstBindingMultiple, bool combinedLayout) { if (!GD.Features.ComputeShader) { return; } Debug.Assert((GD.StructuredBufferMinOffsetAlignment % sizeof(uint)) == 0); uint valueCount = 512; uint dataSize = valueCount * sizeof(uint); uint totalSrcAlignment = GD.StructuredBufferMinOffsetAlignment * (srcSetMultiple + srcBindingMultiple); uint totalDstAlignment = GD.StructuredBufferMinOffsetAlignment * (dstSetMultiple + dstBindingMultiple); DeviceBuffer copySrc = RF.CreateBuffer( new BufferDescription(totalSrcAlignment + dataSize, BufferUsage.StructuredBufferReadOnly, sizeof(uint))); DeviceBuffer copyDst = RF.CreateBuffer( new BufferDescription(totalDstAlignment + dataSize, BufferUsage.StructuredBufferReadWrite, sizeof(uint))); ResourceLayout[] layouts; ResourceSet[] sets; DeviceBufferRange srcRange = new DeviceBufferRange(copySrc, srcSetMultiple * GD.StructuredBufferMinOffsetAlignment, dataSize); DeviceBufferRange dstRange = new DeviceBufferRange(copyDst, dstSetMultiple * GD.StructuredBufferMinOffsetAlignment, dataSize); if (combinedLayout) { layouts = new[] { RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription( "CopySrc", ResourceKind.StructuredBufferReadOnly, ShaderStages.Compute, ResourceLayoutElementOptions.DynamicBinding), new ResourceLayoutElementDescription( "CopyDst", ResourceKind.StructuredBufferReadWrite, ShaderStages.Compute, ResourceLayoutElementOptions.DynamicBinding))) }; sets = new[] { RF.CreateResourceSet(new ResourceSetDescription(layouts[0], srcRange, dstRange)) }; } else { layouts = new[] { RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription( "CopySrc", ResourceKind.StructuredBufferReadOnly, ShaderStages.Compute, ResourceLayoutElementOptions.DynamicBinding))), RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription( "CopyDst", ResourceKind.StructuredBufferReadWrite, ShaderStages.Compute, ResourceLayoutElementOptions.DynamicBinding))) }; sets = new[] { RF.CreateResourceSet(new ResourceSetDescription(layouts[0], srcRange)), RF.CreateResourceSet(new ResourceSetDescription(layouts[1], dstRange)), }; } Pipeline pipeline = RF.CreateComputePipeline(new ComputePipelineDescription( TestShaders.LoadCompute(RF, combinedLayout ? "FillBuffer" : "FillBuffer_SeparateLayout"), layouts, 1, 1, 1)); uint[] srcData = Enumerable.Range(0, (int)copySrc.SizeInBytes / sizeof(uint)).Select(i => (uint)i).ToArray(); GD.UpdateBuffer(copySrc, 0, srcData); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.SetPipeline(pipeline); if (combinedLayout) { uint[] offsets = new[] { srcBindingMultiple *GD.StructuredBufferMinOffsetAlignment, dstBindingMultiple *GD.StructuredBufferMinOffsetAlignment }; cl.SetComputeResourceSet(0, sets[0], offsets); } else { uint offset = srcBindingMultiple * GD.StructuredBufferMinOffsetAlignment; cl.SetComputeResourceSet(0, sets[0], 1, ref offset); offset = dstBindingMultiple * GD.StructuredBufferMinOffsetAlignment; cl.SetComputeResourceSet(1, sets[1], 1, ref offset); } cl.Dispatch(512, 1, 1); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); DeviceBuffer readback = GetReadback(copyDst); MappedResourceView <uint> readView = GD.Map <uint>(readback, MapMode.Read); for (uint i = 0; i < valueCount; i++) { uint srcIndex = totalSrcAlignment / sizeof(uint) + i; uint expected = srcData[(int)srcIndex]; uint dstIndex = totalDstAlignment / sizeof(uint) + i; uint actual = readView[dstIndex]; Assert.Equal(expected, actual); } GD.Unmap(readback); }
public void BasicCompute() { if (!GD.Features.ComputeShader) { return; } ResourceLayout layout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("Params", ResourceKind.UniformBuffer, ShaderStages.Compute), new ResourceLayoutElementDescription("Source", ResourceKind.StructuredBufferReadWrite, ShaderStages.Compute), new ResourceLayoutElementDescription("Destination", ResourceKind.StructuredBufferReadWrite, ShaderStages.Compute))); uint width = 1024; uint height = 1024; DeviceBuffer paramsBuffer = RF.CreateBuffer(new BufferDescription((uint)Unsafe.SizeOf <BasicComputeTestParams>(), BufferUsage.UniformBuffer)); DeviceBuffer sourceBuffer = RF.CreateBuffer(new BufferDescription(width * height * 4, BufferUsage.StructuredBufferReadWrite, 4)); DeviceBuffer destinationBuffer = RF.CreateBuffer(new BufferDescription(width * height * 4, BufferUsage.StructuredBufferReadWrite, 4)); GD.UpdateBuffer(paramsBuffer, 0, new BasicComputeTestParams { Width = width, Height = height }); float[] sourceData = new float[width * height]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int index = y * (int)width + x; sourceData[index] = index; } } GD.UpdateBuffer(sourceBuffer, 0, sourceData); ResourceSet rs = RF.CreateResourceSet(new ResourceSetDescription(layout, paramsBuffer, sourceBuffer, destinationBuffer)); Pipeline pipeline = RF.CreateComputePipeline(new ComputePipelineDescription( TestShaders.LoadCompute(RF, "BasicComputeTest"), layout, 16, 16, 1)); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.SetPipeline(pipeline); cl.SetComputeResourceSet(0, rs); cl.Dispatch(width / 16, width / 16, 1); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); DeviceBuffer sourceReadback = GetReadback(sourceBuffer); DeviceBuffer destinationReadback = GetReadback(destinationBuffer); MappedResourceView <float> sourceReadView = GD.Map <float>(sourceReadback, MapMode.Read); MappedResourceView <float> destinationReadView = GD.Map <float>(destinationReadback, MapMode.Read); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int index = y * (int)width + x; Assert.Equal(2 * sourceData[index], sourceReadView[index]); Assert.Equal(sourceData[index], destinationReadView[index]); } } GD.Unmap(sourceReadback); GD.Unmap(destinationReadback); }
public void ComputeShader3dTexture() { // Just a dumb compute shader that fills a 3D texture with the same value from a uniform multiplied by the depth. string shaderText = @" #version 450 layout(set = 0, binding = 0, rgba32f) uniform image3D TextureToFill; layout(set = 0, binding = 1) uniform FillValueBuffer { float FillValue; float Padding1; float Padding2; float Padding3; }; layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; void main() { ivec3 textureCoordinate = ivec3(gl_GlobalInvocationID.xyz); float dataToStore = FillValue * (textureCoordinate.z + 1); imageStore(TextureToFill, textureCoordinate, vec4(dataToStore)); } "; const float FillValue = 42.42f; const uint OutputTextureSize = 32; using Shader computeShader = RF.CreateFromSpirv(new ShaderDescription( ShaderStages.Compute, Encoding.ASCII.GetBytes(shaderText), "main")); using ResourceLayout computeLayout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("TextureToFill", ResourceKind.TextureReadWrite, ShaderStages.Compute), new ResourceLayoutElementDescription("FillValueBuffer", ResourceKind.UniformBuffer, ShaderStages.Compute))); using Pipeline computePipeline = RF.CreateComputePipeline(new ComputePipelineDescription( computeShader, computeLayout, 16, 16, 1)); using DeviceBuffer fillValueBuffer = RF.CreateBuffer(new BufferDescription((uint)Marshal.SizeOf <FillValueStruct>(), BufferUsage.UniformBuffer)); // Create our output texture. using Texture computeTargetTexture = RF.CreateTexture(TextureDescription.Texture3D( OutputTextureSize, OutputTextureSize, OutputTextureSize, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.Sampled | TextureUsage.Storage)); using TextureView computeTargetTextureView = RF.CreateTextureView(computeTargetTexture); using ResourceSet computeResourceSet = RF.CreateResourceSet(new ResourceSetDescription( computeLayout, computeTargetTextureView, fillValueBuffer)); using CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.UpdateBuffer(fillValueBuffer, 0, new FillValueStruct(FillValue)); // Use the compute shader to fill the texture. cl.SetPipeline(computePipeline); cl.SetComputeResourceSet(0, computeResourceSet); const uint GroupDivisorXY = 16; cl.Dispatch(OutputTextureSize / GroupDivisorXY, OutputTextureSize / GroupDivisorXY, OutputTextureSize); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); // Read back from our texture and make sure it has been properly filled. for (uint depth = 0; depth < computeTargetTexture.Depth; depth++) { RgbaFloat expectedFillValue = new RgbaFloat(new System.Numerics.Vector4(FillValue * (depth + 1))); int notFilledCount = CountTexelsNotFilledAtDepth(GD, computeTargetTexture, expectedFillValue, depth); if (notFilledCount == 0) { // Expected behavior: Console.WriteLine($"All texels were properly set at depth {depth}"); } else { // Unexpected behavior: uint totalTexels = computeTargetTexture.Width * computeTargetTexture.Height; throw new Exception($"{notFilledCount} of {totalTexels} texels were not properly set at depth {depth}"); } } }
public void SampleTexture1D(bool arrayTexture) { if (!GD.Features.Texture1D) { return; } Texture target = RF.CreateTexture(TextureDescription.Texture2D( 50, 50, 1, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.RenderTarget)); Texture staging = RF.CreateTexture(TextureDescription.Texture2D( 50, 50, 1, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.Staging)); Framebuffer framebuffer = RF.CreateFramebuffer(new FramebufferDescription(null, target)); string SetName = arrayTexture ? "FullScreenTriSampleTextureArray" : "FullScreenTriSampleTexture"; ShaderSetDescription shaderSet = new ShaderSetDescription( Array.Empty <VertexLayoutDescription>(), TestShaders.LoadVertexFragment(RF, SetName)); uint layers = arrayTexture ? 10u : 1u; Texture tex1D = RF.CreateTexture( TextureDescription.Texture1D(128, 1, layers, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.Sampled)); RgbaFloat[] colors = new RgbaFloat[tex1D.Width]; for (int i = 0; i < colors.Length; i++) { colors[i] = RgbaFloat.Pink; } GD.UpdateTexture(tex1D, colors, 0, 0, 0, tex1D.Width, 1, 1, 0, 0); ResourceLayout layout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("Tex", ResourceKind.TextureReadOnly, ShaderStages.Fragment), new ResourceLayoutElementDescription("Smp", ResourceKind.Sampler, ShaderStages.Fragment))); ResourceSet set = RF.CreateResourceSet(new ResourceSetDescription(layout, tex1D, GD.PointSampler)); GraphicsPipelineDescription gpd = new GraphicsPipelineDescription( BlendStateDescription.SingleOverrideBlend, DepthStencilStateDescription.Disabled, RasterizerStateDescription.CullNone, PrimitiveTopology.TriangleList, shaderSet, layout, framebuffer.OutputDescription); Pipeline pipeline = RF.CreateGraphicsPipeline(ref gpd); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.SetFramebuffer(framebuffer); cl.SetFullViewports(); cl.SetFullScissorRects(); cl.ClearColorTarget(0, RgbaFloat.Black); cl.SetPipeline(pipeline); cl.SetGraphicsResourceSet(0, set); cl.Draw(3); cl.CopyTexture(target, staging); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); MappedResourceView <RgbaFloat> readView = GD.Map <RgbaFloat>(staging, MapMode.Read); for (int x = 0; x < staging.Width; x++) { Assert.Equal(RgbaFloat.Pink, readView[x, 0]); } GD.Unmap(staging); }
public void Points_WithUShortNormColor() { Texture target = RF.CreateTexture(TextureDescription.Texture2D( 50, 50, 1, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.RenderTarget)); Texture staging = RF.CreateTexture(TextureDescription.Texture2D( 50, 50, 1, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.Staging)); Framebuffer framebuffer = RF.CreateFramebuffer(new FramebufferDescription(null, target)); DeviceBuffer orthoBuffer = RF.CreateBuffer(new BufferDescription(64, BufferUsage.UniformBuffer)); Matrix4x4 orthoMatrix = Matrix4x4.CreateOrthographicOffCenter( 0, framebuffer.Width, framebuffer.Height, 0, -1, 1); GD.UpdateBuffer(orthoBuffer, 0, ref orthoMatrix); ShaderSetDescription shaderSet = new ShaderSetDescription( new VertexLayoutDescription[] { new VertexLayoutDescription( new VertexElementDescription("Position", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float2), new VertexElementDescription("Color", VertexElementSemantic.TextureCoordinate, VertexElementFormat.UShort4_Norm)) }, TestShaders.LoadVertexFragment(RF, "U16NormVertexAttribs")); ResourceLayout layout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("Ortho", ResourceKind.UniformBuffer, ShaderStages.Vertex))); ResourceSet set = RF.CreateResourceSet(new ResourceSetDescription(layout, orthoBuffer)); GraphicsPipelineDescription gpd = new GraphicsPipelineDescription( BlendStateDescription.SingleOverrideBlend, DepthStencilStateDescription.Disabled, RasterizerStateDescription.Default, PrimitiveTopology.PointList, shaderSet, layout, framebuffer.OutputDescription); Pipeline pipeline = RF.CreateGraphicsPipeline(ref gpd); VertexCPU_UShortNorm[] vertices = new VertexCPU_UShortNorm[] { new VertexCPU_UShortNorm { Position = new Vector2(0.5f, 0.5f), R = UShortNorm(0.25f), G = UShortNorm(0.5f), B = UShortNorm(0.75f), }, new VertexCPU_UShortNorm { Position = new Vector2(10.5f, 12.5f), R = UShortNorm(0.25f), G = UShortNorm(0.5f), B = UShortNorm(0.75f), }, new VertexCPU_UShortNorm { Position = new Vector2(25.5f, 35.5f), R = UShortNorm(0.75f), G = UShortNorm(0.5f), B = UShortNorm(0.25f), }, new VertexCPU_UShortNorm { Position = new Vector2(49.5f, 49.5f), R = UShortNorm(0.15f), G = UShortNorm(0.25f), B = UShortNorm(0.35f), }, }; DeviceBuffer vb = RF.CreateBuffer( new BufferDescription((uint)(Unsafe.SizeOf <VertexCPU_UShortNorm>() * vertices.Length), BufferUsage.VertexBuffer)); GD.UpdateBuffer(vb, 0, vertices); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.SetFramebuffer(framebuffer); cl.SetFullViewports(); cl.SetFullScissorRects(); cl.ClearColorTarget(0, RgbaFloat.Black); cl.SetPipeline(pipeline); cl.SetVertexBuffer(0, vb); cl.SetGraphicsResourceSet(0, set); cl.Draw((uint)vertices.Length); cl.CopyTexture(target, staging); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); MappedResourceView <RgbaFloat> readView = GD.Map <RgbaFloat>(staging, MapMode.Read); foreach (VertexCPU_UShortNorm vertex in vertices) { uint x = (uint)vertex.Position.X; uint y = (uint)vertex.Position.Y; if (!GD.IsUvOriginTopLeft || GD.IsClipSpaceYInverted) { y = framebuffer.Height - y - 1; } RgbaFloat expectedColor = new RgbaFloat( vertex.R / (float)ushort.MaxValue, vertex.G / (float)ushort.MaxValue, vertex.B / (float)ushort.MaxValue, 1); Assert.Equal(expectedColor, readView[x, y], RgbaFloatFuzzyComparer.Instance); } GD.Unmap(staging); }
public void Points_WithFloat16Color() { Texture target = RF.CreateTexture(TextureDescription.Texture2D( 50, 50, 1, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.RenderTarget)); Texture staging = RF.CreateTexture(TextureDescription.Texture2D( 50, 50, 1, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.Staging)); Framebuffer framebuffer = RF.CreateFramebuffer(new FramebufferDescription(null, target)); DeviceBuffer infoBuffer = RF.CreateBuffer(new BufferDescription(16, BufferUsage.UniformBuffer)); DeviceBuffer orthoBuffer = RF.CreateBuffer(new BufferDescription(64, BufferUsage.UniformBuffer)); Matrix4x4 orthoMatrix = Matrix4x4.CreateOrthographicOffCenter( 0, framebuffer.Width, framebuffer.Height, 0, -1, 1); GD.UpdateBuffer(orthoBuffer, 0, ref orthoMatrix); ShaderSetDescription shaderSet = new ShaderSetDescription( new VertexLayoutDescription[] { new VertexLayoutDescription( new VertexElementDescription("Position", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float2), new VertexElementDescription("Color_Half", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Half4)) }, TestShaders.LoadVertexFragment(RF, "F16VertexAttribs")); ResourceLayout layout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("InfoBuffer", ResourceKind.UniformBuffer, ShaderStages.Vertex), new ResourceLayoutElementDescription("OrthoBuffer", ResourceKind.UniformBuffer, ShaderStages.Vertex))); ResourceSet set = RF.CreateResourceSet(new ResourceSetDescription(layout, infoBuffer, orthoBuffer)); GraphicsPipelineDescription gpd = new GraphicsPipelineDescription( BlendStateDescription.SingleOverrideBlend, DepthStencilStateDescription.Disabled, RasterizerStateDescription.Default, PrimitiveTopology.PointList, shaderSet, layout, framebuffer.OutputDescription); Pipeline pipeline = RF.CreateGraphicsPipeline(ref gpd); uint colorNormalizationFactor = 2500; const ushort f16_375 = 0x5DDC; // 375.0 const ushort f16_500 = 0x5FD0; // 500.0 const ushort f16_625 = 0x60E2; // 625.0 const ushort f16_875 = 0x62D6; // 875.0 const ushort f16_1250 = 0x64E2; // 1250.0 const ushort f16_1875 = 0x6753; // 1875.0 VertexCPU_UShort[] vertices = new VertexCPU_UShort[] { new VertexCPU_UShort { Position = new Vector2(0.5f, 0.5f), R = f16_625, G = f16_1250, B = f16_1875, }, new VertexCPU_UShort { Position = new Vector2(10.5f, 12.5f), R = f16_625, G = f16_1250, B = f16_1875, }, new VertexCPU_UShort { Position = new Vector2(25.5f, 35.5f), R = f16_1875, G = f16_1250, B = f16_625, }, new VertexCPU_UShort { Position = new Vector2(49.5f, 49.5f), R = f16_375, G = f16_500, B = f16_875, }, }; RgbaFloat[] expectedColors = new[] { new RgbaFloat( 625.0f / colorNormalizationFactor, 1250.0f / colorNormalizationFactor, 1875.0f / colorNormalizationFactor, 1), new RgbaFloat( 625.0f / colorNormalizationFactor, 1250.0f / colorNormalizationFactor, 1875.0f / colorNormalizationFactor, 1), new RgbaFloat( 1875.0f / colorNormalizationFactor, 1250.0f / colorNormalizationFactor, 625.0f / colorNormalizationFactor, 1), new RgbaFloat( 375.0f / colorNormalizationFactor, 500.0f / colorNormalizationFactor, 875.0f / colorNormalizationFactor, 1), }; DeviceBuffer vb = RF.CreateBuffer( new BufferDescription((uint)(Unsafe.SizeOf <UIntVertexAttribsVertex>() * vertices.Length), BufferUsage.VertexBuffer)); GD.UpdateBuffer(vb, 0, vertices); GD.UpdateBuffer(infoBuffer, 0, new UIntVertexAttribsInfo { ColorNormalizationFactor = colorNormalizationFactor }); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.SetFramebuffer(framebuffer); cl.SetFullViewports(); cl.SetFullScissorRects(); cl.ClearColorTarget(0, RgbaFloat.Black); cl.SetPipeline(pipeline); cl.SetVertexBuffer(0, vb); cl.SetGraphicsResourceSet(0, set); cl.Draw((uint)vertices.Length); cl.CopyTexture(target, staging); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); MappedResourceView <RgbaFloat> readView = GD.Map <RgbaFloat>(staging, MapMode.Read); for (int i = 0; i < vertices.Length; i++) { VertexCPU_UShort vertex = vertices[i]; uint x = (uint)vertex.Position.X; uint y = (uint)vertex.Position.Y; if (!GD.IsUvOriginTopLeft || GD.IsClipSpaceYInverted) { y = framebuffer.Height - y - 1; } RgbaFloat expectedColor = expectedColors[i]; Assert.Equal(expectedColor, readView[x, y], RgbaFloatFuzzyComparer.Instance); } GD.Unmap(staging); }
public void ComputeGeneratedTexture() { if (!GD.Features.ComputeShader) { return; } uint width = 4; uint height = 1; TextureDescription texDesc = TextureDescription.Texture2D( width, height, 1, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.Sampled | TextureUsage.Storage); Texture computeOutput = RF.CreateTexture(texDesc); texDesc.Usage = TextureUsage.RenderTarget; Texture finalOutput = RF.CreateTexture(texDesc); Framebuffer framebuffer = RF.CreateFramebuffer(new FramebufferDescription(null, finalOutput)); ResourceLayout computeLayout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("ComputeOutput", ResourceKind.TextureReadWrite, ShaderStages.Compute))); ResourceSet computeSet = RF.CreateResourceSet(new ResourceSetDescription(computeLayout, computeOutput)); Pipeline computePipeline = RF.CreateComputePipeline(new ComputePipelineDescription( TestShaders.LoadCompute(RF, "ComputeTextureGenerator"), computeLayout, 4, 1, 1)); ResourceLayout graphicsLayout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("Input", ResourceKind.TextureReadOnly, ShaderStages.Fragment), new ResourceLayoutElementDescription("InputSampler", ResourceKind.Sampler, ShaderStages.Fragment))); ResourceSet graphicsSet = RF.CreateResourceSet(new ResourceSetDescription(graphicsLayout, computeOutput, GD.PointSampler)); Pipeline graphicsPipeline = RF.CreateGraphicsPipeline(new GraphicsPipelineDescription( BlendStateDescription.SingleOverrideBlend, DepthStencilStateDescription.Disabled, RasterizerStateDescription.CullNone, PrimitiveTopology.TriangleStrip, new ShaderSetDescription( Array.Empty <VertexLayoutDescription>(), TestShaders.LoadVertexFragment(RF, "FullScreenBlit")), graphicsLayout, framebuffer.OutputDescription)); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.SetPipeline(computePipeline); cl.SetComputeResourceSet(0, computeSet); cl.Dispatch(1, 1, 1); cl.SetFramebuffer(framebuffer); cl.ClearColorTarget(0, new RgbaFloat()); cl.SetPipeline(graphicsPipeline); cl.SetGraphicsResourceSet(0, graphicsSet); cl.Draw(4); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); Texture readback = GetReadback(finalOutput); MappedResourceView <RgbaFloat> readView = GD.Map <RgbaFloat>(readback, MapMode.Read); Assert.Equal(RgbaFloat.Red, readView[0, 0]); Assert.Equal(RgbaFloat.Green, readView[1, 0]); Assert.Equal(RgbaFloat.Blue, readView[2, 0]); Assert.Equal(RgbaFloat.White, readView[3, 0]); GD.Unmap(readback); }
public unsafe void Copy_Compressed_Array(bool separateLayerCopies) { PixelFormat format = PixelFormat.BC3_UNorm; if (!GD.GetPixelFormatSupport(format, TextureType.Texture2D, TextureUsage.Sampled)) { return; } TextureDescription texDesc = TextureDescription.Texture2D( 16, 16, 1, 4, format, TextureUsage.Sampled); Texture copySrc = RF.CreateTexture(texDesc); texDesc.Usage = TextureUsage.Staging; Texture copyDst = RF.CreateTexture(texDesc); for (uint layer = 0; layer < copySrc.ArrayLayers; layer++) { int byteCount = 16 * 16; byte[] data = Enumerable.Range(0, byteCount).Select(i => (byte)(i + layer)).ToArray(); GD.UpdateTexture( copySrc, data, 0, 0, 0, 16, 16, 1, 0, layer); } CommandList copyCL = RF.CreateCommandList(); copyCL.Begin(); if (separateLayerCopies) { for (uint layer = 0; layer < copySrc.ArrayLayers; layer++) { copyCL.CopyTexture(copySrc, 0, 0, 0, 0, layer, copyDst, 0, 0, 0, 0, layer, 16, 16, 1, 1); } } else { copyCL.CopyTexture(copySrc, 0, 0, 0, 0, 0, copyDst, 0, 0, 0, 0, 0, 16, 16, 1, copySrc.ArrayLayers); } copyCL.End(); Fence fence = RF.CreateFence(false); GD.SubmitCommands(copyCL, fence); GD.WaitForFence(fence); for (uint layer = 0; layer < copyDst.ArrayLayers; layer++) { MappedResource map = GD.Map(copyDst, MapMode.Read, layer); byte * basePtr = (byte *)map.Data; int index = 0; uint rowSize = 64; uint numRows = 4; for (uint row = 0; row < numRows; row++) { byte *rowBase = basePtr + (row * map.RowPitch); for (uint x = 0; x < rowSize; x++) { Assert.Equal((byte)(index + layer), rowBase[x]); index += 1; } } GD.Unmap(copyDst, layer); } }
public void Points_WithUShortColor() { Texture target = RF.CreateTexture(TextureDescription.Texture2D( 50, 50, 1, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.RenderTarget)); Texture staging = RF.CreateTexture(TextureDescription.Texture2D( 50, 50, 1, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.Staging)); Framebuffer framebuffer = RF.CreateFramebuffer(new FramebufferDescription(null, target)); DeviceBuffer infoBuffer = RF.CreateBuffer(new BufferDescription(16, BufferUsage.UniformBuffer)); DeviceBuffer orthoBuffer = RF.CreateBuffer(new BufferDescription(64, BufferUsage.UniformBuffer)); Matrix4x4 orthoMatrix = Matrix4x4.CreateOrthographicOffCenter( 0, framebuffer.Width, framebuffer.Height, 0, -1, 1); GD.UpdateBuffer(orthoBuffer, 0, ref orthoMatrix); ShaderSetDescription shaderSet = new ShaderSetDescription( new VertexLayoutDescription[] { new VertexLayoutDescription( new VertexElementDescription("Position", VertexElementSemantic.Position, VertexElementFormat.Float2), new VertexElementDescription("Color_UInt", VertexElementSemantic.Color, VertexElementFormat.UShort4)) }, new Shader[] { TestShaders.Load(RF, "U16VertexAttribs", ShaderStages.Vertex, "VS"), TestShaders.Load(RF, "U16VertexAttribs", ShaderStages.Fragment, "FS") }); ResourceLayout layout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("InfoBuffer", ResourceKind.UniformBuffer, ShaderStages.Vertex), new ResourceLayoutElementDescription("Ortho", ResourceKind.UniformBuffer, ShaderStages.Vertex))); ResourceSet set = RF.CreateResourceSet(new ResourceSetDescription(layout, infoBuffer, orthoBuffer)); GraphicsPipelineDescription gpd = new GraphicsPipelineDescription( BlendStateDescription.SingleOverrideBlend, DepthStencilStateDescription.Disabled, RasterizerStateDescription.Default, PrimitiveTopology.PointList, shaderSet, layout, framebuffer.OutputDescription); Pipeline pipeline = RF.CreateGraphicsPipeline(ref gpd); uint colorNormalizationFactor = 2500; VertexCPU_UShort[] vertices = new VertexCPU_UShort[] { new VertexCPU_UShort { Position = new Vector2(0.5f, 0.5f), R = (ushort)(0.25f * colorNormalizationFactor), G = (ushort)(0.5f * colorNormalizationFactor), B = (ushort)(0.75f * colorNormalizationFactor), }, new VertexCPU_UShort { Position = new Vector2(10.5f, 12.5f), R = (ushort)(0.25f * colorNormalizationFactor), G = (ushort)(0.5f * colorNormalizationFactor), B = (ushort)(0.75f * colorNormalizationFactor), }, new VertexCPU_UShort { Position = new Vector2(25.5f, 35.5f), R = (ushort)(0.75f * colorNormalizationFactor), G = (ushort)(0.5f * colorNormalizationFactor), B = (ushort)(0.25f * colorNormalizationFactor), }, new VertexCPU_UShort { Position = new Vector2(49.5f, 49.5f), R = (ushort)(0.15f * colorNormalizationFactor), G = (ushort)(0.2f * colorNormalizationFactor), B = (ushort)(0.35f * colorNormalizationFactor), }, }; DeviceBuffer vb = RF.CreateBuffer( new BufferDescription((uint)(Unsafe.SizeOf <UIntVertexAttribs.Vertex>() * vertices.Length), BufferUsage.VertexBuffer)); GD.UpdateBuffer(vb, 0, vertices); GD.UpdateBuffer(infoBuffer, 0, new UIntVertexAttribs.Info { ColorNormalizationFactor = colorNormalizationFactor }); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.SetFramebuffer(framebuffer); cl.SetFullViewports(); cl.SetFullScissorRects(); cl.ClearColorTarget(0, RgbaFloat.Black); cl.SetPipeline(pipeline); cl.SetVertexBuffer(0, vb); cl.SetGraphicsResourceSet(0, set); cl.Draw((uint)vertices.Length); cl.SetFramebuffer(GD.SwapchainFramebuffer); cl.ClearColorTarget(0, RgbaFloat.Red); cl.CopyTexture(target, staging); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); MappedResourceView <RgbaFloat> readView = GD.Map <RgbaFloat>(staging, MapMode.Read); foreach (VertexCPU_UShort vertex in vertices) { uint x = (uint)vertex.Position.X; uint y = (uint)vertex.Position.Y; if (GD.BackendType == GraphicsBackend.OpenGL) { y = framebuffer.Height - y - 1; } RgbaFloat expectedColor = new RgbaFloat( vertex.R / (float)colorNormalizationFactor, vertex.G / (float)colorNormalizationFactor, vertex.B / (float)colorNormalizationFactor, 1); Assert.Equal(expectedColor, readView[x, y], RgbaFloatFuzzyComparer.Instance); } GD.Unmap(staging); }
public unsafe void Points_WithTexture_UpdateUnrelated(bool useTextureView) { // This is a regression test for the case where a user modifies an unrelated texture // at a time after a ResourceSet containing a texture has been bound. The OpenGL // backend was caching texture state improperly, resulting in wrong textures being sampled. Texture target = RF.CreateTexture(TextureDescription.Texture2D( 50, 50, 1, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.RenderTarget)); Texture staging = RF.CreateTexture(TextureDescription.Texture2D( 50, 50, 1, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.Staging)); Framebuffer framebuffer = RF.CreateFramebuffer(new FramebufferDescription(null, target)); DeviceBuffer orthoBuffer = RF.CreateBuffer(new BufferDescription(64, BufferUsage.UniformBuffer)); Matrix4x4 orthoMatrix = Matrix4x4.CreateOrthographicOffCenter( 0, framebuffer.Width, framebuffer.Height, 0, -1, 1); GD.UpdateBuffer(orthoBuffer, 0, ref orthoMatrix); Texture sampledTexture = RF.CreateTexture( TextureDescription.Texture2D(1, 1, 1, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.Sampled)); RgbaFloat white = RgbaFloat.White; GD.UpdateTexture(sampledTexture, (IntPtr)(&white), (uint)Unsafe.SizeOf <RgbaFloat>(), 0, 0, 0, 1, 1, 1, 0, 0); Texture shouldntBeSampledTexture = RF.CreateTexture( TextureDescription.Texture2D(1, 1, 1, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.Sampled)); ShaderSetDescription shaderSet = new ShaderSetDescription( new VertexLayoutDescription[] { new VertexLayoutDescription( new VertexElementDescription("Position", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float2)) }, TestShaders.LoadVertexFragment(RF, "TexturedPoints")); ResourceLayout layout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("Ortho", ResourceKind.UniformBuffer, ShaderStages.Vertex), new ResourceLayoutElementDescription("Tex", ResourceKind.TextureReadOnly, ShaderStages.Fragment), new ResourceLayoutElementDescription("Smp", ResourceKind.Sampler, ShaderStages.Fragment))); ResourceSet set; if (useTextureView) { TextureView view = RF.CreateTextureView(sampledTexture); set = RF.CreateResourceSet(new ResourceSetDescription(layout, orthoBuffer, view, GD.PointSampler)); } else { set = RF.CreateResourceSet(new ResourceSetDescription(layout, orthoBuffer, sampledTexture, GD.PointSampler)); } GraphicsPipelineDescription gpd = new GraphicsPipelineDescription( BlendStateDescription.SingleOverrideBlend, DepthStencilStateDescription.Disabled, RasterizerStateDescription.Default, PrimitiveTopology.PointList, shaderSet, layout, framebuffer.OutputDescription); Pipeline pipeline = RF.CreateGraphicsPipeline(ref gpd); Vector2[] vertices = new Vector2[] { new Vector2(0.5f, 0.5f), new Vector2(15.5f, 15.5f), new Vector2(25.5f, 26.5f), new Vector2(3.5f, 25.5f), }; DeviceBuffer vb = RF.CreateBuffer( new BufferDescription((uint)(Unsafe.SizeOf <Vector2>() * vertices.Length), BufferUsage.VertexBuffer)); GD.UpdateBuffer(vb, 0, vertices); CommandList cl = RF.CreateCommandList(); for (int i = 0; i < 2; i++) { cl.Begin(); cl.SetFramebuffer(framebuffer); cl.ClearColorTarget(0, RgbaFloat.Black); cl.SetPipeline(pipeline); cl.SetVertexBuffer(0, vb); cl.SetGraphicsResourceSet(0, set); // Modify an unrelated texture. // This must have no observable effect on the next draw call. RgbaFloat pink = RgbaFloat.Pink; GD.UpdateTexture(shouldntBeSampledTexture, (IntPtr)(&pink), (uint)Unsafe.SizeOf <RgbaFloat>(), 0, 0, 0, 1, 1, 1, 0, 0); cl.Draw((uint)vertices.Length); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); } cl.Begin(); cl.CopyTexture(target, staging); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); MappedResourceView <RgbaFloat> readView = GD.Map <RgbaFloat>(staging, MapMode.Read); foreach (Vector2 vertex in vertices) { uint x = (uint)vertex.X; uint y = (uint)vertex.Y; if (!GD.IsUvOriginTopLeft || GD.IsClipSpaceYInverted) { y = framebuffer.Height - y - 1; } Assert.Equal(white, readView[x, y], RgbaFloatFuzzyComparer.Instance); } GD.Unmap(staging); }
public void ComputeGeneratedVertices() { if (!GD.Features.ComputeShader) { return; } uint width = 512; uint height = 512; Texture output = RF.CreateTexture( TextureDescription.Texture2D(width, height, 1, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.RenderTarget)); Framebuffer framebuffer = RF.CreateFramebuffer(new FramebufferDescription(null, output)); uint vertexSize = (uint)Unsafe.SizeOf <ColoredVertex>(); DeviceBuffer buffer = RF.CreateBuffer(new BufferDescription( vertexSize * 4, BufferUsage.StructuredBufferReadWrite, vertexSize, true)); ResourceLayout computeLayout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("OutputVertices", ResourceKind.StructuredBufferReadWrite, ShaderStages.Compute))); ResourceSet computeSet = RF.CreateResourceSet(new ResourceSetDescription(computeLayout, buffer)); Pipeline computePipeline = RF.CreateComputePipeline(new ComputePipelineDescription( TestShaders.LoadCompute(RF, "ComputeColoredQuadGenerator"), computeLayout, 1, 1, 1)); ResourceLayout graphicsLayout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("InputVertices", ResourceKind.StructuredBufferReadOnly, ShaderStages.Vertex))); ResourceSet graphicsSet = RF.CreateResourceSet(new ResourceSetDescription(graphicsLayout, buffer)); Pipeline graphicsPipeline = RF.CreateGraphicsPipeline(new GraphicsPipelineDescription( BlendStateDescription.SingleOverrideBlend, DepthStencilStateDescription.Disabled, RasterizerStateDescription.Default, PrimitiveTopology.TriangleStrip, new ShaderSetDescription( Array.Empty <VertexLayoutDescription>(), TestShaders.LoadVertexFragment(RF, "ColoredQuadRenderer")), graphicsLayout, framebuffer.OutputDescription)); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.SetPipeline(computePipeline); cl.SetComputeResourceSet(0, computeSet); cl.Dispatch(1, 1, 1); cl.SetFramebuffer(framebuffer); cl.ClearColorTarget(0, new RgbaFloat()); cl.SetPipeline(graphicsPipeline); cl.SetGraphicsResourceSet(0, graphicsSet); cl.Draw(4); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); Texture readback = GetReadback(output); MappedResourceView <RgbaFloat> readView = GD.Map <RgbaFloat>(readback, MapMode.Read); for (uint y = 0; y < height; y++) { for (uint x = 0; x < width; x++) { Assert.Equal(RgbaFloat.Red, readView[x, y]); } } GD.Unmap(readback); }