Example #1
0
        /// <summary>
        /// Function to return the appropriate draw call based on the states provided.
        /// </summary>
        /// <param name="texture">The texture to display.</param>
        /// <param name="blendState">The blending state for the texture.</param>
        /// <param name="samplerState">The sampler state for the texture.</param>
        /// <param name="shader">The pixel shader to use.</param>
        /// <param name="constantBuffers">Constant buffers for the pixel shader, if required.</param>
        private void GetDrawCall(GorgonTexture2DView texture, GorgonBlendState blendState, GorgonSamplerState samplerState, GorgonPixelShader shader, GorgonConstantBuffers constantBuffers)
        {
            if ((_drawCall != null) &&
                (shader == _pixelShader) &&
                (_drawCall.PixelShader.Samplers[0] == samplerState) &&
                (_pipelineState.BlendStates[0] == blendState) &&
                (_drawCall.PixelShader.ShaderResources[0] == texture) &&
                (_drawCall.PixelShader.ConstantBuffers.DirtyEquals(constantBuffers)))
            {
                // This draw call hasn't changed, so return the previous one.
                return;
            }

            if (_pipelineState.BlendStates[0] != blendState)
            {
                _pipelineState = _pipeStateBuilder
                                 .BlendState(blendState)
                                 .Build();

                _drawCallBuilder.PipelineState(_pipelineState);
            }

            _drawCall = _drawCallBuilder.ConstantBuffers(ShaderType.Pixel, constantBuffers)
                        .SamplerState(ShaderType.Pixel, samplerState)
                        .ShaderResource(ShaderType.Pixel, texture)
                        .Build(_drawAllocator);
        }
Example #2
0
        /// <summary>
        /// Function to flush the cache data into the buffers and render the renderables.
        /// </summary>
        /// <param name="drawCall">The draw call that will be used to render the renderables.</param>
        public void RenderBatches(GorgonDrawCall drawCall)
        {
            GorgonVertexBuffer vertexBuffer = VertexBuffer.VertexBuffer;
            int cacheIndex = _currentVertexIndex - _allocatedVertexCount;

            while (_allocatedVertexCount > 0)
            {
                int vertexCount = _allocatedVertexCount.Min(MaxVertexCount);
                int byteCount   = Gorgon2DVertex.SizeInBytes * vertexCount;

                // If we've exceeded our vertex or index buffer size, we need to reset from the beginning.
                if ((_vertexBufferByteOffset + byteCount) >= vertexBuffer.SizeInBytes)
                {
                    _indexStart                 = 0;
                    _vertexBufferByteOffset     = 0;
                    _vertexBufferIndex          = 0;
                    _indexBufferBaseVertexIndex = 0;
                }

                CopyMode copyMode = _vertexBufferByteOffset == 0 ? CopyMode.Discard : CopyMode.NoOverwrite;

                // Copy a chunk of the cache.
                vertexBuffer.SetData(_vertexCache, cacheIndex, vertexCount, _vertexBufferByteOffset, copyMode);

                drawCall.VertexStartIndex = _vertexBufferIndex;
                drawCall.VertexCount      = vertexCount;
                Graphics.Submit(drawCall);

                // Move to the next block of bytes to render.
                _vertexBufferByteOffset     += byteCount;
                _vertexBufferIndex          += vertexCount;
                _allocatedVertexCount       -= vertexCount;
                _indexBufferBaseVertexIndex += vertexCount;
                cacheIndex += vertexCount;
            }

            // Invalidate the cache.
            _currentVertexIndex   = 0;
            _allocatedVertexCount = 0;
            _indexCount           = 0;
        }
