/// <summary> /// Optimizes the slot links. /// </summary> /// <param name="stageBlock">The stage block.</param> private void PrepareSlotLinks(ref StageBlock stageBlock) { // Allocate slots only when needed stageBlock.Slots = new List<SlotLinkSet>[1 + (int)EffectResourceType.UnorderedAccessView]; // Retrieve Constant buffer resource index as It has been updated by the reordering of resources for (int i = 0; i < stageBlock.ConstantBufferLinks.Length; i++) { stageBlock.ConstantBufferLinks[i].ResourceIndex = stageBlock.ConstantBufferLinks[i].Parameter.Offset; } // Compute default slot links link foreach (var parameter in stageBlock.Parameters) { var slots = stageBlock.Slots[(int)parameter.ResourceType]; if (slots == null) { slots = new List<SlotLinkSet>(); stageBlock.Slots[(int)parameter.ResourceType] = slots; } var parameterRaw = (EffectData.ResourceParameter)parameter.ParameterDescription; var range = new SlotLinkSet() { SlotCount = parameterRaw.Count, SlotIndex = parameterRaw.Slot }; slots.Add(range); range.Links.Add(new SlotLink(parameter.Offset, 0, parameterRaw.Count)); } if (EnableDebug) { DebugLog.WriteLine("*** Before OptimizeSlotLinks ****"); PrintLinks(ref stageBlock); } // Optimize all slots foreach (var slotRangePerResourceType in stageBlock.Slots) { if (slotRangePerResourceType == null) continue; var previousRange = slotRangePerResourceType[0]; for (int i = 1; i < slotRangePerResourceType.Count; i++) { var currentRange = slotRangePerResourceType[i]; int endIndex = previousRange.SlotIndex + previousRange.SlotCount; var delta = (currentRange.SlotIndex - endIndex); // If there is at maximum a 1 if (delta <= 1) { foreach (var slotLink in currentRange.Links) { var previousLink = previousRange.Links[previousRange.Links.Count - 1]; // Merge consecutive individual slot link if ((previousLink.GlobalIndex + previousLink.SlotCount) == slotLink.GlobalIndex && (previousLink.SlotIndex + previousLink.SlotCount) == (currentRange.SlotIndex + slotLink.SlotIndex)) { previousLink.SlotCount += slotLink.SlotCount; previousRange.Links[previousRange.Links.Count - 1] = previousLink; } else { previousRange.Links.Add(new SlotLink(slotLink.GlobalIndex, (slotLink.SlotIndex + previousRange.SlotCount + delta), slotLink.SlotCount)); } } // Update the total slot count previousRange.SlotCount += delta + currentRange.SlotCount; slotRangePerResourceType.RemoveAt(i); i--; } else { previousRange = currentRange; } } } if (EnableDebug) { DebugLog.WriteLine("*** After OptimizeSlotLinks ****"); PrintLinks(ref stageBlock); } }
/// <summary> /// Initializes the stage block. /// </summary> /// <param name="stageBlock">The stage block.</param> /// <param name="logger">The logger.</param> private void InitStageBlock(StageBlock stageBlock, Logger logger) { // If null shader, then skip init if (stageBlock.Index < 0) { return; } stageBlock.Shader = Effect.Pool.GetOrCompileShader(stageBlock.Type, stageBlock.Index); var shaderRaw = Effect.Pool.EffectData.Shaders[stageBlock.Index]; // Cache the input signature if (shaderRaw.Type == EffectShaderType.Vertex) { inputSignatureManager = graphicsDevice.GetOrCreateInputSignatureManager(shaderRaw.InputSignature.Bytecode, shaderRaw.InputSignature.Hashcode); } for (int i = 0; i < shaderRaw.ConstantBuffers.Count; i++) { var constantBufferRaw = shaderRaw.ConstantBuffers[i]; // Constant buffers with a null size are skipped if (constantBufferRaw.Size == 0) continue; var constantBuffer = Effect.GetOrCreateConstantBuffer(Effect.GraphicsDevice, constantBufferRaw); // IF constant buffer is null, it means that there is a conflict if (constantBuffer == null) { logger.Error("Constant buffer [{0}] cannot have multiple size or different content declaration inside the same effect pool", constantBufferRaw.Name); continue; } // Test if this constant buffer is not already part of the effect if (Effect.ConstantBuffers[constantBufferRaw.Name] == null) { // Add the declared constant buffer to the effect shader. Effect.ConstantBuffers.Add(constantBuffer); // Declare all parameter from constant buffer at the effect level. foreach (var parameter in constantBuffer.Parameters) { var previousParameter = Effect.Parameters[parameter.Name]; if (previousParameter == null) { // Add an effect parameter linked to the approriate constant buffer at the effect level. Effect.Parameters.Add(new EffectParameter((EffectData.ValueTypeParameter) parameter.ParameterDescription, constantBuffer)); } else if (parameter.ParameterDescription != previousParameter.ParameterDescription || parameter.buffer != previousParameter.buffer) { // If registered parameters is different logger.Error("Parameter [{0}] defined in Constant buffer [{0}] is already defined by another constant buffer with the definition [{2}]", parameter, constantBuffer.Name, previousParameter); } } } } var constantBufferLinks = new List<ConstantBufferLink>(); // Declare all resource parameters at the effect level. foreach (var parameterRaw in shaderRaw.ResourceParameters) { EffectParameter parameter; var previousParameter = Effect.Parameters[parameterRaw.Name]; // Skip enmpty constant buffers. if (parameterRaw.Type == EffectParameterType.ConstantBuffer && Effect.ConstantBuffers[parameterRaw.Name] == null) { continue; } int resourceIndex = Effect.ResourceLinker.Count; if (previousParameter == null) { parameter = new EffectParameter(parameterRaw, EffectResourceTypeHelper.ConvertFromParameterType(parameterRaw.Type), Effect.ResourceLinker.Count, Effect.ResourceLinker); Effect.Parameters.Add(parameter); Effect.ResourceLinker.Count++; } else { resourceIndex = ((EffectData.ResourceParameter) previousParameter.ParameterDescription).Slot; if (CompareResourceParameter(parameterRaw, (EffectData.ResourceParameter) previousParameter.ParameterDescription)) { // If registered parameters is different logger.Error("Resource Parameter [{0}] is already defined with a different definition [{1}]", parameterRaw, previousParameter.ParameterDescription); } parameter = previousParameter; } // For constant buffers, we need to store explicit link if (parameter.ResourceType == EffectResourceType.ConstantBuffer) { constantBufferLinks.Add(new ConstantBufferLink(Effect.ConstantBuffers[parameter.Name], parameter.Offset)); } // Allocate slots only when needed if (stageBlock.Slots == null) { stageBlock.Slots = new List<SlotLinkSet>[1 + (int) EffectResourceType.SamplerState]; } var slots = stageBlock.Slots[(int) parameter.ResourceType]; if (slots == null) { slots = new List<SlotLinkSet>(); stageBlock.Slots[(int) parameter.ResourceType] = slots; } var range = new SlotLinkSet() {SlotCount = parameterRaw.Count, SlotIndex = parameterRaw.Slot}; slots.Add(range); range.Links.Add(new SlotLink(parameter.Offset, 0, parameterRaw.Count)); } stageBlock.ConstantBufferLinks = constantBufferLinks.ToArray(); // Optimize the current stage block OptimizeSlotLinks(ref stageBlock); }