/// <summary> /// Performs a indirect multi-draw, with parameters from a GPU buffer. /// </summary> /// <param name="engine">3D engine where this method is being called</param> /// <param name="topology">Primitive topology</param> /// <param name="indirectBuffer">GPU buffer with the draw parameters, such as count, first index, etc</param> /// <param name="parameterBuffer">GPU buffer with the draw count</param> /// <param name="maxDrawCount">Maximum number of draws that can be made</param> /// <param name="stride">Distance in bytes between each element on the <paramref name="indirectBuffer"/> array</param> public void MultiDrawIndirectCount( ThreedClass engine, int indexCount, PrimitiveTopology topology, BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride) { engine.Write(IndexBufferCountMethodOffset * 4, indexCount); _context.Renderer.Pipeline.SetPrimitiveTopology(topology); _drawState.Topology = topology; ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable( _context, _channel.MemoryManager, _state.State.RenderEnableAddress, _state.State.RenderEnableCondition); if (renderEnable == ConditionalRenderEnabled.False) { _drawState.DrawIndexed = false; return; } _drawState.FirstIndex = _state.State.IndexBufferState.First; _drawState.IndexCount = indexCount; engine.UpdateState(); if (_drawState.DrawIndexed) { _context.Renderer.Pipeline.MultiDrawIndexedIndirectCount(indirectBuffer, parameterBuffer, maxDrawCount, stride); } else { _context.Renderer.Pipeline.MultiDrawIndirectCount(indirectBuffer, parameterBuffer, maxDrawCount, stride); } _drawState.DrawIndexed = false; if (renderEnable == ConditionalRenderEnabled.Host) { _context.Renderer.Pipeline.EndHostConditionalRendering(); } }
/// <summary> /// Performs a indirect multi-draw, with parameters from a GPU buffer. /// </summary> /// <param name="state">Current GPU state</param> /// <param name="topology">Primitive topology</param> /// <param name="indirectBuffer">GPU buffer with the draw parameters, such as count, first index, etc</param> /// <param name="parameterBuffer">GPU buffer with the draw count</param> /// <param name="maxDrawCount">Maximum number of draws that can be made</param> /// <param name="stride">Distance in bytes between each element on the <paramref name="indirectBuffer"/> array</param> public void MultiDrawIndirectCount( GpuState state, PrimitiveTopology topology, BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride) { _context.Renderer.Pipeline.SetPrimitiveTopology(topology); Topology = topology; ConditionalRenderEnabled renderEnable = GetRenderEnable(state); if (renderEnable == ConditionalRenderEnabled.False) { _drawIndexed = false; return; } var indexBuffer = state.Get <IndexBufferState>(MethodOffset.IndexBufferState); FlushUboDirty(); UpdateState(state, indexBuffer.First, indexBuffer.Count); if (_drawIndexed) { _context.Renderer.Pipeline.MultiDrawIndexedIndirectCount(indirectBuffer, parameterBuffer, maxDrawCount, stride); } else { _context.Renderer.Pipeline.MultiDrawIndirectCount(indirectBuffer, parameterBuffer, maxDrawCount, stride); } _drawIndexed = false; if (renderEnable == ConditionalRenderEnabled.Host) { _context.Renderer.Pipeline.EndHostConditionalRendering(); } }
/// <summary> /// Finishes the draw call. /// This draws geometry on the bound buffers based on the current GPU state. /// </summary> /// <param name="engine">3D engine where this method is being called</param> /// <param name="firstIndex">Index of the first index buffer element used on the draw</param> /// <param name="indexCount">Number of index buffer elements used on the draw</param> private void DrawEnd(ThreedClass engine, int firstIndex, int indexCount) { ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable( _context, _channel.MemoryManager, _state.State.RenderEnableAddress, _state.State.RenderEnableCondition); if (renderEnable == ConditionalRenderEnabled.False || _instancedDrawPending) { if (renderEnable == ConditionalRenderEnabled.False) { PerformDeferredDraws(); } _drawState.DrawIndexed = false; if (renderEnable == ConditionalRenderEnabled.Host) { _context.Renderer.Pipeline.EndHostConditionalRendering(); } return; } _drawState.FirstIndex = firstIndex; _drawState.IndexCount = indexCount; engine.UpdateState(); bool instanced = _drawState.VsUsesInstanceId || _drawState.IsAnyVbInstanced; if (instanced) { _instancedDrawPending = true; _instancedIndexed = _drawState.DrawIndexed; _instancedFirstIndex = firstIndex; _instancedFirstVertex = (int)_state.State.FirstVertex; _instancedFirstInstance = (int)_state.State.FirstInstance; _instancedIndexCount = indexCount; var drawState = _state.State.VertexBufferDrawState; _instancedDrawStateFirst = drawState.First; _instancedDrawStateCount = drawState.Count; _drawState.DrawIndexed = false; if (renderEnable == ConditionalRenderEnabled.Host) { _context.Renderer.Pipeline.EndHostConditionalRendering(); } return; } int firstInstance = (int)_state.State.FirstInstance; int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount(); if (inlineIndexCount != 0) { int firstVertex = (int)_state.State.FirstVertex; BufferRange br = new BufferRange(_drawState.IbStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4); _channel.BufferManager.SetIndexBuffer(br, IndexType.UInt); _context.Renderer.Pipeline.DrawIndexed(inlineIndexCount, 1, firstIndex, firstVertex, firstInstance); } else if (_drawState.DrawIndexed) { int firstVertex = (int)_state.State.FirstVertex; _context.Renderer.Pipeline.DrawIndexed(indexCount, 1, firstIndex, firstVertex, firstInstance); } else { var drawState = _state.State.VertexBufferDrawState; _context.Renderer.Pipeline.Draw(drawState.Count, 1, drawState.First, firstInstance); } _drawState.DrawIndexed = false; if (renderEnable == ConditionalRenderEnabled.Host) { _context.Renderer.Pipeline.EndHostConditionalRendering(); } }
/// <summary> /// Finishes the draw call. /// This draws geometry on the bound buffers based on the current GPU state. /// </summary> /// <param name="state">Current GPU state</param> /// <param name="firstIndex">Index of the first index buffer element used on the draw</param> /// <param name="indexCount">Number of index buffer elements used on the draw</param> private void DrawEnd(GpuState state, int firstIndex, int indexCount) { ConditionalRenderEnabled renderEnable = GetRenderEnable(state); if (renderEnable == ConditionalRenderEnabled.False || _instancedDrawPending) { if (renderEnable == ConditionalRenderEnabled.False) { PerformDeferredDraws(); } _drawIndexed = false; if (renderEnable == ConditionalRenderEnabled.Host) { _context.Renderer.Pipeline.EndHostConditionalRendering(); } return; } FlushUboDirty(); UpdateState(state, firstIndex, indexCount); bool instanced = _vsUsesInstanceId || _isAnyVbInstanced; if (instanced) { _instancedDrawPending = true; _instancedIndexed = _drawIndexed; _instancedFirstIndex = firstIndex; _instancedFirstVertex = state.Get <int>(MethodOffset.FirstVertex); _instancedFirstInstance = state.Get <int>(MethodOffset.FirstInstance); _instancedIndexCount = indexCount; var drawState = state.Get <VertexBufferDrawState>(MethodOffset.VertexBufferDrawState); _instancedDrawStateFirst = drawState.First; _instancedDrawStateCount = drawState.Count; _drawIndexed = false; if (renderEnable == ConditionalRenderEnabled.Host) { _context.Renderer.Pipeline.EndHostConditionalRendering(); } return; } int firstInstance = state.Get <int>(MethodOffset.FirstInstance); int inlineIndexCount = _ibStreamer.GetAndResetInlineIndexCount(); if (inlineIndexCount != 0) { int firstVertex = state.Get <int>(MethodOffset.FirstVertex); BufferRange br = new BufferRange(_ibStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4); _context.Methods.BufferManager.SetIndexBuffer(br, IndexType.UInt); _context.Renderer.Pipeline.DrawIndexed( inlineIndexCount, 1, firstIndex, firstVertex, firstInstance); } else if (_drawIndexed) { int firstVertex = state.Get <int>(MethodOffset.FirstVertex); _context.Renderer.Pipeline.DrawIndexed( indexCount, 1, firstIndex, firstVertex, firstInstance); } else { var drawState = state.Get <VertexBufferDrawState>(MethodOffset.VertexBufferDrawState); _context.Renderer.Pipeline.Draw( drawState.Count, 1, drawState.First, firstInstance); } _drawIndexed = false; if (renderEnable == ConditionalRenderEnabled.Host) { _context.Renderer.Pipeline.EndHostConditionalRendering(); } }
/// <summary> /// Clears the current color and depth-stencil buffers. /// Which buffers should be cleared is also specified on the argument. /// </summary> /// <param name="engine">3D engine where this method is being called</param> /// <param name="argument">Method call argument</param> public void Clear(ThreedClass engine, int argument) { ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable( _context, _channel.MemoryManager, _state.State.RenderEnableAddress, _state.State.RenderEnableCondition); if (renderEnable == ConditionalRenderEnabled.False) { return; } // Scissor and rasterizer discard also affect clears. engine.UpdateState((1UL << StateUpdater.RasterizerStateIndex) | (1UL << StateUpdater.ScissorStateIndex)); int index = (argument >> 6) & 0xf; engine.UpdateRenderTargetState(useControl: false, singleUse: index); _channel.TextureManager.UpdateRenderTargets(); bool clearDepth = (argument & 1) != 0; bool clearStencil = (argument & 2) != 0; uint componentMask = (uint)((argument >> 2) & 0xf); if (componentMask != 0) { var clearColor = _state.State.ClearColors; ColorF color = new ColorF(clearColor.Red, clearColor.Green, clearColor.Blue, clearColor.Alpha); _context.Renderer.Pipeline.ClearRenderTargetColor(index, componentMask, color); } if (clearDepth || clearStencil) { float depthValue = _state.State.ClearDepthValue; int stencilValue = (int)_state.State.ClearStencilValue; int stencilMask = 0; if (clearStencil) { stencilMask = _state.State.StencilTestState.FrontMask; } _context.Renderer.Pipeline.ClearRenderTargetDepthStencil( depthValue, clearDepth, stencilValue, stencilMask); } engine.UpdateRenderTargetState(useControl: true); if (renderEnable == ConditionalRenderEnabled.Host) { _context.Renderer.Pipeline.EndHostConditionalRendering(); } }
/// <summary> /// Clears the current color and depth-stencil buffers. /// Which buffers should be cleared is also specified on the argument. /// </summary> /// <param name="state">Current GPU state</param> /// <param name="argument">Method call argument</param> private void Clear(GpuState state, int argument) { ConditionalRenderEnabled renderEnable = GetRenderEnable(state); if (renderEnable == ConditionalRenderEnabled.False) { return; } // Scissor and rasterizer discard also affect clears. if (state.QueryModified(MethodOffset.ScissorState)) { UpdateScissorState(state); } if (state.QueryModified(MethodOffset.RasterizeEnable)) { UpdateRasterizerState(state); } int index = (argument >> 6) & 0xf; UpdateRenderTargetState(state, useControl: false, singleUse: index); state.Channel.TextureManager.UpdateRenderTargets(); bool clearDepth = (argument & 1) != 0; bool clearStencil = (argument & 2) != 0; uint componentMask = (uint)((argument >> 2) & 0xf); if (componentMask != 0) { var clearColor = state.Get <ClearColors>(MethodOffset.ClearColors); ColorF color = new ColorF( clearColor.Red, clearColor.Green, clearColor.Blue, clearColor.Alpha); _context.Renderer.Pipeline.ClearRenderTargetColor(index, componentMask, color); } if (clearDepth || clearStencil) { float depthValue = state.Get <float>(MethodOffset.ClearDepthValue); int stencilValue = state.Get <int> (MethodOffset.ClearStencilValue); int stencilMask = 0; if (clearStencil) { stencilMask = state.Get <StencilTestState>(MethodOffset.StencilTestState).FrontMask; } _context.Renderer.Pipeline.ClearRenderTargetDepthStencil( depthValue, clearDepth, stencilValue, stencilMask); } UpdateRenderTargetState(state, useControl: true); if (renderEnable == ConditionalRenderEnabled.Host) { _context.Renderer.Pipeline.EndHostConditionalRendering(); } }
/// <summary> /// Finishes draw call. /// This draws geometry on the bound buffers based on the current GPU state. /// </summary> /// <param name="state">Current GPU state</param> /// <param name="argument">Method call argument</param> private void DrawEnd(GpuState state, int argument) { ConditionalRenderEnabled renderEnable = GetRenderEnable(state); if (renderEnable == ConditionalRenderEnabled.False || _instancedDrawPending) { if (renderEnable == ConditionalRenderEnabled.False) { PerformDeferredDraws(); } _drawIndexed = false; if (renderEnable == ConditionalRenderEnabled.Host) { _context.Renderer.Pipeline.EndHostConditionalRendering(); } return; } UpdateState(state); bool instanced = _vsUsesInstanceId || _isAnyVbInstanced; if (instanced) { _instancedDrawPending = true; _instancedIndexed = _drawIndexed; _instancedFirstIndex = _firstIndex; _instancedFirstVertex = state.Get <int>(MethodOffset.FirstVertex); _instancedFirstInstance = state.Get <int>(MethodOffset.FirstInstance); _instancedIndexCount = _indexCount; var drawState = state.Get <VertexBufferDrawState>(MethodOffset.VertexBufferDrawState); _instancedDrawStateFirst = drawState.First; _instancedDrawStateCount = drawState.Count; _drawIndexed = false; if (renderEnable == ConditionalRenderEnabled.Host) { _context.Renderer.Pipeline.EndHostConditionalRendering(); } return; } int firstInstance = state.Get <int>(MethodOffset.FirstInstance); if (_drawIndexed) { _drawIndexed = false; int firstVertex = state.Get <int>(MethodOffset.FirstVertex); _context.Renderer.Pipeline.DrawIndexed( _indexCount, 1, _firstIndex, firstVertex, firstInstance); } else { var drawState = state.Get <VertexBufferDrawState>(MethodOffset.VertexBufferDrawState); _context.Renderer.Pipeline.Draw( drawState.Count, 1, drawState.First, firstInstance); } if (renderEnable == ConditionalRenderEnabled.Host) { _context.Renderer.Pipeline.EndHostConditionalRendering(); } }