Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        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);
        }
        protected override void Draw(float delta)
        {
            if (InputTracker.GetKeyDown(Key.F1))
            {
                _lightFromCamera = !_lightFromCamera;
            }

            // Begin() must be called before commands can be issued.
            _commandList.Begin();

            // Update per-frame resources.
            MappedResourceView <Matrix4x4> writeMap = GraphicsDevice.Map <Matrix4x4>(_cameraProjViewBuffer, MapMode.Write);

            writeMap[0] = _camera.ViewMatrix;
            writeMap[1] = _camera.ProjectionMatrix;
            GraphicsDevice.Unmap(_cameraProjViewBuffer);

            if (_lightFromCamera)
            {
                GraphicsDevice.UpdateBuffer(_lightInfoBuffer, 0, new LightInfo(_camera.Forward, _camera.Position));
            }
            else
            {
                GraphicsDevice.UpdateBuffer(_lightInfoBuffer, 0, new LightInfo(_lightDir, _camera.Position));
            }

            _localRotation  += delta * ((float)Math.PI * 2 / 9);
            _globalRotation += -delta * ((float)Math.PI * 2 / 240);
            GraphicsDevice.UpdateBuffer(_rotationInfoBuffer, 0, new Vector4(_localRotation, _globalRotation, 0, 0));

            Matrix4x4.Invert(_camera.ProjectionMatrix, out Matrix4x4 inverseProjection);
            Matrix4x4.Invert(_camera.ViewMatrix, out Matrix4x4 inverseView);
            GraphicsDevice.UpdateBuffer(_viewInfoBuffer, 0, new InvCameraInfo(
                                            inverseProjection,
                                            inverseView));

            // We want to render directly to the output window.
            _commandList.SetFramebuffer(MainSwapchain.Framebuffer);
            _commandList.ClearColorTarget(0, RgbaFloat.White);
            _commandList.ClearDepthStencil(1f);

            //// First, draw the background starfield.
            _commandList.SetPipeline(_starfieldPipeline);
            _commandList.SetGraphicsResourceSet(0, _viewInfoSet);
            _commandList.Draw(4);

            // Next, draw our orbiting rocks with instanced drawing.
            _commandList.SetPipeline(_instancePipeline);
            // Set uniforms
            _commandList.SetGraphicsResourceSet(0, _sharedResourceSet); // Always after SetPipeline
            _commandList.SetGraphicsResourceSet(1, _instanceTextureSet);

            _commandList.SetVertexBuffer(0, _rockModel.VertexBuffer);
            _commandList.SetIndexBuffer(_rockModel.IndexBuffer, _rockModel.IndexFormat);
            _commandList.SetVertexBuffer(1, _instanceVB);

            // Issue a Draw command for two instances with 4 indices.
            _commandList.DrawIndexed(
                indexCount: _rockModel.IndexCount,
                instanceCount: _instanceCount,
                indexStart: 0,
                vertexOffset: 0,
                instanceStart: 0);

            // Next, we draw our central planet.
            _commandList.SetPipeline(_planetPipeline);
            _commandList.SetGraphicsResourceSet(1, _planetTextureSet);
            _commandList.SetVertexBuffer(0, _planetModel.VertexBuffer);
            _commandList.SetIndexBuffer(_planetModel.IndexBuffer, _planetModel.IndexFormat);

            // The planet is drawn with regular indexed drawing -- not instanced.
            _commandList.DrawIndexed(_planetModel.IndexCount);

            // End() must be called before commands can be submitted for execution.
            _commandList.End();
            GraphicsDevice.SubmitCommands(_commandList);

            // Once commands have been submitted, the rendered image can be presented to the application window.
            GraphicsDevice.SwapBuffers(MainSwapchain);
        }
Ejemplo n.º 4
0
    public static unsafe Texture CreateArrayTexture <T>(GraphicsDevice gd, TextureUsage usage, IReadOnlyTexture <T> texture) where T : unmanaged
    {
        if (gd == null)
        {
            throw new ArgumentNullException(nameof(gd));
        }
        if (texture == null)
        {
            throw new ArgumentNullException(nameof(texture));
        }

        var  pixelFormat = GetFormat(typeof(T));
        bool mip         = (usage & TextureUsage.GenerateMipmaps) != 0;
        uint mipLevels   = mip ? MipLevelCount(texture.Width, texture.Height) : 1;

        using Texture staging = gd.ResourceFactory.CreateTexture(new TextureDescription(
                                                                     (uint)texture.Width, (uint)texture.Height, 1, mipLevels,
                                                                     (uint)texture.ArrayLayers,
                                                                     pixelFormat,
                                                                     TextureUsage.Staging,
                                                                     TextureType.Texture2D));

        staging.Name = "T_" + texture.Name + "_Staging";

        for (int layer = 0; layer < texture.ArrayLayers; layer++)
        {
            var mapped = gd.Map(staging, MapMode.Write, (uint)layer * mipLevels);
            try
            {
                var span  = new Span <T>(mapped.Data.ToPointer(), (int)mapped.SizeInBytes / sizeof(T));
                int pitch = (int)(mapped.RowPitch / sizeof(T));

                var source = texture.GetLayerBuffer(layer);
                var dest   = new ImageBuffer <T>(texture.Width, texture.Height, pitch, span);

                BlitUtil.BlitDirect(source, dest);

                //gd.UpdateTexture(
                //    staging, (IntPtr) texDataPtr, (uint) (buffer.Buffer.Length * Unsafe.SizeOf<T>()),
                //    0, 0, 0,
                //    (uint) texture.Width, (uint) texture.Height, 1,
                //    0, (uint) layer);
            }
            finally { gd.Unmap(staging, (uint)layer * mipLevels); }
        }

        Texture veldridTexture = gd.ResourceFactory.CreateTexture(new TextureDescription(
                                                                      (uint)texture.Width, (uint)texture.Height, 1,
                                                                      mipLevels,
                                                                      (uint)texture.ArrayLayers,
                                                                      pixelFormat,
                                                                      usage,
                                                                      TextureType.Texture2D));

        veldridTexture.Name = "T_" + texture.Name;

        using CommandList cl = gd.ResourceFactory.CreateCommandList();
        cl.Begin();
        cl.CopyTexture(staging, veldridTexture);
        if (mip)
        {
            cl.GenerateMipmaps(veldridTexture);
        }
        cl.End();
        gd.SubmitCommands(cl);

        return(veldridTexture);
    }
Ejemplo n.º 5
0
        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);
        }
