/// <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); }
/// <summary> /// Function to load the resources for the layer. /// </summary> public override void LoadResources() { _drawCalls = new List <GorgonDrawIndexCall>(); BuildConstantBuffers(); for (int i = 0; i < Planets.Count; ++i) { Planet planet = Planets[i]; for (int j = 0; j < planet.Layers.Count; ++j) { PlanetaryLayer layer = planet.Layers[j]; GorgonVertexShader vertexShader = _resources.VertexShaders[layer.Mesh.Material.VertexShader]; GorgonPixelShader pixelShader = _resources.PixelShaders[layer.Mesh.Material.PixelShader]; // Create our vertex layout now. if (_vertexLayout == null) { _vertexLayout = _vertexLayout = GorgonInputLayout.CreateUsingType <Vertex3D>(_graphics, vertexShader); } // Set up a pipeline state for the mesh. GorgonPipelineState pipelineState = _stateBuilder.Clear() .PixelShader(pixelShader) .VertexShader(vertexShader) .BlendState(layer.Mesh.Material.BlendState) .PrimitiveType(PrimitiveType.TriangleList) .Build(); _drawCallBuilder.Clear() .PipelineState(pipelineState) .IndexBuffer(layer.Mesh.IndexBuffer, 0, layer.Mesh.IndexCount) .VertexBuffer(_vertexLayout, new GorgonVertexBufferBinding(layer.Mesh.VertexBuffer, Vertex3D.Size)) .ConstantBuffer(ShaderType.Vertex, _viewProjectionBuffer) .ConstantBuffer(ShaderType.Vertex, _worldBuffer, 1) .ConstantBuffer(ShaderType.Pixel, _cameraBuffer) .ConstantBuffer(ShaderType.Pixel, _lightBuffer, 1) .ConstantBuffer(ShaderType.Pixel, _materialBuffer, 2); (int startTexture, int textureCount) = layer.Mesh.Material.Textures.GetDirtyItems(); for (int k = startTexture; k < startTexture + textureCount; ++k) { GorgonTexture2DView texture = _resources.Textures[layer.Mesh.Material.Textures[k]]; _drawCallBuilder.ShaderResource(ShaderType.Pixel, texture, k); // We should have this in the material, but since we know what we've got here, this will be fine. _drawCallBuilder.SamplerState(ShaderType.Pixel, GorgonSamplerState.Wrapping, k); } _drawCalls.Add(_drawCallBuilder.Build()); } } UpdateLightTransforms(); }
/// <summary> /// Function to create a draw call based on a mesh. /// </summary> /// <param name="mesh">The mesh to evaluate.</param> private void AddDrawCall(Mesh mesh) { // Find out which shaders are used by the mesh and retrieve them from the cache. if (!ShaderCache.TryGetValue(mesh.Material.VertexShader, out GorgonShader shader)) { return; } var vertexShader = (GorgonVertexShader)shader; if (!ShaderCache.TryGetValue(mesh.Material.PixelShader, out shader)) { return; } // Not an ideal place for this, but since we don't know when a vertex shader will be added to our renderer, and we require a vertex shader for our // input layout, then this will have to suffice. In a real renderer, we'd cache the vertex inputs per shader and just look it up because the type // of vertex may not be what we expect. In this case, we *know* that we're using Vertex3D and no other vertex type, so we're 100% safe doing it // here in this example. if ((_vertexLayout == null) && (vertexShader != null)) { _vertexLayout = GorgonInputLayout.CreateUsingType <Vertex3D>(_graphics, vertexShader); } var pixelShader = (GorgonPixelShader)shader; GorgonPipelineState pipelineState = _stateBuilder.Clear() .DepthStencilState(mesh.IsDepthWriteEnabled ? GorgonDepthStencilState.DepthEnabled : GorgonDepthStencilState.DepthEnabledNoWrite) .PixelShader(pixelShader) .VertexShader(vertexShader) .BlendState(mesh.Material.BlendState) .PrimitiveType(mesh.PrimitiveType) .Build(); _drawBuilder.Clear() .PipelineState(pipelineState) .IndexBuffer(mesh.IndexBuffer, 0, mesh.IndexCount) .VertexBuffer(_vertexLayout, new GorgonVertexBufferBinding(mesh.VertexBuffer, Vertex3D.Size)) .ConstantBuffer(ShaderType.Vertex, _viewProjectionBuffer) .ConstantBuffer(ShaderType.Vertex, _worldBuffer, 1) .ConstantBuffer(ShaderType.Pixel, _cameraBuffer) .ConstantBuffer(ShaderType.Pixel, _lightBuffer, 1) .ConstantBuffer(ShaderType.Pixel, _materialBuffer, 2); ref readonly (int Start, int Count)textures = ref mesh.Material.Textures.GetDirtyItems();
/// <summary> /// Function to initialize the blitter. /// </summary> public void Initialize() { try { // We've been initialized, so leave. if ((_vertexShader != null) || (Interlocked.Increment(ref _initializedFlag) > 1)) { // Trap other threads until we're done initializing and then release them. while ((_vertexShader == null) && (_initializedFlag > 0)) { var wait = new SpinWait(); wait.SpinOnce(); } return; } _vertexShader = GorgonShaderFactory.Compile <GorgonVertexShader>(_graphics, Resources.GraphicsShaders, "GorgonBltVertexShader", GorgonGraphics.IsDebugEnabled); _pixelShader = GorgonShaderFactory.Compile <GorgonPixelShader>(_graphics, Resources.GraphicsShaders, "GorgonBltPixelShader", GorgonGraphics.IsDebugEnabled); _inputLayout = GorgonInputLayout.CreateUsingType <BltVertex>(_graphics, _vertexShader); _vertexBufferBindings = new GorgonVertexBufferBindings(_inputLayout) { [0] = GorgonVertexBufferBinding.CreateVertexBuffer <BltVertex>(_graphics, 4, ResourceUsage.Dynamic, bufferName: "Gorgon Blitter Vertex Buffer") }; _wvpBuffer = GorgonConstantBufferView.CreateConstantBuffer(_graphics, new GorgonConstantBufferInfo("Gorgon Blitter WVP Buffer") { Usage = ResourceUsage.Dynamic, SizeInBytes = DX.Matrix.SizeInBytes }); // Finish initalizing the draw call. _pipelineState = _pipeStateBuilder.VertexShader(_vertexShader) .BlendState(GorgonBlendState.NoBlending) .DepthStencilState(GorgonDepthStencilState.Default) .PrimitiveType(PrimitiveType.TriangleStrip) .RasterState(GorgonRasterState.Default) .PixelShader(_pixelShader) .Build(); _drawCallBuilder.VertexBuffers(_inputLayout, _vertexBufferBindings) .VertexRange(0, 4) .SamplerState(ShaderType.Pixel, GorgonSamplerState.Default) .PipelineState(_pipelineState) .ConstantBuffer(ShaderType.Vertex, _wvpBuffer); _defaultTexture = Resources.White_2x2.ToTexture2D(_graphics, new GorgonTexture2DLoadOptions { Name = "Gorgon_Default_White_Texture", Usage = ResourceUsage.Immutable, Binding = TextureBinding.ShaderResource }).GetShaderResourceView(); } finally { Interlocked.Decrement(ref _initializedFlag); } }