Esempio n. 1
0
        /// <summary>
        /// Sets a transform feedback buffer on the graphics pipeline.
        /// The output from the vertex transformation stages are written into the feedback buffer.
        /// </summary>
        /// <param name="index">Index of the transform feedback buffer</param>
        /// <param name="gpuVa">Start GPU virtual address of the buffer</param>
        /// <param name="size">Size in bytes of the transform feedback buffer</param>
        public void SetTransformFeedbackBuffer(int index, ulong gpuVa, ulong size)
        {
            ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);

            _transformFeedbackBuffers[index] = new BufferBounds(address, size);
            _transformFeedbackBuffersDirty   = true;
        }
Esempio n. 2
0
        /// <summary>
        /// Sets a transform feedback buffer on the graphics pipeline.
        /// The output from the vertex transformation stages are written into the feedback buffer.
        /// </summary>
        /// <param name="index">Index of the transform feedback buffer</param>
        /// <param name="gpuVa">Start GPU virtual address of the buffer</param>
        /// <param name="size">Size in bytes of the transform feedback buffer</param>
        public void SetTransformFeedbackBuffer(int index, ulong gpuVa, ulong size)
        {
            ulong address = TranslateAndCreateBuffer(gpuVa, size);

            _transformFeedbackBuffers[index] = new BufferBounds(address, size);
            _transformFeedbackBuffersDirty   = true;
        }
