/// <summary>
        /// Executes a given test for a specified shader.
        /// </summary>
        /// <typeparam name="T">The type of shader to test.</typeparam>
        /// <param name="device">The device to use.</param>
        /// <param name="factory">A producer to create an instance of the shader to run.</param>
        /// <param name="delta">The comparison delta.</param>
        private static void RunAndCompareShader <T>(Device device, Func <ReadWriteTexture2D <Rgba32, Float4>, T> factory, float delta)
            where T : struct, IComputeShader
        {
            _ = device.Get();

            string expectedPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) !, "Assets", $"{typeof(T).Name}.png");

            IImageInfo imageInfo = Image.Identify(expectedPath);

            using Image <ImageSharpRgba32> image = new(imageInfo.Width, imageInfo.Height);

            using (ReadWriteTexture2D <Rgba32, Float4> texture = device.Get().AllocateReadWriteTexture2D <Rgba32, Float4>(imageInfo.Width, imageInfo.Height))
            {
                device.Get().For(texture.Width, texture.Height, factory(texture));

                _ = image.TryGetSinglePixelSpan(out Span <ImageSharpRgba32> span);

                texture.CopyTo(MemoryMarshal.Cast <ImageSharpRgba32, Rgba32>(span));
            }

            string actualPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) !, "Shaders", $"{typeof(T).Name}.png");

            _ = Directory.CreateDirectory(Path.GetDirectoryName(actualPath) !);

            image.SaveAsPng(actualPath, new PngEncoder()
            {
                CompressionLevel = PngCompressionLevel.BestCompression, ColorType = PngColorType.Rgb
            });

            ImagingTests.TolerantImageComparer.AssertEqual(expectedPath, actualPath, delta);
        }
