public override void Reset() { base.Reset(); FrameLayouts.Clear(false); }
/// <inheritdoc/> public override void Prepare(RenderDrawContext context) { EffectObjectNodes.Clear(false); // Make sure descriptor set pool is large enough var expectedDescriptorSetPoolSize = RenderNodes.Count * effectDescriptorSetSlots.Count; if (ResourceGroupPool.Length < expectedDescriptorSetPoolSize) { Array.Resize(ref ResourceGroupPool, expectedDescriptorSetPoolSize); } // Allocate PerFrame, PerView and PerDraw resource groups and constant buffers var renderEffects = RenderData.GetData(RenderEffectKey); int effectSlotCount = EffectPermutationSlotCount; foreach (var view in RenderSystem.Views) { var viewFeature = view.Features[Index]; Dispatcher.ForEach(viewFeature.RenderNodes, () => prepareThreadContext.Value, (renderNodeReference, batch) => { var threadContext = batch.Context; var renderNode = this.GetRenderNode(renderNodeReference); var renderObject = renderNode.RenderObject; // Get RenderEffect var staticObjectNode = renderObject.StaticObjectNode; var staticEffectObjectNode = staticObjectNode * effectSlotCount + effectSlots[renderNode.RenderStage.Index].Index; var renderEffect = renderEffects[staticEffectObjectNode]; // Not compiled yet? if (renderEffect.Effect == null) { renderNode.RenderEffect = renderEffect; renderNode.EffectObjectNode = EffectObjectNodeReference.Invalid; renderNode.Resources = null; RenderNodes[renderNodeReference.Index] = renderNode; return; } var renderEffectReflection = renderEffect.Reflection; // PerView resources/cbuffer var viewLayout = renderEffectReflection.PerViewLayout; if (viewLayout != null) { var viewCount = RenderSystem.Views.Count; if (viewLayout.Entries?.Length < viewCount) { // TODO: Should this be a first loop? lock (viewLayout) { if (viewLayout.Entries?.Length < viewCount) { var newEntries = new ResourceGroupEntry[viewCount]; for (int index = 0; index < viewLayout.Entries.Length; index++) { newEntries[index] = viewLayout.Entries[index]; } for (int index = viewLayout.Entries.Length; index < viewCount; index++) { newEntries[index].Resources = new ResourceGroup(); } viewLayout.Entries = newEntries; } } } if (viewLayout.Entries[view.Index].MarkAsUsed(RenderSystem)) { threadContext.ResourceGroupAllocator.PrepareResourceGroup(viewLayout, BufferPoolAllocationType.UsedMultipleTime, viewLayout.Entries[view.Index].Resources); // Register it in list of view layouts to update for this frame viewFeature.Layouts.Add(viewLayout); } } // PerFrame resources/cbuffer var frameLayout = renderEffect.Reflection.PerFrameLayout; if (frameLayout != null && frameLayout.Entry.MarkAsUsed(RenderSystem)) { threadContext.ResourceGroupAllocator.PrepareResourceGroup(frameLayout, BufferPoolAllocationType.UsedMultipleTime, frameLayout.Entry.Resources); // Register it in list of view layouts to update for this frame FrameLayouts.Add(frameLayout); } // PerDraw resources/cbuffer // Get nodes var viewObjectNode = GetViewObjectNode(renderNode.ViewObjectNode); // Allocate descriptor set renderNode.Resources = threadContext.ResourceGroupAllocator.AllocateResourceGroup(); if (renderEffectReflection.PerDrawLayout != null) { threadContext.ResourceGroupAllocator.PrepareResourceGroup(renderEffectReflection.PerDrawLayout, BufferPoolAllocationType.UsedOnce, renderNode.Resources); } // Create EffectObjectNode var effectObjectNodeIndex = EffectObjectNodes.Add(new EffectObjectNode(renderEffect, viewObjectNode.ObjectNode)); // Link to EffectObjectNode (created right after) // TODO: rewrite this renderNode.EffectObjectNode = new EffectObjectNodeReference(effectObjectNodeIndex); renderNode.RenderEffect = renderEffect; // Bind well-known descriptor sets var descriptorSetPoolOffset = ComputeResourceGroupOffset(renderNodeReference); ResourceGroupPool[descriptorSetPoolOffset + perFrameDescriptorSetSlot.Index] = frameLayout?.Entry.Resources; ResourceGroupPool[descriptorSetPoolOffset + perViewDescriptorSetSlot.Index] = renderEffect.Reflection.PerViewLayout?.Entries[view.Index].Resources; ResourceGroupPool[descriptorSetPoolOffset + perDrawDescriptorSetSlot.Index] = renderNode.Resources; // Create resource group for everything else in case of fallback effects if (renderEffect.State != RenderEffectState.Normal && renderEffect.FallbackParameters != null) { if (renderEffect.FallbackParameterUpdater.ResourceGroups == null) { // First time renderEffect.FallbackParameterUpdater = new EffectParameterUpdater(renderEffect.Reflection.FallbackUpdaterLayout, renderEffect.FallbackParameters); } renderEffect.FallbackParameterUpdater.Update(RenderSystem.GraphicsDevice, threadContext.ResourceGroupAllocator, renderEffect.FallbackParameters); var fallbackResourceGroupMapping = renderEffect.Reflection.FallbackResourceGroupMapping; for (int i = 0; i < fallbackResourceGroupMapping.Length; ++i) { ResourceGroupPool[descriptorSetPoolOffset + fallbackResourceGroupMapping[i]] = renderEffect.FallbackParameterUpdater.ResourceGroups[i]; } } // Compile pipeline state object (if first time or need change) // TODO GRAPHICS REFACTOR how to invalidate if we want to change some state? (setting to null should be fine) if (renderEffect.PipelineState == null) { var mutablePipelineState = batch.MutablePipelineState; var pipelineState = mutablePipelineState.State; pipelineState.SetDefaults(); // Effect pipelineState.EffectBytecode = renderEffect.Effect.Bytecode; pipelineState.RootSignature = renderEffect.Reflection.RootSignature; // Extract outputs from render stage pipelineState.Output = renderNode.RenderStage.Output; pipelineState.RasterizerState.MultisampleCount = renderNode.RenderStage.Output.MultisampleCount; // Bind VAO ProcessPipelineState(Context, renderNodeReference, ref renderNode, renderObject, pipelineState); foreach (var pipelineProcessor in PipelineProcessors) { pipelineProcessor.Process(renderNodeReference, ref renderNode, renderObject, pipelineState); } mutablePipelineState.Update(); renderEffect.PipelineState = mutablePipelineState.CurrentState; } RenderNodes[renderNodeReference.Index] = renderNode; }); viewFeature.RenderNodes.Close(); viewFeature.Layouts.Close(); } EffectObjectNodes.Close(); FrameLayouts.Close(); }