Example #3
0
        /// <summary>
        /// Function to initialize the application.
        /// </summary>
        /// <returns>The main window.</returns>
        private static FormMain Initialize()
        {
            // Create our form and center on the primary monitor.
            FormMain window = GorgonExample.Initialize(new DX.Size2(1280, 800), "Gorgon MiniTri");

            try
            {
                // First we create and enumerate the list of video devices installed in the computer.
                // We must do this in order to tell Gorgon which video device we intend to use. Note that this method may be quite slow (particularly when running DEBUG versions of
                // Direct 3D). To counter this, this object and its Enumerate method are thread safe so this can be run in the background while keeping the main UI responsive.
                // Find out which devices we have installed in the system.

                // If no suitable device was found (no Direct 3D 12.0 support) in the computer, this method will throw an exception. However, if it succeeds, then the devices object
                // will be populated with the IGorgonVideoDeviceInfo for each video device in the system.
                //
                // Using this method, we could also enumerate the software rasterizer. These devices are typically used to determine if there's a driver error, and can be terribly slow to render
                // It is recommended that these only be used in diagnostic scenarios only.
                IReadOnlyList <IGorgonVideoAdapterInfo> deviceList = GorgonGraphics.EnumerateAdapters();

                if (deviceList.Count == 0)
                {
                    throw new
                          NotSupportedException("There are no suitable video adapters available in the system. This example is unable to continue and will now exit.");
                }

                // Now we create the main graphics interface with the first applicable video device.
                _graphics = new GorgonGraphics(deviceList[0]);

                // Check to ensure that we can support the format required for our swap chain.
                // If a video device can't support this format, then the odds are good it won't render anything. Since we're asking for a very common display format, this will
                // succeed nearly 100% of the time (unless you've somehow gotten an ancient video device to work with Direct 3D 11.1). Regardless, it's good form to the check for a
                // working display format prior to setting up the swap chain.
                //
                // This method is also used to determine if a format can be used for other objects (e.g. a texture, render target, etc...) Like the swap chain format, this is also a
                // best practice to check if the object you're creating supports the desired format.
                if ((_graphics.FormatSupport[BufferFormat.R8G8B8A8_UNorm].FormatSupport & BufferFormatSupport.Display) != BufferFormatSupport.Display)
                {
                    // We should never see this unless you've performed some form of black magic.
                    GorgonDialogs.ErrorBox(window, "We should not see this error.");
                    return(window);
                }

                // Finally, create a swap chain to display our output.
                // In this case we're setting up our swap chain to bind with our main window, and we use its client size to determine the width/height of the swap chain back buffers.
                // This width/height does not need to be the same size as the window, but, except for some scenarios, that would produce undesirable image quality.
                _swap = new GorgonSwapChain(_graphics,
                                            window,
                                            new GorgonSwapChainInfo("Main Swap Chain")
                {
                    Format = BufferFormat.R8G8B8A8_UNorm,
                    Width  = window.ClientSize.Width,
                    Height = window.ClientSize.Height
                })
                {
                    DoNotAutoResizeBackBuffer = true
                };

                // Create the shaders used to render the triangle.
                // These shaders provide transformation and coloring for the output pixel data.
                CreateShaders();

                // Set up our input layout.
                //
                // We'll be using this to describe to Direct 3D how the elements of a vertex is laid out in memory.
                // In order to provide synchronization between the layout on the CPU side and the GPU side, we have to pass the vertex shader because it will contain the vertex
                // layout to match with our C# input layout.
                _inputLayout = GorgonInputLayout.CreateUsingType <MiniTriVertex>(_graphics, _vertexShader);

                // Set up the triangle vertices.
                CreateVertexBuffer();

                // Set up the constant buffer.
                //
                // This is used (but could be used for more) to transform the vertex data from 3D space into 2D space.
                CreateConstantBuffer(window);

                // This defines where to send the pixel data when rendering. For now, this goes to our swap chain.
                _graphics.SetRenderTarget(_swap.RenderTargetView);

                // Create our draw call.
                //
                // This will pass all the necessary information to the GPU to render the triangle
                //
                // Since draw calls are immutable objects, we use builders to create them (and any pipeline state). Once a draw
                // call is built, it cannot be changed (except for the vertex, and if applicable, index, and instance ranges).
                //
                // Builders work on a fluent interface.  Much like LINQ and can be used to create multiple draw calls from the same
                // builder.
                var drawCallBuilder      = new GorgonDrawCallBuilder();
                var pipelineStateBuilder = new GorgonPipelineStateBuilder(_graphics);

                _drawCall = drawCallBuilder.VertexBuffer(_inputLayout, _vertexBuffer)
                            .VertexRange(0, 3)
                            .ConstantBuffer(ShaderType.Vertex, _constantBuffer)
                            .PipelineState(pipelineStateBuilder
                                           .PixelShader(_pixelShader)
                                           .VertexShader(_vertexShader)
                                           .RasterState(GorgonRasterState.NoCulling))
                            .Build();

                GorgonExample.LoadResources(_graphics);

                return(window);
            }
            finally
            {
                GorgonExample.EndInit();
            }
        }
Example #4
0
        /// <summary>
        /// Function used to initialize the application.
        /// </summary>
        private static void Initialize()
        {
            GorgonExample.ResourceBaseDirectory = new DirectoryInfo(Settings.Default.ResourceLocation);

            // Build the form so we can actually show something.
            _mainForm = GorgonExample.Initialize(new DX.Size2(1280, 800), "Geometry Shaders");

            try
            {
                // Now we create and enumerate the list of video devices installed in the computer.
                // We must do this in order to tell Gorgon which video device we intend to use. Note that this method may be quite slow (particularly when running DEBUG versions of
                // Direct 3D). To counter this, this object and its Enumerate method are thread safe so this can be run in the background while keeping the main UI responsive.
                //
                // If no suitable device was found (no Direct 3D 11.4 support) in the computer, this method will return an empty list. However, if it succeeds, then the devices list
                // will be populated with an IGorgonVideoDeviceInfo for each suitable video device in the system.
                //
                // Using this method, we could also enumerate the WARP software rasterizer, and/of the D3D Reference device (only if the DEBUG functionality provided by the Windows
                // SDK is installed). These devices are typically used to determine if there's a driver error, and can be terribly slow to render (reference moreso than WARP). It is
                // recommended that these only be used in diagnostic scenarios only.
                IReadOnlyList <IGorgonVideoAdapterInfo> devices = GorgonGraphics.EnumerateAdapters(log: GorgonApplication.Log);

                if (devices.Count == 0)
                {
                    GorgonDialogs.ErrorBox(_mainForm, "This example requires a video adapter that supports Direct3D 11.4 or better.");
                    GorgonApplication.Quit();
                    return;
                }

                // Now we create the main graphics interface with the first applicable video device.
                _graphics = new GorgonGraphics(devices[0], log: GorgonApplication.Log);

                // Check to ensure that we can support the format required for our swap chain.
                // If a video device can't support this format, then the odds are good it won't render anything. Since we're asking for a very common display format, this will
                // succeed nearly 100% of the time. Regardless, it's good form to the check for a working display format prior to setting up the swap chain.
                //
                // This is also used to determine if a format can be used for other objects (e.g. a texture, render target, etc...) And like the swap chain format, it is also best
                // practice to check if the object you're creating supports the desired format.
                if (!_graphics.FormatSupport[BufferFormat.R8G8B8A8_UNorm].IsDisplayFormat)
                {
                    // We should never see this unless you've got some very esoteric hardware.
                    GorgonDialogs.ErrorBox(_mainForm, "We should not see this error.");
                    return;
                }

                // Finally, create a swap chain to display our output.
                // In this case we're setting up our swap chain to bind with our main window, and we use its client size to determine the width/height of the swap chain back buffers.
                // This width/height does not need to be the same size as the window, but, except for some scenarios, that would produce undesirable image quality.
                _swap = new GorgonSwapChain(_graphics,
                                            _mainForm,
                                            new GorgonSwapChainInfo("Main Swap Chain")
                {
                    Format = BufferFormat.R8G8B8A8_UNorm, Width = _mainForm.ClientSize.Width, Height = _mainForm.ClientSize.Height
                });

                // Assign events so we can update our projection with our window size.
                _swap.BeforeSwapChainResized += Swap_BeforeSwapChainResized;
                _swap.AfterSwapChainResized  += Swap_AfterSwapChainResized;

                // We'll need a depth buffer for this example, or else our pyramid will look weird when rotating as back faces will appear through front faces.
                // So, first we should check for support of a proper depth/stencil format.  That said, if we don't have this format, then we're likely not running hardware from the last decade or more.
                if (!_graphics.FormatSupport[BufferFormat.D24_UNorm_S8_UInt].IsDepthBufferFormat)
                {
                    GorgonDialogs.ErrorBox(_mainForm, "A 24 bit depth buffer is required for this example.");
                    return;
                }

                _depthStencil = GorgonDepthStencil2DView.CreateDepthStencil(_graphics,
                                                                            new GorgonTexture2DInfo
                {
                    Format  = BufferFormat.D24_UNorm_S8_UInt,
                    Binding = TextureBinding.DepthStencil,
                    Usage   = ResourceUsage.Default,
                    Width   = _swap.Width,
                    Height  = _swap.Height
                });

                // Load the shaders from a file on disc.
                LoadShaders();

                // Load the texture.
                _texture = GorgonTexture2DView.FromFile(_graphics,
                                                        Path.Combine(GorgonExample.GetResourcePath(@"Textures\GeometryShader\").FullName, "GSTexture.png"),
                                                        new GorgonCodecPng());

                // Create our builders so we can compose a draw call and pipeline state.
                _drawCallBuilder  = new GorgonDrawCallBuilder();
                _pipeStateBuilder = new GorgonPipelineStateBuilder(_graphics);

                // Create a constant buffer so we can adjust the positioning of the data.
                DX.Matrix.PerspectiveFovLH((65.0f).ToRadians(), (float)_swap.Width / _swap.Height, 0.125f, 1000.0f, out _projection);
                _vsConstants = GorgonConstantBufferView.CreateConstantBuffer(_graphics,
                                                                             new GorgonConstantBufferInfo("WorldProjection CBuffer")
                {
                    SizeInBytes = (DX.Matrix.SizeInBytes * 2) + DX.Vector4.SizeInBytes
                });
                _vsConstants.Buffer.SetData(ref _projection, copyMode: CopyMode.Discard);
                _vsConstants.Buffer.SetData(ref _worldMatrix, 64, CopyMode.NoOverwrite);

                // Create a draw call so we actually have something we can draw.
                _drawCall = _drawCallBuilder.VertexRange(0, 3)
                            .PipelineState(_pipeStateBuilder.PixelShader(_pixelShader)
                                           .VertexShader(_bufferless)
                                           .GeometryShader(_geometryShader)
                                           .DepthStencilState(GorgonDepthStencilState.DepthEnabled))
                            .ShaderResource(ShaderType.Pixel, _texture)
                            .ConstantBuffer(ShaderType.Vertex, _vsConstants)
                            .ConstantBuffer(ShaderType.Geometry, _vsConstants)
                            .Build();
                // Finally set our swap chain as the active rendering target and the depth/stencil buffer.
                _graphics.SetRenderTarget(_swap.RenderTargetView, _depthStencil);

                GorgonExample.LoadResources(_graphics);
            }
            finally
            {
                GorgonExample.EndInit();
            }
        }