Beispiel #1
0
        /// <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();
        }
Beispiel #2
0
        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;
        }
Beispiel #4
0
        /// <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;
        }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        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;
        }
Beispiel #8
0
 public void SetPipelineState(PipelineState pipelineState)
 {
     newPipelineState = pipelineState ?? GraphicsDevice.DefaultPipelineState;
 }
 public void SetPipelineState(PipelineState pipelineState)
 {
     NullHelper.ToImplement();
 }
Beispiel #10
0
 public void SetPipelineState(PipelineState pipelineState)
 {
     newPipelineState = pipelineState ?? GraphicsDevice.DefaultPipelineState;
 }
Beispiel #11
0
        /// <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();
        }
Beispiel #12
0
 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;
        }