private void UpdateConstantBufferReflection(EffectConstantBufferDescription reflectionConstantBuffer) { // Used to compute constant buffer size and member offsets (std140 rule) int constantBufferOffset = 0; // Fill members for (int index = 0; index < reflectionConstantBuffer.Members.Length; index++) { var member = reflectionConstantBuffer.Members[index]; // Properly compute size and offset according to DX rules var memberSize = ComputeMemberSize(ref member.Type, ref constantBufferOffset); // Store size/offset info member.Offset = constantBufferOffset; member.Size = memberSize; // Adjust offset for next item constantBufferOffset += memberSize; reflectionConstantBuffer.Members[index] = member; } // Round buffer size to next multiple of 16 reflectionConstantBuffer.Size = (constantBufferOffset + 15) / 16 * 16; }
private void LinkConstant(string cbName, Variable variable, LocalParameterKey parameterKey) { // If the constant buffer is not present, add it var constantBuffer = effectReflection.ConstantBuffers.FirstOrDefault(buffer => buffer.Name == cbName); if (constantBuffer == null) { constantBuffer = new EffectConstantBufferDescription() { Name = cbName, Type = ConstantBufferType.ConstantBuffer }; effectReflection.ConstantBuffers.Add(constantBuffer); var constantBufferBinding = new EffectResourceBindingDescription { KeyInfo = { KeyName = cbName }, Class = EffectParameterClass.ConstantBuffer, Type = EffectParameterType.ConstantBuffer, RawName = cbName, SlotStart = -1, SlotCount = 1, ResourceGroup = cbName }; effectReflection.ResourceBindings.Add(constantBufferBinding); valueBindings.Add(constantBuffer, new List <EffectValueDescription>()); } // Get the list of members of this constant buffer var members = valueBindings[constantBuffer]; var binding = new EffectValueDescription { KeyInfo = { KeyName = parameterKey.Name, }, LogicalGroup = (string)variable.GetTag(XenkoTags.LogicalGroup), Type = parameterKey.Type, RawName = variable.Name, }; members.Add(binding); }
public ResourceGroupDescription(DescriptorSetLayoutBuilder descriptorSetLayout, EffectConstantBufferDescription constantBufferReflection) : this() { DescriptorSetLayout = descriptorSetLayout; ConstantBufferReflection = constantBufferReflection; // We combine both hash for DescriptorSet and cbuffer itself (if it exists) Hash = descriptorSetLayout.Hash; if (constantBufferReflection != null) { ObjectId.Combine(ref Hash, ref constantBufferReflection.Hash, out Hash); } }
public EffectParameterUpdaterLayout(GraphicsDevice graphicsDevice, Effect effect, DescriptorSetLayoutBuilder[] layouts) { Layouts = layouts; // Process constant buffers ResourceGroupLayouts = new ResourceGroupLayout[layouts.Length]; for (int layoutIndex = 0; layoutIndex < layouts.Length; layoutIndex++) { var layout = layouts[layoutIndex]; if (layout == null) { continue; } ParameterCollectionLayout.ProcessResources(layout); EffectConstantBufferDescription cbuffer = null; for (int entryIndex = 0; entryIndex < layout.Entries.Count; ++entryIndex) { var layoutEntry = layout.Entries[entryIndex]; if (layoutEntry.Class == EffectParameterClass.ConstantBuffer) { // For now we assume first cbuffer will be the main one if (cbuffer == null) { cbuffer = effect.Bytecode.Reflection.ConstantBuffers.First(x => x.Name == layoutEntry.Key.Name); ParameterCollectionLayout.ProcessConstantBuffer(cbuffer); } } } var resourceGroupDescription = new ResourceGroupDescription(layout, cbuffer); ResourceGroupLayouts[layoutIndex] = ResourceGroupLayout.New(graphicsDevice, resourceGroupDescription, effect.Bytecode); } }
public static void ProcessConstantBuffer(this ParameterCollectionLayout parameterCollectionLayout, EffectConstantBufferDescription constantBuffer) { foreach (var member in constantBuffer.Members) { parameterCollectionLayout.LayoutParameterKeyInfos.Add(new ParameterKeyInfo(member.KeyInfo.Key, parameterCollectionLayout.BufferSize + member.Offset, member.Type.Elements > 0 ? member.Type.Elements : 1)); } parameterCollectionLayout.BufferSize += constantBuffer.Size; }
private void ValidateConstantBufferReflection(ConstantBuffer constantBufferRaw, ref ConstantBufferDescription constantBufferRawDesc, EffectConstantBufferDescription constantBuffer, LoggerResult log) { switch (constantBufferRawDesc.Type) { case SharpDX.D3DCompiler.ConstantBufferType.ConstantBuffer: if (constantBuffer.Type != ConstantBufferType.ConstantBuffer) { log.Error($"Invalid buffer type for {constantBuffer.Name}: {constantBuffer.Type} instead of {ConstantBufferType.ConstantBuffer}"); } break; case SharpDX.D3DCompiler.ConstantBufferType.TextureBuffer: if (constantBuffer.Type != ConstantBufferType.TextureBuffer) { log.Error($"Invalid buffer type for {constantBuffer.Name}: {constantBuffer.Type} instead of {ConstantBufferType.TextureBuffer}"); } break; default: if (constantBuffer.Type != ConstantBufferType.Unknown) { log.Error($"Invalid buffer type for {constantBuffer.Name}: {constantBuffer.Type} instead of {ConstantBufferType.Unknown}"); } break; } // ConstantBuffers variables for (int i = 0; i < constantBufferRawDesc.VariableCount; i++) { var variable = constantBufferRaw.GetVariable(i); var variableType = variable.GetVariableType(); var variableDescription = variable.Description; var variableTypeDescription = variableType.Description; if (variableTypeDescription.Offset != 0) { log.Error($"Unexpected offset [{variableTypeDescription.Offset}] for variable [{variableDescription.Name}] in constant buffer [{constantBuffer.Name}]"); } var binding = constantBuffer.Members[i]; // Retrieve Link Member if (binding.RawName != variableDescription.Name) { log.Error($"Variable [{variableDescription.Name}] in constant buffer [{constantBuffer.Name}] has no link"); } else { var parameter = new EffectValueDescription() { Type = { Class = (EffectParameterClass)variableTypeDescription.Class, Type = ConvertVariableValueType(variableTypeDescription.Type, log), Elements = variableTypeDescription.ElementCount, RowCount = (byte)variableTypeDescription.RowCount, ColumnCount = (byte)variableTypeDescription.ColumnCount, }, RawName = variableDescription.Name, Offset = variableDescription.StartOffset, Size = variableDescription.Size, }; if (parameter.Offset != binding.Offset || parameter.Size != binding.Size || parameter.Type.Elements != binding.Type.Elements || ((parameter.Type.Class != EffectParameterClass.Struct) && // Ignore columns/rows if it's a struct (sometimes it contains weird data) (parameter.Type.RowCount != binding.Type.RowCount || parameter.Type.ColumnCount != binding.Type.ColumnCount))) { log.Error($"Variable [{variableDescription.Name}] in constant buffer [{constantBuffer.Name}] binding doesn't match what was expected"); } } } if (constantBuffer.Size != constantBufferRawDesc.Size) { log.Error($"Error precomputing buffer size for {constantBuffer.Name}: {constantBuffer.Size} instead of {constantBufferRawDesc.Size}"); } }
private void AddUniform(EffectReflection effectReflection, bool[] validConstantBuffers, int uniformSize, int uniformCount, string uniformName, ActiveUniformType uniformType) { // OpenGL ES 2 is adding uniform for each cbuffer member, so we need to remove array and struct indexers so that we can identify it in cbuffer and find offset var uniformParts = new List <UniformPart>(8); var uniformLastStart = 0; for (var index = 0; index <= uniformName.Length; index++) { char c = index == uniformName.Length ? '.' : uniformName[index]; // Treat string end same as '.' if (c == '.' || c == '[') { var uniformPart = new UniformPart { Start = uniformLastStart, Count = index - uniformLastStart, Indexer = -1 }; // Read array index (if any) if (c == '[') { var indexerStart = ++index; while (uniformName[index] != ']') { index++; } // TODO: Avoid substring uniformPart.Indexer = int.Parse(uniformName.Substring(indexerStart, index - indexerStart)); index++; } uniformParts.Add(uniformPart); uniformLastStart = index + 1; } } var variableName = uniformName.Substring(0, uniformParts[0].Count); // check that this uniform is in a constant buffer int indexOfConstantBuffer = -1; int indexOfMember = -1; EffectConstantBufferDescription constantBufferDescription = null; for (int cbIndex = 0; cbIndex < effectReflection.ConstantBuffers.Count; cbIndex++) { var currentConstantBuffer = effectReflection.ConstantBuffers[cbIndex]; for (int index = 0; index < currentConstantBuffer.Members.Length; index++) { var member = currentConstantBuffer.Members[index]; if (member.RawName.Equals(variableName)) { indexOfConstantBuffer = cbIndex; indexOfMember = index; constantBufferDescription = currentConstantBuffer; break; } } if (constantBufferDescription != null) { break; } } if (constantBufferDescription == null) { throw new Exception("The uniform value " + variableName + " is defined outside of a uniform block, which is not supported by the engine."); } var indexOfResource = effectReflection.ResourceBindings.FindIndex(x => x.RawName == constantBufferDescription.Name); if (indexOfResource == -1) { reflectionResult.Error($"Unable to find uniform [{uniformName}] in any constant buffer"); return; } //var constantBufferDescription = effectReflection.ConstantBuffers[indexOfConstantBufferDescription]; var constantBuffer = effectReflection.ResourceBindings[indexOfResource]; // First time we encounter this cbuffer? if (!validConstantBuffers[indexOfConstantBuffer]) { constantBuffer.SlotStart = ConstantBufferOffsets.Length - 1; // Find next cbuffer slot Array.Resize(ref ConstantBufferOffsets, ConstantBufferOffsets.Length + 1); effectReflection.ResourceBindings[indexOfResource] = constantBuffer; ConstantBufferOffsets[constantBuffer.SlotStart + 1] = ConstantBufferOffsets[constantBuffer.SlotStart] + constantBufferDescription.Size; validConstantBuffers[indexOfConstantBuffer] = true; } //var elementSize = uniformSize; // For array, each element is rounded to register size //if (uniformSize%16 != 0 && uniformCount > 1) //{ // constantBufferDescription.Size = (constantBufferDescription.Size + 15)/16*16; // uniformSize = (uniformSize + 15)/16*16; //} // Check if it can fits in the same register, otherwise starts at the next one //if (uniformCount == 1 && constantBufferDescription.Size/16 != (constantBufferDescription.Size + uniformSize - 1)/16) // constantBufferDescription.Size = (constantBufferDescription.Size + 15)/16*16; var variable = constantBufferDescription.Members[indexOfMember]; // Resolve array/member var offset = variable.Offset; var type = variable.Type; for (int i = 0; i < uniformParts.Count; ++i) { var uniformPart = uniformParts[i]; // Apply member if (i > 0) { if (type.Members == null) { throw new InvalidOperationException($"Tried to find member \"{uniformName.Substring(uniformPart.Start, uniformPart.Count)}\" on a non-struct type when processing \"{uniformName}\""); } bool memberFound = false; for (int memberIndex = 0; memberIndex < type.Members.Length; ++memberIndex) { var member = type.Members[memberIndex]; if (string.Compare(member.Name, 0, uniformName, uniformPart.Start, uniformPart.Count) == 0) { // Adjust offset and set new type offset += member.Offset; type = member.Type; memberFound = true; break; } } if (!memberFound) { throw new InvalidOperationException($"Couldn't find member \"{uniformName.Substring(uniformPart.Start, uniformPart.Count)}\" on struct type \"{type.Name}\" when processing \"{uniformName}\""); } } // Apply indexer for arrays if (uniformPart.Indexer != -1) { offset += (type.ElementSize + 15) / 16 * 16 * uniformPart.Indexer; } } // Check type if (type.Type != GetTypeFromActiveUniformType(uniformType)) { throw new InvalidOperationException($"Uniform [{uniformName}] of type [{variable.Type.Type}] doesn't match OpenGL shader expected type [{GetTypeFromActiveUniformType(uniformType)}]"); } // No need to compare last element padding. // TODO: In case of float1/float2 arrays (rare) it is quite non-optimal to do a CompareMemory //variable.Size = uniformSize * (uniformCount - 1) + elementSize; //constantBufferDescription.Members[indexOfUniform] = variable; Uniforms.Add(new Uniform { Type = uniformType, Count = uniformCount, CompareSize = uniformSize + (uniformSize + 15) / 16 * 16 * (uniformCount - 1), ConstantBufferSlot = constantBuffer.SlotStart, Offset = offset, UniformIndex = GL.GetUniformLocation(ProgramId, uniformName) }); }
private void LinkConstant(string cbName, Variable variable, LocalParameterKey parameterKey) { // If the constant buffer is not present, add it var constantBuffer = effectReflection.ConstantBuffers.FirstOrDefault(buffer => buffer.Name == cbName); if (constantBuffer == null) { constantBuffer = new EffectConstantBufferDescription() {Name = cbName, Type = ConstantBufferType.ConstantBuffer}; effectReflection.ConstantBuffers.Add(constantBuffer); var constantBufferBinding = new EffectResourceBindingDescription { KeyInfo = { KeyName = cbName }, Class = EffectParameterClass.ConstantBuffer, Type = EffectParameterType.ConstantBuffer, RawName = cbName, SlotStart = -1, SlotCount = 1, ResourceGroup = cbName }; effectReflection.ResourceBindings.Add(constantBufferBinding); valueBindings.Add(constantBuffer, new List<EffectValueDescription>()); } // Get the list of members of this constant buffer var members = valueBindings[constantBuffer]; var binding = new EffectValueDescription { KeyInfo = { KeyName = parameterKey.Name, }, LogicalGroup = (string)variable.GetTag(XenkoTags.LogicalGroup), Type = parameterKey.Type, RawName = variable.Name, }; members.Add(binding); }
private void ValidateConstantBufferReflection(ConstantBuffer constantBufferRaw, ref ConstantBufferDescription constantBufferRawDesc, EffectConstantBufferDescription constantBuffer, LoggerResult log) { switch (constantBufferRawDesc.Type) { case SharpDX.D3DCompiler.ConstantBufferType.ConstantBuffer: if (constantBuffer.Type != ConstantBufferType.ConstantBuffer) log.Error($"Invalid buffer type for {constantBuffer.Name}: {constantBuffer.Type} instead of {ConstantBufferType.ConstantBuffer}"); break; case SharpDX.D3DCompiler.ConstantBufferType.TextureBuffer: if (constantBuffer.Type != ConstantBufferType.TextureBuffer) log.Error($"Invalid buffer type for {constantBuffer.Name}: {constantBuffer.Type} instead of {ConstantBufferType.TextureBuffer}"); break; default: if (constantBuffer.Type != ConstantBufferType.Unknown) log.Error($"Invalid buffer type for {constantBuffer.Name}: {constantBuffer.Type} instead of {ConstantBufferType.Unknown}"); break; } // ConstantBuffers variables for (int i = 0; i < constantBufferRawDesc.VariableCount; i++) { var variable = constantBufferRaw.GetVariable(i); var variableType = variable.GetVariableType(); var variableDescription = variable.Description; var variableTypeDescription = variableType.Description; if (variableTypeDescription.Offset != 0) { log.Error("Unexpected offset [{0}] for variable [{1}] in constant buffer [{2}]", variableTypeDescription.Offset, variableDescription.Name, constantBuffer.Name); } var binding = constantBuffer.Members[i]; // Retrieve Link Member if (binding.RawName != variableDescription.Name) { log.Error("Variable [{0}] in constant buffer [{1}] has no link", variableDescription.Name, constantBuffer.Name); } else { var parameter = new EffectValueDescription() { Type = { Class = (EffectParameterClass)variableTypeDescription.Class, Type = ConvertVariableValueType(variableTypeDescription.Type, log), Elements = variableTypeDescription.ElementCount, RowCount = (byte)variableTypeDescription.RowCount, ColumnCount = (byte)variableTypeDescription.ColumnCount, }, RawName = variableDescription.Name, Offset = variableDescription.StartOffset, Size = variableDescription.Size, }; if (parameter.Offset != binding.Offset || parameter.Size != binding.Size || parameter.Type.Elements != binding.Type.Elements || ((parameter.Type.Class != EffectParameterClass.Struct) && // Ignore columns/rows if it's a struct (sometimes it contains weird data) (parameter.Type.RowCount != binding.Type.RowCount || parameter.Type.ColumnCount != binding.Type.ColumnCount))) { log.Error("Variable [{0}] in constant buffer [{1}] binding doesn't match what was expected", variableDescription.Name, constantBuffer.Name); } } } if (constantBuffer.Size != constantBufferRawDesc.Size) { log.Error($"Error precomputing buffer size for {constantBuffer.Name}: {constantBuffer.Size} instead of {constantBufferRawDesc.Size}"); } }