Ejemplo n.º 6
0
        static void Main(string[] args)
        {
            _useOculus = true;
            if (!VRContext.IsOculusSupported())
            {
                _useOculus = false;
                if (!VRContext.IsOpenVRSupported())
                {
                    Console.WriteLine("This sample requires an Oculus or OpenVR-capable headset.");
                    return;
                }
            }

            Sdl2Window window = VeldridStartup.CreateWindow(
                new WindowCreateInfo(
                    Sdl2Native.SDL_WINDOWPOS_CENTERED, Sdl2Native.SDL_WINDOWPOS_CENTERED,
                    1280, 720,
                    WindowState.Normal,
                    "Veldrid.VirtualReality Sample"));

            VRContextOptions options = new VRContextOptions
            {
                EyeFramebufferSampleCount = TextureSampleCount.Count4
            };
            VRContext vrContext = _useOculus ? VRContext.CreateOculus(options) : VRContext.CreateOpenVR(options);

            GraphicsBackend backend = GraphicsBackend.Direct3D11;

            bool debug = false;

#if DEBUG
            debug = true;
#endif

            GraphicsDeviceOptions gdo = new GraphicsDeviceOptions(debug, null, false, ResourceBindingModel.Improved, true, true, true);

            if (backend == GraphicsBackend.Vulkan)
            {
                // Oculus runtime causes validation errors.
                gdo.Debug = false;
            }

            (GraphicsDevice gd, Swapchain sc) = CreateDeviceAndSwapchain(window, vrContext, backend, gdo);
            window.Resized += () => sc.Resize((uint)window.Width, (uint)window.Height);

            vrContext.Initialize(gd);

            ImGuiRenderer igr = new ImGuiRenderer(gd, sc.Framebuffer.OutputDescription, window.Width, window.Height, ColorSpaceHandling.Linear);
            window.Resized += () => igr.WindowResized(window.Width, window.Height);

            AssimpMesh mesh = new AssimpMesh(
                gd,
                vrContext.LeftEyeFramebuffer.OutputDescription,
                Path.Combine(AppContext.BaseDirectory, "cat", "cat.obj"),
                Path.Combine(AppContext.BaseDirectory, "cat", "cat_diff.png"));

            Skybox skybox = new Skybox(
                Image.Load(Path.Combine(AppContext.BaseDirectory, "skybox", "miramar_ft.png")),
                Image.Load(Path.Combine(AppContext.BaseDirectory, "skybox", "miramar_bk.png")),
                Image.Load(Path.Combine(AppContext.BaseDirectory, "skybox", "miramar_lf.png")),
                Image.Load(Path.Combine(AppContext.BaseDirectory, "skybox", "miramar_rt.png")),
                Image.Load(Path.Combine(AppContext.BaseDirectory, "skybox", "miramar_up.png")),
                Image.Load(Path.Combine(AppContext.BaseDirectory, "skybox", "miramar_dn.png")));
            skybox.CreateDeviceObjects(gd, vrContext.LeftEyeFramebuffer.OutputDescription);

            CommandList windowCL = gd.ResourceFactory.CreateCommandList();
            CommandList eyesCL   = gd.ResourceFactory.CreateCommandList();

            MirrorTextureEyeSource eyeSource = MirrorTextureEyeSource.BothEyes;

            Stopwatch sw            = Stopwatch.StartNew();
            double    lastFrameTime = sw.Elapsed.TotalSeconds;

            while (window.Exists)
            {
                double newFrameTime = sw.Elapsed.TotalSeconds;
                double deltaSeconds = newFrameTime - lastFrameTime;
                lastFrameTime = newFrameTime;

                InputSnapshot snapshot = window.PumpEvents();
                if (!window.Exists)
                {
                    break;
                }
                InputTracker.UpdateFrameInput(snapshot);
                HandleInputs(deltaSeconds);

                igr.Update(1f / 60f, snapshot);

                if (ImGui.BeginMainMenuBar())
                {
                    if (ImGui.BeginMenu("Settings"))
                    {
                        if (ImGui.BeginMenu("Mirror Texture"))
                        {
                            if (ImGui.MenuItem("Both Eyes", null, eyeSource == MirrorTextureEyeSource.BothEyes))
                            {
                                eyeSource = MirrorTextureEyeSource.BothEyes;
                            }
                            if (ImGui.MenuItem("Left Eye", null, eyeSource == MirrorTextureEyeSource.LeftEye))
                            {
                                eyeSource = MirrorTextureEyeSource.LeftEye;
                            }
                            if (ImGui.MenuItem("Right Eye", null, eyeSource == MirrorTextureEyeSource.RightEye))
                            {
                                eyeSource = MirrorTextureEyeSource.RightEye;
                            }

                            ImGui.EndMenu();
                        }

                        if (ImGui.BeginMenu("VR API"))
                        {
                            if (ImGui.MenuItem("Oculus", null, _useOculus) && !_useOculus)
                            {
                                _useOculus       = true;
                                _switchVRContext = true;
                            }
                            if (ImGui.MenuItem("OpenVR", null, !_useOculus) && _useOculus)
                            {
                                _useOculus       = false;
                                _switchVRContext = true;
                            }

                            ImGui.EndMenu();
                        }

                        ImGui.EndMenu();
                    }

                    ImGui.EndMainMenuBar();
                }

                windowCL.Begin();
                windowCL.SetFramebuffer(sc.Framebuffer);
                windowCL.ClearColorTarget(0, new RgbaFloat(0f, 0f, 0.2f, 1f));
                vrContext.RenderMirrorTexture(windowCL, sc.Framebuffer, eyeSource);
                igr.Render(gd, windowCL);
                windowCL.End();
                gd.SubmitCommands(windowCL);
                gd.SwapBuffers(sc);

                HmdPoseState poses = vrContext.WaitForPoses();

                // Render Eyes
                eyesCL.Begin();

                eyesCL.PushDebugGroup("Left Eye");
                Matrix4x4 leftView = poses.CreateView(VREye.Left, _userPosition, -Vector3.UnitZ, Vector3.UnitY);
                RenderEye(eyesCL, vrContext.LeftEyeFramebuffer, mesh, skybox, poses.LeftEyeProjection, leftView);
                eyesCL.PopDebugGroup();

                eyesCL.PushDebugGroup("Right Eye");
                Matrix4x4 rightView = poses.CreateView(VREye.Right, _userPosition, -Vector3.UnitZ, Vector3.UnitY);
                RenderEye(eyesCL, vrContext.RightEyeFramebuffer, mesh, skybox, poses.RightEyeProjection, rightView);
                eyesCL.PopDebugGroup();

                eyesCL.End();
                gd.SubmitCommands(eyesCL);

                vrContext.SubmitFrame();

                if (_switchVRContext)
                {
                    _switchVRContext = false;
                    vrContext.Dispose();
                    vrContext = _useOculus ? VRContext.CreateOculus() : VRContext.CreateOpenVR();
                    vrContext.Initialize(gd);
                }
            }

            vrContext.Dispose();
            gd.Dispose();
        }
