private static int ComputeMemberSize(ref EffectParameterValueData member, ref int constantBufferOffset) { var elementSize = ComputeTypeSize(member.Param.Type); int size; int alignment; switch (member.Param.Class) { case EffectParameterClass.Scalar: { size = elementSize; alignment = size; break; } case EffectParameterClass.Color: case EffectParameterClass.Vector: { size = elementSize * member.ColumnCount; alignment = (member.ColumnCount == 3 ? 4 : member.ColumnCount) * elementSize; // vec3 uses alignment of vec4 break; } case EffectParameterClass.MatrixColumns: { size = elementSize * 4 * member.ColumnCount; alignment = size; break; } case EffectParameterClass.MatrixRows: { size = elementSize * 4 * member.RowCount; alignment = size; break; } default: throw new NotImplementedException(); } // Array if (member.Count > 0) { var roundedSize = (size + 15) / 16 * 16; // Round up to vec4 size = roundedSize * member.Count; alignment = roundedSize * member.Count; } // Alignment is maxed up to vec4 if (alignment > 16) { alignment = 16; } // Align offset and store it as member offset constantBufferOffset = (constantBufferOffset + alignment - 1) / alignment * alignment; return(size); }
private static int ComputeMemberSize(ref EffectParameterValueData member, ref int constantBufferOffset) { var elementSize = ComputeTypeSize(member.Param.Type); int size; int alignment = 4; switch (member.Param.Class) { case EffectParameterClass.Scalar: { size = elementSize; break; } case EffectParameterClass.Color: case EffectParameterClass.Vector: { size = elementSize * member.ColumnCount; break; } case EffectParameterClass.MatrixColumns: { size = elementSize * (4 * (member.ColumnCount - 1) + member.RowCount); break; } case EffectParameterClass.MatrixRows: { size = elementSize * (4 * (member.RowCount - 1) + member.ColumnCount); break; } default: throw new NotImplementedException(); } // Array if (member.Count > 0) { var roundedSize = (size + 15) / 16 * 16; // Round up to vec4 size += roundedSize * (member.Count - 1); alignment = 16; } // Align to float4 if it is bigger than leftover space in current float4 if (constantBufferOffset / 16 != (constantBufferOffset + size - 1) / 16) { alignment = 16; } // Align offset and store it as member offset constantBufferOffset = (constantBufferOffset + alignment - 1) / alignment * alignment; return(size); }
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 ShaderConstantBufferDescription() { Name = cbName, Type = ConstantBufferType.ConstantBuffer }; effectReflection.ConstantBuffers.Add(constantBuffer); var constantBufferBinding = new EffectParameterResourceData { Param = { KeyName = cbName, Class = EffectParameterClass.ConstantBuffer, Type = EffectParameterType.Buffer, RawName = cbName, ResourceGroup = cbName }, SlotStart = -1, SlotCount = 1 }; effectReflection.ResourceBindings.Add(constantBufferBinding); valueBindings.Add(constantBuffer, new List <EffectParameterValueData>()); } // Get the list of members of this constant buffer var members = valueBindings[constantBuffer]; var binding = new EffectParameterValueData { Param = { KeyName = parameterKey.Name, Class = parameterKey.Class, Type = parameterKey.Type, RawName = variable.Name }, RowCount = parameterKey.RowCount, ColumnCount = parameterKey.ColumnCount, Count = parameterKey.Count, }; members.Add(binding); }
private ShaderConstantBufferDescription GetConstantBufferReflection(ConstantBuffer constantBufferRaw, ref ConstantBufferDescription constantBufferRawDesc, ShaderConstantBufferDescription linkBuffer, LoggerResult log) { var constantBuffer = new ShaderConstantBufferDescription { Name = constantBufferRawDesc.Name, Size = constantBufferRawDesc.Size, }; switch (constantBufferRawDesc.Type) { case SharpDX.D3DCompiler.ConstantBufferType.ConstantBuffer: constantBuffer.Type = ConstantBufferType.ConstantBuffer; break; case SharpDX.D3DCompiler.ConstantBufferType.TextureBuffer: constantBuffer.Type = ConstantBufferType.TextureBuffer; break; default: constantBuffer.Type = ConstantBufferType.Unknown; break; } // ConstantBuffers variables var members = new List<EffectParameterValueData>(); 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; var parameter = new EffectParameterValueData() { Param = { Class = (EffectParameterClass)variableTypeDescription.Class, Type = ConvertVariableValueType(variableTypeDescription.Type, log), RawName = variableDescription.Name, }, Offset = variableDescription.StartOffset, Size = variableDescription.Size, Count = variableTypeDescription.ElementCount == 0 ? 1 : variableTypeDescription.ElementCount, RowCount = (byte)variableTypeDescription.RowCount, ColumnCount = (byte)variableTypeDescription.ColumnCount, }; if (variableTypeDescription.Offset != 0) { log.Error("Unexpected offset [{0}] for variable [{1}] in constant buffer [{2}]", variableTypeDescription.Offset, variableDescription.Name, constantBuffer.Name); } bool bindingNotFound = true; // Retrieve Link Member foreach (var binding in linkBuffer.Members) { if (binding.Param.RawName == variableDescription.Name) { // TODO: should we replicate linkMember.Count/RowCount/ColumnCount? or use what is retrieved by D3DCompiler reflection parameter.Param.KeyName = binding.Param.KeyName; bindingNotFound = false; break; } } if (bindingNotFound) { log.Error("Variable [{0}] in constant buffer [{1}] has no link", variableDescription.Name, constantBuffer.Name); } members.Add(parameter); } constantBuffer.Members = members.ToArray(); return constantBuffer; }
private unsafe bool UpdateValue(ShaderParameterUpdater parameterUpdater, ref EffectParameterValueData shaderVariable, int i) { if (shaderVariable.Param.KeyIndex == -1) { throw new InvalidOperationException(); } BoundConstantBufferParam paramReference = constantBufferParams[i]; var internalValue = parameterUpdater.GetInternalValue(shaderVariable.Param.KeyIndex); // TODO: Comparing Counter+DataPointer is not enough (if realloc on same address) if (internalValue.Counter == paramReference.DirtyCount && internalValue == paramReference.DataPointer) { return(false); } constantBufferParams[i] = new BoundConstantBufferParam { DataPointer = internalValue, DirtyCount = internalValue.Counter }; var destination = (byte *)(Data + shaderVariable.Offset); int sourceOffset = 0; float *variableData = (float *)destination; // + shaderVariable.Offset); Matrix tempMatrix; switch (shaderVariable.Param.Class) { case EffectParameterClass.Struct: internalValue.ReadFrom((IntPtr)variableData, sourceOffset, shaderVariable.Size); break; case EffectParameterClass.Scalar: for (int elt = 0; elt < shaderVariable.Count; ++elt) { internalValue.ReadFrom((IntPtr)variableData, sourceOffset, sizeof(float)); //*variableData = *source++; sourceOffset += 4; variableData += 4; // 4 floats } break; case EffectParameterClass.Vector: case EffectParameterClass.Color: for (int elt = 0; elt < shaderVariable.Count; ++elt) { //Framework.Utilities.CopyMemory((IntPtr)variableData, (IntPtr)source, (int)(shaderVariable.ColumnCount * sizeof(float))); internalValue.ReadFrom((IntPtr)variableData, sourceOffset, (int)(shaderVariable.ColumnCount * sizeof(float))); sourceOffset += (int)shaderVariable.ColumnCount * 4; variableData += 4; } break; case EffectParameterClass.MatrixColumns: for (int elt = 0; elt < shaderVariable.Count; ++elt) { //fixed (Matrix* p = &tempMatrix) { internalValue.ReadFrom((IntPtr)(byte *)&tempMatrix, sourceOffset, (int)(shaderVariable.ColumnCount * shaderVariable.RowCount * sizeof(float))); ((Matrix *)variableData)->CopyMatrixFrom((float *)&tempMatrix, unchecked ((int)shaderVariable.ColumnCount), unchecked ((int)shaderVariable.RowCount)); sourceOffset += (int)(shaderVariable.ColumnCount * shaderVariable.RowCount) * 4; variableData += 4 * shaderVariable.RowCount; } } break; case EffectParameterClass.MatrixRows: for (int elt = 0; elt < shaderVariable.Count; ++elt) { //fixed (Matrix* p = &tempMatrix) { internalValue.ReadFrom((IntPtr)(byte *)&tempMatrix, sourceOffset, (int)(shaderVariable.ColumnCount * shaderVariable.RowCount * sizeof(float))); ((Matrix *)variableData)->TransposeMatrixFrom((float *)&tempMatrix, unchecked ((int)shaderVariable.ColumnCount), unchecked ((int)shaderVariable.RowCount)); //source += shaderVariable.ColumnCount * shaderVariable.RowCount; sourceOffset += (int)(shaderVariable.ColumnCount * shaderVariable.RowCount) * 4; variableData += 4 * shaderVariable.RowCount; } } break; } return(true); }
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 ShaderConstantBufferDescription() {Name = cbName}; effectReflection.ConstantBuffers.Add(constantBuffer); var constantBufferBinding = new EffectParameterResourceData { Param = { KeyName = cbName, Class = EffectParameterClass.ConstantBuffer, Type = EffectParameterType.Buffer, RawName = cbName }, SlotStart = -1 }; effectReflection.ResourceBindings.Add(constantBufferBinding); valueBindings.Add(constantBuffer, new List<EffectParameterValueData>()); } // Get the list of members of this constant buffer var members = valueBindings[constantBuffer]; var binding = new EffectParameterValueData { Param = { KeyName = parameterKey.Name, Class = parameterKey.Class, Type = parameterKey.Type, RawName = variable.Name }, RowCount = parameterKey.RowCount, ColumnCount = parameterKey.ColumnCount, Count = parameterKey.Count, }; members.Add(binding); }
private static ParameterKey FindOrCreateValueKey <T>(EffectParameterValueData binding) where T : struct { var name = binding.Param.KeyName; return(ParameterKeys.FindByName(name) ?? ParameterKeys.NewValue <T>(default(T), name)); }
private static void UpdateValueBindingKey(ref EffectParameterValueData binding) { switch (binding.Param.Class) { case EffectParameterClass.Scalar: switch (binding.Param.Type) { case EffectParameterType.Bool: binding.Param.Key = FindOrCreateValueKey <bool>(binding); break; case EffectParameterType.Int: binding.Param.Key = FindOrCreateValueKey <int>(binding); break; case EffectParameterType.UInt: binding.Param.Key = FindOrCreateValueKey <uint>(binding); break; case EffectParameterType.Float: binding.Param.Key = FindOrCreateValueKey <float>(binding); break; } break; case EffectParameterClass.Color: { var componentCount = binding.RowCount != 1 ? binding.RowCount : binding.ColumnCount; switch (binding.Param.Type) { case EffectParameterType.Float: binding.Param.Key = componentCount == 4 ? FindOrCreateValueKey <Color4>(binding) : (componentCount == 3 ? (ParameterKey)FindOrCreateValueKey <Color3>(binding) : null); break; } } break; case EffectParameterClass.Vector: { var componentCount = binding.RowCount != 1 ? binding.RowCount : binding.ColumnCount; switch (binding.Param.Type) { case EffectParameterType.Bool: case EffectParameterType.Int: binding.Param.Key = componentCount == 4 ? (ParameterKey)FindOrCreateValueKey <Int4>(binding) : (componentCount == 3 ? FindOrCreateValueKey <Int3>(binding) : null); break; case EffectParameterType.UInt: binding.Param.Key = componentCount == 4 ? FindOrCreateValueKey <UInt4>(binding) : null; break; case EffectParameterType.Float: binding.Param.Key = componentCount == 4 ? FindOrCreateValueKey <Vector4>(binding) : (componentCount == 3 ? (ParameterKey)FindOrCreateValueKey <Vector3>(binding) : (componentCount == 2 ? FindOrCreateValueKey <Vector2>(binding) : null)); break; } } break; case EffectParameterClass.MatrixRows: case EffectParameterClass.MatrixColumns: binding.Param.Key = FindOrCreateValueKey <Matrix>(binding); break; case EffectParameterClass.Struct: binding.Param.Key = ParameterKeys.FindByName(binding.Param.KeyName); break; } if (binding.Param.Key == null) { throw new InvalidOperationException(string.Format("Unable to find/generate key [{0}] with unsupported type [{1}/{2}]", binding.Param.KeyName, binding.Param.Class, binding.Param.Type)); } }
private ParameterKey FindOrCreateValueKey <T>(EffectParameterValueData binding) where T : struct { var name = binding.Param.KeyName; return(ParameterKeys.FindByName(name) ?? (binding.Count > 1 ? (ParameterKey)ParameterKeys.New <T[]>(name) : ParameterKeys.New <T>(name))); }
private ParameterKey UpdateValueBindingKey(ref EffectParameterValueData binding) { switch (binding.Param.Class) { case EffectParameterClass.Scalar: switch (binding.Param.Type) { case EffectParameterType.Bool: binding.Param.Key = FindOrCreateValueKey <bool>(binding); break; case EffectParameterType.Int: binding.Param.Key = FindOrCreateValueKey <int>(binding); break; case EffectParameterType.UInt: binding.Param.Key = FindOrCreateValueKey <uint>(binding); break; case EffectParameterType.Float: binding.Param.Key = FindOrCreateValueKey <float>(binding); break; } break; case EffectParameterClass.Color: { var componentCount = binding.RowCount != 1 ? binding.RowCount : binding.ColumnCount; switch (binding.Param.Type) { case EffectParameterType.Float: binding.Param.Key = componentCount == 4 ? FindOrCreateValueKey <Color4>(binding) : (componentCount == 3 ? (ParameterKey)FindOrCreateValueKey <Color3>(binding) : null); break; } } break; case EffectParameterClass.Vector: { var componentCount = binding.RowCount != 1 ? binding.RowCount : binding.ColumnCount; switch (binding.Param.Type) { case EffectParameterType.Bool: case EffectParameterType.Int: binding.Param.Key = componentCount == 4 ? (ParameterKey)FindOrCreateValueKey <Int4>(binding) : (componentCount == 3 ? FindOrCreateValueKey <Int3>(binding) : null); break; case EffectParameterType.UInt: binding.Param.Key = componentCount == 4 ? FindOrCreateValueKey <UInt4>(binding) : null; break; case EffectParameterType.Float: binding.Param.Key = componentCount == 4 ? FindOrCreateValueKey <Vector4>(binding) : (componentCount == 3 ? (ParameterKey)FindOrCreateValueKey <Vector3>(binding) : (componentCount == 2 ? FindOrCreateValueKey <Vector2>(binding) : null)); break; } } break; case EffectParameterClass.MatrixRows: case EffectParameterClass.MatrixColumns: binding.Param.Key = FindOrCreateValueKey <Matrix>(binding); break; case EffectParameterClass.Struct: binding.Param.Key = ParameterKeys.FindByName(binding.Param.KeyName); break; } if (binding.Param.Key == null) { throw new InvalidOperationException(string.Format("Unable to find/generate key [{0}] with unsupported type [{1}/{2}]", binding.Param.KeyName, binding.Param.Class, binding.Param.Type)); } if (binding.Count > 1) { // Unspecified array length: guess from shader and set default parameter with array matching shader size binding.Param.Key = binding.Param.Key.CloneLength(binding.Count); } return(binding.Param.Key); }
private void ValidateConstantBufferReflection(ConstantBuffer constantBufferRaw, ref ConstantBufferDescription constantBufferRawDesc, ShaderConstantBufferDescription 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.Param.RawName != variableDescription.Name) { log.Error("Variable [{0}] in constant buffer [{1}] has no link", variableDescription.Name, constantBuffer.Name); } else { var parameter = new EffectParameterValueData() { Param = { Class = (EffectParameterClass)variableTypeDescription.Class, Type = ConvertVariableValueType(variableTypeDescription.Type, log), RawName = variableDescription.Name, }, Offset = variableDescription.StartOffset, Size = variableDescription.Size, Count = variableTypeDescription.ElementCount, RowCount = (byte)variableTypeDescription.RowCount, ColumnCount = (byte)variableTypeDescription.ColumnCount, }; if (parameter.Offset != binding.Offset || parameter.Size != binding.Size || parameter.Count != binding.Count || parameter.RowCount != binding.RowCount || parameter.ColumnCount != binding.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}"); } }