public override void PrepareEffectPermutations(RenderDrawContext context) { base.PrepareEffectPermutations(context); var rootEffectRenderFeature = ((RootEffectRenderFeature)RootRenderFeature); var renderEffects = RootRenderFeature.RenderData.GetData(((RootEffectRenderFeature)RootRenderFeature).RenderEffectKey); int effectSlotCount = ((RootEffectRenderFeature)RootRenderFeature).EffectPermutationSlotCount; Dispatcher.ForEach(RootRenderFeature.ObjectNodeReferences, objectNodeReference => { var objectNode = RootRenderFeature.GetObjectNode(objectNodeReference); var renderMesh = (RenderMesh)objectNode.RenderObject; var staticObjectNode = renderMesh.StaticObjectNode; renderMesh.ActiveMeshDraw = renderMesh.Mesh.Draw; foreach (var stage in RenderSystem.RenderStages) { if (stage == null) { continue; } var effectSlot = rootEffectRenderFeature.GetEffectPermutationSlot(stage); var staticEffectObjectNode = staticObjectNode * effectSlotCount + effectSlot.Index; var renderEffect = renderEffects[staticEffectObjectNode]; if (renderEffect != null) { renderEffect.EffectValidator.ValidateParameterThreaded(XenkoEffectBaseKeys.ComputeVelocityShader, new ShaderClassSource("MeshVelocity")); } } }); }
/// <inheritdoc/> public override void Extract() { var renderModelObjectInfo = RootRenderFeature.RenderData.GetData(RenderModelObjectInfoKey); //for (int index = 0; index < RootRenderFeature.ObjectNodeReferences.Count; index++) Dispatcher.For(0, RootRenderFeature.ObjectNodeReferences.Count, index => { var objectNodeReference = RootRenderFeature.ObjectNodeReferences[index]; var objectNode = RootRenderFeature.GetObjectNode(objectNodeReference); var renderMesh = objectNode.RenderObject as RenderMesh; // TODO: Extract world renderModelObjectInfo[objectNodeReference].World = renderMesh != null ? renderMesh.World : Matrix.Identity; }); }
/// <param name="context"></param> /// <inheritdoc/> public override void PrepareEffectPermutations(RenderDrawContext context) { var skinningInfos = RootRenderFeature.RenderData.GetData(skinningInfoKey); var renderEffects = RootRenderFeature.RenderData.GetData(renderEffectKey); int effectSlotCount = ((RootEffectRenderFeature)RootRenderFeature).EffectPermutationSlotCount; //foreach (var objectNodeReference in RootRenderFeature.ObjectNodeReferences) Dispatcher.ForEach(((RootEffectRenderFeature)RootRenderFeature).ObjectNodeReferences, objectNodeReference => { var objectNode = RootRenderFeature.GetObjectNode(objectNodeReference); var renderMesh = (RenderMesh)objectNode.RenderObject; var staticObjectNode = renderMesh.StaticObjectNode; ref var skinningInfo = ref skinningInfos[staticObjectNode]; var parameters = renderMesh.Mesh.Parameters; if (parameters != skinningInfo.Parameters || parameters.PermutationCounter != skinningInfo.PermutationCounter) { skinningInfo.Parameters = parameters; skinningInfo.PermutationCounter = parameters.PermutationCounter; skinningInfo.HasSkinningPosition = parameters.Get(MaterialKeys.HasSkinningPosition); skinningInfo.HasSkinningNormal = parameters.Get(MaterialKeys.HasSkinningNormal); skinningInfo.HasSkinningTangent = parameters.Get(MaterialKeys.HasSkinningTangent); } for (int i = 0; i < effectSlotCount; ++i) { var staticEffectObjectNode = staticObjectNode * effectSlotCount + i; var renderEffect = renderEffects[staticEffectObjectNode]; // Skip effects not used during this frame if (renderEffect == null || !renderEffect.IsUsedDuringThisFrame(RenderSystem)) { continue; } if (renderMesh.Mesh.Skinning != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.HasSkinningPosition, skinningInfo.HasSkinningPosition); renderEffect.EffectValidator.ValidateParameter(MaterialKeys.HasSkinningNormal, skinningInfo.HasSkinningNormal); renderEffect.EffectValidator.ValidateParameter(MaterialKeys.HasSkinningTangent, skinningInfo.HasSkinningTangent); var skinningBones = Math.Max(MaxBones, renderMesh.Mesh.Skinning.Bones.Length); renderEffect.EffectValidator.ValidateParameter(MaterialKeys.SkinningMaxBones, skinningBones); } } });
/// <param name="context"></param> /// <inheritdoc/> public override unsafe void Prepare(RenderDrawContext context) { // Compute WorldView, WorldViewProj var renderModelObjectInfoData = RootRenderFeature.RenderData.GetData(RenderModelObjectInfoKey); var renderModelViewInfoData = RootRenderFeature.RenderData.GetData(RenderModelViewInfoKey); // Update PerFrame (time) // TODO Move that to RootEffectRenderFeature? float timeStep = (float)Context.Time.Elapsed.TotalSeconds * GlobalKeys.TimeScale; scaledTimeAccumulator += timeStep; foreach (var frameLayout in ((RootEffectRenderFeature)RootRenderFeature).FrameLayouts) { var timeOffset = frameLayout.GetConstantBufferOffset(time); if (timeOffset == -1) { continue; } var resourceGroup = frameLayout.Entry.Resources; var mappedCB = resourceGroup.ConstantBuffer.Data; var perFrameTime = (PerFrameTime *)((byte *)mappedCB + timeOffset); perFrameTime->TimeStep = timeStep; perFrameTime->Time = scaledTimeAccumulator; } // Update PerView (View, Proj, etc...) for (int index = 0; index < RenderSystem.Views.Count; index++) { var view = RenderSystem.Views[index]; var viewFeature = view.Features[RootRenderFeature.Index]; // Compute WorldView and WorldViewProjection Dispatcher.ForEach(viewFeature.ViewObjectNodes, renderPerViewNodeReference => { var renderPerViewNode = RootRenderFeature.GetViewObjectNode(renderPerViewNodeReference); ref var renderModelFrameInfo = ref renderModelObjectInfoData[renderPerViewNode.ObjectNode]; ref var renderModelViewInfo = ref renderModelViewInfoData[renderPerViewNodeReference]; Matrix.Multiply(ref renderModelFrameInfo.World, ref view.View, out renderModelViewInfo.WorldView); Matrix.Multiply(ref renderModelFrameInfo.World, ref view.ViewProjection, out renderModelViewInfo.WorldViewProjection); });
/// <summary> /// Attach this <see cref="SubRenderFeature"/> to a <see cref="RootRenderFeature"/>. /// </summary> /// <param name="rootRenderFeature"></param> internal void AttachRootRenderFeature(RootRenderFeature rootRenderFeature) { this.RootRenderFeature = rootRenderFeature; RenderSystem = rootRenderFeature.RenderSystem; }
public override unsafe void Prepare(RenderDrawContext context) { var previousTransformationInfoData = RootRenderFeature.RenderData.GetData(previousTransformationInfoKey); var previousTransformationViewInfoData = RootRenderFeature.RenderData.GetData(previousTransformationViewInfoKey); var renderModelObjectInfoData = RootRenderFeature.RenderData.GetData(renderModelObjectInfoKey); // Calculate previous WVP matrix per view and object usageCounter++; for (int index = 0; index < RenderSystem.Views.Count; index++) { var view = RenderSystem.Views[index]; var viewFeature = view.Features[RootRenderFeature.Index]; bool useView = false; foreach (var stage in RenderSystem.RenderStages) { foreach (var renderViewStage in view.RenderStages) { if (renderViewStage.Index == stage.Index && stage.OutputValidator?.Find <VelocityTargetSemantic>() >= 0) { useView = true; break; } } } if (!useView) { continue; } // Cache per-view data locally RenderViewData viewData; if (!renderViewDatas.TryGetValue(view, out viewData)) { viewData = new RenderViewData(); renderViewDatas.Add(view, viewData); } Dispatcher.ForEach(viewFeature.ViewObjectNodes, renderPerViewNodeReference => { var renderPerViewNode = RootRenderFeature.GetViewObjectNode(renderPerViewNodeReference); var renderModelFrameInfo = renderModelObjectInfoData[renderPerViewNode.ObjectNode]; Matrix previousViewProjection = viewData.PreviousViewProjection; Matrix previousWorldViewProjection; Matrix.Multiply(ref renderModelFrameInfo.World, ref previousViewProjection, out previousWorldViewProjection); previousTransformationViewInfoData[renderPerViewNodeReference] = new PreviousObjectViewInfo { WorldViewProjection = previousWorldViewProjection, }; }); // Shift current view projection transform into previous viewData.PreviousViewProjection = view.ViewProjection; viewData.UsageCounter = usageCounter; updatedViews.Add(view); } foreach (var view in renderViewDatas.Keys.ToArray()) { if (!updatedViews.Contains(view)) { renderViewDatas.Remove(view); } } updatedViews.Clear(); // Update cbuffer for previous WVP matrix Dispatcher.ForEach(((RootEffectRenderFeature)RootRenderFeature).RenderNodes, (ref RenderNode renderNode) => { var perDrawLayout = renderNode.RenderEffect?.Reflection?.PerDrawLayout; if (perDrawLayout == null) { return; } var previousWvpOffset = perDrawLayout.GetConstantBufferOffset(previousWorldViewProjection); if (previousWvpOffset == -1) { return; } var mappedCB = renderNode.Resources.ConstantBuffer.Data; var previousPerDraw = (PreviousPerDraw *)((byte *)mappedCB + previousWvpOffset); var renderModelFrameInfo = renderModelObjectInfoData[renderNode.RenderObject.ObjectNode]; var renderModelPreviousFrameInfo = previousTransformationViewInfoData[renderNode.ViewObjectNode]; // Shift current world transform into previous transform previousTransformationInfoData[renderNode.RenderObject.StaticObjectNode] = new StaticObjectInfo { World = renderModelFrameInfo.World, }; previousPerDraw->PreviousWorldViewProjection = renderModelPreviousFrameInfo.WorldViewProjection; }); }
public RenderNodeFeatureReference(RootRenderFeature rootRenderFeature, RenderNodeReference renderNode, RenderObject renderObject) { RootRenderFeature = rootRenderFeature; RenderNode = renderNode; RenderObject = renderObject; }
/// <summary> /// Performs most of the work (computation and resource preparation). Later game simulation might be running during that step. /// </summary> /// <param name="context"></param> public unsafe void Prepare(RenderDrawContext context) { // Sync point: after extract, before prepare (game simulation could resume now) // Split up Prepare Effects Dispatcher.For(0, RenderFeatures.Count, i => { // Divide into task chunks for parallelism RootRenderFeature renderFeature = RenderFeatures[i]; renderFeature.PrepareEffectPermutations(context); }); // split up Prepares Dispatcher.For(0, RenderFeatures.Count, i => { // Divide into task chunks for parallelism RootRenderFeature renderFeature = RenderFeatures[i]; renderFeature.Prepare(context); }); // Sort Dispatcher.ForEach(Views, view => { Dispatcher.For(0, view.RenderStages.Count, () => prepareThreadLocals.Acquire(), (index, local) => { var renderViewStage = view.RenderStages[index]; var renderNodes = renderViewStage.RenderNodes; if (renderNodes.Count == 0) { return; } var renderStage = RenderStages[renderViewStage.Index]; var sortedRenderNodes = renderViewStage.SortedRenderNodes; // Fast clear, since it's cleared properly in Reset() sortedRenderNodes.Resize(renderViewStage.RenderNodes.Count, true); if (renderStage.SortMode != null) { // Make sure sortKeys is big enough if (local.SortKeys == null || local.SortKeys.Length < renderNodes.Count) { Array.Resize(ref local.SortKeys, renderNodes.Count); } // renderNodes[start..end] belongs to the same render feature fixed(SortKey * sortKeysPtr = local.SortKeys) renderStage.SortMode.GenerateSortKey(view, renderViewStage, sortKeysPtr); Dispatcher.Sort(local.SortKeys, 0, renderNodes.Count, Comparer <SortKey> .Default); // Reorder list for (int i = 0; i < renderNodes.Count; ++i) { sortedRenderNodes[i] = renderNodes[local.SortKeys[i].Index]; } } else { // No sorting, copy as is for (int i = 0; i < renderNodes.Count; ++i) { sortedRenderNodes[i] = renderNodes[i]; } } }, state => prepareThreadLocals.Release(state)); }); // Flush the resources uploaded during Prepare context.ResourceGroupAllocator.Flush(); context.RenderContext.Flush(); }