Ejemplo n.º 7
0
        static int Main(string[] args)
        {
            if (args.Length != 2)
            {
                Console.WriteLine($"ImageTint <image-path> <out>: Tints the image at <image-path> and saves it to <out>.");
                return(1);
            }

            string inPath  = args[0];
            string outPath = args[1];

            // This demo uses WindowState.Hidden to avoid popping up an unnecessary window to the user.

            VeldridStartup.CreateWindowAndGraphicsDevice(
                new WindowCreateInfo
            {
                WindowInitialState = WindowState.Hidden,
            },
                new GraphicsDeviceOptions(),
                out Sdl2Window window,
                out GraphicsDevice gd);

            DisposeCollectorResourceFactory factory = new DisposeCollectorResourceFactory(gd.ResourceFactory);

            ImageSharpTexture inputImage   = new ImageSharpTexture(inPath, false);
            Texture           inputTexture = inputImage.CreateDeviceTexture(gd, factory);
            TextureView       view         = factory.CreateTextureView(inputTexture);

            Texture output = factory.CreateTexture(TextureDescription.Texture2D(
                                                       inputImage.Width,
                                                       inputImage.Height,
                                                       1,
                                                       1,
                                                       PixelFormat.R8_G8_B8_A8_UNorm,
                                                       TextureUsage.RenderTarget));
            Framebuffer framebuffer = factory.CreateFramebuffer(new FramebufferDescription(null, output));

            DeviceBuffer vertexBuffer = factory.CreateBuffer(new BufferDescription(64, BufferUsage.VertexBuffer));

            Vector4[] quadVerts =
            {
                new Vector4(-1,  1, 0, 0),
                new Vector4(1,   1, 1, 0),
                new Vector4(-1, -1, 0, 1),
                new Vector4(1,  -1, 1, 1),
            };
            gd.UpdateBuffer(vertexBuffer, 0, quadVerts);

            ShaderSetDescription shaderSet = new ShaderSetDescription(
                new[]
            {
                new VertexLayoutDescription(
                    new VertexElementDescription("Position", VertexElementSemantic.Position, VertexElementFormat.Float2),
                    new VertexElementDescription("TextureCoordinates", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float2))
            },
                new[]
            {
                SampleApplication.LoadShader(factory, "TintShader", ShaderStages.Vertex, "VS"),
                SampleApplication.LoadShader(factory, "TintShader", ShaderStages.Fragment, "FS")
            });

            ResourceLayout layout = factory.CreateResourceLayout(new ResourceLayoutDescription(
                                                                     new ResourceLayoutElementDescription("Input", ResourceKind.TextureReadOnly, ShaderStages.Fragment),
                                                                     new ResourceLayoutElementDescription("Sampler", ResourceKind.Sampler, ShaderStages.Fragment),
                                                                     new ResourceLayoutElementDescription("Tint", ResourceKind.UniformBuffer, ShaderStages.Fragment)));

            Pipeline pipeline = factory.CreateGraphicsPipeline(new GraphicsPipelineDescription(
                                                                   BlendStateDescription.SingleOverrideBlend,
                                                                   DepthStencilStateDescription.Disabled,
                                                                   RasterizerStateDescription.Default,
                                                                   PrimitiveTopology.TriangleStrip,
                                                                   shaderSet,
                                                                   layout,
                                                                   framebuffer.OutputDescription));

            DeviceBuffer tintInfoBuffer = factory.CreateBuffer(new BufferDescription(16, BufferUsage.UniformBuffer));

            gd.UpdateBuffer(
                tintInfoBuffer, 0,
                new TintInfo(
                    new Vector3(1f, 0.2f, 0.1f), // Change this to modify the tint color.
                    0.25f));

            ResourceSet resourceSet = factory.CreateResourceSet(
                new ResourceSetDescription(layout, view, gd.PointSampler, tintInfoBuffer));

            // RenderTarget textures are not CPU-visible, so to get our tinted image back, we need to first copy it into
            // a "staging Texture", which is a Texture that is CPU-visible (it can be Mapped).
            Texture stage = factory.CreateTexture(TextureDescription.Texture2D(
                                                      inputImage.Width,
                                                      inputImage.Height,
                                                      1,
                                                      1,
                                                      PixelFormat.R8_G8_B8_A8_UNorm,
                                                      TextureUsage.Staging));

            CommandList cl = factory.CreateCommandList();

            cl.Begin();
            cl.SetFramebuffer(framebuffer);
            cl.SetFullViewports();
            cl.SetVertexBuffer(0, vertexBuffer);
            cl.SetPipeline(pipeline);
            cl.SetGraphicsResourceSet(0, resourceSet);
            cl.Draw(4, 1, 0, 0);
            cl.CopyTexture(
                output, 0, 0, 0, 0, 0,
                stage, 0, 0, 0, 0, 0,
                stage.Width, stage.Height, 1, 1);
            cl.End();
            gd.SubmitCommands(cl);
            gd.WaitForIdle();

            // When a texture is mapped into a CPU-visible region, it is often not laid out linearly.
            // Instead, it is laid out as a series of rows, which are all spaced out evenly by a "row pitch".
            // This spacing is provided in MappedResource.RowPitch.

            // It is also possible to obtain a "structured view" of a mapped data region, which is what is done below.
            // With a structured view, you can read individual elements from the region.
            // The code below simply iterates over the two-dimensional region and places each texel into a linear buffer.
            // ImageSharp requires the pixel data be contained in a linear buffer.
            MappedResourceView <Rgba32> map = gd.Map <Rgba32>(stage, MapMode.Read);

            // Rgba32 is synonymous with PixelFormat.R8_G8_B8_A8_UNorm.
            Rgba32[] pixelData = new Rgba32[stage.Width * stage.Height];
            for (int y = 0; y < stage.Height; y++)
            {
                for (int x = 0; x < stage.Width; x++)
                {
                    int index = (int)(y * stage.Width + x);
                    pixelData[index] = map[x, y];
                }
            }
            gd.Unmap(stage); // Resources should be Unmapped when the region is no longer used.

            Image <Rgba32> outputImage = Image.LoadPixelData(pixelData, (int)stage.Width, (int)stage.Height);

            outputImage.Save(outPath);

            factory.DisposeCollector.DisposeAll();

            gd.Dispose();
            window.Close();
            return(0);
        }
Ejemplo n.º 8
0
        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);
        }
Ejemplo n.º 9
0
        // TODO: Cleanup
        public Texture CreateDeviceTexture(GraphicsDevice gd, ResourceFactory rf, TextureUsage usage)
        {
            if (gd == null)
            {
                throw new ArgumentNullException(nameof(gd));
            }
            if (rf == null)
            {
                throw new ArgumentNullException(nameof(rf));
            }
            using var _ = PerfTracker.FrameEvent("6.1.2.1 Rebuild MultiTextures");
            if (IsMetadataDirty)
            {
                RebuildLayers();
            }

            var palette = PaletteManager.Palette.GetCompletePalette();

            using var staging = rf.CreateTexture(new TextureDescription(Width, Height, Depth, MipLevels, ArrayLayers, Format.ToVeldrid(), TextureUsage.Staging, Type));
            staging.Name      = "T_" + Name + "_Staging";

            Span <uint> toBuffer = stackalloc uint[(int)(Width * Height)];

            foreach (var lsi in LogicalSubImages)
            {
                //if (!rebuildAll && !lsi.IsPaletteAnimated) // TODO: Requires caching a single Texture and then modifying it
                //    continue;

                for (int i = 0; i < lsi.Frames; i++)
                {
                    toBuffer.Fill(lsi.IsAlphaTested ? 0 : 0xff000000);
                    Rebuild(lsi, i, toBuffer, palette);

                    uint destinationLayer = (uint)LayerLookup[new LayerKey(lsi.Id, i)];

                    unsafe
                    {
                        fixed(uint *toBufferPtr = toBuffer)
                        {
                            gd.UpdateTexture(
                                staging, (IntPtr)toBufferPtr, Width * Height * sizeof(uint),
                                0, 0, 0,
                                Width, Height, 1,
                                0, destinationLayer);
                        }
                    }
                }
            }

            /* TODO: Mipmap
             *  for (uint level = 1; level < MipLevels; level++)
             *  {
             *  } //*/

            var texture = rf.CreateTexture(new TextureDescription(Width, Height, Depth, MipLevels, ArrayLayers, Format.ToVeldrid(), usage, Type));

            texture.Name = "T_" + Name;

            using (CommandList cl = rf.CreateCommandList())
            {
                cl.Begin();
                cl.CopyTexture(staging, texture);
                cl.End();
                gd.SubmitCommands(cl);
            }

            IsDirty = false;
            return(texture);
        }
