public override unsafe void GenerateSortKey(RenderView renderView, RenderViewStage renderViewStage, SortKey *sortKeys) { Matrix viewInverse = renderView.View; viewInverse.Invert(); var plane = new Plane(viewInverse.Forward, Vector3.Dot(viewInverse.TranslationVector, viewInverse.Forward)); // TODO: Point-normal-constructor seems wrong. Check. var renderNodes = renderViewStage.RenderNodes; int distanceShift = 32 - distancePrecision; int stateShift = 32 - statePrecision; for (int i = 0; i < renderNodes.Count; ++i) { var renderNode = renderNodes[i]; var renderObject = renderNode.RenderObject; var distance = CollisionHelper.DistancePlanePoint(ref plane, ref renderObject.BoundingBox.Center); var distanceI = ComputeDistance(distance); if (reverseDistance) { distanceI = ~distanceI; } // Compute sort key sortKeys[i] = new SortKey { Value = ((ulong)renderNode.RootRenderFeature.SortKey << 56) | ((ulong)(distanceI >> distanceShift) << distancePosition) | ((ulong)(renderObject.StateSortKey >> stateShift) << statePosition), Index = i, StableIndex = renderObject.Index }; } }
public override unsafe void GenerateSortKey(RenderView renderView, RenderViewStage renderViewStage, SortKey* sortKeys) { Matrix viewInverse = renderView.View; viewInverse.Invert(); var plane = new Plane(viewInverse.Forward, Vector3.Dot(viewInverse.TranslationVector, viewInverse.Forward)); // TODO: Point-normal-constructor seems wrong. Check. var renderNodes = renderViewStage.RenderNodes; int distanceShift = 32 - distancePrecision; int stateShift = 32 - statePrecision; for (int i = 0; i < renderNodes.Count; ++i) { var renderNode = renderNodes[i]; var renderObject = renderNode.RenderObject; var distance = CollisionHelper.DistancePlanePoint(ref plane, ref renderObject.BoundingBox.Center); var distanceI = ComputeDistance(distance); if (reverseDistance) distanceI = ~distanceI; // Compute sort key sortKeys[i] = new SortKey { Value = ((ulong)renderNode.RootRenderFeature.SortKey << 56) | ((ulong)(distanceI >> distanceShift) << distancePosition) | ((ulong)(renderObject.StateSortKey >> stateShift) << statePosition), Index = i }; } }
/// <inheritdoc/> public override void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage) { foreach (var renderFeature in RenderFeatures) { renderFeature.Draw(context, renderView, renderViewStage); } }
public void Draw(RenderDrawContext renderDrawContext, RenderView renderView, RenderStage renderStage) { // Sync point: draw (from now, we should execute with a graphics device context to perform rendering) // Look for the RenderViewStage corresponding to this RenderView | RenderStage combination RenderViewStage renderViewStage = null; foreach (var currentRenderViewStage in renderView.RenderStages) { if (currentRenderViewStage.RenderStage == renderStage) { renderViewStage = currentRenderViewStage; break; } } if (renderViewStage == null) { throw new InvalidOperationException("Requested RenderView|RenderStage combination doesn't exist. Please add it to RenderView.RenderStages."); } // Generate and execute draw jobs var renderNodes = renderViewStage.SortedRenderNodes; var renderNodeCount = renderViewStage.RenderNodes.Count; int currentStart, currentEnd; for (currentStart = 0; currentStart < renderNodeCount; currentStart = currentEnd) { var currentRenderFeature = renderNodes[currentStart].RootRenderFeature; currentEnd = currentStart + 1; while (currentEnd < renderNodeCount && renderNodes[currentEnd].RootRenderFeature == currentRenderFeature) { currentEnd++; } // Divide into task chunks for parallelism currentRenderFeature.Draw(renderDrawContext, renderView, renderViewStage, currentStart, currentEnd); } }
/// <summary> /// Performs GPU updates and/or draw. /// </summary> /// <param name="context"></param> /// <param name="renderView"></param> /// <param name="renderViewStage"></param> /// <param name="startIndex"></param> /// <param name="endIndex"></param> public virtual void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex) { }
/// <inheritdoc/> public override void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex) { var commandList = context.CommandList; foreach (var renderFeature in RenderFeatures) { renderFeature.Draw(context, renderView, renderViewStage, startIndex, endIndex); } // TODO: stackalloc? var descriptorSetsLocal = descriptorSets.Value; if (descriptorSetsLocal == null || descriptorSetsLocal.Length < EffectDescriptorSetSlotCount) { descriptorSetsLocal = descriptorSets.Value = new DescriptorSet[EffectDescriptorSetSlotCount]; } MeshDraw currentDrawData = null; for (int index = startIndex; index < endIndex; index++) { var renderNodeReference = renderViewStage.SortedRenderNodes[index].RenderNode; var renderNode = GetRenderNode(renderNodeReference); var renderMesh = (RenderMesh)renderNode.RenderObject; var drawData = renderMesh.ActiveMeshDraw; // Get effect // TODO: Use real effect slot var renderEffect = renderNode.RenderEffect; if (renderEffect.Effect == null) { continue; } // Bind VB if (currentDrawData != drawData) { for (int i = 0; i < drawData.VertexBuffers.Length; i++) { var vertexBuffer = drawData.VertexBuffers[i]; commandList.SetVertexBuffer(i, vertexBuffer.Buffer, vertexBuffer.Offset, vertexBuffer.Stride); } if (drawData.IndexBuffer != null) { commandList.SetIndexBuffer(drawData.IndexBuffer.Buffer, drawData.IndexBuffer.Offset, drawData.IndexBuffer.Is32Bit); } currentDrawData = drawData; } var resourceGroupOffset = ComputeResourceGroupOffset(renderNodeReference); // Update cbuffer renderEffect.Reflection.BufferUploader.Apply(context.CommandList, ResourceGroupPool, resourceGroupOffset); // Bind descriptor sets for (int i = 0; i < descriptorSetsLocal.Length; ++i) { var resourceGroup = ResourceGroupPool[resourceGroupOffset++]; if (resourceGroup != null) { descriptorSetsLocal[i] = resourceGroup.DescriptorSet; } } commandList.SetPipelineState(renderEffect.PipelineState); commandList.SetDescriptorSets(0, descriptorSetsLocal); // Draw if (drawData.IndexBuffer == null) { commandList.Draw(drawData.DrawCount, drawData.StartLocation); } else { commandList.DrawIndexed(drawData.DrawCount, drawData.StartLocation); } } }
public void Draw(RenderDrawContext renderDrawContext, RenderView renderView, RenderStage renderStage) { // Sync point: draw (from now, we should execute with a graphics device context to perform rendering) // Look for the RenderViewStage corresponding to this RenderView | RenderStage combination RenderViewStage renderViewStage = null; foreach (var currentRenderViewStage in renderView.RenderStages) { if (currentRenderViewStage.RenderStage == renderStage) { renderViewStage = currentRenderViewStage; break; } } if (renderViewStage == null) { throw new InvalidOperationException("Requested RenderView|RenderStage combination doesn't exist. Please add it to RenderView.RenderStages."); } // Generate and execute draw jobs var renderNodes = renderViewStage.SortedRenderNodes; var renderNodeCount = renderViewStage.RenderNodes.Count; if (renderNodeCount == 0) { return; } if (!GraphicsDevice.IsDeferred) { int currentStart, currentEnd; for (currentStart = 0; currentStart < renderNodeCount; currentStart = currentEnd) { var currentRenderFeature = renderNodes[currentStart].RootRenderFeature; currentEnd = currentStart + 1; while (currentEnd < renderNodeCount && renderNodes[currentEnd].RootRenderFeature == currentRenderFeature) { currentEnd++; } // Divide into task chunks for parallelism currentRenderFeature.Draw(renderDrawContext, renderView, renderViewStage, currentStart, currentEnd); } } else { // Create at most one batch per processor int batchCount = Math.Min(Environment.ProcessorCount, renderNodeCount); int batchSize = (renderNodeCount + (batchCount - 1)) / batchCount; batchCount = (renderNodeCount + (batchSize - 1)) / batchSize; // Remember state var depthStencilBuffer = renderDrawContext.CommandList.DepthStencilBuffer; var renderTargetView = renderDrawContext.CommandList.RenderTargetCount > 0 ? renderDrawContext.CommandList.RenderTarget : null; var viewport = renderDrawContext.CommandList.Viewport; // Collect one command list per batch and the main one up to this point if (commandLists == null || commandLists.Length < batchCount + 1) { Array.Resize(ref commandLists, batchCount + 1); } commandLists[0] = renderDrawContext.CommandList.Close(); Dispatcher.For(0, batchCount, () => renderDrawContext.RenderContext.GetThreadContext(), (batchIndex, threadContext) => { threadContext.CommandList.Reset(); threadContext.CommandList.ClearState(); // Transfer state to all command lists threadContext.CommandList.SetRenderTarget(depthStencilBuffer, renderTargetView); threadContext.CommandList.SetViewport(viewport); var currentStart = batchSize * batchIndex; int currentEnd; var endExclusive = Math.Min(renderNodeCount, currentStart + batchSize); if (endExclusive <= currentStart) { return; } for (; currentStart < endExclusive; currentStart = currentEnd) { var currentRenderFeature = renderNodes[currentStart].RootRenderFeature; currentEnd = currentStart + 1; while (currentEnd < endExclusive && renderNodes[currentEnd].RootRenderFeature == currentRenderFeature) { currentEnd++; } // Divide into task chunks for parallelism currentRenderFeature.Draw(threadContext, renderView, renderViewStage, currentStart, currentEnd); } commandLists[batchIndex + 1] = threadContext.CommandList.Close(); }); GraphicsDevice.ExecuteCommandLists(batchCount + 1, commandLists); renderDrawContext.CommandList.Reset(); renderDrawContext.CommandList.ClearState(); // Reapply previous state renderDrawContext.CommandList.SetRenderTarget(depthStencilBuffer, renderTargetView); renderDrawContext.CommandList.SetViewport(viewport); } }
/// <inheritdoc/> public override void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex) { var commandList = context.CommandList; foreach (var renderFeature in RenderFeatures) { renderFeature.Draw(context, renderView, renderViewStage, startIndex, endIndex); } var descriptorSets = new DescriptorSet[EffectDescriptorSetSlotCount]; MeshDraw currentDrawData = null; for (int index = startIndex; index < endIndex; index++) { var renderNodeReference = renderViewStage.SortedRenderNodes[index].RenderNode; var renderNode = GetRenderNode(renderNodeReference); var renderMesh = (RenderMesh)renderNode.RenderObject; var drawData = renderMesh.ActiveMeshDraw; // Get effect // TODO: Use real effect slot var renderEffect = renderNode.RenderEffect; if (renderEffect.Effect == null) continue; // Bind VB if (currentDrawData != drawData) { for (int i = 0; i < drawData.VertexBuffers.Length; i++) { var vertexBuffer = drawData.VertexBuffers[i]; commandList.SetVertexBuffer(i, vertexBuffer.Buffer, vertexBuffer.Offset, vertexBuffer.Stride); } if (drawData.IndexBuffer != null) commandList.SetIndexBuffer(drawData.IndexBuffer.Buffer, drawData.IndexBuffer.Offset, drawData.IndexBuffer.Is32Bit); currentDrawData = drawData; } var resourceGroupOffset = ComputeResourceGroupOffset(renderNodeReference); // Update cbuffer renderEffect.Reflection.BufferUploader.Apply(context.CommandList, ResourceGroupPool, resourceGroupOffset); // Bind descriptor sets for (int i = 0; i < descriptorSets.Length; ++i) { var resourceGroup = ResourceGroupPool[resourceGroupOffset++]; if (resourceGroup != null) descriptorSets[i] = resourceGroup.DescriptorSet; } commandList.SetPipelineState(renderEffect.PipelineState); commandList.SetDescriptorSets(0, descriptorSets); // Draw if (drawData.IndexBuffer == null) { commandList.Draw(drawData.DrawCount, drawData.StartLocation); } else { commandList.DrawIndexed(drawData.DrawCount, drawData.StartLocation); } } }
public abstract unsafe void GenerateSortKey(RenderView renderView, RenderViewStage renderViewStage, SortKey* sortKeys);
public abstract bool IsVisible(RenderObject renderObject, RenderView renderView, RenderViewStage renderViewStage);
/// <inheritdoc/> public override unsafe void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex) { var commandList = context.CommandList; // Per view - this code was moved here from Prepare(...) so that we can apply the correct Viewport { var view = renderView; var viewFeature = view.Features[Index]; Matrix.Multiply(ref view.View, ref view.Projection, out view.ViewProjection); // Copy ViewProjection to PerFrame cbuffer foreach (var viewLayout in viewFeature.Layouts) { var resourceGroup = viewLayout.Entries[view.Index].Resources; var mappedCB = resourceGroup.ConstantBuffer.Data; // PerView constant buffer var perViewOffset = viewLayout.GetConstantBufferOffset(this.perViewCBufferOffset); if (perViewOffset != -1) { var perView = (ParticleUtilitiesPerView*)((byte*)mappedCB + perViewOffset); perView->ViewMatrix = view.View; perView->ProjectionMatrix = view.Projection; perView->ViewProjectionMatrix = view.ViewProjection; perView->ViewFrustum = new Vector4(view.ViewSize.X, view.ViewSize.Y, view.NearClipPlane, view.FarClipPlane); perView->Viewport = new Vector4(0, 0, ((float)context.CommandList.Viewport.Width) / ((float)context.CommandList.RenderTarget.Width), ((float)context.CommandList.Viewport.Height) / ((float)context.CommandList.RenderTarget.Height)); } } } var renderParticleNodeData = RenderData.GetData(renderParticleNodeKey); // TODO: stackalloc? var descriptorSetsLocal = descriptorSets.Value; if (descriptorSetsLocal == null || descriptorSetsLocal.Length < EffectDescriptorSetSlotCount) { descriptorSetsLocal = descriptorSets.Value = new DescriptorSet[EffectDescriptorSetSlotCount]; } for (var index = startIndex; index < endIndex; index++) { var renderNodeReference = renderViewStage.SortedRenderNodes[index].RenderNode; // Get effect var renderEffect = GetRenderNode(renderNodeReference).RenderEffect; if (renderEffect.Effect == null) continue; // Get the extra node data var nodeData = renderParticleNodeData[renderNodeReference]; if (nodeData.IndexCount <= 0) continue; var resourceGroupOffset = ComputeResourceGroupOffset(renderNodeReference); // Update cbuffer renderEffect.Reflection.BufferUploader.Apply(commandList, ResourceGroupPool, resourceGroupOffset); // Bind descriptor sets for (int i = 0; i < descriptorSetsLocal.Length; ++i) { var resourceGroup = ResourceGroupPool[resourceGroupOffset++]; if (resourceGroup != null) descriptorSetsLocal[i] = resourceGroup.DescriptorSet; } commandList.SetPipelineState(renderEffect.PipelineState); commandList.SetDescriptorSets(0, descriptorSetsLocal); // Bind the buffers and draw commandList.SetVertexBuffer(0, nodeData.VertexBuffer, nodeData.VertexBufferOffset, nodeData.VertexBufferStride); commandList.SetIndexBuffer(nodeData.IndexBuffer, nodeData.IndexBufferOffset, ParticleBufferContext.IndexStride != sizeof(short)); commandList.DrawIndexed(nodeData.IndexCount, 0); } }
/// <inheritdoc/> public override void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex) { var commandList = context.CommandList; // TODO: PerView data Matrix viewInverse; Matrix.Invert(ref renderView.View, out viewInverse); var descriptorSets = new DescriptorSet[EffectDescriptorSetSlotCount]; for (var index = startIndex; index < endIndex; index++) { var renderNodeReference = renderViewStage.SortedRenderNodes[index].RenderNode; var renderNode = GetRenderNode(renderNodeReference); var renderParticleEmitter = (RenderParticleEmitter)renderNode.RenderObject; if (renderParticleEmitter.ParticleEmitter.VertexBuilder.ResourceContext == null) continue; // Generate vertices // TODO: Just just unmap/barrier here renderParticleEmitter.ParticleEmitter.BuildVertexBuffer(context.CommandList, ref viewInverse); // Get effect var renderEffect = renderNode.RenderEffect; if (renderEffect.Effect == null) continue; // TODO GRAPHICS REFACTOR: Extract data var particleSystemComponent = renderParticleEmitter.RenderParticleSystem.ParticleSystemComponent; var particleSystem = particleSystemComponent.ParticleSystem; var vertexBuilder = renderParticleEmitter.ParticleEmitter.VertexBuilder; // Bind VB var vertexBuffer = vertexBuilder.ResourceContext.VertexBuffer; var indexBuffer = vertexBuilder.ResourceContext.IndexBuffer; commandList.SetVertexBuffer(0, vertexBuffer.Buffer, vertexBuffer.Offset, vertexBuffer.Stride); commandList.SetIndexBuffer(indexBuffer.Buffer, indexBuffer.Offset, indexBuffer.Is32Bit); var resourceGroupOffset = ComputeResourceGroupOffset(renderNodeReference); // Update cbuffer renderEffect.Reflection.BufferUploader.Apply(context.CommandList, ResourceGroupPool, resourceGroupOffset); // Bind descriptor sets for (int i = 0; i < descriptorSets.Length; ++i) { var resourceGroup = ResourceGroupPool[resourceGroupOffset++]; if (resourceGroup != null) descriptorSets[i] = resourceGroup.DescriptorSet; } commandList.SetPipelineState(renderEffect.PipelineState); commandList.SetDescriptorSets(0, descriptorSets); commandList.DrawIndexed(vertexBuilder.LivingQuads * vertexBuilder.IndicesPerQuad, vertexBuilder.ResourceContext.IndexBufferPosition); } }
public abstract unsafe void GenerateSortKey(RenderView renderView, RenderViewStage renderViewStage, SortKey *sortKeys);
/// <summary> /// Performs GPU updates and/or drawing, everytime a render view changes. /// </summary> /// <param name="context"></param> /// <param name="renderView"></param> /// <param name="renderViewStage"></param> public virtual void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage) { }
public override void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex) { base.Draw(context, renderView, renderViewStage, startIndex, endIndex); BlendStateDescription? previousBlendState = null; DepthStencilStateDescription? previousDepthStencilState = null; EffectInstance previousEffect = null; //TODO string comparison ...? var isPicking = renderViewStage.RenderStage.Name == "Picking"; var device = RenderSystem.GraphicsDevice; var hasBegin = false; for (var index = startIndex; index < endIndex; index++) { var renderNodeReference = renderViewStage.SortedRenderNodes[index].RenderNode; var renderNode = GetRenderNode(renderNodeReference); var spriteState = (RenderSpriteStudio)renderNode.RenderObject; var transfoComp = spriteState.TransformComponent; var depthStencilState = DepthStencilStates.DepthRead; foreach (var node in spriteState.SpriteStudioComponent.SortedNodes) { if (node.Sprite?.Texture == null || node.Sprite.Region.Width <= 0 || node.Sprite.Region.Height <= 0f || node.Hide != 0) continue; // Update the sprite batch BlendStateDescription spriteBlending; switch (node.BaseNode.AlphaBlending) { case SpriteStudioBlending.Mix: spriteBlending = BlendStates.AlphaBlend; break; case SpriteStudioBlending.Multiplication: spriteBlending = MultBlendState; break; case SpriteStudioBlending.Addition: spriteBlending = BlendStates.Additive; break; case SpriteStudioBlending.Subtraction: spriteBlending = SubBlendState; break; default: throw new ArgumentOutOfRangeException(); } // TODO: this should probably be moved to Prepare() // Project the position // TODO: This could be done in a SIMD batch, but we need to figure-out how to plugin in with RenderMesh object var worldPosition = new Vector4(transfoComp.WorldMatrix.TranslationVector, 1.0f); Vector4 projectedPosition; Vector4.Transform(ref worldPosition, ref renderView.ViewProjection, out projectedPosition); var projectedZ = projectedPosition.Z / projectedPosition.W; var blendState = isPicking ? BlendStates.Default : spriteBlending; var currentEffect = isPicking ? GetOrCreatePickingSpriteEffect() : ShadowObject.IsObjectSelected(spriteState.SpriteStudioComponent) ? GetOrCreateSelectedSpriteEffect() : null; // TODO remove this code when material are available if (previousEffect != currentEffect || blendState != previousBlendState || depthStencilState != previousDepthStencilState) { if (hasBegin) { sprite3DBatch.End(); } sprite3DBatch.Begin(context.GraphicsContext, renderView.ViewProjection, SpriteSortMode.Deferred, blendState, null, depthStencilState, RasterizerStates.CullNone, currentEffect); hasBegin = true; } previousEffect = currentEffect; previousBlendState = blendState; previousDepthStencilState = depthStencilState; var sourceRegion = node.Sprite.Region; var texture = node.Sprite.Texture; // skip the sprite if no texture is set. if (texture == null) continue; var color4 = Color4.White; if (isPicking) { // TODO move this code corresponding to picking out of the runtime code. color4 = new Color4(RuntimeIdHelper.ToRuntimeId(spriteState.SpriteStudioComponent)); } else { if (node.BlendFactor > 0.0f) { switch (node.BlendType) //todo this should be done in a shader { case SpriteStudioBlending.Mix: color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency; break; case SpriteStudioBlending.Multiplication: color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency; break; case SpriteStudioBlending.Addition: color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency; break; case SpriteStudioBlending.Subtraction: color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency; break; default: throw new ArgumentOutOfRangeException(); } } else { color4 *= node.FinalTransparency; } } var worldMatrix = node.ModelTransform*transfoComp.WorldMatrix; // calculate normalized position of the center of the sprite (takes into account the possible rotation of the image) var normalizedCenter = new Vector2(node.Sprite.Center.X/sourceRegion.Width - 0.5f, 0.5f - node.Sprite.Center.Y/sourceRegion.Height); if (node.Sprite.Orientation == ImageOrientation.Rotated90) { var oldCenterX = normalizedCenter.X; normalizedCenter.X = -normalizedCenter.Y; normalizedCenter.Y = oldCenterX; } // apply the offset due to the center of the sprite var size = node.Sprite.Size; var centerOffset = Vector2.Modulate(normalizedCenter, size); worldMatrix.M41 -= centerOffset.X*worldMatrix.M11 + centerOffset.Y*worldMatrix.M21; worldMatrix.M42 -= centerOffset.X*worldMatrix.M12 + centerOffset.Y*worldMatrix.M22; // draw the sprite sprite3DBatch.Draw(texture, ref worldMatrix, ref sourceRegion, ref size, ref color4, node.Sprite.Orientation, SwizzleMode.None, projectedZ); } } if(hasBegin) sprite3DBatch.End(); }