/// <summary> /// Prepares a draw call. This method is called before each Draw() method to setup the correct Primitive, InputLayout and VertexBuffers. /// </summary> /// <exception cref="System.InvalidOperationException">Cannot GraphicsDevice.Draw*() without an effect being previously applied with Effect.Apply() method</exception> private void PrepareDraw() { // Pipeline state if (newPipelineState != currentPipelineState) { newPipelineState.Apply(this, currentPipelineState); currentPipelineState = newPipelineState; } // Resources if (newPipelineState != null) { newPipelineState.ResourceBinder.BindResources(this, currentDescriptorSets); } SetViewportImpl(); }
private void ClearStateImpl() { NativeDeviceContext.ClearState(); for (int i = 0; i < samplerStates.Length; ++i) samplerStates[i] = null; for (int i = 0; i < constantBuffers.Length; ++i) constantBuffers[i] = null; for (int i = 0; i < unorderedAccessViews.Length; ++i) unorderedAccessViews[i] = null; for (int i = 0; i < currentRenderTargetViews.Length; i++) currentRenderTargetViews[i] = null; // Since nothing can be drawn in default state, no need to set anything (another SetPipelineState should happen before) currentPipelineState = GraphicsDevice.DefaultPipelineState; newPipelineState = GraphicsDevice.DefaultPipelineState; }
public void Reset() { GraphicsDevice.ReleaseTemporaryResources(); ResetSrvHeap(true); ResetSamplerHeap(true); // Clear descriptor mappings srvMapping.Clear(); samplerMapping.Clear(); // Get a new allocator nativeCommandAllocator = GraphicsDevice.CommandAllocators.GetObject(); NativeCommandList.Reset(nativeCommandAllocator, null); NativeCommandList.SetDescriptorHeaps(2, descriptorHeaps); boundPipelineState = null; }
/// <summary> /// Determine and updates <see cref="CurrentState"/> from <see cref="State"/>. /// </summary> public void Update() { // Hash current state var hashedState = new PipelineStateDescriptionWithHash(State); // Find existing PipelineState object PipelineState pipelineState; // TODO GRAPHICS REFACTOR We could avoid lock by adding them to a ThreadLocal (or RenderContext) and merge at end of frame lock (cache) { if (!cache.TryGetValue(hashedState, out pipelineState)) { // Otherwise, instantiate it // First, make an copy hashedState = new PipelineStateDescriptionWithHash(State.Clone()); cache.Add(hashedState, pipelineState = PipelineState.New(graphicsDevice, ref State)); } } CurrentState = pipelineState; }
/// <summary> /// Determine and updates <see cref="CurrentState"/> from <see cref="State"/>. /// </summary> public void Update() { // Hash current state var hashedState = new PipelineStateDescriptionWithHash(State); // Find existing PipelineState object PipelineState pipelineState; // TODO GRAPHICS REFACTOR We could avoid lock by adding them to a ThreadLocal (or RenderContext) and merge at end of frame lock (cache) { if (!cache.TryGetValue(hashedState, out pipelineState)) { // Otherwise, instantiate it // First, make an copy hashedState = new PipelineStateDescriptionWithHash(State.Clone()); cache.Add(hashedState, pipelineState = PipelineState.New(graphicsDevice, ref State)); } } CurrentState = pipelineState; }
public static PipelineState New(GraphicsDevice graphicsDevice, ref PipelineStateDescription pipelineStateDescription) { // Hash the current state var hashedState = new PipelineStateDescriptionWithHash(pipelineStateDescription); // Store SamplerState in a cache (D3D seems to have quite bad concurrency when using CreateSampler while rendering) PipelineState pipelineState; lock (graphicsDevice.CachedPipelineStates) { if (graphicsDevice.CachedPipelineStates.TryGetValue(hashedState, out pipelineState)) { // TODO: Appropriate destroy pipelineState.AddReferenceInternal(); } else { pipelineState = new PipelineState(graphicsDevice, pipelineStateDescription); graphicsDevice.CachedPipelineStates.Add(hashedState, pipelineState); } } return(pipelineState); }
private void ClearStateImpl() { NativeDeviceContext.ClearState(); for (int i = 0; i < samplerStates.Length; ++i) { samplerStates[i] = null; } for (int i = 0; i < constantBuffers.Length; ++i) { constantBuffers[i] = null; } for (int i = 0; i < unorderedAccessViews.Length; ++i) { unorderedAccessViews[i] = null; } for (int i = 0; i < currentRenderTargetViews.Length; i++) { currentRenderTargetViews[i] = null; } // Since nothing can be drawn in default state, no need to set anything (another SetPipelineState should happen before) currentPipelineState = GraphicsDevice.DefaultPipelineState; }
public void SetPipelineState(PipelineState pipelineState) { newPipelineState = pipelineState ?? GraphicsDevice.DefaultPipelineState; }
public void SetPipelineState(PipelineState pipelineState) { NullHelper.ToImplement(); }
public void SetPipelineState(PipelineState pipelineState) { newPipelineState = pipelineState ?? GraphicsDevice.DefaultPipelineState; }
/// <summary> /// Prepares a draw call. This method is called before each Draw() method to setup the correct Primitive, InputLayout and VertexBuffers. /// </summary> /// <exception cref="System.InvalidOperationException">Cannot GraphicsDevice.Draw*() without an effect being previously applied with Effect.Apply() method</exception> private void PrepareDraw() { // Pipeline state if (newPipelineState != currentPipelineState) { newPipelineState.Apply(this, currentPipelineState); currentPipelineState = newPipelineState; } // Resources if (newPipelineState != null) newPipelineState.ResourceBinder.BindResources(this, currentDescriptorSets); SetViewportImpl(); }
public void SetPipelineState(PipelineState pipelineState) { boundPipelineState = pipelineState; if (pipelineState.CompiledState != null) { NativeCommandList.PipelineState = pipelineState.CompiledState; NativeCommandList.SetGraphicsRootSignature(pipelineState.RootSignature); } NativeCommandList.PrimitiveTopology = pipelineState.PrimitiveTopology; }
internal void Apply(CommandList commandList, PipelineState previousPipeline) { var nativeDeviceContext = commandList.NativeDeviceContext; if (rootSignature != previousPipeline.rootSignature) { //rootSignature.Apply } if (effectBytecode != previousPipeline.effectBytecode) { if (computeShader != null) { if (computeShader != previousPipeline.computeShader) { nativeDeviceContext.ComputeShader.Set(computeShader); } } else { if (vertexShader != previousPipeline.vertexShader) { nativeDeviceContext.VertexShader.Set(vertexShader); } if (pixelShader != previousPipeline.pixelShader) { nativeDeviceContext.PixelShader.Set(pixelShader); } if (hullShader != previousPipeline.hullShader) { nativeDeviceContext.HullShader.Set(hullShader); } if (domainShader != previousPipeline.domainShader) { nativeDeviceContext.DomainShader.Set(domainShader); } if (geometryShader != previousPipeline.geometryShader) { nativeDeviceContext.GeometryShader.Set(geometryShader); } } } if (blendState != previousPipeline.blendState || sampleMask != previousPipeline.sampleMask) { nativeDeviceContext.OutputMerger.SetBlendState(blendState, nativeDeviceContext.OutputMerger.BlendFactor, sampleMask); } if (rasterizerState != previousPipeline.rasterizerState) { nativeDeviceContext.Rasterizer.State = rasterizerState; } if (depthStencilState != previousPipeline.depthStencilState) { nativeDeviceContext.OutputMerger.DepthStencilState = depthStencilState; } if (inputLayout != previousPipeline.inputLayout) { nativeDeviceContext.InputAssembler.InputLayout = inputLayout; } if (primitiveTopology != previousPipeline.primitiveTopology) { nativeDeviceContext.InputAssembler.PrimitiveTopology = primitiveTopology; } }
private void ClearStateImpl() { #if DEBUG GraphicsDevice.EnsureContextActive(); #endif // Clear sampler states for (int i = 0; i < samplerStates.Length; ++i) samplerStates[i] = null; for (int i = 0; i < boundShaderResourceViews.Length; ++i) { shaderResourceViews[i] = null; } // Clear active texture state activeTexture = 0; GL.ActiveTexture(TextureUnit.Texture0); // set default states currentPipelineState = GraphicsDevice.DefaultPipelineState; newPipelineState = GraphicsDevice.DefaultPipelineState; // Actually reset states //currentPipelineState.BlendState.Apply(); GL.Disable(EnableCap.Blend); GL.ColorMask(true, true, true, true); currentPipelineState.DepthStencilState.Apply(this); currentPipelineState.RasterizerState.Apply(this); #if SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLCORE GL.Enable(EnableCap.FramebufferSrgb); #endif }
internal unsafe void PreDraw() { #if SILICONSTUDIO_PLATFORM_ANDROID // Device with no background loading context: check if some loading is pending if (GraphicsDevice.AsyncPendingTaskWaiting) GraphicsDevice.ExecutePendingTasks(); #endif // Bind program var program = newPipelineState.EffectProgram.ProgramId; if (program != boundProgram) { boundProgram = program; GL.UseProgram(boundProgram); } int vertexBufferSlot = -1; var vertexBufferView = default(VertexBufferView); Buffer vertexBuffer = null; var vertexBufferBase = IntPtr.Zero; // TODO OPENGL compare newPipelineState.VertexAttribs directly if (newPipelineState.VertexAttribs != currentPipelineState.VertexAttribs) { vboDirty = true; } // Setup vertex buffers and vertex attributes if (vboDirty) { foreach (var vertexAttrib in newPipelineState.VertexAttribs) { if (vertexAttrib.VertexBufferSlot != vertexBufferSlot) { vertexBufferSlot = vertexAttrib.VertexBufferSlot; vertexBufferView = vertexBuffers[vertexBufferSlot]; vertexBuffer = vertexBufferView.Buffer; if (vertexBuffer != null) { var vertexBufferResource = vertexBufferView.Buffer.BufferId; GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferResource); vertexBufferBase = vertexBufferView.Buffer.StagingData; } } var vertexAttribMask = 1U << vertexAttrib.AttributeIndex; if (vertexBuffer == null) { // No VB bound, turn off this attribute if ((enabledVertexAttribArrays & vertexAttribMask) != 0) { enabledVertexAttribArrays &= ~vertexAttribMask; GL.DisableVertexAttribArray(vertexAttrib.AttributeIndex); } continue; } // Enable this attribute if not previously enabled if ((enabledVertexAttribArrays & vertexAttribMask) == 0) { enabledVertexAttribArrays |= vertexAttribMask; GL.EnableVertexAttribArray(vertexAttrib.AttributeIndex); } #if !SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES if (vertexAttrib.IsInteger && !vertexAttrib.Normalized) GL.VertexAttribIPointer(vertexAttrib.AttributeIndex, vertexAttrib.Size, (VertexAttribIntegerType)vertexAttrib.Type, vertexBufferView.Stride, vertexBufferBase + vertexBufferView.Offset + vertexAttrib.Offset); else #endif GL.VertexAttribPointer(vertexAttrib.AttributeIndex, vertexAttrib.Size, vertexAttrib.Type, vertexAttrib.Normalized, vertexBufferView.Stride, vertexBufferBase + vertexBufferView.Offset + vertexAttrib.Offset); } vboDirty = false; } // Resources newPipelineState.ResourceBinder.BindResources(this, currentDescriptorSets); // States newPipelineState.Apply(this, currentPipelineState); foreach (var textureInfo in newPipelineState.EffectProgram.Textures) { var boundTexture = boundShaderResourceViews[textureInfo.TextureUnit]; var shaderResourceView = shaderResourceViews[textureInfo.TextureUnit]; if (shaderResourceView != null) { var texture = shaderResourceView as Texture; var boundSamplerState = texture?.BoundSamplerState ?? GraphicsDevice.DefaultSamplerState; var samplerState = samplerStates[textureInfo.TextureUnit] ?? GraphicsDevice.SamplerStates.LinearClamp; bool textureChanged = shaderResourceView != boundTexture; bool samplerStateChanged = texture != null && samplerState != boundSamplerState; if (textureChanged || samplerStateChanged) { if (activeTexture != textureInfo.TextureUnit) { activeTexture = textureInfo.TextureUnit; GL.ActiveTexture(TextureUnit.Texture0 + textureInfo.TextureUnit); } // Lazy update for texture if (textureChanged) { boundShaderResourceViews[textureInfo.TextureUnit] = shaderResourceView; GL.BindTexture(shaderResourceView.TextureTarget, shaderResourceView.TextureId); } // Lazy update for sampler state if (samplerStateChanged && texture != null) { // TODO: Include hasMipmap in samplerStateChanged bool hasMipmap = texture.Description.MipLevels > 1; samplerState.Apply(hasMipmap, boundSamplerState, texture.TextureTarget); texture.BoundSamplerState = samplerState; } } } } // Update viewports SetViewportImpl(); #if SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES if (GraphicsDevice.IsOpenGLES2) { fixed(byte* boundUniforms = newPipelineState.EffectProgram.BoundUniforms) { foreach (var uniform in newPipelineState.EffectProgram.Uniforms) { var constantBuffer = constantBuffers[uniform.ConstantBufferSlot]; if (constantBuffer == null) continue; var constantBufferOffsetStart = newPipelineState.EffectProgram.ConstantBufferOffsets[uniform.ConstantBufferSlot]; var constantBufferData = constantBuffer.StagingData; var firstUniformIndex = uniform.UniformIndex; var lastUniformIndex = firstUniformIndex + uniform.Count; var offset = uniform.Offset; var boundData = (IntPtr)boundUniforms + offset + constantBufferOffsetStart; var currentData = constantBufferData + offset; // Already updated? Early exit. // TODO: Not optimal for float1/float2 arrays (rare?) // Better to do "sparse" comparison, not sure if C# code would behave well though if (SiliconStudio.Core.Utilities.CompareMemory(boundData, currentData, uniform.CompareSize)) continue; // Update bound cache for early exit SiliconStudio.Core.Utilities.CopyMemory(boundData, currentData, uniform.CompareSize); switch (uniform.Type) { case ActiveUniformType.Float: for (int uniformIndex = firstUniformIndex; uniformIndex < lastUniformIndex; ++uniformIndex) { GL.Uniform1(uniformIndex, 1, (float*)currentData); currentData += 16; // Each array element is spaced by 16 bytes } break; case ActiveUniformType.FloatVec2: for (int uniformIndex = firstUniformIndex; uniformIndex < lastUniformIndex; ++uniformIndex) { GL.Uniform2(uniformIndex, 1, (float*)currentData); currentData += 16; // Each array element is spaced by 16 bytes } break; case ActiveUniformType.FloatVec3: for (int uniformIndex = firstUniformIndex; uniformIndex < lastUniformIndex; ++uniformIndex) { GL.Uniform3(uniformIndex, 1, (float*)currentData); currentData += 16; // Each array element is spaced by 16 bytes } break; case ActiveUniformType.FloatVec4: GL.Uniform4(firstUniformIndex, uniform.Count, (float*)currentData); break; case ActiveUniformType.FloatMat4: GL.UniformMatrix4(uniform.UniformIndex, uniform.Count, false, (float*)currentData); break; case ActiveUniformType.Bool: case ActiveUniformType.Int: for (int uniformIndex = firstUniformIndex; uniformIndex < lastUniformIndex; ++uniformIndex) { GL.Uniform1(uniformIndex, 1, (int*)currentData); currentData += 16; // Each array element is spaced by 16 bytes } break; case ActiveUniformType.BoolVec2: case ActiveUniformType.IntVec2: for (int uniformIndex = firstUniformIndex; uniformIndex < lastUniformIndex; ++uniformIndex) { GL.Uniform2(uniformIndex, 1, (int*)currentData); currentData += 16; // Each array element is spaced by 16 bytes } break; case ActiveUniformType.BoolVec3: case ActiveUniformType.IntVec3: for (int uniformIndex = firstUniformIndex; uniformIndex < lastUniformIndex; ++uniformIndex) { GL.Uniform3(uniformIndex, 1, (int*)currentData); currentData += 16; // Each array element is spaced by 16 bytes } break; case ActiveUniformType.BoolVec4: case ActiveUniformType.IntVec4: GL.Uniform4(firstUniformIndex, uniform.Count, (int*)currentData); break; default: Internal.Refactor.ThrowNotImplementedException(); break; } } } } #endif currentPipelineState = newPipelineState; }