Ejemplo n.º 10
0
        [STAThread] // Needed for ASIOOutput.StartDriver method
        static void Main(string[] args)
        {
            // Create window, GraphicsDevice, and all resources necessary for the demo.
            VeldridStartup.CreateWindowAndGraphicsDevice(
                new WindowCreateInfo(50, 50, 3600, 2000, WindowState.Normal, "Vector Engine Editor"),
                new GraphicsDeviceOptions(true, null, true),
                out _window,
                out _gd);

            _gd.MainSwapchain.SyncToVerticalBlank = false;

            _window.Resized += () =>
            {
                _gd.MainSwapchain.Resize((uint)_window.Width, (uint)_window.Height);
                _controller.WindowResized(_window.Width, _window.Height);
            };
            _cl         = _gd.ResourceFactory.CreateCommandList();
            _controller = new ImGuiController(_gd, _gd.MainSwapchain.Framebuffer.OutputDescription, _window.Width, _window.Height);

            string assetsPath = HostHelper.AssetsPath;

            FileLoader.Init(assetsPath);
            FileLoader.LoadAllComponentGroups();

            if (_showEditor)
            {
                HostHelper.StopGame(true);
            }
            else
            {
                HostHelper.PlayGame(true);
            }

            // Main application loop
            while (_window.Exists)
            {
                GameLoop.Tick();

                InputSnapshot snapshot = _window.PumpEvents();
                if (!_window.Exists)
                {
                    break;
                }

                foreach (var keypress in snapshot.KeyEvents)
                {
                    if (keypress.Key == Key.E && keypress.Down && keypress.Modifiers == ModifierKeys.Control)
                    {
                        _showEditor = !_showEditor;
                    }
                    if (keypress.Key == Key.S && keypress.Down && keypress.Modifiers == ModifierKeys.Control)
                    {
                        HostHelper.SaveScene();
                    }
                    if (keypress.Key == Key.D && keypress.Down && keypress.Modifiers == ModifierKeys.Control)
                    {
                        HostHelper.Duplicate();
                    }
                }

                if (_showEditor)
                {
                    if (EditorCamera == null)
                    {
                        foreach (var component in EntityAdmin.Instance.Components)
                        {
                            if (component.Entity.Name == EmptyScene.EDITOR_CAM_ENTITY_NAME)
                            {
                                EditorCamera = component.Entity;
                                break;
                            }
                        }
                    }

                    if (midi == null)
                    {
                        midi = new MIDI();
                        midi.SetupWatchersAndPorts();
                        while (!midi.SetupComplete)
                        {
                            Thread.Sleep(1);
                        }
                    }

                    IMidiMessage midiMessage;
                    while (midi.MidiMessageQueue.TryDequeue(out midiMessage))
                    {
                        MidiState.UpdateState(midiMessage);
                    }

                    // TODO: figure out why LastFrameTime makes ImGui run stupid fast... (for things like key repeats)
                    _controller.Update(GameTime.LastFrameTime / 10f, snapshot); // Feed the input events to our ImGui controller, which passes them through to ImGui.

                    EditorUI.SubmitUI(EntityAdmin.Instance);

                    _cl.Begin();
                    _cl.SetFramebuffer(_gd.MainSwapchain.Framebuffer);
                    _cl.ClearColorTarget(0, new RgbaFloat(ClearColor.X, ClearColor.Y, ClearColor.Z, 1f));
                    _controller.Render(_gd, _cl);
                    _cl.End();
                    _gd.SubmitCommands(_cl);
                    _gd.SwapBuffers(_gd.MainSwapchain);
                }
            }

            if (!HostHelper.PlayingGame)
            {
                HostHelper.SaveScene();
            }

            // Clean up Veldrid resources
            _gd.WaitForIdle();
            _controller.Dispose();
            _cl.Dispose();
            _gd.Dispose();
        }
Ejemplo n.º 11
0
        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);

                Assert.Equal(0, notFilledCount);
            }
        }
Ejemplo n.º 12
0
 public static void EndDraw()
 {
     // End() must be called before commands can be submitted for execution.
     CommandList.End();
     Device.SubmitCommands(CommandList);
 }
Ejemplo n.º 13
0
        protected override void Draw(float deltaSeconds, long ticks)
        {
            if (Death && CurDeathWaitTicks == DeathWaitTicks)
            {
                PrevTicks = ticks;
            }

            if (Death)
            {
                CurDeathWaitTicks--;
                if (CurDeathWaitTicks <= 0)
                {
                    CurDeathWaitTicks = -1;
                    Death             = false;
                    PrevTicks         = ticks;
                    ticks             = 0;
                }
                else
                {
                    ticks = PrevTicks;
                }
            }
            else
            {
                ticks -= PrevTicks;
            }

            CommandList.Begin();

            CommandList.SetFramebuffer(GraphicsDevice.SwapchainFramebuffer);
            CommandList.UpdateBuffer(ProjectionBuffer, 0, Matrix4x4.CreateOrthographicOffCenter(
                                         0,
                                         GraphicsDevice.SwapchainFramebuffer.Width,
                                         GraphicsDevice.SwapchainFramebuffer.Height,
                                         0,
                                         -1,
                                         1
                                         ));

            CommandList.UpdateBuffer(ViewBuffer, 0, Matrix4x4.CreateTranslation(Vector3.Zero));

            if (PlayerJumping >= 0)
            {
                CurPlayerVertPos += PlayerVelocity;
                PlayerVelocity   += EnergyLoss;
                PlayerJumping++;
            }

            if (PlayerJumping > NumJumpCycles)
            {
                CurPlayerVertPos = 320;
                PlayerJumping    = -1;
                PlayerVelocity   = StartingPlayerVelocity;
            }

            CommandList.UpdateBuffer(WorldBuffer, 0, Matrix4x4.CreateTranslation(new Vector3(PlayerX, CurPlayerVertPos, 0)));

            CommandList.ClearColorTarget(0, RgbaFloat.White);
            CommandList.ClearDepthStencil(1f);
            CommandList.SetPipeline(Pipeline);
            CommandList.SetVertexBuffer(0, VertexBuffer);
            CommandList.SetIndexBuffer(IndexBuffer, IndexFormat.UInt16);
            CommandList.SetGraphicsResourceSet(0, ProjViewSet);
            CommandList.SetGraphicsResourceSet(1, MainAvatarTextureSet);
            CommandList.DrawIndexed(6, 1, 0, 0, 0);
            var xCoord = (0 - (ticks * SpeedFactor) % 2000);

            CommandList.UpdateBuffer(WorldBuffer, 0, Matrix4x4.CreateTranslation(new Vector3(xCoord, 150, 0)));
            CommandList.DrawIndexed(6, 1, 12, 0, 0);
            xCoord = 2000 - ((ticks * SpeedFactor) % 2000);
            CommandList.UpdateBuffer(WorldBuffer, 0, Matrix4x4.CreateTranslation(new Vector3(xCoord, 150, 0)));
            CommandList.DrawIndexed(6, 1, 12, 0, 0);

            for (var i = 0; i < CactusPlacements.Length; i++)
            {
                var cactusPlacement       = CactusPlacements[i];
                var actualCactusPlacement = cactusPlacement - ((ticks * SpeedFactor) % 3650);
                if (actualCactusPlacement > 0 && actualCactusPlacement < 190 && CurPlayerVertPos > 200 && !Death)
                {
                    Death             = true;
                    CurDeathWaitTicks = DeathWaitTicks;
                    break;
                }

                CommandList.UpdateBuffer(WorldBuffer, 0,
                                         Matrix4x4.CreateTranslation(new Vector3(actualCactusPlacement, 300, 0)));
                CommandList.DrawIndexed(6, 1, IndexStartMap[CactusTypes[i % CactusTypes.Length]], 0, 0);
            }

            CommandList.End();
            if (!Death)
            {
                GraphicsDevice.SubmitCommands(CommandList);
            }
            GraphicsDevice.SwapBuffers();
            GraphicsDevice.WaitForIdle();
        }
