Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // This is an extract of a HLSL fx binary file loader in C# developed in an unreleased internal project in SharpDX
- // The principle is to use this loader to discover annotations/techniques/passes/vertex|pixel shader bytecodes, blend|rasterizer|depth states and D3D11 reflection for variable binding in constant buffers.
- // Copyright (c) 2010 SharpDX - Alexandre Mutel
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IO;
- using System.Runtime.InteropServices;
- using SharpDX.D3DCompiler;
- namespace SharpDX.Framework.Graphics
- {
- /// <summary>
- /// Effect provider for HLSL EffectsHLSLFx.
- ///
- /// Doc StreamOutputDeclaration : http://msdn.microsoft.com/en-us/library/ff476168%28v=VS.85%29.aspx
- /// </summary>
- public class EffectsHLSLFx : IEffectCompiler, IEffectCompilerFactory
- {
- private BinaryHeader _binaryHeader;
- private BinaryHeader11 _binaryHeader11;
- private IntPtr _currentPtr;
- private IntPtr _unStructuredDataBlock;
- private CConstantBuffer[] _binaryConstantBuffers;
- private CObjectVariable[] _objectVariables;
- private CInterfaceVariable[] _interfaceVariables;
- private CFxGroup[] _fxGroups;
- /// <summary>
- /// Instantiate a new effect compiler from this factory.
- /// </summary>
- /// <returns>an effect compiler</returns>
- public IEffectCompiler NewCompiler()
- {
- return new EffectsHLSLFx();
- }
- /// <summary>
- /// Compiles the specified Effect source code.
- /// </summary>
- /// <param name="source">The Effect source code.</param>
- /// <param name="compilerOptions">The compiler options.</param>
- /// <returns></returns>
- EffectBytecode IEffectCompiler.Compile(string source, EffectCompilerOptions compilerOptions)
- {
- var bytecode = ShaderBytecode.Compile(source, "fx_5_0", (ShaderFlags)compilerOptions, EffectFlags.None);
- return new EffectsHLSLFxBytecode(bytecode);
- }
- /// <summary>
- /// Reads the specified bytecode from the stream.
- /// </summary>
- /// <param name="bytecodeStream">The bytecode stream.</param>
- /// <returns>an instance of EffectBytecode if this compiler was able to read the bytecode, null otherwise</returns>
- EffectBytecode IEffectCompiler.Read(Stream bytecodeStream)
- {
- var reader = new BinaryReader(bytecodeStream);
- int version = reader.ReadInt32();
- if (Enum.IsDefined(typeof(VersionTag), version))
- {
- bytecodeStream.Position = 0;
- var bytecode = ShaderBytecode.FromStream(bytecodeStream);
- if (bytecode != null)
- return new EffectsHLSLFxBytecode(bytecode);
- }
- return null;
- }
- /// <summary>
- /// Loads the specified effect from bytecode.
- /// </summary>
- /// <param name="bytecode">The compiled bytecode for an effect.</param>
- /// <param name="toEffect">The effect to be filled-in by this provider.</param>
- /// <returns>
- /// <c>true</c> if this Effect Provider was able to load this bytecode otherwise, <c>false</c>.
- /// </returns>
- bool IEffectCompiler.Load(EffectBytecode bytecode, Effect toEffect)
- {
- IntPtr buffer = bytecode.DataPointer;
- _currentPtr = buffer;
- // Bytecode should be EffectsHLSLFx
- if (!(bytecode is EffectsHLSLFxBytecode))
- return false;
- if (toEffect.Bytecode != null)
- return false;
- // Just make sure that the bytecode buffer is enough large, otherwise, return false
- if (buffer == IntPtr.Zero || bytecode.Length < 4)
- return false;
- // Check version of this effect bytecode
- var tag = (VersionTag) Marshal.ReadInt32(buffer);
- if (tag == VersionTag.Fx50)
- {
- _binaryHeader11 = Read<BinaryHeader11>();
- _binaryHeader = _binaryHeader11.Header;
- }
- else if (tag == VersionTag.Fx40 || tag == VersionTag.Fx41)
- {
- _binaryHeader = Read<BinaryHeader>();
- }
- else
- {
- // The fileformat is not recognized
- return false;
- }
- // Set the bytecode to the effect
- toEffect.Bytecode = bytecode;
- bytecode.Position = 0;
- // Effect file format structures /////////////////////////////////////////////
- // File format:
- // File Header (BinaryHeader Header)
- // Unstructured data block (BYTE[Header.cbUnstructured))
- // Structured data block
- // ConstantBuffer (BinaryContantBuffer CB) * Header.Effect.ConstantBufferCount
- // uint NumAnnotations
- // Annotation data (BinaryAnnotation) * (NumAnnotations) *this structure is variable sized
- // Variable data (BinaryNumericVariable Var) * (CB.VariableCount)
- // uint NumAnnotations
- // Annotation data (BinaryAnnotation) * (NumAnnotations) *this structure is variable sized
- // Object variables (BinaryObjectVariable Var) * (Header.ObjectVariableCount) *this structure is variable sized
- // uint NumAnnotations
- // Annotation data (BinaryAnnotation) * (NumAnnotations) *this structure is variable sized
- // Interface variables (BinaryInterfaceVariable Var) * (Header.InterfaceVariableCount) *this structure is variable sized
- // uint NumAnnotations
- // Annotation data (BinaryAnnotation) * (NumAnnotations) *this structure is variable sized
- // Groups (BinaryGroup Group) * Header.GroupCount
- // uint NumAnnotations
- // Annotation data (BinaryAnnotation) * (NumAnnotations) *this structure is variable sized
- // Techniques (BinaryTechnique Technique) * Group.TechniqueCount
- // uint NumAnnotations
- // Annotation data (BinaryAnnotation) * (NumAnnotations) *this structure is variable sized
- // Pass (BinaryPass Pass) * Technique.PassCount
- // uint NumAnnotations
- // Annotation data (BinaryAnnotation) * (NumAnnotations) *this structure is variable sized
- // Pass assignments (BinaryAssignment) * Pass.AssignmentCount
- _unStructuredDataBlock = _currentPtr;
- _currentPtr += (int)_binaryHeader11.Header.cbUnstructured;
- // Load binary data from fx bytecode
- LoadContantBuffers();
- LoadObjectVariables();
- LoadInterfaceVariables();
- LoadFxGroups();
- // Transform binary data to effect object model.
- Fill(toEffect);
- return true;
- }
- private void Fill(Effect effect)
- {
- FillGroups(effect);
- effect.Init();
- PostFillInformationForParameters(effect);
- }
- private static void FillAnnotations(CAnnotation[] fromAnnotations, EffectAnnotationCollection toAnnotationCollection)
- {
- foreach (var fromAnnotation in fromAnnotations)
- toAnnotationCollection.Add(new EffectAnnotation(fromAnnotation.Name) {Value = fromAnnotation.Value});
- }
- /// <summary>
- /// Postfill annotations and semantic for parameters.
- /// </summary>
- /// <param name="effect">The effect.</param>
- private void PostFillInformationForParameters(Effect effect)
- {
- // Fill annotation for paramaters
- // TODO handle annotation for structure members
- foreach (var rawConstantBuffer in _binaryConstantBuffers)
- {
- var constantBuffer = effect.ParameterBuffers[rawConstantBuffer.Name];
- FillAnnotations(rawConstantBuffer.Annotations, constantBuffer.Annotations);
- foreach (var rawNumericVariable in rawConstantBuffer.Variables)
- {
- var parameter = constantBuffer.Parameters[rawNumericVariable.Name];
- if (parameter != null)
- {
- FillAnnotations(rawNumericVariable.Annotations, parameter.Annotations);
- parameter.Semantic = rawNumericVariable.Semantic;
- }
- }
- }
- // Fill annotation for all object variables
- foreach (var rawObjectVariable in _objectVariables)
- {
- var objectVariable = effect.Parameters[rawObjectVariable.Name];
- if (objectVariable != null)
- {
- FillAnnotations(rawObjectVariable.Annotations, objectVariable.Annotations);
- objectVariable.Semantic = rawObjectVariable.Semantic;
- }
- }
- }
- private void FillGroups(Effect effect)
- {
- // Add object variable (SamplerState) that are instantiated by the fx file
- foreach (var rawObjectVariable in _objectVariables)
- {
- if (rawObjectVariable.GraphicsResource != null)
- {
- var parameter = new EffectParameter(rawObjectVariable.Name)
- {
- ParameterClass = EffectParameterClass.Object,
- ParameterType = rawObjectVariable.GraphicsResourceType,
- GraphicsResource = rawObjectVariable.GraphicsResource,
- Parent = effect,
- };
- effect.InternalParameters.Add(parameter);
- }
- }
- // Add Effect groups, techniques, pass
- foreach (var rawFxGroup in _fxGroups)
- {
- var fxGroup = new EffectGroup(rawFxGroup.Name) {Parent = effect};
- effect.Groups.Add(fxGroup);
- FillAnnotations(rawFxGroup.Annotations, fxGroup.Annotations);
- foreach (var rawTechnique in rawFxGroup.Techniques)
- {
- var technique = new EffectTechnique(rawTechnique.Name) { Parent = fxGroup};
- FillAnnotations(rawTechnique.Annotations, technique.Annotations);
- fxGroup.Techniques.Add(technique);
- // Add also the technique to the top effect
- effect.Techniques.Add(fxGroup.Name, technique);
- foreach (var rawPass in rawTechnique.Passes)
- {
- var pass = new EffectPass(rawPass.Name, effect) {Parent = technique};
- FillAnnotations(rawPass.Annotations, pass.Annotations);
- technique.Passes.Add(pass);
- foreach (var rawAssignment in rawPass.Assignments)
- {
- ShaderBytecode bytecode = null;
- if (rawAssignment.ByteCode != null)
- {
- bytecode = new ShaderBytecode(rawAssignment.ByteCode.Pointer, rawAssignment.ByteCode.Size);
- if (rawAssignment.StreamOutputDeclarationString != null)
- pass.GeometryStreamOutputDeclaration = new string[] {rawAssignment.StreamOutputDeclarationString};
- }
- else if (rawAssignment.InlineShader5 != null)
- {
- bytecode = new ShaderBytecode(rawAssignment.InlineShader5.Bytecode.Pointer, rawAssignment.InlineShader5.Bytecode.Size);
- pass.GeometryStreamOutputDeclaration = rawAssignment.InlineShader5.StreamOutputDeclarationString;
- pass.GeometryStreamOutputRasterizedStream = rawAssignment.InlineShader5.RasterizedStream;
- }
- if (bytecode != null)
- {
- switch (rawAssignment.LeftHandSideValue.ShaderType)
- {
- case ShaderVariableType.Vertexshader:
- pass.VertexShaderBytecode = bytecode;
- break;
- case ShaderVariableType.Geometryshader:
- pass.GeometryShaderBytecode = bytecode;
- break;
- case ShaderVariableType.Pixelshader:
- pass.PixelShaderBytecode = bytecode;
- break;
- case ShaderVariableType.Computeshader:
- pass.ComputeShaderBytecode = bytecode;
- break;
- case ShaderVariableType.Domainshader:
- pass.DomainShaderBytecode = bytecode;
- break;
- case ShaderVariableType.Hullshader:
- pass.HullShaderBytecode = bytecode;
- break;
- }
- }
- }
- }
- }
- }
- }
- /// <summary>
- /// Loads the contant buffers.
- /// </summary>
- private void LoadContantBuffers()
- {
- _binaryConstantBuffers = new CConstantBuffer[_binaryHeader.Effect.ConstantBufferCount];
- for (int i = 0; i < _binaryConstantBuffers.Length; i++)
- _binaryConstantBuffers[i] = LoadContantBuffer();
- }
- /// <summary>
- /// Loads a contant buffer.
- /// </summary>
- /// <returns></returns>
- private CConstantBuffer LoadContantBuffer()
- {
- var cBuf = new CConstantBuffer();
- Read(cBuf);
- cBuf.Name = LoadString(cBuf.Binary.OffsetName);
- cBuf.Annotations = LoadAnnotations();
- cBuf.Variables = new CNumericVariable[cBuf.Binary.VariableCount];
- for (int j = 0; j < cBuf.Variables.Length; j++)
- cBuf.Variables[j] = LoadNumericVariable();
- return cBuf;
- }
- /// <summary>
- /// Loads the object variables.
- /// </summary>
- private void LoadObjectVariables()
- {
- _objectVariables = new CObjectVariable[_binaryHeader.Effect.ObjectVariableCount];
- for (int i = 0; i < _objectVariables.Length; i++)
- _objectVariables[i] = LoadObjectVariable();
- }
- /// <summary>
- /// Loads an object variable.
- /// </summary>
- /// <returns></returns>
- private CObjectVariable LoadObjectVariable()
- {
- var objectVariable = new CObjectVariable();
- Read(objectVariable);
- objectVariable.Name = LoadString(objectVariable.Binary.OffsetName);
- objectVariable.Semantic = LoadString(objectVariable.Binary.OffsetSemantic);
- objectVariable.Type = LoadType(objectVariable.Binary.OffsetType);
- int nbElementToRead = (int)Math.Max(1, objectVariable.Type.Binary.ElementCount);
- // Initializer data:
- //
- // The type structure pointed to by OffsetType gives you ElementCount,
- // VarType (must be Object), and ObjectType
- //
- // For ObjectType == Blend, DepthStencil, Rasterizer, Sampler
- // struct
- // {
- // UINT AssignmentCount;
- // BinaryAssignment Assignments[AssignmentCount];
- // } Blocks[ElementCount]
- //
- // For ObjectType == Texture*, Buffer
- // <nothing>
- //
- // For ObjectType == *Shader, String
- // UINT OffsetData[ElementCount]; // offsets to a shader data block or a NULL-terminated string
- //
- // For ObjectType == GeometryShaderSO
- // BinaryGeometryShaderStreamOutputInitializer[ElementCount]
- //
- // For ObjectType == *Shader5
- // BinaryShaderDataFx5[ElementCount]
- switch (objectVariable.Type.ObjectType)
- {
- case ObjectType.Blend:
- for (int i = 0; i < nbElementToRead; i++)
- objectVariable.Assignments = LoadAssignments(Read<int>());
- objectVariable.UpdateBlendState();
- break;
- case ObjectType.DepthStencil:
- for (int i = 0; i < nbElementToRead; i++)
- objectVariable.Assignments = LoadAssignments(Read<int>());
- objectVariable.UpdateDepthStencilState();
- break;
- case ObjectType.Rasterizer:
- for (int i = 0; i < nbElementToRead; i++)
- objectVariable.Assignments = LoadAssignments(Read<int>());
- objectVariable.UpdateRasterizerState();
- break;
- case ObjectType.Sampler:
- for (int i = 0; i < nbElementToRead; i++)
- objectVariable.Assignments = LoadAssignments(Read<int>());
- objectVariable.UpdateSamplerState();
- break;
- case ObjectType.Buffer:
- case ObjectType.Texture:
- case ObjectType.Texture1D:
- case ObjectType.Texture1DArray:
- case ObjectType.Texture2D:
- case ObjectType.Texture2DArray:
- case ObjectType.Texture2DMS:
- case ObjectType.Texture2DMSArray:
- case ObjectType.Texture3D:
- case ObjectType.TextureCube:
- case ObjectType.TextureCubeArray:
- case ObjectType.RWBuffer:
- case ObjectType.RWByteAddressBuffer:
- case ObjectType.RWStructuredBuffer:
- case ObjectType.RWTexture1D:
- case ObjectType.RWTexture2D:
- case ObjectType.RWTexture3D:
- break;
- case ObjectType.VertexShader:
- case ObjectType.GeometryShader:
- case ObjectType.PixelShader:
- objectVariable.Bytecodes = new CShaderBytecode[nbElementToRead];
- for (int i = 0; i < nbElementToRead; i++)
- objectVariable.Bytecodes[i] = LoadByteCode(Read<uint>());
- break;
- case ObjectType.GeometryShaderSO:
- objectVariable.StreamOutputInitializers = new CGeometryShaderStreamOutputInitializer[nbElementToRead];
- for (int i = 0; i < nbElementToRead; i++)
- {
- var streamOutputInitializer = new CGeometryShaderStreamOutputInitializer();
- Read(streamOutputInitializer);
- streamOutputInitializer.ByteCode = LoadByteCode(streamOutputInitializer.Binary.OffsetShader);
- streamOutputInitializer.StreamOutputDeclarationString = LoadString(streamOutputInitializer.Binary.OffsetStreamOutputDeclaration);
- objectVariable.StreamOutputInitializers[i] = streamOutputInitializer;
- }
- break;
- case ObjectType.PixelShader5:
- case ObjectType.VertexShader5:
- case ObjectType.GeometryShader5:
- case ObjectType.ComputeShader5:
- case ObjectType.HullShader5:
- case ObjectType.DomainShader5:
- objectVariable.ShaderData = new CShaderDataFx5[nbElementToRead];
- for (int i = 0; i < nbElementToRead; i++)
- objectVariable.ShaderData[i] = LoadShaderDataFx5();
- break;
- default:
- LogError("Unsupported object variable {0} {1}", objectVariable.Name, objectVariable.Type.ObjectType);
- break;
- }
- objectVariable.Annotations = LoadAnnotations();
- return objectVariable;
- }
- /// <summary>
- /// Loads the interface variables.
- /// </summary>
- private void LoadInterfaceVariables()
- {
- _interfaceVariables = new CInterfaceVariable[_binaryHeader11.InterfaceVariableCount];
- for (int i = 0; i < _interfaceVariables.Length; i++)
- _interfaceVariables[i] = LoadInterfaceVariable();
- }
- /// <summary>
- /// Loads an interface variable.
- /// </summary>
- /// <returns></returns>
- private CInterfaceVariable LoadInterfaceVariable()
- {
- var interfaceVariable = new CInterfaceVariable();
- Read(interfaceVariable);
- interfaceVariable.Name = LoadString(interfaceVariable.Binary.OffsetName);
- interfaceVariable.Type = LoadType(interfaceVariable.Binary.OffsetType);
- interfaceVariable.Annotations = LoadAnnotations();
- return interfaceVariable;
- }
- /// <summary>
- /// Loads the fxgroups.
- /// </summary>
- private void LoadFxGroups()
- {
- _fxGroups = new CFxGroup[_binaryHeader11.GroupCount];
- for (int i = 0; i < _fxGroups.Length; i++)
- _fxGroups[i] = LoadFxGroup();
- }
- /// <summary>
- /// Loads a fxgroup.
- /// </summary>
- /// <returns></returns>
- private CFxGroup LoadFxGroup()
- {
- var group = new CFxGroup();
- Read(group);
- group.Name = LoadString(group.Binary.OffsetName);
- group.Annotations = LoadAnnotations();
- group.Techniques = LoadTechniques((int)group.Binary.TechniqueCount);
- return group;
- }
- /// <summary>
- /// Loads the techniques.
- /// </summary>
- /// <param name="techniqueCount">The technique count.</param>
- /// <returns></returns>
- private CTechnique[] LoadTechniques(int techniqueCount)
- {
- var techniques = new CTechnique[techniqueCount];
- for (int i = 0; i < techniques.Length; i++)
- techniques[i] = LoadTechnique();
- return techniques;
- }
- /// <summary>
- /// Loads a technique.
- /// </summary>
- /// <returns></returns>
- private CTechnique LoadTechnique()
- {
- var technique = new CTechnique();
- Read(technique);
- technique.Name = LoadString(technique.Binary.OffsetName);
- technique.Annotations = LoadAnnotations();
- technique.Passes = LoadPasses((int)technique.Binary.PassCount);
- return technique;
- }
- /// <summary>
- /// Loads the passes.
- /// </summary>
- /// <param name="passCount">The pass count.</param>
- /// <returns></returns>
- private CPass[] LoadPasses(int passCount)
- {
- var passes = new CPass[passCount];
- for (int i = 0; i < passes.Length; i++)
- passes[i] = LoadPass();
- return passes;
- }
- /// <summary>
- /// Loads a pass.
- /// </summary>
- /// <returns></returns>
- private CPass LoadPass()
- {
- var pass = new CPass();
- Read(pass);
- pass.Name = LoadString(pass.Binary.OffsetName);
- pass.Annotations = LoadAnnotations();
- pass.Assignments = LoadAssignments((int)pass.Binary.AssignmentCount);
- return pass;
- }
- /// <summary>
- /// Loads the assignments.
- /// </summary>
- /// <param name="nbAssignments">The nb assignments.</param>
- /// <returns></returns>
- private CAssignment[] LoadAssignments(int nbAssignments)
- {
- var assignments = new CAssignment[nbAssignments];
- for (int i = 0; i < assignments.Length; i++)
- assignments[i] = LoadAssignment();
- return assignments;
- }
- /// <summary>
- /// Loads an assignment.
- /// </summary>
- /// <returns></returns>
- private CAssignment LoadAssignment()
- {
- var assignment = new CAssignment();
- Read(assignment);
- assignment.LeftHandSideValue = LeftHandSideValues[assignment.Binary.StateIndex];
- assignment.IndexMax = assignment.LeftHandSideValue.IndexMax;
- assignment.Index = unchecked((int)assignment.Binary.Index);
- IntPtr initData = _unStructuredDataBlock + (int)assignment.Binary.OffsetInitializer;
- // We handle only assignement for shaders
- var shaderVariableType = assignment.LeftHandSideValue.ShaderType;
- switch (assignment.Binary.AssignmentType)
- {
- case CompilerAssignmentType.InlineShader:
- var inlineShader = Read<BinaryAssignment.InlineShader>(ref initData);
- assignment.ByteCode = LoadByteCode(inlineShader.OffsetShader);
- if (assignment.LeftHandSideValue.ShaderType == ShaderVariableType.Geometryshader)
- {
- if (inlineShader.OffsetStreamOutputDeclaration != 0)
- assignment.StreamOutputDeclarationString = LoadString(inlineShader.OffsetStreamOutputDeclaration);
- }
- break;
- case CompilerAssignmentType.InlineShader5:
- assignment.InlineShader5 = LoadShaderDataFx5(ref initData);
- break;
- case CompilerAssignmentType.Variable:
- string variableName = LoadString(assignment.Binary.OffsetInitializer);
- var variable = FindVariable(variableName);
- if (variable.ShaderData != null && variable.ShaderData.Length == 1)
- {
- assignment.InlineShader5 = variable.ShaderData[0];
- } else
- {
- switch (assignment.LeftHandSideValue.Type)
- {
- case LeftHandSideValueType.VertexShaderBlock:
- case LeftHandSideValueType.GeometryShaderBlock:
- case LeftHandSideValueType.PixelShaderBlock:
- assignment.ByteCode = variable.Bytecodes[0];
- break;
- case LeftHandSideValueType.GeometryShaderSO:
- assignment.ByteCode = variable.StreamOutputInitializers[0].ByteCode;
- assignment.StreamOutputDeclarationString = variable.StreamOutputInitializers[0].StreamOutputDeclarationString;
- break;
- case LeftHandSideValueType.DepthStencilBlock:
- assignment.IsDepthStencilBlock = true;
- assignment.Variable = variable;
- break;
- case LeftHandSideValueType.RasterizerBlock:
- assignment.IsRasterizerBlock = true;
- assignment.Variable = variable;
- break;
- case LeftHandSideValueType.BlendBlock:
- assignment.IsBlendBlock = true;
- assignment.Variable = variable;
- break;
- default:
- LogError("Unexpected object variable assignement [{0}]", variableName);
- break;
- }
- }
- break;
- case CompilerAssignmentType.Constant:
- uint nbConstants = Read<uint>(ref initData);
- //if (nbConstants != 1)
- //{
- // LogError("Invalid number of constants [{0}] for variable type [{1}]. Must be == 1", nbConstants,
- // shaderVariableType);
- // return assignment;
- //}
- object[] values = new object[nbConstants];
- for (int i = 0; i < nbConstants; i++)
- {
- var binaryConstant = Read<BinaryConstant>(ref initData);
- switch (binaryConstant.Type)
- {
- case ScalarType.Int:
- case ScalarType.UInt:
- if (shaderVariableType == ShaderVariableType.Bool)
- {
- values[i] = binaryConstant.IntegerValue != 0;
- }
- else
- {
- values[i] = binaryConstant.IntegerValue;
- }
- break;
- case ScalarType.Bool:
- values[i] = binaryConstant.BooleanValue;
- break;
- case ScalarType.Float:
- values[i] = binaryConstant.FloatValue;
- break;
- }
- }
- // If this is a single constant value, then store it only this value
- if (values.Length == 1)
- {
- assignment.ConstantValue = values[0];
- }
- else
- {
- // else store the array
- assignment.ConstantValue = values;
- }
- break;
- default:
- LogError("Unexpected assignement type [{0}] for variable type [{1}]", assignment.Binary.AssignmentType, shaderVariableType);
- break;
- }
- //ResolveDependency(assignment);
- return assignment;
- }
- /// <summary>
- /// Loads the shader data FX5.
- /// </summary>
- /// <returns></returns>
- private CShaderDataFx5 LoadShaderDataFx5()
- {
- return LoadShaderDataFx5(ref _currentPtr);
- }
- /// <summary>
- /// Loads the shader data FX5.
- /// </summary>
- /// <param name="fromPointer">From pointer.</param>
- /// <returns></returns>
- private CShaderDataFx5 LoadShaderDataFx5(ref IntPtr fromPointer)
- {
- var shader = new CShaderDataFx5 { Binary = Read<BinaryShaderDataFx5>(ref fromPointer) };
- shader.Bytecode = LoadByteCode(shader.Binary.OffsetShader);
- shader.StreamOutputDeclarationString = new string[shader.Binary.StreamOutputDeclarationCount];
- for (int i = 0; i < shader.StreamOutputDeclarationString.Length; i++)
- shader.StreamOutputDeclarationString[i] = LoadString(shader.Binary.OffsetStreamOutputDeclarationString[i]);
- shader.RasterizedStream = unchecked((int) shader.Binary.RasterizedStream);
- return shader;
- }
- /// <summary>
- /// Finds a constant buffer by name.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns></returns>
- private CConstantBuffer FindConstantBuffer(string name)
- {
- foreach (var binaryConstantBuffer in _binaryConstantBuffers)
- {
- if (binaryConstantBuffer.Name == name)
- {
- return binaryConstantBuffer;
- }
- }
- return null;
- }
- /// <summary>
- /// Finds a variable by name.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns></returns>
- private CObjectVariable FindVariable(string name)
- {
- foreach (var objectVariable in _objectVariables)
- {
- if (objectVariable.Name == name)
- {
- return objectVariable;
- }
- }
- return null;
- }
- /// <summary>
- /// Loads a numeric variable.
- /// </summary>
- /// <returns></returns>
- private CNumericVariable LoadNumericVariable()
- {
- var cNumericVariable = new CNumericVariable();
- Read(cNumericVariable);
- cNumericVariable.Name = LoadString(cNumericVariable.Binary.OffsetName);
- cNumericVariable.Semantic = LoadString(cNumericVariable.Binary.OffsetSemantic);
- cNumericVariable.Type = LoadType(cNumericVariable.Binary.OffsetType);
- cNumericVariable.Annotations = LoadAnnotations();
- return cNumericVariable;
- }
- /// <summary>
- /// Loads the annotations.
- /// </summary>
- /// <returns></returns>
- private CAnnotation[] LoadAnnotations()
- {
- int numAnnotations = Read<int>();
- var annotations = new CAnnotation[numAnnotations];
- for (int i = 0; i < annotations.Length; i++)
- annotations[i] = LoadAnnotation();
- return annotations;
- }
- /// <summary>
- /// Loads an annotation.
- /// </summary>
- /// <returns></returns>
- private CAnnotation LoadAnnotation()
- {
- var annotation = new CAnnotation();
- Read(annotation);
- annotation.Name = LoadString(annotation.Binary.OffsetName);
- annotation.Type = LoadType(annotation.Binary.OffsetType);
- // For numeric annotations:
- // UINT OffsetDefaultValue; // Offset to default initializer value
- //
- // For string annotations:
- // UINT oStringOffsets[ElementCount]; // ElementCount comes from the type data at OffsetType
- if (annotation.Type.Binary.VarType == VariableType.Numeric)
- {
- object annotationValue = null;
- uint offsetToUnstructured = Read<uint>();
- //uint sizeOfElement = annotation.Type.Binary.PackedSize;
- switch (annotation.Type.Name)
- {
- case "int":
- annotationValue = Read<int>(offsetToUnstructured);
- break;
- case "uint":
- annotationValue = Read<uint>(offsetToUnstructured);
- break;
- case "float":
- annotationValue = Read<float>(offsetToUnstructured);
- break;
- case "double":
- annotationValue = Read<double>(offsetToUnstructured);
- break;
- case "bool":
- annotationValue = Read<int>(offsetToUnstructured) != 0;
- break;
- case "float2":
- annotationValue = Read<Vector2>(offsetToUnstructured);
- break;
- case "float3":
- annotationValue = Read<Vector3>(offsetToUnstructured);
- break;
- case "float4":
- annotationValue = Read<Vector4>(offsetToUnstructured);
- break;
- default:
- LogError("Annotation default value type not handled [{0}]", annotation.Type.Name);
- break;
- }
- annotation.Value = annotationValue;
- }
- else if (annotation.Type.Binary.VarType == VariableType.Object && annotation.Type.ObjectType == ObjectType.String)
- {
- uint elementCount = Math.Max(1, annotation.Type.Binary.ElementCount);
- if (elementCount > 1)
- LogError("Invalid number [{0}] of strings for annotation [{1}]", elementCount, annotation.Name);
- annotation.Value = LoadString(Read<uint>());
- }
- return annotation;
- }
- /// <summary>
- /// Loads a string from the unstructured data block.
- /// </summary>
- /// <param name="offset">The offset.</param>
- /// <returns></returns>
- private string LoadString(uint offset)
- {
- IntPtr ptr = _unStructuredDataBlock + (int)offset;
- return Marshal.PtrToStringAnsi(ptr);
- }
- /// <summary>
- /// Loads shader byte code from the unstructured data block.
- /// </summary>
- /// <param name="offset">The offset.</param>
- /// <returns></returns>
- private CShaderBytecode LoadByteCode(uint offset)
- {
- var bytecode = new CShaderBytecode();
- IntPtr typeBuffer = _unStructuredDataBlock + (int)offset;
- bytecode.Size = Read<int>(ref typeBuffer);
- bytecode.Pointer = typeBuffer;
- return bytecode;
- }
- /// <summary>
- /// Loads a type from the unstructured data block.
- /// </summary>
- /// <param name="offset">The offset.</param>
- /// <returns></returns>
- private CType LoadType(uint offset)
- {
- var type = new CType();
- IntPtr typeBuffer = _unStructuredDataBlock + (int)offset;
- Read(ref typeBuffer, type);
- type.Name = LoadString(type.Binary.OffsetTypeName);
- if (type.Binary.VarType == VariableType.Object)
- {
- type.ObjectType = (ObjectType)Read<int>(ref typeBuffer);
- }
- return type;
- }
- /// <summary>
- /// Reads the T type from the current structured buffer.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <returns></returns>
- private T Read<T>()
- {
- return Read<T>(ref _currentPtr);
- }
- /// <summary>
- /// Reads the T type from the unstructured buffer.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <returns></returns>
- private T Read<T>(uint offset)
- {
- IntPtr ptr = _unStructuredDataBlock + (int)offset;
- return Read<T>(ref ptr);
- }
- /// <summary>
- /// Reads the T type from the speicifed pointer. The pointer is moved according to the sizeof(T).
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="from">From.</param>
- /// <returns></returns>
- private static T Read<T>(ref IntPtr from)
- {
- object o = Marshal.PtrToStructure(from, typeof(T));
- from += Marshal.SizeOf(typeof(T));
- return (T)o;
- }
- /// <summary>
- /// Fills a BinaryStruct object.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="from">From.</param>
- /// <param name="value">The value.</param>
- private static void Read<T>(ref IntPtr from, BinaryStruct<T> value)
- {
- value.Binary = Read<T>(ref from);
- }
- /// <summary>
- /// Reads a BinaryStruct object.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="value">The value.</param>
- private void Read<T>(BinaryStruct<T> value)
- {
- value.Binary = Read<T>();
- }
- /// <summary>
- /// Gets a value indicating whether this instance has error.
- /// </summary>
- /// <value><c>true</c> if this instance has error; otherwise, <c>false</c>.</value>
- private bool HasError { get; set; }
- /// <summary>
- /// Logs an error.
- /// </summary>
- /// <param name="message">The message.</param>
- /// <param name="args">The args.</param>
- private void LogError(string message, params object[] args)
- {
- HasError = true;
- Trace.TraceWarning(message, args);
- }
- //////////////////////////////////////////////////////////////////////////
- #region Intermediate Struct Container
- //////////////////////////////////////////////////////////////////////////
- /// <summary>
- /// Root class for structure container
- /// </summary>
- /// <typeparam name="T"></typeparam>
- class BinaryStruct<T>
- {
- public T Binary;
- }
- /// <summary>
- /// Constant Buffer
- /// </summary>
- class CConstantBuffer : BinaryStruct<BinaryContantBuffer>
- {
- public string Name;
- public CAnnotation[] Annotations;
- public CNumericVariable[] Variables;
- }
- /// <summary>
- /// Annotation
- /// </summary>
- class CAnnotation : BinaryStruct<BinaryAnnotation>
- {
- public string Name;
- public CType Type;
- public object Value;
- }
- /// <summary>
- /// Type
- /// </summary>
- class CType : BinaryStruct<BinaryType>
- {
- public string Name;
- public ObjectType ObjectType;
- }
- /// <summary>
- /// Numeric Variable
- /// </summary>
- class CNumericVariable : BinaryStruct<BinaryNumericVariable>
- {
- public string Name;
- public string Semantic;
- public CType Type;
- public CAnnotation[] Annotations;
- }
- /// <summary>
- /// Object Variable
- /// </summary>
- class CObjectVariable : BinaryStruct<BinaryObjectVariable>
- {
- public string Name;
- public string Semantic;
- public CType Type;
- public CAnnotation[] Annotations;
- public CAssignment[] Assignments;
- public CShaderBytecode[] Bytecodes;
- public CGeometryShaderStreamOutputInitializer[] StreamOutputInitializers;
- public CShaderDataFx5[] ShaderData;
- // Specific data for assignments
- public EffectParameterType GraphicsResourceType;
- public GraphicsResource GraphicsResource;
- /// <summary>
- /// Creates a BlendState object from the FX description.
- /// </summary>
- public void UpdateBlendState()
- {
- if (Assignments == null || Assignments.Length == 0)
- return;
- var blendState = new BlendState();
- GraphicsResourceType = EffectParameterType.SamplerState;
- GraphicsResource = blendState;
- blendState.AlphaToCoverageEnable = false;
- blendState.IndependentBlendEnable = true;
- foreach (var assignment in Assignments)
- {
- int rtIndex = assignment.Index;
- switch (assignment.LeftHandSideValue.Type)
- {
- case LeftHandSideValueType.AlphaToCoverage:
- blendState.AlphaToCoverageEnable = (bool)assignment.ConstantValue;
- break;
- case LeftHandSideValueType.BlendEnable:
- blendState.RenderTargets[rtIndex].BlendEnable = (bool)assignment.ConstantValue;
- break;
- case LeftHandSideValueType.SrcBlend:
- blendState.RenderTargets[rtIndex].ColorSourceBlend = (Blend)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.DestBlend:
- blendState.RenderTargets[rtIndex].ColorDestinationBlend = (Blend)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.BlendOp:
- blendState.RenderTargets[rtIndex].ColorBlendFunction = (BlendFunction)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.SrcBlendAlpha:
- blendState.RenderTargets[rtIndex].AlphaSourceBlend = (Blend)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.DestBlendAlpha:
- blendState.RenderTargets[rtIndex].AlphaDestinationBlend = (Blend)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.BlendOpAlpha:
- blendState.RenderTargets[rtIndex].AlphaBlendFunction = (BlendFunction)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.RenderTargetWriteMask:
- blendState.RenderTargets[rtIndex].ColorWriteChannels = (ColorWriteChannels)((int)assignment.ConstantValue);
- break;
- }
- }
- }
- /// <summary>
- /// Creates a RasterizerState object from the FX description.
- /// </summary>
- public void UpdateRasterizerState()
- {
- if (Assignments == null || Assignments.Length == 0)
- return;
- var rasterizerState = new RasterizerState();
- GraphicsResourceType = EffectParameterType.RasterizerState; // Defaults are the same than strict fx_5_0 files
- GraphicsResource = rasterizerState;
- foreach (var assignment in Assignments)
- {
- switch (assignment.LeftHandSideValue.Type)
- {
- case LeftHandSideValueType.FillMode:
- rasterizerState.FillMode = (FillMode)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.CullMode:
- rasterizerState.CullMode = (CullMode)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.FrontCC:
- rasterizerState.FrontFaceCounterClockwise = (bool)assignment.ConstantValue;
- break;
- case LeftHandSideValueType.DepthBias:
- rasterizerState.DepthBias = ((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.DepthBiasClamp:
- rasterizerState.DepthBiasClamp = ((float)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.SlopeScaledDepthBias:
- rasterizerState.SlopeScaleDepthBias = ((float)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.DepthClipEnable:
- rasterizerState.DepthClipEnable = ((bool)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.ScissorEnable:
- rasterizerState.ScissorTestEnable = ((bool)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.MultisampleEnable:
- rasterizerState.MultiSampleAntiAlias = ((bool)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.AntialiasedLineEnable:
- rasterizerState.MultiSampleAntiAliasLine = ((bool)assignment.ConstantValue);
- break;
- }
- }
- }
- /// <summary>
- /// Creates a DepthStencilState state object from the FX description.
- /// </summary>
- public void UpdateDepthStencilState()
- {
- if (Assignments == null || Assignments.Length == 0)
- return;
- var depthStencilState = new DepthStencilState();
- GraphicsResourceType = EffectParameterType.DepthStencilState; // Defaults are the same than strict fx_5_0 files
- GraphicsResource = depthStencilState;
- foreach (var assignment in Assignments)
- {
- switch (assignment.LeftHandSideValue.Type)
- {
- case LeftHandSideValueType.DepthEnable:
- depthStencilState.DepthBufferEnable = ((bool)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.DepthWriteMask:
- depthStencilState.DepthBufferWriteEnable = ((int) assignment.ConstantValue) != 0;
- break;
- case LeftHandSideValueType.DepthFunc:
- depthStencilState.DepthBufferFunction = (CompareFunction)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.StencilEnable:
- depthStencilState.StencilEnable = ((bool)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.StencilReadMask:
- depthStencilState.StencilMask = ((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.StencilWriteMask:
- depthStencilState.StencilWriteMask = ((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.FrontFaceStencilFailOp:
- depthStencilState.StencilFail = (StencilOperation)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.FrontFaceStencilDepthFailOp:
- depthStencilState.StencilDepthBufferFail = (StencilOperation)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.FrontFaceStencilPassOp:
- depthStencilState.StencilPass = (StencilOperation)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.FrontFaceStencilFunc:
- depthStencilState.StencilFunction = (CompareFunction)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.BackFaceStencilFailOp:
- depthStencilState.CounterClockwiseStencilFail = (StencilOperation)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.BackFaceStencilDepthFailOp:
- depthStencilState.CounterClockwiseStencilFail = (StencilOperation)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.BackFaceStencilPassOp:
- depthStencilState.CounterClockwiseStencilFail = (StencilOperation)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.BackFaceStencilFunc:
- depthStencilState.CounterClockwiseStencilFunction = (CompareFunction)((int)assignment.ConstantValue);
- break;
- }
- }
- }
- /// <summary>
- /// Creates a SamplerState state object from the FX description.
- /// </summary>
- public void UpdateSamplerState()
- {
- if (Assignments == null || Assignments.Length == 0)
- return;
- var samplerState = new SamplerState();
- GraphicsResourceType = EffectParameterType.SamplerState;
- GraphicsResource = samplerState;
- // Defaults are slightly different here
- samplerState.AddressU = TextureAddressMode.Clamp;
- samplerState.AddressV = TextureAddressMode.Clamp;
- samplerState.AddressW = TextureAddressMode.Clamp;
- foreach (var assignment in Assignments)
- {
- switch (assignment.LeftHandSideValue.Type)
- {
- case LeftHandSideValueType.Filter:
- samplerState.Filter = (TextureFilter)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.AddressU:
- samplerState.AddressU = (TextureAddressMode) ((int) assignment.ConstantValue);
- break;
- case LeftHandSideValueType.AddressV:
- samplerState.AddressV = (TextureAddressMode) ((int) assignment.ConstantValue);
- break;
- case LeftHandSideValueType.AddressW:
- samplerState.AddressW = (TextureAddressMode) ((int) assignment.ConstantValue);
- break;
- case LeftHandSideValueType.MipLODBias:
- samplerState.MipMapLevelOfDetailBias = ((float)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.MaxAnisotropy:
- samplerState.MaxAnisotropy = ((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.ComparisonFunc:
- samplerState.CompareFunction = (CompareFunction)((int)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.BorderColor:
- var values = (object[])assignment.ConstantValue;
- samplerState.BorderColor = new Color4((float) values[3], (float) values[0], (float) values[1], (float) values[2]);
- break;
- case LeftHandSideValueType.MinLOD:
- samplerState.MinMipLevel = ((float)assignment.ConstantValue);
- break;
- case LeftHandSideValueType.MaxLOD:
- samplerState.MaxMipLevel = ((float)assignment.ConstantValue);
- break;
- }
- }
- }
- }
- /// <summary>
- /// Interface Variable
- /// </summary>
- class CInterfaceVariable : BinaryStruct<BinaryInterfaceVariable>
- {
- public string Name;
- public CType Type;
- public CAnnotation[] Annotations;
- }
- /// <summary>
- /// Fx Group
- /// </summary>
- class CFxGroup : BinaryStruct<BinaryGroup>
- {
- public string Name;
- public CAnnotation[] Annotations;
- public CTechnique[] Techniques;
- }
- /// <summary>
- /// Technique
- /// </summary>
- class CTechnique : BinaryStruct<BinaryTechnique>
- {
- public string Name;
- public CAnnotation[] Annotations;
- public CPass[] Passes;
- }
- /// <summary>
- /// Pass
- /// </summary>
- class CPass : BinaryStruct<BinaryPass>
- {
- public string Name;
- public CAnnotation[] Annotations;
- public CAssignment[] Assignments;
- }
- /// <summary>
- /// Assignment
- /// </summary>
- class CAssignment : BinaryStruct<BinaryAssignment>
- {
- public LeftHandSideValue LeftHandSideValue;
- public int Index;
- public int IndexMax;
- // Fx4 shaders
- public CShaderBytecode ByteCode;
- public string StreamOutputDeclarationString;
- // Fx5 shaders
- public CShaderDataFx5 InlineShader5;
- public bool IsDepthStencilBlock;
- public bool IsRasterizerBlock;
- public bool IsBlendBlock;
- /// <summary>
- /// Variable
- /// </summary>
- public CObjectVariable Variable;
- // Constant value
- public object ConstantValue;
- }
- /// <summary>
- /// ShaderBytecode
- /// </summary>
- class CShaderBytecode
- {
- public int Size;
- public IntPtr Pointer;
- }
- /// <summary>
- /// ShaderData Fx5
- /// </summary>
- class CShaderDataFx5 : BinaryStruct<BinaryShaderDataFx5>
- {
- public CShaderBytecode Bytecode; // from OffsetShader
- public string[] StreamOutputDeclarationString; // Offset to StreamOutput decl strings
- public int RasterizedStream; // Which stream is used for rasterization
- }
- /// <summary>
- /// GeometryShaderStreamOutputInitializer
- /// </summary>
- class CGeometryShaderStreamOutputInitializer : BinaryStruct<BinaryGeometryShaderStreamOutputInitializer>
- {
- public CShaderBytecode ByteCode;
- public string StreamOutputDeclarationString;
- }
- #endregion
- //////////////////////////////////////////////////////////////////////////
- #region Native Structures
- //////////////////////////////////////////////////////////////////////////
- internal enum VersionTag : uint
- {
- Fx40 = 0xFEFF1001, // fx_4_0
- Fx41 = 0xFEFF1011, // fx_4_1
- Fx50 = 0xFEFF2001, // fx_5_0
- }
- // Enumeration of the possible left-hand side values of an assignment,
- // divided up categorically by the type of block they may appear in
- internal enum LeftHandSideValueType
- {
- Invalid,
- // Pass block assignment types
- PixelShaderBlock, // SBlock *pValue points to the block to apply
- VertexShaderBlock,
- GeometryShaderBlock,
- RenderTargetView,
- DepthStencilView,
- RasterizerBlock,
- DepthStencilBlock,
- BlendBlock,
- GenerateMips, // This is really a call to D3D::GenerateMips
- // Various SAssignment.Value.*
- DS_StencilRef, // SAssignment.Value.pdValue
- B_BlendFactor, // D3D10_BLEND_CONFIG.BlendFactor, points to a float4
- B_SampleMask, // D3D10_BLEND_CONFIG.SampleMask
- GeometryShaderSO,
- // When setting SO assignments, GeometryShaderSO precedes the actual GeometryShader assn
- ComputeShaderBlock,
- HullShaderBlock,
- DomainShaderBlock,
- // Rasterizer
- FillMode = 0x20000,
- CullMode,
- FrontCC,
- DepthBias,
- DepthBiasClamp,
- SlopeScaledDepthBias,
- DepthClipEnable,
- ScissorEnable,
- MultisampleEnable,
- AntialiasedLineEnable,
- // Sampler
- Filter = 0x30000,
- AddressU,
- AddressV,
- AddressW,
- MipLODBias,
- MaxAnisotropy,
- ComparisonFunc,
- BorderColor,
- MinLOD,
- MaxLOD,
- Texture,
- // DepthStencil
- DepthEnable = 0x40000,
- DepthWriteMask,
- DepthFunc,
- StencilEnable,
- StencilReadMask,
- StencilWriteMask,
- FrontFaceStencilFailOp,
- FrontFaceStencilDepthFailOp,
- FrontFaceStencilPassOp,
- FrontFaceStencilFunc,
- BackFaceStencilFailOp,
- BackFaceStencilDepthFailOp,
- BackFaceStencilPassOp,
- BackFaceStencilFunc,
- // BlendState
- AlphaToCoverage = 0x50000,
- BlendEnable,
- SrcBlend,
- DestBlend,
- BlendOp,
- SrcBlendAlpha,
- DestBlendAlpha,
- BlendOpAlpha,
- RenderTargetWriteMask,
- }
- internal enum BlockType
- {
- Invalid,
- DepthStencil,
- Blend,
- Rasterizer,
- Sampler,
- Pass
- }
- internal enum VariableType
- {
- Invalid,
- Numeric,
- Object,
- Struct,
- Interface,
- }
- internal enum ScalarType
- {
- Invalid,
- Float,
- Int,
- UInt,
- Bool,
- Count
- }
- internal enum NumericLayout
- {
- Invalid,
- Scalar,
- Vector,
- Matrix,
- Count
- }
- internal enum ObjectType
- {
- Invalid,
- String,
- Blend,
- DepthStencil,
- Rasterizer,
- PixelShader,
- VertexShader,
- GeometryShader, // Regular geometry shader
- GeometryShaderSO, // Geometry shader with a attached StreamOut decl
- Texture,
- Texture1D,
- Texture1DArray,
- Texture2D,
- Texture2DArray,
- Texture2DMS,
- Texture2DMSArray,
- Texture3D,
- TextureCube,
- ConstantBuffer,
- RenderTargetView,
- DepthStencilView,
- Sampler,
- Buffer,
- TextureCubeArray,
- Count,
- PixelShader5,
- VertexShader5,
- GeometryShader5,
- ComputeShader5,
- HullShader5,
- DomainShader5,
- RWTexture1D,
- RWTexture1DArray,
- RWTexture2D,
- RWTexture2DArray,
- RWTexture3D,
- RWBuffer,
- ByteAddressBuffer,
- RWByteAddressBuffer,
- StructuredBuffer,
- RWStructuredBuffer,
- RWStructuredBufferAlloc,
- RWStructuredBufferConsume,
- AppendStructuredBuffer,
- ConsumeStructuredBuffer,
- }
- // Effect file format structures /////////////////////////////////////////////
- // File format:
- // File Header (BinaryHeader Header)
- // Unstructured data block (BYTE[Header.cbUnstructured))
- // Structured data block
- // ConstantBuffer (BinaryContantBuffer CB) * Header.Effect.ConstantBufferCount
- // uint NumAnnotations
- // Annotation data (BinaryAnnotation) * (NumAnnotations) *this structure is variable sized
- // Variable data (BinaryNumericVariable Var) * (CB.VariableCount)
- // uint NumAnnotations
- // Annotation data (BinaryAnnotation) * (NumAnnotations) *this structure is variable sized
- // Object variables (BinaryObjectVariable Var) * (Header.ObjectVariableCount) *this structure is variable sized
- // uint NumAnnotations
- // Annotation data (BinaryAnnotation) * (NumAnnotations) *this structure is variable sized
- // Interface variables (BinaryInterfaceVariable Var) * (Header.InterfaceVariableCount) *this structure is variable sized
- // uint NumAnnotations
- // Annotation data (BinaryAnnotation) * (NumAnnotations) *this structure is variable sized
- // Groups (BinaryGroup Group) * Header.GroupCount
- // uint NumAnnotations
- // Annotation data (BinaryAnnotation) * (NumAnnotations) *this structure is variable sized
- // Techniques (BinaryTechnique Technique) * Group.TechniqueCount
- // uint NumAnnotations
- // Annotation data (BinaryAnnotation) * (NumAnnotations) *this structure is variable sized
- // Pass (SBinaryPass Pass) * Technique.PassCount
- // uint NumAnnotations
- // Annotation data (BinaryAnnotation) * (NumAnnotations) *this structure is variable sized
- // Pass assignments (BinaryAssignment) * Pass.AssignmentCount
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryHeader
- {
- internal struct SVarCounts
- {
- public uint ConstantBufferCount;
- public uint NumericVariableCount;
- public uint ObjectVariableCount;
- } ;
- public VersionTag Tag; // should be equal to c_EffectFileTag
- // this is used to identify ASCII vs Binary files
- public SVarCounts Effect;
- public SVarCounts Pool;
- public uint TechniqueCount;
- public uint cbUnstructured;
- public uint StringCount;
- public uint ShaderResourceCount;
- public uint DepthStencilBlockCount;
- public uint BlendStateBlockCount;
- public uint RasterizerStateBlockCount;
- public uint SamplerCount;
- public uint RenderTargetViewCount;
- public uint DepthStencilViewCount;
- public uint TotalShaderCount;
- public uint InlineShaderCount;
- // of the aforementioned shaders, the number that are defined inline within pass blocks
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryHeader11
- {
- public BinaryHeader Header;
- public uint GroupCount;
- public uint UnorderedAccessViewCount;
- public uint InterfaceVariableCount;
- public uint InterfaceVariableElementCount;
- public uint ClassInstanceElementCount;
- }
- // Constant buffer definition
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryContantBuffer
- {
- // flags
- public const uint c_IsTBuffer = (1 << 0);
- public const uint c_IsSingle = (1 << 1);
- public uint OffsetName; // Offset to constant buffer name
- public uint Size; // Size, in bytes
- public uint Flags;
- public uint VariableCount; // # of variables inside this buffer
- public uint ExplicitBindPoint;
- // Defined if the effect file specifies a bind point using the register keyword
- // otherwise, -1
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryAnnotation
- {
- public uint OffsetName; // Offset to variable name
- public uint OffsetType; // Offset to type information (BinaryType)
- // For numeric annotations:
- // uint OffsetDefaultValue; // Offset to default initializer value
- //
- // For string annotations:
- // uint oStringOffsets[ElementCount]; // ElementCount comes from the type data at OffsetType
- } ;
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryNumericVariable
- {
- public uint OffsetName; // Offset to variable name
- public uint OffsetType; // Offset to type information (BinaryType)
- public uint OffsetSemantic; // Offset to semantic information
- public uint Offset; // Offset in parent constant buffer
- public uint OffsetDefaultValue; // Offset to default initializer value
- public uint Flags; // Explicit bind point
- } ;
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryInterfaceVariable
- {
- public uint OffsetName; // Offset to variable name
- public uint OffsetType; // Offset to type information (BinaryType)
- public uint OffsetDefaultValue; // Offset to default initializer array (BinaryInterfaceInitializer[ElementCount])
- public uint Flags;
- } ;
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryInterfaceInitializer
- {
- public uint OffsetInstanceName;
- public uint ArrayIndex;
- } ;
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryObjectVariable
- {
- public uint OffsetName; // Offset to variable name
- public uint OffsetType; // Offset to type information (BinaryType)
- public uint OffsetSemantic; // Offset to semantic information
- public uint ExplicitBindPoint; // Used when a variable has been explicitly bound (register(XX)). -1 if not
- // Initializer data:
- //
- // The type structure pointed to by OffsetType gives you ElementCount,
- // VarType (must be Object), and ObjectType
- //
- // For ObjectType == Blend, DepthStencil, Rasterizer, Sampler
- // struct
- // {
- // uint AssignmentCount;
- // BinaryAssignment Assignments[AssignmentCount];
- // } Blocks[ElementCount]
- //
- // For ObjectType == Texture*, Buffer
- // <nothing>
- //
- // For ObjectType == *Shader, String
- // uint OffsetData[ElementCount]; // offsets to a shader data block or a NULL-terminated string
- //
- // For ObjectType == GeometryShaderSO
- // BinaryGeometryShaderStreamOutputInitializer[ElementCount]
- //
- // For ObjectType == *Shader5
- // BinaryShaderDataFx5[ElementCount]
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryGeometryShaderStreamOutputInitializer
- {
- public uint OffsetShader; // Offset to shader bytecode data block
- public uint OffsetStreamOutputDeclaration; // Offset to StreamOutput decl string
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryShaderDataFx5
- {
- public uint OffsetShader; // Offset to shader bytecode data block
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- public uint[] OffsetStreamOutputDeclarationString; // Offset to StreamOutput decl strings
- public uint StreamOutputDeclarationCount; // Count of valid oSODecls entries.
- public uint RasterizedStream; // Which stream is used for rasterization
- public uint InterfaceBindingCount; // Count of interface bindings.
- public uint OffsetInterfaceBindings; // Offset to BinaryInterfaceInitializer[InterfaceBindingCount].
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryType
- {
- public uint OffsetTypeName; // Offset to friendly type name ("float4", "VS_OUTPUT")
- public VariableType VarType; // Numeric, Object, or Struct
- public uint ElementCount; // # of array elements (0 for non-arrays)
- public uint TotalSize; // Size in bytes; not necessarily Stride * ElementCount for arrays
- // because of possible gap left in final register
- public uint Stride; // If an array, this is the spacing between elements.
- // For unpacked arrays, always divisible by 16-bytes (1 register).
- // No support for packed arrays
- public uint PackedSize; // Size, in bytes, of this data typed when fully packed
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryMember
- {
- public uint OffsetName; // Offset to structure member name ("m_pFoo")
- public uint OffsetSemantic; // Offset to semantic ("POSITION0")
- public uint Offset; // Offset, in bytes, relative to start of parent structure
- public uint OffsetType; // Offset to member's type descriptor
- } ;
- // the data that follows depends on the VarType:
- // Numeric: SType::SNumericType
- // Object: ObjectType
- // Struct:
- // struct
- // {
- // uint cMembers;
- // SBinaryMembers Members[cMembers];
- // } MemberInfo
- // struct
- // {
- // uint oBaseClassType; // Offset to type information (BinaryType)
- // uint InterfaceCount;
- // uint oInterfaceTypes[InterfaceCount];
- // } BinaryTypeInheritance
- // Interface: (nothing)
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryNumericType
- {
- //ENumericLayout NumericLayout : 3; // scalar (1x1), vector (1xN), matrix (NxN)
- //EScalarType ScalarType : 5; // float32, int32, int8, etc.
- //uint Rows : 3; // 1 <= Rows <= 4
- //uint Columns : 3; // 1 <= Columns <= 4
- //uint IsColumnMajor : 1; // applies only to matrices
- //uint IsPackedArray : 1; // if this is an array, indicates whether elements should be greedily packed
- public byte PackedValue1;
- public byte PackedValue2;
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryTypeInheritance
- {
- public uint OffsetBaseClass; // Offset to base class type info or 0 if no base class.
- public uint InterfaceCount;
- // Followed by uint[InterfaceCount] with offsets to the type
- // info of each interface.
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryGroup
- {
- public uint OffsetName;
- public uint TechniqueCount;
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryTechnique
- {
- public uint OffsetName;
- public uint PassCount;
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryPass
- {
- public uint OffsetName;
- public uint AssignmentCount;
- }
- internal enum CompilerAssignmentType
- {
- Invalid, // Assignment-specific data (always in the unstructured blob)
- Constant, // -N SConstant structures
- Variable, // -NULL terminated string with variable name ("foo")
- ConstIndex, // -ConstantIndex structure
- VariableIndex, // -VariableIndex structure
- ExpressionIndex, // -IndexedObjectExpression structure
- Expression, // -Data block containing FXLVM code
- InlineShader, // -Data block containing shader
- InlineShader5, // -Data block containing shader with extended 5.0 data (BinaryShaderDataFx5)
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct BinaryAssignment
- {
- public uint StateIndex; // index into g_lvGeneral
- public uint Index; // the particular index to assign to (see g_lvGeneral to find the # of valid indices)
- public CompilerAssignmentType AssignmentType;
- public uint OffsetInitializer; // Offset of assignment-specific data
- //struct SConstantAssignment
- //{
- // uint NumConstants; // number of constants to follow
- // SBinaryConstant Constants[NumConstants];
- //};
- [StructLayout(LayoutKind.Sequential)]
- internal struct ConstantIndex
- {
- public uint OffsetArrayName;
- public uint Index;
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct VariableIndex
- {
- public uint OffsetArrayName;
- public uint OffsetIndexVariableName;
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct IndexedObjectExpression
- {
- public uint OffsetArrayName;
- public uint OffsetCode;
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct InlineShader
- {
- public uint OffsetShader;
- public uint OffsetStreamOutputDeclaration;
- }
- //struct SExpression or InlineShader
- //{
- // uint DataSize;
- // BYTE Data[DataSize];
- //}
- }
- [StructLayout(LayoutKind.Explicit)]
- internal struct BinaryConstant
- {
- [FieldOffset(0)]
- public ScalarType Type;
- [FieldOffset(4)]
- public bool BooleanValue;
- [FieldOffset(4)]
- public int IntegerValue;
- [FieldOffset(4)]
- public float FloatValue;
- }
- internal class LeftHandSideValue
- {
- public LeftHandSideValue(LeftHandSideValueType type, BlockType blockType, ShaderVariableType shaderType, int columnCount, int indexMax, bool vectorScalar)
- {
- Type = type;
- BlockType = blockType;
- ShaderType = shaderType;
- ColumnCount = columnCount;
- IndexMax = indexMax;
- VectorScalar = vectorScalar;
- }
- public LeftHandSideValueType Type { get; set; }
- public BlockType BlockType { get; set; }
- public ShaderVariableType ShaderType { get; set; }
- public int ColumnCount { get; set; }
- public int IndexMax { get; set; }
- public bool VectorScalar { get; set; }
- }
- private static readonly LeftHandSideValue[] LeftHandSideValues = new LeftHandSideValue[]
- {
- new LeftHandSideValue(LeftHandSideValueType.RasterizerBlock, BlockType.Pass, ShaderVariableType.Rasterizer, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.DepthStencilBlock, BlockType.Pass, ShaderVariableType.Depthstencil, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.BlendBlock, BlockType.Pass, ShaderVariableType.Blend, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.RenderTargetView, BlockType.Pass, ShaderVariableType.Rendertargetview, 1, 8, false),
- new LeftHandSideValue(LeftHandSideValueType.DepthStencilView, BlockType.Pass, ShaderVariableType.Depthstencilview, 1, 8, false),
- new LeftHandSideValue(LeftHandSideValueType.GenerateMips, BlockType.Pass, ShaderVariableType.Texture, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.VertexShaderBlock, BlockType.Pass, ShaderVariableType.Vertexshader, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.PixelShaderBlock, BlockType.Pass, ShaderVariableType.Pixelshader, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.GeometryShaderBlock, BlockType.Pass, ShaderVariableType.Geometryshader, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.DS_StencilRef, BlockType.Pass, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.B_BlendFactor, BlockType.Pass, ShaderVariableType.Float, 4, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.B_SampleMask, BlockType.Pass, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.FillMode, BlockType.Rasterizer, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.CullMode, BlockType.Rasterizer, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.FrontCC, BlockType.Rasterizer, ShaderVariableType.Bool, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.DepthBias, BlockType.Rasterizer, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.DepthBiasClamp, BlockType.Rasterizer, ShaderVariableType.Float, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.SlopeScaledDepthBias, BlockType.Rasterizer, ShaderVariableType.Float, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.DepthClipEnable, BlockType.Rasterizer, ShaderVariableType.Bool, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.ScissorEnable, BlockType.Rasterizer, ShaderVariableType.Bool, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.MultisampleEnable, BlockType.Rasterizer, ShaderVariableType.Bool, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.AntialiasedLineEnable, BlockType.Rasterizer, ShaderVariableType.Bool, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.DepthEnable, BlockType.DepthStencil, ShaderVariableType.Bool, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.DepthWriteMask, BlockType.DepthStencil, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.DepthFunc, BlockType.DepthStencil, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.StencilEnable, BlockType.DepthStencil, ShaderVariableType.Bool, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.StencilReadMask, BlockType.DepthStencil, ShaderVariableType.UInt8, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.StencilWriteMask, BlockType.DepthStencil, ShaderVariableType.UInt8, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.FrontFaceStencilFailOp, BlockType.DepthStencil, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.FrontFaceStencilDepthFailOp, BlockType.DepthStencil, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.FrontFaceStencilPassOp, BlockType.DepthStencil, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.FrontFaceStencilFunc, BlockType.DepthStencil, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.BackFaceStencilFailOp, BlockType.DepthStencil, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.BackFaceStencilDepthFailOp, BlockType.DepthStencil, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.BackFaceStencilPassOp, BlockType.DepthStencil, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.BackFaceStencilFunc, BlockType.DepthStencil, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.AlphaToCoverage, BlockType.Blend, ShaderVariableType.Bool, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.BlendEnable, BlockType.Blend, ShaderVariableType.Bool, 1, 8, false),
- new LeftHandSideValue(LeftHandSideValueType.SrcBlend, BlockType.Blend, ShaderVariableType.UInt, 1, 8, true),
- new LeftHandSideValue(LeftHandSideValueType.DestBlend, BlockType.Blend, ShaderVariableType.UInt, 1, 8, true),
- new LeftHandSideValue(LeftHandSideValueType.BlendOp, BlockType.Blend, ShaderVariableType.UInt, 1, 8, true),
- new LeftHandSideValue(LeftHandSideValueType.SrcBlendAlpha, BlockType.Blend, ShaderVariableType.UInt, 1, 8, true),
- new LeftHandSideValue(LeftHandSideValueType.DestBlendAlpha, BlockType.Blend, ShaderVariableType.UInt, 1, 8, true),
- new LeftHandSideValue(LeftHandSideValueType.BlendOpAlpha, BlockType.Blend, ShaderVariableType.UInt, 1, 8, true),
- new LeftHandSideValue(LeftHandSideValueType.RenderTargetWriteMask, BlockType.Blend, ShaderVariableType.UInt8, 1, 8, false),
- new LeftHandSideValue(LeftHandSideValueType.Filter, BlockType.Sampler, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.AddressU, BlockType.Sampler, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.AddressV, BlockType.Sampler, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.AddressW, BlockType.Sampler, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.MipLODBias, BlockType.Sampler, ShaderVariableType.Float, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.MaxAnisotropy, BlockType.Sampler, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.ComparisonFunc, BlockType.Sampler, ShaderVariableType.UInt, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.BorderColor, BlockType.Sampler, ShaderVariableType.Float, 4, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.MinLOD, BlockType.Sampler, ShaderVariableType.Float, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.MaxLOD, BlockType.Sampler, ShaderVariableType.Float, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.Texture, BlockType.Sampler, ShaderVariableType.Texture, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.HullShaderBlock, BlockType.Pass, ShaderVariableType.Hullshader, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.DomainShaderBlock, BlockType.Pass, ShaderVariableType.Domainshader, 1, 1, false),
- new LeftHandSideValue(LeftHandSideValueType.ComputeShaderBlock, BlockType.Pass, ShaderVariableType.Computeshader, 1, 1, false),
- };
- #endregion
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement