/// <summary> /// Initializes a new instance of the <see cref="DrawCallFactory"/> class. /// </summary> /// <param name="graphics">The graphics interface to use when creating states.</param> /// <param name="defaultTexture">The default texture to use as a fallback when no texture is passed by renderable.</param> /// <param name="inputLayout">The input layout defining a vertex type.</param> public DrawCallFactory(GorgonGraphics graphics, GorgonTexture2DView defaultTexture, GorgonInputLayout inputLayout) { _inputLayout = inputLayout; _drawIndexAllocator = new GorgonDrawCallPoolAllocator <GorgonDrawIndexCall>(128); _drawAllocator = new GorgonDrawCallPoolAllocator <GorgonDrawCall>(128); _drawIndexBuilder = new GorgonDrawIndexCallBuilder(); _drawBuilder = new GorgonDrawCallBuilder(); _stateBuilder = new GorgonPipelineStateBuilder(graphics); _defaultTexture = defaultTexture; }
/// <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(); } }
/// <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(); } }