Ejemplo n.º 14
0
        private void RenderAllSingleThread(GraphicsDevice gd, CommandList cl, SceneContext sc)
        {
            float depthClear = gd.IsDepthRangeZeroToOne ? 0f : 1f;
            Matrix4x4 cameraProj = Camera.ProjectionMatrix;
            Vector4 nearLimitCS = Vector4.Transform(new Vector3(0, 0, -_nearCascadeLimit), cameraProj);
            Vector4 midLimitCS = Vector4.Transform(new Vector3(0, 0, -_midCascadeLimit), cameraProj);
            Vector4 farLimitCS = Vector4.Transform(new Vector3(0, 0, -_farCascadeLimit), cameraProj);

            cl.UpdateBuffer(sc.DepthLimitsBuffer, 0, new DepthCascadeLimits
            {
                NearLimit = nearLimitCS.Z,
                MidLimit = midLimitCS.Z,
                FarLimit = farLimitCS.Z
            });

            cl.UpdateBuffer(sc.LightInfoBuffer, 0, sc.DirectionalLight.GetInfo());

            Vector3 lightPos = sc.DirectionalLight.Transform.Position - sc.DirectionalLight.Direction * 1000f;
            // Near
            Matrix4x4 viewProj0 = UpdateDirectionalLightMatrices(
                gd,
                sc,
                Camera.NearDistance,
                _nearCascadeLimit,
                sc.ShadowMapTexture.Width,
                out BoundingFrustum lightFrustum);
            cl.UpdateBuffer(sc.LightViewProjectionBuffer0, 0, ref viewProj0);
            cl.SetFramebuffer(sc.NearShadowMapFramebuffer);
            cl.SetFullViewports();
            cl.ClearDepthStencil(depthClear);
            Render(gd, cl, sc, RenderPasses.ShadowMapNear, lightFrustum, lightPos, _renderQueues[0], _cullableStage[0], _renderableStage[0], null, false);

            // Mid
            Matrix4x4 viewProj1 = UpdateDirectionalLightMatrices(
                gd,
                sc,
                _nearCascadeLimit,
                _midCascadeLimit,
                sc.ShadowMapTexture.Width,
                out lightFrustum);
            cl.UpdateBuffer(sc.LightViewProjectionBuffer1, 0, ref viewProj1);
            cl.SetFramebuffer(sc.MidShadowMapFramebuffer);
            cl.SetFullViewports();
            cl.ClearDepthStencil(depthClear);
            Render(gd, cl, sc, RenderPasses.ShadowMapMid, lightFrustum, lightPos, _renderQueues[0], _cullableStage[0], _renderableStage[0], null, false);

            // Far
            Matrix4x4 viewProj2 = UpdateDirectionalLightMatrices(
                gd,
                sc,
                _midCascadeLimit,
                _farCascadeLimit,
                sc.ShadowMapTexture.Width,
                out lightFrustum);
            cl.UpdateBuffer(sc.LightViewProjectionBuffer2, 0, ref viewProj2);
            cl.SetFramebuffer(sc.FarShadowMapFramebuffer);
            cl.SetFullViewports();
            cl.ClearDepthStencil(depthClear);
            Render(gd, cl, sc, RenderPasses.ShadowMapFar, lightFrustum, lightPos, _renderQueues[0], _cullableStage[0], _renderableStage[0], null, false);

            // Reflections
            cl.SetFramebuffer(sc.ReflectionFramebuffer);
            float fbWidth = sc.ReflectionFramebuffer.Width;
            float fbHeight = sc.ReflectionFramebuffer.Height;
            cl.SetViewport(0, new Viewport(0, 0, fbWidth, fbHeight, 0, 1));
            cl.SetFullViewports();
            cl.SetFullScissorRects();
            cl.ClearColorTarget(0, RgbaFloat.Black);
            cl.ClearDepthStencil(depthClear);

            // Render reflected scene.
            Matrix4x4 planeReflectionMatrix = Matrix4x4.CreateReflection(MirrorMesh.Plane);
            CameraInfo camInfo = new CameraInfo();
            camInfo.CameraLookDirection = Vector3.Normalize(Vector3.Reflect(_camera.LookDirection, MirrorMesh.Plane.Normal));
            camInfo.CameraPosition_WorldSpace = Vector3.Transform(_camera.Position, planeReflectionMatrix);
            cl.UpdateBuffer(sc.CameraInfoBuffer, 0, ref camInfo);

            Matrix4x4 view = sc.Camera.ViewMatrix;
            view = planeReflectionMatrix * view;
            cl.UpdateBuffer(sc.ViewMatrixBuffer, 0, view);

            Matrix4x4 projection = _camera.ProjectionMatrix;
            cl.UpdateBuffer(sc.ReflectionViewProjBuffer, 0, view * projection);

            BoundingFrustum cameraFrustum = new BoundingFrustum(view * projection);
            Render(gd, cl, sc, RenderPasses.ReflectionMap, cameraFrustum, _camera.Position, _renderQueues[0], _cullableStage[0], _renderableStage[0], null, false);

            cl.GenerateMipmaps(sc.ReflectionColorTexture);

            // Main scene
            cl.SetFramebuffer(sc.MainSceneFramebuffer);
            fbWidth = sc.MainSceneFramebuffer.Width;
            fbHeight = sc.MainSceneFramebuffer.Height;
            cl.SetViewport(0, new Viewport(0, 0, fbWidth, fbHeight, 0, 1));
            cl.SetFullViewports();
            cl.SetFullScissorRects();
            cl.ClearDepthStencil(depthClear);
            sc.UpdateCameraBuffers(cl); // Re-set because reflection step changed it.
            cameraFrustum = new BoundingFrustum(_camera.ViewMatrix * _camera.ProjectionMatrix);
            Render(gd, cl, sc, RenderPasses.Standard, cameraFrustum, _camera.Position, _renderQueues[0], _cullableStage[0], _renderableStage[0], null, false);
            Render(gd, cl, sc, RenderPasses.AlphaBlend, cameraFrustum, _camera.Position, _renderQueues[0], _cullableStage[0], _renderableStage[0], null, false);
            Render(gd, cl, sc, RenderPasses.Overlay, cameraFrustum, _camera.Position, _renderQueues[0], _cullableStage[0], _renderableStage[0], null, false);

            if (sc.MainSceneColorTexture.SampleCount != TextureSampleCount.Count1)
            {
                cl.ResolveTexture(sc.MainSceneColorTexture, sc.MainSceneResolvedColorTexture);
            }

            cl.SetFramebuffer(sc.DuplicatorFramebuffer);
            fbWidth = sc.DuplicatorFramebuffer.Width;
            fbHeight = sc.DuplicatorFramebuffer.Height;
            cl.SetFullViewports();
            Render(gd, cl, sc, RenderPasses.Duplicator, new BoundingFrustum(), _camera.Position, _renderQueues[0], _cullableStage[0], _renderableStage[0], null, false);

            cl.SetFramebuffer(gd.SwapchainFramebuffer);
            fbWidth = gd.SwapchainFramebuffer.Width;
            fbHeight = gd.SwapchainFramebuffer.Height;
            cl.SetFullViewports();
            Render(gd, cl, sc, RenderPasses.SwapchainOutput, new BoundingFrustum(), _camera.Position, _renderQueues[0], _cullableStage[0], _renderableStage[0], null, false);

            cl.End();

            _resourceUpdateCL.Begin();
            foreach (Renderable renderable in _allPerFrameRenderablesSet)
            {
                renderable.UpdatePerFrameResources(gd, _resourceUpdateCL, sc);
            }
            _resourceUpdateCL.End();

            gd.SubmitCommands(_resourceUpdateCL);
            gd.SubmitCommands(cl);
        }
Ejemplo n.º 15
0
        public static unsafe Texture LoadTexture(
            GraphicsDevice gd,
            ResourceFactory factory,
            string assetPath,
            PixelFormat format)
        {
            KtxFile tex2D;

            using (FileStream fs = File.OpenRead(assetPath))
            {
                tex2D = KtxFile.Load(fs, false);
            }

            uint width  = tex2D.Header.PixelWidth;
            uint height = tex2D.Header.PixelHeight;

            if (height == 0)
            {
                height = width;
            }

            uint mipLevels = tex2D.Header.NumberOfMipmapLevels;

            Texture ret = factory.CreateTexture(TextureDescription.Texture2D(
                                                    width, height, mipLevels, 1,
                                                    format, TextureUsage.Sampled));

            Texture stagingTex = factory.CreateTexture(TextureDescription.Texture2D(
                                                           width, height, mipLevels, 1,
                                                           format, TextureUsage.Staging));

            // Copy texture data into staging buffer
            for (uint level = 0; level < mipLevels; level++)
            {
                KtxMipmap mipmap    = tex2D.Faces[0].Mipmaps[level];
                byte[]    pixelData = mipmap.Data;
                fixed(byte *pixelDataPtr = &pixelData[0])
                {
                    gd.UpdateTexture(stagingTex, (IntPtr)pixelDataPtr, (uint)pixelData.Length,
                                     0, 0, 0, mipmap.Width, mipmap.Height, 1, level, 0);
                }
            }

            CommandList copyCL = factory.CreateCommandList();

            copyCL.Begin();
            for (uint level = 0; level < mipLevels; level++)
            {
                uint levelWidth  = tex2D.Faces[0].Mipmaps[level].Width;
                uint levelHeight = tex2D.Faces[0].Mipmaps[level].Height;
                copyCL.CopyTexture(stagingTex, 0, 0, 0, level, 0,
                                   ret, 0, 0, 0, level, 0, levelWidth, levelHeight, 1, 1);
            }
            copyCL.End();
            gd.SubmitCommands(copyCL);

            gd.DisposeWhenIdle(copyCL);
            gd.DisposeWhenIdle(stagingTex);

            return(ret);
        }