Beispiel #2
0
    /// <summary>
    /// Retrieves a wrapping <see cref="IReadOnlyNormalizedTexture2D{TPixel}"/> instance for the input resource.
    /// </summary>
    /// <typeparam name="T">The type of items to store in the texture.</typeparam>
    /// <typeparam name="TPixel">The type of pixels used on the GPU side.</typeparam>
    /// <param name="texture">The input <see cref="ReadWriteTexture2D{T, TPixel}"/> instance to create a wrapper for.</param>
    /// <returns>An <see cref="IReadOnlyNormalizedTexture2D{TPixel}"/> instance wrapping the current resource.</returns>
    /// <remarks>
    /// <para>The returned instance can be used in a shader to enable texture sampling.</para>
    /// <para>
    /// This is an advanced API that can only be used after the current instance has been transitioned to be in a readonly state. To do so,
    /// use <see cref="ComputeContextExtensions.Transition{T, TPixel}(in ComputeContext, ReadWriteTexture2D{T, TPixel}, ResourceState)"/>,
    /// and specify <see cref="ResourceState.ReadOnly"/>. After that, this method can be used to get a readonly wrapper for
    /// the current texture to use in a shader. This instance should not be cached or reused, but just passed directly to a shader
    /// being dispatched through that same <see cref="ComputeContext"/>, as it will not work if the texture changes state later on.
    /// Before the end of that list of operations, the texture also needs to be transitioned back to writeable state, using the same
    /// API as before but specifying <see cref="ResourceState.ReadWrite"/>. Failing to do so results in undefined behavior.
    /// </para>
    /// </remarks>
    /// <exception cref="ObjectDisposedException">Thrown if the current instance or its associated device are disposed.</exception>
    /// <exception cref="InvalidOperationException">Thrown if the current instance is not in a readonly state.</exception>
    public static IReadOnlyNormalizedTexture2D <TPixel> AsReadOnly <T, TPixel>(this ReadWriteTexture2D <T, TPixel> texture)
        where T : unmanaged, IPixel <T, TPixel>
        where TPixel : unmanaged
    {
        Guard.IsNotNull(texture);

        return(texture.AsReadOnly());
    }
        public static ulong ValidateAndGetGpuDescriptorHandle <T>(ReadWriteTexture2D <T> texture, GraphicsDevice device)
            where T : unmanaged
        {
            texture.ThrowIfDisposed();
            texture.ThrowIfDeviceMismatch(device);

            return(Unsafe.As <D3D12_GPU_DESCRIPTOR_HANDLE, ulong>(ref Unsafe.AsRef(in texture.D3D12GpuDescriptorHandle)));
        }
                static void RunComputeShader <T>(ReadWriteTexture2D <Rgba32, float4> texture)
                    where T : struct, IComputeShader
                {
                    ShaderInfo info = ReflectionServices.GetShaderInfo <T>();

                    Assert.IsFalse(info.RequiresDoublePrecisionSupport);

                    texture.GraphicsDevice.For(texture.Width, texture.Height, (T)Activator.CreateInstance(typeof(T), texture, 0f) !);
                }
    public void Dispatch_NormalizedTexture2D(Device device, Type t, Type tPixel)
    {
        if (t == typeof(Bgra32) && tPixel == typeof(Float4))
        {
            using ReadOnlyTexture2D <Bgra32, Float4> source       = device.Get().AllocateReadOnlyTexture2D <Bgra32, Float4>(128, 128);
            using ReadWriteTexture2D <Bgra32, Float4> destination = device.Get().AllocateReadWriteTexture2D <Bgra32, Float4>(128, 128);

            device.Get().For(128, 128, new Shader_Unorm_Bgra32_Float4(source, destination));
        }
        if (t == typeof(R16) && tPixel == typeof(float))
        {
            using ReadOnlyTexture2D <R16, float> source       = device.Get().AllocateReadOnlyTexture2D <R16, float>(128, 128);
            using ReadWriteTexture2D <R16, float> destination = device.Get().AllocateReadWriteTexture2D <R16, float>(128, 128);

            device.Get().For(128, 128, new Shader_Unorm_R16_float(source, destination));
        }
        if (t == typeof(R8) && tPixel == typeof(float))
        {
            using ReadOnlyTexture2D <R8, float> source       = device.Get().AllocateReadOnlyTexture2D <R8, float>(128, 128);
            using ReadWriteTexture2D <R8, float> destination = device.Get().AllocateReadWriteTexture2D <R8, float>(128, 128);

            device.Get().For(128, 128, new Shader_Unorm_R8_float(source, destination));
        }
        if (t == typeof(Rg16) && tPixel == typeof(Float2))
        {
            using ReadOnlyTexture2D <Rg16, Float2> source       = device.Get().AllocateReadOnlyTexture2D <Rg16, Float2>(128, 128);
            using ReadWriteTexture2D <Rg16, Float2> destination = device.Get().AllocateReadWriteTexture2D <Rg16, Float2>(128, 128);

            device.Get().For(128, 128, new Shader_Unorm_Rg16_Float2(source, destination));
        }
        if (t == typeof(Rg32) && tPixel == typeof(Float2))
        {
            using ReadOnlyTexture2D <Rg32, Float2> source       = device.Get().AllocateReadOnlyTexture2D <Rg32, Float2>(128, 128);
            using ReadWriteTexture2D <Rg32, Float2> destination = device.Get().AllocateReadWriteTexture2D <Rg32, Float2>(128, 128);

            device.Get().For(128, 128, new Shader_Unorm_Rg32_Float2(source, destination));
        }
        if (t == typeof(Rgba32) && tPixel == typeof(Float4))
        {
            using ReadOnlyTexture2D <Rgba32, Float4> source       = device.Get().AllocateReadOnlyTexture2D <Rgba32, Float4>(128, 128);
            using ReadWriteTexture2D <Rgba32, Float4> destination = device.Get().AllocateReadWriteTexture2D <Rgba32, Float4>(128, 128);

            device.Get().For(128, 128, new Shader_Unorm_Rgba32_Float4(source, destination));
        }
        if (t == typeof(Rgba64) && tPixel == typeof(Float4))
        {
            using ReadOnlyTexture2D <Rgba64, Float4> source       = device.Get().AllocateReadOnlyTexture2D <Rgba64, Float4>(128, 128);
            using ReadWriteTexture2D <Rgba64, Float4> destination = device.Get().AllocateReadWriteTexture2D <Rgba64, Float4>(128, 128);

            device.Get().For(128, 128, new Shader_Unorm_Rgba64_Float4(source, destination));
        }
    }
    /// <summary>
    /// Executes a given test for a specified shader.
    /// </summary>
    /// <param name="device">The device to use.</param>
    /// <param name="shaderType">The type of shader being executed.</param>
    /// <param name="delta">The comparison delta.</param>
    private static void RunAndCompareShader(Device device, Type shaderType, float delta)
    {
        _ = device.Get();

        string expectedPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) !, "Assets", $"{shaderType.Name}.png");

        IImageInfo imageInfo = Image.Identify(expectedPath);

        using Image <ImageSharpRgba32> image = new(imageInfo.Width, imageInfo.Height);

        using (ReadWriteTexture2D <Rgba32, float4> texture = device.Get().AllocateReadWriteTexture2D <Rgba32, float4>(imageInfo.Width, imageInfo.Height))
        {
            if (typeof(IComputeShader).IsAssignableFrom(shaderType))
            {
    /// <summary>
    /// Applies the actual resize logic that was scheduled from <see cref="OnResize"/>.
    /// </summary>
    private unsafe void ApplyResize()
    {
        this.d3D12CommandQueue.Get()->Signal(this.d3D12Fence.Get(), this.nextD3D12FenceValue);

        // Wait for the fence again to ensure there are no pending operations
        this.d3D12Fence.Get()->SetEventOnCompletion(this.nextD3D12FenceValue, default);

        this.nextD3D12FenceValue++;

        // Dispose the old buffers before resizing the buffer
        this.d3D12Resource0.Dispose();
        this.d3D12Resource1.Dispose();

        // Resize the swap chain buffers
        this.dxgiSwapChain1.Get()->ResizeBuffers(0, 0, 0, DXGI_FORMAT.DXGI_FORMAT_UNKNOWN, 0);

        // Get the index of the initial back buffer
        using (ComPtr <IDXGISwapChain3> dxgiSwapChain3 = default)
        {
            _ = this.dxgiSwapChain1.CopyTo(dxgiSwapChain3.GetAddressOf());

            this.currentBufferIndex = dxgiSwapChain3.Get()->GetCurrentBackBufferIndex();
        }

        // Retrieve the back buffers for the swap chain
        fixed(ID3D12Resource **d3D12Resource0 = this.d3D12Resource0)
        fixed(ID3D12Resource **d3D12Resource1 = this.d3D12Resource1)
        {
            _ = dxgiSwapChain1.Get()->GetBuffer(0, Windows.__uuidof <ID3D12Resource>(), (void **)d3D12Resource0);
            _ = dxgiSwapChain1.Get()->GetBuffer(1, Windows.__uuidof <ID3D12Resource>(), (void **)d3D12Resource1);
        }

        this.texture?.Dispose();

        D3D12_RESOURCE_DESC d3D12Resource0Description = this.d3D12Resource0.Get()->GetDesc();

        // Create the 2D texture to use to generate frames to display
        this.texture = GraphicsDevice.Default.AllocateReadWriteTexture2D <Rgba32, float4>(
            (int)d3D12Resource0Description.Width,
            (int)d3D12Resource0Description.Height);
    }
Beispiel #8
0
    public void Verify_DispatchAsPixelShader(Device device)
    {
        using ReadWriteTexture2D <Rgba32, float4> texture = device.Get().AllocateReadWriteTexture2D <Rgba32, float4>(256, 256);

        device.Get().ForEach <DispatchPixelShader, float4>(texture);

        Rgba32[,] data = texture.ToArray();

        for (int y = 0; y < texture.Height; y++)
        {
            for (int x = 0; x < texture.Width; x++)
            {
                Rgba32 pixel = data[y, x];

                Assert.AreEqual((float)pixel.R / 255, (float)x / texture.Width, 0.1f);
                Assert.AreEqual((float)pixel.G / 255, (float)y / texture.Height, 0.1f);
                Assert.AreEqual(pixel.B, 255);
                Assert.AreEqual(pixel.A, 255);
            }
        }
    }
    public unsafe void PixelShader_EarlyReturn(Device device)
    {
        using ReadWriteTexture2D <Rgba32, float4> texture = device.Get().AllocateReadWriteTexture2D <Rgba32, float4>(128, 128);

        device.Get().ForEach <EarlyReturnShader, float4>(texture);

        Rgba32[,] result = texture.ToArray();

        for (int i = 0; i < texture.Height; i++)
        {
            for (int j = 0; j < texture.Width; j++)
            {
                if (j % 2 == 0)
                {
                    Assert.AreEqual(result[i, j], new Rgba32(255, 0, 0, 0));
                }
                else
                {
                    Assert.AreEqual(result[i, j], new Rgba32(0, 255, 0, 0));
                }
            }
        }
    }
 static ReadOnly InitializeWrapper(ReadWriteTexture2D <T> texture)
 {
     return(texture.readOnlyWrapper = new(texture));
 }
Beispiel #11
0
    /// <summary>
    /// Retrieves a wrapping <see cref="IReadOnlyTexture2D{T}"/> instance for the input resource.
    /// </summary>
    /// <param name="texture">The input <see cref="ReadWriteTexture2D{T}"/> instance to create a wrapper for.</param>
    /// <returns>An <see cref="IReadOnlyTexture2D{T}"/> instance wrapping the current resource.</returns>
    /// <remarks>
    /// <para>The returned instance can be used in a shader to enable texture sampling.</para>
    /// <para>
    /// This is an advanced API that can only be used after the current instance has been transitioned to be in a readonly state. To do so,
    /// use <see cref="ComputeContextExtensions.Transition(in ComputeContext, ReadWriteTexture2D{Float3}, ResourceState)"/>,
    /// and specify <see cref="ResourceState.ReadOnly"/>. After that, this method can be used to get a readonly wrapper for
    /// the current texture to use in a shader. This instance should not be cached or reused, but just passed directly to a shader
    /// being dispatched through that same <see cref="ComputeContext"/>, as it will not work if the texture changes state later on.
    /// Before the end of that list of operations, the texture also needs to be transitioned back to writeable state, using the same
    /// API as before but specifying <see cref="ResourceState.ReadWrite"/>. Failing to do so results in undefined behavior.
    /// </para>
    /// </remarks>
    /// <exception cref="ObjectDisposedException">Thrown if the current instance or its associated device are disposed.</exception>
    /// <exception cref="InvalidOperationException">Thrown if the current instance is not in a readonly state.</exception>
    public static IReadOnlyTexture2D <Float3> AsReadOnly(this ReadWriteTexture2D <Float3> texture)
    {
        Guard.IsNotNull(texture);

        return(texture.AsReadOnly());
    }