Esempio n. 3
0
        /// <summary>
        /// Binds a buffer on the host API.
        /// </summary>
        /// <param name="index">Index to bind the buffer into</param>
        /// <param name="stage">Shader stage to bind the buffer into</param>
        /// <param name="bounds">Buffer address and size</param>
        /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
        private void BindBuffer(int index, ShaderStage stage, BufferBounds bounds, bool isStorage)
        {
            BufferRange buffer = GetBufferRange(bounds.Address, bounds.Size);

            if (isStorage)
            {
                _context.Renderer.Pipeline.SetStorageBuffer(index, stage, buffer);
            }
            else
            {
                _context.Renderer.Pipeline.SetUniformBuffer(index, stage, buffer);
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Ensures that the compute engine bindings are visible to the host GPU.
        /// Note: this actually performs the binding using the host graphics API.
        /// </summary>
        public void CommitComputeBindings()
        {
            uint enableMask = _cpStorageBuffers.EnableMask;

            for (int index = 0; (enableMask >> index) != 0; index++)
            {
                if ((enableMask & (1u << index)) == 0)
                {
                    continue;
                }

                BufferBounds bounds = _cpStorageBuffers.Buffers[index];

                if (bounds.Address == 0)
                {
                    continue;
                }

                BufferRange buffer = GetBufferRange(bounds.Address, bounds.Size);

                int bindingPoint = CurrentShaderMeta(ShaderStage.Compute).GetStorageBufferBindingPoint(ShaderStage.Compute, index);

                _context.Renderer.Pipeline.SetStorageBuffer(bindingPoint, buffer);
            }

            enableMask = _cpUniformBuffers.EnableMask;

            for (int index = 0; (enableMask >> index) != 0; index++)
            {
                if ((enableMask & (1u << index)) == 0)
                {
                    continue;
                }

                BufferBounds bounds = _cpUniformBuffers.Buffers[index];

                if (bounds.Address == 0)
                {
                    continue;
                }

                BufferRange buffer = GetBufferRange(bounds.Address, bounds.Size);

                int bindingPoint = CurrentShaderMeta(ShaderStage.Compute).GetUniformBufferBindingPoint(ShaderStage.Compute, index);

                _context.Renderer.Pipeline.SetUniformBuffer(bindingPoint, buffer);
            }

            // Force rebind after doing compute work.
            _rebind = true;
        }
Esempio n. 5
0
        /// <summary>
        /// Ensures that the compute engine bindings are visible to the host GPU.
        /// Note: this actually performs the binding using the host graphics API.
        /// </summary>
        public void CommitComputeBindings()
        {
            int sCount = _cpStorageBufferBindings;

            Span <BufferRange> sRanges = sCount < StackToHeapThreshold ? stackalloc BufferRange[sCount] : new BufferRange[sCount];

            for (int index = 0; index < _cpStorageBuffers.Count; index++)
            {
                ref var bindingInfo = ref _cpStorageBuffers.Bindings[index];

                BufferBounds bounds = _cpStorageBuffers.Buffers[bindingInfo.Slot];

                if (bounds.Address != 0)
                {
                    sRanges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size, bounds.Flags.HasFlag(BufferUsageFlags.Write));
                }
            }
Esempio n. 6
0
        /// <summary>
        /// Binds a buffer on the host API.
        /// </summary>
        /// <param name="index">Index to bind the buffer into</param>
        /// <param name="stage">Shader stage to bind the buffer into</param>
        /// <param name="bounds">Buffer address and size</param>
        /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
        private void BindBuffer(int index, ShaderStage stage, BufferBounds bounds, bool isStorage)
        {
            BufferRange buffer = GetBufferRange(bounds.Address, bounds.Size);

            if (isStorage)
            {
                int bindingPoint = CurrentShaderMeta(stage).GetStorageBufferBindingPoint(stage, index);

                _context.Renderer.Pipeline.SetStorageBuffer(bindingPoint, buffer);
            }
            else
            {
                int bindingPoint = CurrentShaderMeta(stage).GetUniformBufferBindingPoint(stage, index);

                _context.Renderer.Pipeline.SetUniformBuffer(bindingPoint, buffer);
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Ensures that the compute engine bindings are visible to the host GPU.
        /// Note: this actually performs the binding using the host graphics API.
        /// </summary>
        public void CommitComputeBindings()
        {
            int sCount = _cpStorageBufferBindings;

            Span <BufferRange> sRanges = sCount < StackToHeapThreshold ? stackalloc BufferRange[sCount] : new BufferRange[sCount];

            for (int index = 0; index < _cpStorageBuffers.Count; index++)
            {
                ref var bindingInfo = ref _cpStorageBuffers.Bindings[index];

                BufferBounds bounds = _cpStorageBuffers.Buffers[bindingInfo.Slot];

                if (bounds.Address != 0)
                {
                    // The storage buffer size is not reliable (it might be lower than the actual size),
                    // so we bind the entire buffer to allow otherwise out of range accesses to work.
                    sRanges[bindingInfo.Binding] = GetBufferRangeTillEnd(
                        bounds.Address,
                        bounds.Size,
                        bounds.Flags.HasFlag(BufferUsageFlags.Write));
                }
            }
Esempio n. 8
0
        private void BindBuffers(BufferCache bufferCache, BuffersPerStage[] bindings, bool isStorage)
        {
            int rangesFirst = 0;
            int rangesCount = 0;

            Span <BufferRange> ranges = _ranges;

            for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
            {
                ref var buffers = ref bindings[(int)stage - 1];

                for (int index = 0; index < buffers.Count; index++)
                {
                    ref var bindingInfo = ref buffers.Bindings[index];

                    BufferBounds bounds = buffers.Buffers[bindingInfo.Slot];

                    if (bounds.Address != 0)
                    {
                        var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
                        var range   = isStorage
                            ? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
                            : bufferCache.GetBufferRange(bounds.Address, bounds.Size);

                        if (rangesCount == 0)
                        {
                            rangesFirst = bindingInfo.Binding;
                        }
                        else if (bindingInfo.Binding != rangesFirst + rangesCount)
                        {
                            SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
                            rangesFirst = bindingInfo.Binding;
                            rangesCount = 0;
                        }

                        ranges[rangesCount++] = range;
                    }
                }
Esempio n. 9
0
        /// <summary>
        /// This binds buffers into the host API, or updates data for already bound buffers.
        /// </summary>
        /// <param name="bindings">Bindings to bind or update</param>
        /// <param name="bind">True to bind, false to update</param>
        /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
        private void BindOrUpdateBuffers(BuffersPerStage[] bindings, bool bind, bool isStorage = false)
        {
            for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
            {
                uint enableMask = bindings[(int)stage - 1].EnableMask;

                if (enableMask == 0)
                {
                    continue;
                }

                for (int index = 0; (enableMask >> index) != 0; index++)
                {
                    if ((enableMask & (1u << index)) == 0)
                    {
                        continue;
                    }

                    BufferBounds bounds = bindings[(int)stage - 1].Buffers[index];

                    if (bounds.Address == 0)
                    {
                        continue;
                    }

                    if (bind)
                    {
                        BindBuffer(index, stage, bounds, isStorage);
                    }
                    else
                    {
                        SynchronizeBufferRange(bounds.Address, bounds.Size);
                    }
                }
            }
        }
Esempio n. 10
0
 /// <summary>
 /// Sets the region of a buffer at a given slot.
 /// </summary>
 /// <param name="index">Buffer slot</param>
 /// <param name="address">Region virtual address</param>
 /// <param name="size">Region size in bytes</param>
 /// <param name="flags">Buffer usage flags</param>
 public void SetBounds(int index, ulong address, ulong size, BufferUsageFlags flags = BufferUsageFlags.None)
 {
     Buffers[index] = new BufferBounds(address, size, flags);
 }
Esempio n. 11
0
 /// <summary>
 /// Creates a new instance of the shader stage buffer information.
 /// </summary>
 /// <param name="count">Maximum amount of buffers that the shader stage can use</param>
 public BuffersPerStage(int count)
 {
     Bindings = new BufferDescriptor[count];
     Buffers  = new BufferBounds[count];
 }
Esempio n. 12
0
        /// <summary>
        /// Ensures that the graphics engine bindings are visible to the host GPU.
        /// Note: this actually performs the binding using the host graphics API.
        /// </summary>
        public void CommitGraphicsBindings()
        {
            if (_indexBufferDirty || _rebind)
            {
                _indexBufferDirty = false;

                if (_indexBuffer.Address != 0)
                {
                    BufferRange buffer = GetBufferRange(_indexBuffer.Address, _indexBuffer.Size);

                    _context.Renderer.Pipeline.SetIndexBuffer(buffer, _indexBuffer.Type);
                }
            }
            else if (_indexBuffer.Address != 0)
            {
                SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size);
            }

            uint vbEnableMask = _vertexBuffersEnableMask;

            if (_vertexBuffersDirty || _rebind)
            {
                _vertexBuffersDirty = false;

                Span <VertexBufferDescriptor> vertexBuffers = stackalloc VertexBufferDescriptor[Constants.TotalVertexBuffers];

                for (int index = 0; (vbEnableMask >> index) != 0; index++)
                {
                    VertexBuffer vb = _vertexBuffers[index];

                    if (vb.Address == 0)
                    {
                        continue;
                    }

                    BufferRange buffer = GetBufferRange(vb.Address, vb.Size);

                    vertexBuffers[index] = new VertexBufferDescriptor(buffer, vb.Stride, vb.Divisor);
                }

                _context.Renderer.Pipeline.SetVertexBuffers(vertexBuffers);
            }
            else
            {
                for (int index = 0; (vbEnableMask >> index) != 0; index++)
                {
                    VertexBuffer vb = _vertexBuffers[index];

                    if (vb.Address == 0)
                    {
                        continue;
                    }

                    SynchronizeBufferRange(vb.Address, vb.Size);
                }
            }

            if (_transformFeedbackBuffersDirty || _rebind)
            {
                _transformFeedbackBuffersDirty = false;

                for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
                {
                    BufferBounds tfb = _transformFeedbackBuffers[index];

                    if (tfb.Address == 0)
                    {
                        _context.Renderer.Pipeline.SetTransformFeedbackBuffer(index, new BufferRange(BufferHandle.Null, 0, 0));

                        continue;
                    }

                    BufferRange buffer = GetBufferRange(tfb.Address, tfb.Size);

                    _context.Renderer.Pipeline.SetTransformFeedbackBuffer(index, buffer);
                }
            }
            else
            {
                for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
                {
                    BufferBounds tfb = _transformFeedbackBuffers[index];

                    if (tfb.Address == 0)
                    {
                        continue;
                    }

                    SynchronizeBufferRange(tfb.Address, tfb.Size);
                }
            }

            if (_gpStorageBuffersDirty || _rebind)
            {
                _gpStorageBuffersDirty = false;

                BindBuffers(_gpStorageBuffers, isStorage: true);
            }
            else
            {
                UpdateBuffers(_gpStorageBuffers);
            }

            if (_gpUniformBuffersDirty || _rebind)
            {
                _gpUniformBuffersDirty = false;

                BindBuffers(_gpUniformBuffers, isStorage: false);
            }
            else
            {
                UpdateBuffers(_gpUniformBuffers);
            }

            _rebind = false;
        }
Esempio n. 13
0
        /// <summary>
        /// Ensures that the graphics engine bindings are visible to the host GPU.
        /// Note: this actually performs the binding using the host graphics API.
        /// </summary>
        public void CommitGraphicsBindings()
        {
            var bufferCache = _channel.MemoryManager.Physical.BufferCache;

            if (_indexBufferDirty || _rebind)
            {
                _indexBufferDirty = false;

                if (_indexBuffer.Address != 0)
                {
                    BufferRange buffer = bufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size);

                    _context.Renderer.Pipeline.SetIndexBuffer(buffer, _indexBuffer.Type);
                }
            }
            else if (_indexBuffer.Address != 0)
            {
                bufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size);
            }

            uint vbEnableMask = _vertexBuffersEnableMask;

            if (_vertexBuffersDirty || _rebind)
            {
                _vertexBuffersDirty = false;

                Span <VertexBufferDescriptor> vertexBuffers = stackalloc VertexBufferDescriptor[Constants.TotalVertexBuffers];

                for (int index = 0; (vbEnableMask >> index) != 0; index++)
                {
                    VertexBuffer vb = _vertexBuffers[index];

                    if (vb.Address == 0)
                    {
                        continue;
                    }

                    BufferRange buffer = bufferCache.GetBufferRange(vb.Address, vb.Size);

                    vertexBuffers[index] = new VertexBufferDescriptor(buffer, vb.Stride, vb.Divisor);
                }

                _context.Renderer.Pipeline.SetVertexBuffers(vertexBuffers);
            }
            else
            {
                for (int index = 0; (vbEnableMask >> index) != 0; index++)
                {
                    VertexBuffer vb = _vertexBuffers[index];

                    if (vb.Address == 0)
                    {
                        continue;
                    }

                    bufferCache.SynchronizeBufferRange(vb.Address, vb.Size);
                }
            }

            if (_transformFeedbackBuffersDirty || _rebind)
            {
                _transformFeedbackBuffersDirty = false;

                Span <BufferRange> tfbs = stackalloc BufferRange[Constants.TotalTransformFeedbackBuffers];

                for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
                {
                    BufferBounds tfb = _transformFeedbackBuffers[index];

                    if (tfb.Address == 0)
                    {
                        tfbs[index] = BufferRange.Empty;
                        continue;
                    }

                    tfbs[index] = bufferCache.GetBufferRange(tfb.Address, tfb.Size, write: true);
                }

                _context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs);
            }
            else
            {
                for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
                {
                    BufferBounds tfb = _transformFeedbackBuffers[index];

                    if (tfb.Address == 0)
                    {
                        continue;
                    }

                    bufferCache.SynchronizeBufferRange(tfb.Address, tfb.Size);
                }
            }

            if (_gpStorageBuffersDirty || _rebind)
            {
                _gpStorageBuffersDirty = false;

                BindBuffers(bufferCache, _gpStorageBuffers, isStorage: true);
            }
            else
            {
                UpdateBuffers(_gpStorageBuffers);
            }

            if (_gpUniformBuffersDirty || _rebind)
            {
                _gpUniformBuffersDirty = false;

                BindBuffers(bufferCache, _gpUniformBuffers, isStorage: false);
            }
            else
            {
                UpdateBuffers(_gpUniformBuffers);
            }

            CommitBufferTextureBindings();

            _rebind = false;
        }
Esempio n. 14
0
 /// <summary>
 /// Sets the region of a buffer at a given slot.
 /// </summary>
 /// <param name="index">Buffer slot</param>
 /// <param name="address">Region virtual address</param>
 /// <param name="size">Region size in bytes</param>
 public void SetBounds(int index, ulong address, ulong size)
 {
     Buffers[index] = new BufferBounds(address, size);
 }