Ejemplo n.º 16
0
        public void Points_WithUIntColor()
        {
            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_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,
                framebuffer.OutputDescription);

            Pipeline pipeline = RF.CreateGraphicsPipeline(ref gpd);

            uint colorNormalizationFactor = 2500;

            UIntVertexAttribsVertex[] vertices = new UIntVertexAttribsVertex[]
            {
                new UIntVertexAttribsVertex
                {
                    Position  = new Vector2(0.5f, 0.5f),
                    Color_Int = new UInt4
                    {
                        X = (uint)(0.25f * colorNormalizationFactor),
                        Y = (uint)(0.5f * colorNormalizationFactor),
                        Z = (uint)(0.75f * colorNormalizationFactor),
                    }
                },
                new UIntVertexAttribsVertex
                {
                    Position  = new Vector2(10.5f, 12.5f),
                    Color_Int = new UInt4
                    {
                        X = (uint)(0.25f * colorNormalizationFactor),
                        Y = (uint)(0.5f * colorNormalizationFactor),
                        Z = (uint)(0.75f * colorNormalizationFactor),
                    }
                },
                new UIntVertexAttribsVertex
                {
                    Position  = new Vector2(25.5f, 35.5f),
                    Color_Int = new UInt4
                    {
                        X = (uint)(0.75f * colorNormalizationFactor),
                        Y = (uint)(0.5f * colorNormalizationFactor),
                        Z = (uint)(0.25f * colorNormalizationFactor),
                    }
                },
                new UIntVertexAttribsVertex
                {
                    Position  = new Vector2(49.5f, 49.5f),
                    Color_Int = new UInt4
                    {
                        X = (uint)(0.15f * colorNormalizationFactor),
                        Y = (uint)(0.25f * colorNormalizationFactor),
                        Z = (uint)(0.35f * colorNormalizationFactor),
                    }
                },
            };

            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);

            foreach (UIntVertexAttribsVertex 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.Color_Int.X / (float)colorNormalizationFactor,
                    vertex.Color_Int.Y / (float)colorNormalizationFactor,
                    vertex.Color_Int.Z / (float)colorNormalizationFactor,
                    1);
                Assert.Equal(expectedColor, readView[x, y], RgbaFloatFuzzyComparer.Instance);
            }
            GD.Unmap(staging);
        }
Ejemplo n.º 17
0
        private void RenderAllMultiThreaded(GraphicsDevice gd, CommandList cl, SceneContext sc)
        {
            Matrix4x4 cameraProj  = Camera.ProjectionMatrix;
            Vector4   nearLimitCS = Vector4.Transform(new Vector3(0, 0, -_nearCascadeLimit), cameraProj);
            Vector4   midLimitCS  = Vector4.Transform(new Vector3(0, 0, -_midCascadeLimit), cameraProj);
            Vector4   farLimitCS  = Vector4.Transform(new Vector3(0, 0, -_farCascadeLimit), cameraProj);

            _resourceUpdateCL.Begin();
            CommandList[] cls = new CommandList[5];
            for (int i = 0; i < cls.Length; i++)
            {
                cls[i] = gd.ResourceFactory.CreateCommandList(); cls[i].Begin();
            }

            _resourceUpdateCL.UpdateBuffer(sc.DepthLimitsBuffer, 0, new DepthCascadeLimits
            {
                NearLimit = nearLimitCS.Z,
                MidLimit  = midLimitCS.Z,
                FarLimit  = farLimitCS.Z
            });

            _resourceUpdateCL.UpdateBuffer(sc.LightInfoBuffer, 0, sc.DirectionalLight.GetInfo());

            _allPerFrameRenderablesSet.Clear();
            _tasks[0] = Task.Run(() =>
            {
                // Near
                Matrix4x4 viewProj0 = UpdateDirectionalLightMatrices(
                    sc,
                    Camera.NearDistance,
                    _nearCascadeLimit,
                    sc.ShadowMapTexture.Width,
                    out BoundingFrustum lightFrustum0);
                cls[1].UpdateBuffer(sc.LightViewProjectionBuffer0, 0, ref viewProj0);

                cls[1].SetFramebuffer(sc.NearShadowMapFramebuffer);
                cls[1].SetViewport(0, new Viewport(0, 0, sc.ShadowMapTexture.Width, sc.ShadowMapTexture.Height, 0, 1));
                cls[1].SetScissorRect(0, 0, 0, sc.ShadowMapTexture.Width, sc.ShadowMapTexture.Height);
                cls[1].ClearDepthStencil(1f);
                Render(gd, cls[1], sc, RenderPasses.ShadowMapNear, lightFrustum0, _renderQueues[0], _cullableStage[0], _renderableStage[0], null, true);
            });

            _tasks[1] = Task.Run(() =>
            {
                // Mid
                Matrix4x4 viewProj1 = UpdateDirectionalLightMatrices(
                    sc,
                    _nearCascadeLimit,
                    _midCascadeLimit,
                    sc.ShadowMapTexture.Width,
                    out var lightFrustum1);
                cls[2].UpdateBuffer(sc.LightViewProjectionBuffer1, 0, ref viewProj1);

                cls[2].SetFramebuffer(sc.MidShadowMapFramebuffer);
                cls[2].SetViewport(0, new Viewport(0, 0, sc.ShadowMapTexture.Width, sc.ShadowMapTexture.Height, 0, 1));
                cls[2].SetScissorRect(0, 0, 0, sc.ShadowMapTexture.Width, sc.ShadowMapTexture.Height);
                cls[2].ClearDepthStencil(1f);
                Render(gd, cls[2], sc, RenderPasses.ShadowMapMid, lightFrustum1, _renderQueues[1], _cullableStage[1], _renderableStage[1], null, true);
            });

            _tasks[2] = Task.Run(() =>
            {
                // Far
                Matrix4x4 viewProj2 = UpdateDirectionalLightMatrices(
                    sc,
                    _midCascadeLimit,
                    _farCascadeLimit,
                    sc.ShadowMapTexture.Width,
                    out var lightFrustum2);
                cls[3].UpdateBuffer(sc.LightViewProjectionBuffer2, 0, ref viewProj2);

                cls[3].SetFramebuffer(sc.FarShadowMapFramebuffer);
                cls[3].SetViewport(0, new Viewport(0, 0, sc.ShadowMapTexture.Width, sc.ShadowMapTexture.Height, 0, 1));
                cls[3].SetScissorRect(0, 0, 0, sc.ShadowMapTexture.Width, sc.ShadowMapTexture.Height);
                cls[3].ClearDepthStencil(1f);
                Render(gd, cls[3], sc, RenderPasses.ShadowMapFar, lightFrustum2, _renderQueues[2], _cullableStage[2], _renderableStage[2], null, true);
            });

            _tasks[3] = Task.Run(() =>
            {
                // Reflections
                cls[4].SetFramebuffer(sc.ReflectionFramebuffer);
                float scWidth  = sc.ReflectionFramebuffer.Width;
                float scHeight = sc.ReflectionFramebuffer.Height;
                cls[4].SetViewport(0, new Viewport(0, 0, scWidth, scHeight, 0, 1));
                cls[4].SetFullViewports();
                cls[4].SetFullScissorRects();
                cls[4].ClearColorTarget(0, RgbaFloat.Black);
                cls[4].ClearDepthStencil(1f);

                // Render reflected scene.
                Matrix4x4 planeReflectionMatrix = Matrix4x4.CreateReflection(MirrorMesh.Plane);
                CameraInfo camInfo                = new CameraInfo();
                camInfo.CameraLookDirection       = Vector3.Normalize(Vector3.Reflect(_camera.LookDirection, MirrorMesh.Plane.Normal));
                camInfo.CameraPosition_WorldSpace = Vector3.Transform(_camera.Position, planeReflectionMatrix);
                cls[4].UpdateBuffer(sc.CameraInfoBuffer, 0, ref camInfo);

                Matrix4x4 view = sc.Camera.ViewMatrix;
                view           = planeReflectionMatrix * view;
                cls[4].UpdateBuffer(sc.ViewMatrixBuffer, 0, view);

                Matrix4x4 projection = _camera.ProjectionMatrix;
                cls[4].UpdateBuffer(sc.ReflectionViewProjBuffer, 0, view * projection);

                BoundingFrustum cameraFrustum = new BoundingFrustum(view * projection);
                Render(gd, cls[4], sc, RenderPasses.ReflectionMap, cameraFrustum, _renderQueues[3], _cullableStage[3], _renderableStage[3], null, true);

                cl.GenerateMipmaps(sc.ReflectionColorTexture);

                // Main scene
                cls[4].SetFramebuffer(sc.MainSceneFramebuffer);
                scWidth  = sc.MainSceneFramebuffer.Width;
                scHeight = sc.MainSceneFramebuffer.Height;
                cls[4].SetViewport(0, new Viewport(0, 0, scWidth, scHeight, 0, 1));
                cls[4].SetScissorRect(0, 0, 0, (uint)scWidth, (uint)scHeight);
                cls[4].ClearColorTarget(0, RgbaFloat.Black);
                cls[4].ClearDepthStencil(1f);
                sc.UpdateCameraBuffers(cls[4]);
                cameraFrustum = new BoundingFrustum(_camera.ViewMatrix * _camera.ProjectionMatrix);
                Render(gd, cls[4], sc, RenderPasses.Standard, cameraFrustum, _renderQueues[3], _cullableStage[3], _renderableStage[3], null, true);
                Render(gd, cls[4], sc, RenderPasses.AlphaBlend, cameraFrustum, _renderQueues[3], _cullableStage[3], _renderableStage[3], null, true);
                Render(gd, cls[4], sc, RenderPasses.Overlay, cameraFrustum, _renderQueues[3], _cullableStage[3], _renderableStage[3], null, true);
            });

            Task.WaitAll(_tasks);

            foreach (Renderable renderable in _allPerFrameRenderablesSet)
            {
                renderable.UpdatePerFrameResources(gd, _resourceUpdateCL, sc);
            }
            _resourceUpdateCL.End();
            gd.SubmitCommands(_resourceUpdateCL);

            for (int i = 0; i < cls.Length; i++)
            {
                cls[i].End(); gd.SubmitCommands(cls[i]); cls[i].Dispose();
            }

            if (sc.MainSceneColorTexture.SampleCount != TextureSampleCount.Count1)
            {
                cl.ResolveTexture(sc.MainSceneColorTexture, sc.MainSceneResolvedColorTexture);
            }

            cl.SetFramebuffer(sc.DuplicatorFramebuffer);
            uint fbWidth  = sc.DuplicatorFramebuffer.Width;
            uint fbHeight = sc.DuplicatorFramebuffer.Height;

            cl.SetViewport(0, new Viewport(0, 0, fbWidth, fbHeight, 0, 1));
            cl.SetViewport(1, new Viewport(0, 0, fbWidth, fbHeight, 0, 1));
            cl.SetScissorRect(0, 0, 0, fbWidth, fbHeight);
            cl.SetScissorRect(1, 0, 0, fbWidth, fbHeight);
            Render(gd, cl, sc, RenderPasses.Duplicator, new BoundingFrustum(), _renderQueues[0], _cullableStage[0], _renderableStage[0], null, false);

            cl.SetFramebuffer(gd.SwapchainFramebuffer);
            fbWidth  = gd.SwapchainFramebuffer.Width;
            fbHeight = gd.SwapchainFramebuffer.Height;
            cl.SetViewport(0, new Viewport(0, 0, fbWidth, fbHeight, 0, 1));
            cl.SetScissorRect(0, 0, 0, fbWidth, fbHeight);
            Render(gd, cl, sc, RenderPasses.SwapchainOutput, new BoundingFrustum(), _renderQueues[0], _cullableStage[0], _renderableStage[0], null, false);

            cl.End();
            gd.SubmitCommands(cl);
        }
Ejemplo n.º 18
0
        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);
        }
Ejemplo n.º 19
0
        public override void Operate()
        {
            _commands.Begin();
            _commands.SetFramebuffer(_framebuffer);
            _commands.ClearColorTarget(0, RgbaFloat.Black);
            _commands.ClearDepthStencil(1f);

            var renderables = World.Where(CanOperateOn)
                              .GroupBy(entity =>
            {
                var mesh = entity.GetComponent <MeshData>();
                return(
                    entity.GetComponent <Material>(),
                    mesh.FrontFace,
                    mesh.PrimitiveTopology,
                    entity.GetComponent <IResourceSet>().ResourceLayout,
                    mesh.VertexBuffer.LayoutDescription
                    );
            });

            foreach (var renderable in renderables)
            {
                var material = renderable.Key.Item1;

                if (!_pipelines.ContainsKey(material))
                {
                    var frontFace         = renderable.Key.FrontFace;
                    var primitiveTopology = renderable.Key.PrimitiveTopology;
                    var resourceLayout    = renderable.Key.ResourceLayout;
                    var vertexLayout      = renderable.Key.LayoutDescription;
                    var pipeline          = CreatePipeline(material,
                                                           frontFace, primitiveTopology,
                                                           resourceLayout, vertexLayout);

                    _pipelines.Add(material, pipeline);
                }

                _commands.SetPipeline(_pipelines[material]);

                var meshesWithUniforms = renderable.Select(entity => (
                                                               entity.GetComponent <MeshData>().VertexBuffer,
                                                               entity.GetComponent <IResourceSet>().ResourceSet
                                                               ));
                foreach (var meshAndUniforms in meshesWithUniforms)
                {
                    var mesh = meshAndUniforms.VertexBuffer;

                    _commands.SetVertexBuffer(0, mesh.Vertices);
                    _commands.SetIndexBuffer(mesh.Indices.DeviceBuffer, IndexFormat.UInt16);
                    _commands.SetGraphicsResourceSet(0, meshAndUniforms.ResourceSet);

                    _commands.DrawIndexed(
                        indexCount: (uint)mesh.Indices.Count,
                        instanceCount: 1, // TODO: Group renderables by MeshData and figure out instance uniforms
                        indexStart: 0,
                        vertexOffset: 0,
                        instanceStart: 0
                        );
                }
            }

            _commands.End();
            _submitCommands(_commands);
        }
Ejemplo n.º 20
0
        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);
        }
Ejemplo n.º 21
0
        public void Execute(RenderContext context)
        {
            RenderedObjectsOpaque      = 0;
            RenderedObjectsTransparent = 0;

            EnsureIntermediateFramebuffer(context.GraphicsDevice, context.RenderTarget);

            _renderList.Clear();

            context.Scene3D?.BuildRenderList(
                _renderList,
                context.Scene3D.Camera,
                context.GameTime);

            BuildingRenderList?.Invoke(this, new BuildingRenderListEventArgs(
                                           _renderList,
                                           context.Scene3D?.Camera,
                                           context.GameTime));

            _commandList.Begin();

            if (context.Scene3D != null)
            {
                _commandList.PushDebugGroup("3D Scene");
                Render3DScene(_commandList, context.Scene3D, context);
                _commandList.PopDebugGroup();
            }
            else
            {
                _commandList.SetFramebuffer(_intermediateFramebuffer);
                _commandList.ClearColorTarget(0, ClearColor);
            }

            // GUI and camera-dependent 2D elements
            {
                _commandList.PushDebugGroup("2D Scene");

                _drawingContext.Begin(
                    _commandList,
                    _loadContext.StandardGraphicsResources.LinearClampSampler,
                    new SizeF(context.RenderTarget.Width, context.RenderTarget.Height));

                context.Scene3D?.Render(_drawingContext);
                context.Scene2D?.Render(_drawingContext);

                _shadowMapRenderer.DrawDebugOverlay(
                    context.Scene3D,
                    _drawingContext);

                Rendering2D?.Invoke(this, new Rendering2DEventArgs(_drawingContext));

                _drawingContext.End();

                _commandList.PopDebugGroup();
            }

            _commandList.End();

            context.GraphicsDevice.SubmitCommands(_commandList);

            _textureCopier.Execute(
                _intermediateTexture,
                context.RenderTarget);
        }
Ejemplo n.º 22
0
        private void Draw()
        {
            Debug.Assert(_window.Exists);
            int width  = _window.Width;
            int height = _window.Height;
            int x      = _window.X;
            int y      = _window.Y;

            if (_windowResized)
            {
                _windowResized = false;

                CFG.Current.GFX_Display_Width  = width;
                CFG.Current.GFX_Display_Height = height;

                _gd.ResizeMainWindow((uint)width, (uint)height);
                //_scene.Camera.WindowResized(width, height);
                _resizeHandled?.Invoke(width, height);
                CommandList cl = _gd.ResourceFactory.CreateCommandList();
                cl.Begin();
                //_sc.RecreateWindowSizedResources(_gd, cl);
                RecreateWindowFramebuffers(cl);
                ImguiRenderer.WindowResized(width, height);
                MSBEditor.EditorResized(_window, _gd);
                ModelEditor.EditorResized(_window, _gd);
                cl.End();
                _gd.SubmitCommands(cl);
                cl.Dispose();
            }

            if (_windowMoved)
            {
                _windowMoved = false;
                CFG.Current.GFX_Display_X = x;
                CFG.Current.GFX_Display_Y = y;
            }

            if (_newSampleCount != null)
            {
                //_sc.MainSceneSampleCount = _newSampleCount.Value;
                _newSampleCount = null;
                //DestroyAllObjects();
                //CreateAllObjects();
            }

            //_frameCommands.Begin();

            //CommonMaterials.FlushAll(_frameCommands);

            //_scene.RenderAllStages(_gd, _frameCommands, _sc);

            //CommandList cl2 = _gd.ResourceFactory.CreateCommandList();
            MainWindowCommandList.Begin();
            //cl2.SetFramebuffer(_gd.SwapchainFramebuffer);
            MainWindowCommandList.SetFramebuffer(_gd.SwapchainFramebuffer);
            MainWindowCommandList.ClearColorTarget(0, new RgbaFloat(0.176f, 0.176f, 0.188f, 1.0f));
            float depthClear = _gd.IsDepthRangeZeroToOne ? 1f : 0f;

            MainWindowCommandList.ClearDepthStencil(0.0f);
            MainWindowCommandList.SetFullViewport(0);
            //MainWindowCommandList.End();
            //_gd.SubmitCommands(MainWindowCommandList);
            //_gd.WaitForIdle();
            if (_msbEditorFocused)
            {
                MSBEditor.Draw(_gd, MainWindowCommandList);
            }
            if (_modelEditorFocused)
            {
                ModelEditor.Draw(_gd, MainWindowCommandList);
            }
            var fence = Scene.Renderer.Frame(MainWindowCommandList, false);

            //GuiCommandList.Begin();
            //GuiCommandList.SetFramebuffer(_gd.SwapchainFramebuffer);
            MainWindowCommandList.SetFullViewport(0);
            MainWindowCommandList.SetFullScissorRects();
            ImguiRenderer.Render(_gd, MainWindowCommandList);
            //GuiCommandList.End();
            MainWindowCommandList.End();
            _gd.SubmitCommands(MainWindowCommandList, fence);
            Scene.Renderer.SubmitPostDrawCommandLists();
            //Scene.SceneRenderPipeline.TestUpdateView(_gd, MainWindowCommandList, TestWorldView.CameraTransform.CameraViewMatrix);

            _gd.SwapBuffers();
        }
Ejemplo n.º 23
0
        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.Position, VertexElementFormat.Float2),
                    new VertexElementDescription("Color", VertexElementSemantic.Color, VertexElementFormat.UShort4_Norm))
            },
                new Shader[]
            {
                TestShaders.Load(RF, "U16NormVertexAttribs", ShaderStages.Vertex, "VS"),
                TestShaders.Load(RF, "U16NormVertexAttribs", ShaderStages.Fragment, "FS")
            });

            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)
                {
                    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);
        }
Ejemplo n.º 24
0
        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);
            }
        }
Ejemplo n.º 25
0
        public byte[] VboToPng(float[] vbo, int trianglesCount, bool flipHorizontal = false)
        {
            Logger.AddLog("VeldridRender.VboToPng");
            CheckThread();
            try
            {
                uint size = (uint)vbo.Length * 4;
                if (size % 16 != 0)
                {
                    size += 16 - size % 16;
                }

                DeviceBuffer vertexBuffer = resourceFactory.CreateBuffer(new BufferDescription(size, BufferUsage.VertexBuffer));
                graphicsDevice.UpdateBuffer(vertexBuffer, 0, vbo);
                graphicsDevice.WaitForIdle();

                CommandList cl = resourceFactory.CreateCommandList();
                cl.Begin();

                cl.SetFramebuffer(_offscreenFB);
                cl.ClearColorTarget(0, background);
                cl.SetFullViewport(0);

                //cl.UpdateBuffer(vertexBuffer, 0, vbo);
                cl.SetVertexBuffer(0, vertexBuffer);

                cl.SetPipeline(_pipeline);

                cl.SetGraphicsResourceSet(0, _uniformsResourceSet);
                cl.SetGraphicsResourceSet(1, _textureSet);

                cl.Draw((uint)(trianglesCount * 3));

                //transfer GPU drawing to CPU readable one
                cl.CopyTexture(_offscreenFB.ColorTargets[0].Target, _offscreenReadOut);

                cl.End();

                graphicsDevice.SubmitCommands(cl);
                //Thread.Sleep(5);
                graphicsDevice.WaitForIdle();
                //Thread.Sleep(5);

                MappedResourceView <byte> view = graphicsDevice.Map <byte>(_offscreenReadOut, MapMode.Read);

                byte[] tmp = new byte[view.SizeInBytes];

                Marshal.Copy(view.MappedResource.Data, tmp, 0, (int)view.SizeInBytes);

                graphicsDevice.Unmap(_offscreenReadOut);

                return(Helpers.ImageProcessing.Rgba32ToPng(
                           new ProcessImage {
                    Load = tmp, Width = (int)_offscreenReadOut.Width, Height = (int)_offscreenReadOut.Height, Type = ProcessImageType.RGBA32
                },
                           flipHorizontal,
                           FlipVertical)
                       .Load);
            }
            catch (Exception ex)
            {
                Logger.AddLog(ex);
            }

            return(null);
        }