#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2013 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License // If the library is compiled as a DLL, this ensures symbols are exported #define NUCLEX_GRAPHICS_SOURCE 1 #include "HlslResourceDefinitionSerializer.h" #include "Nuclex/Graphics/Introspection/ConstantBufferMetadata.h" #define INITGUID 1 #define D3D11_NO_HELPERS #include namespace { // ------------------------------------------------------------------------------------------- // /// Converts a Direct3D shader variable class into a constant order /// Variable class that will be converted /// The constant order equivalent to the Direct3D variable class Nuclex::Graphics::Introspection::ConstantOrder::Enum constantOrderFromShaderVariableClass( D3D_SHADER_VARIABLE_CLASS shaderVariableClass ) { using namespace Nuclex::Graphics::Introspection; switch(shaderVariableClass) { case D3D_SVC_SCALAR: { return ConstantOrder::Scalar; } case D3D_SVC_VECTOR: { return ConstantOrder::Vector; } case D3D_SVC_MATRIX_ROWS: { return ConstantOrder::RowMajorMatrix; } case D3D_SVC_MATRIX_COLUMNS: { return ConstantOrder::ColumnMajorMatrix; } case D3D_SVC_OBJECT: case D3D_SVC_STRUCT: case D3D_SVC_INTERFACE_CLASS: case D3D_SVC_INTERFACE_POINTER: default: { return ConstantOrder::Unknown; } } } // ------------------------------------------------------------------------------------------- // Nuclex::Graphics::Introspection::ConstantType::Enum constantTypeFromShaderVariableType( D3D_SHADER_VARIABLE_TYPE shaderVariableType ) { using namespace Nuclex::Graphics::Introspection; switch(shaderVariableType) { case D3D_SVT_BOOL: { return ConstantType::Boolean; } case D3D_SVT_INT: { return ConstantType::Signed32; } case D3D_SVT_FLOAT: { return ConstantType::Float; } case D3D_SVT_STRING: { return ConstantType::String; } case D3D_SVT_TEXTURE: { return ConstantType::Texture; } case D3D_SVT_TEXTURE1D: { return ConstantType::Texture1; } case D3D_SVT_TEXTURE2D: { return ConstantType::Texture2; } case D3D_SVT_TEXTURE3D: { return ConstantType::Texture3; } case D3D_SVT_TEXTURECUBE: { return ConstantType::CubeTexture; } case D3D_SVT_SAMPLER: { return ConstantType::Sampler; } case D3D_SVT_PIXELSHADER: { return ConstantType::Void; } // Should this be added? case D3D_SVT_VERTEXSHADER: { return ConstantType::Void; } // Should this be added? case D3D_SVT_UINT: { return ConstantType::Unsigned32; } case D3D_SVT_UINT8: { return ConstantType::Unsigned8; } case D3D_SVT_GEOMETRYSHADER: { return ConstantType::Void; } // Should this be added? case D3D_SVT_RASTERIZER: { return ConstantType::Void; } case D3D_SVT_DEPTHSTENCIL: { return ConstantType::Void; } // Should this be added? case D3D_SVT_TEXTURE1DARRAY: { return ConstantType::TextureArray1; } case D3D_SVT_TEXTURE2DARRAY: { return ConstantType::TextureArray2; } case D3D_SVT_RENDERTARGETVIEW: { return ConstantType::RenderTargetView; } case D3D_SVT_DEPTHSTENCILVIEW: { return ConstantType::Void; } // Should this be added? case D3D_SVT_TEXTURECUBEARRAY: { return ConstantType::CubeTextureArray; } case D3D_SVT_HULLSHADER: { return ConstantType::Void; } // Should this be added? case D3D_SVT_DOMAINSHADER: { return ConstantType::Void; } // Should this be added? case D3D_SVT_COMPUTESHADER: { return ConstantType::Void; } // Should this be added? case D3D_SVT_DOUBLE: { return ConstantType::Void; } // Should this be added? default: { return ConstantType::Void; } } } // ------------------------------------------------------------------------------------------- // /// Converts a Direct3D shader variable class into a constant order /// Variable class that will be converted /// The constant order equivalent to the Direct3D variable class Nuclex::Graphics::Introspection::ResourceType::Enum resourceTypeFromShaderInputType( D3D_SHADER_INPUT_TYPE shaderInputType ) { using namespace Nuclex::Graphics::Introspection; switch(shaderInputType) { case D3D_SIT_CBUFFER: { return ResourceType::ConstantBuffer; } case D3D_SIT_TBUFFER: { return ResourceType::TextureBuffer; } case D3D_SIT_TEXTURE: { return ResourceType::Texture; } case D3D_SIT_SAMPLER: { return ResourceType::Sampler; } default: { return ResourceType::Unknown; } } } // ------------------------------------------------------------------------------------------- // /// Converts a Direct3D shader variable class into a constant order /// Variable class that will be converted /// The constant order equivalent to the Direct3D variable class Nuclex::Graphics::Introspection::ResourceOrder::Enum resourceOrderFromDimension( D3D_SRV_DIMENSION dimension ) { using namespace Nuclex::Graphics::Introspection; switch(dimension) { case D3D_SRV_DIMENSION_BUFFER: { return ResourceOrder::Buffer; } case D3D_SRV_DIMENSION_TEXTURE1D: { return ResourceOrder::Texture1; } case D3D_SRV_DIMENSION_TEXTURE1DARRAY: { return ResourceOrder::Texture1Array; } case D3D_SRV_DIMENSION_TEXTURE2D: { return ResourceOrder::Texture2; } case D3D_SRV_DIMENSION_TEXTURE2DARRAY: { return ResourceOrder::Texture2Array; } case D3D_SRV_DIMENSION_TEXTURE3D: { return ResourceOrder::Texture3; } case D3D_SRV_DIMENSION_TEXTURECUBE: { return ResourceOrder::CubeTexture; } default: { return ResourceOrder::Unknown; } } } // ------------------------------------------------------------------------------------------- // } // anonymous namespace namespace Nuclex { namespace Graphics { namespace Introspection { // ------------------------------------------------------------------------------------------- // void HlslResourceDefinitionSerializer::Read( const MiniReader &reader, ShaderMetadata &metadata ) { MiniReader headerReader(reader); // Number of constant buffers the shader uses std::uint32_t constantBufferCount; headerReader.Read(constantBufferCount); // Offset of the constant buffer definitions std::uint32_t constantBufferOffset; headerReader.Read(constantBufferOffset); // Number of resource bindings the shader uses std::uint32_t resourceBindingCount; headerReader.Read(resourceBindingCount); // Offset of the resource bindings in the shader std::uint32_t resourceBindingsOffset; headerReader.Read(resourceBindingsOffset); // Target shader model in low word, unknown content in high word std::uint32_t requiredShaderVersion; headerReader.Read(requiredShaderVersion); // Shader compilation / parse flags, according to MSDN std::uint32_t flags; headerReader.Read(flags); // // The rest of the D3D11_SHADER_DESC structure is following here in seemingly // random order. I just noticed that I'm not really interested in the rest, // so I'll stop here :) // // Read the constant buffer descriptions { MiniReader constantBufferReader(reader); constantBufferReader.Skip(constantBufferOffset); for(std::size_t index = 0; index < constantBufferCount; ++index) { ConstantBufferMetadata constantBufferMetadata; readConstantBuffer(reader, constantBufferReader, constantBufferMetadata); metadata.ConstantBuffers.push_back(constantBufferMetadata); } } // Read the resource binding descriptions { MiniReader resourceBindingReader(reader); resourceBindingReader.Skip(resourceBindingsOffset); for(std::size_t index = 0; index < resourceBindingCount; ++index) { ResourceMetadata resourceMetadata; readResourceBinding(reader, resourceBindingReader, resourceMetadata); metadata.Resources.push_back(resourceMetadata); } } } // ------------------------------------------------------------------------------------------- // void HlslResourceDefinitionSerializer::readConstantBuffer( const MiniReader &reader, MiniReader &constantBufferReader, ConstantBufferMetadata &constantBufferMetadata ) { // Offset in the chunk where the constant buffer's name is stored std::uint32_t nameOffset; constantBufferReader.Read(nameOffset); // Name the user gave the constant buffer { MiniReader nameReader(reader); nameReader.Skip(nameOffset); nameReader.Read(constantBufferMetadata.Name); } // Number of variables in the constant buffer std::uint32_t variableCount; constantBufferReader.Read(variableCount); // Offset of the variable descriptions from the chunk start std::uint32_t variablesOffset; constantBufferReader.Read(variablesOffset); // Read the variables stored in the constant buffer { MiniReader variableReader(reader); variableReader.Skip(variablesOffset); for(std::size_t index = 0; index < variableCount; ++index) { ConstantMetadata constantMetadata; readConstantBufferVariable(reader, variableReader, constantMetadata); constantBufferMetadata.Constants.push_back(constantMetadata); } } // Total size of the constant buffer in bytes std::uint32_t size; constantBufferReader.Read(size); constantBufferMetadata.Size = static_cast(size); // Flags from the D3D_SHADER_CBUFFER_FLAGS enumeration. Currently only specifies if // the HLSL program explicitly specified the input slot, so we don't expose this. std::uint32_t flags; constantBufferReader.Read(flags); // What the constant buffer contains as a value from the D3D11_CBUFFER_TYPE // enumeration. Indicates whether a texture, interface pointers (?!) or constants // are stored in it. We only support constant buffers containing constants, so // this is another value that doesn't get exposed. std::uint32_t type; constantBufferReader.Read(type); } // ------------------------------------------------------------------------------------------- // void HlslResourceDefinitionSerializer::readConstantBufferVariable( const MiniReader &reader, MiniReader &variableReader, ConstantMetadata &constantMetadata ) { // Offset of the variable's name in the chunk std::uint32_t nameOffset; variableReader.Read(nameOffset); // Name the user gave the variable { MiniReader nameReader(reader); nameReader.Skip(nameOffset); nameReader.Read(constantMetadata.Name); } // Offset of the variable's value in the constant buffer std::uint32_t offset; variableReader.Read(offset); constantMetadata.Offset = static_cast(offset); // Number of bytes the variable is long std::uint32_t size; variableReader.Read(size); constantMetadata.Size = static_cast(size); // Flags from the D3D_SHADER_VARIABLE_FLAGS enumeration. Currently, there is no flag // that should be interesting to the user, so it is not exposed. std::uint32_t flags; variableReader.Read(flags); // Offset of the variable's type description in the chunk std::uint32_t typeOffset; variableReader.Read(typeOffset); // Variable type description { MiniReader typeReader(reader); typeReader.Skip(typeOffset); readConstantBufferVariableType(reader, typeReader, constantMetadata); } // Offset of the variable's default value in the chunk std::uint32_t defaultValueOffset; variableReader.Read(defaultValueOffset); // Default value for the variable (seems to be optional) std::vector defaultValue; if(defaultValueOffset != 0) { MiniReader defaultValueReader(reader); defaultValueReader.Skip(defaultValueOffset); defaultValueReader.Read(constantMetadata.DefaultValue, constantMetadata.Size); } else { constantMetadata.DefaultValue.clear(); } } // ------------------------------------------------------------------------------------------- // void HlslResourceDefinitionSerializer::readConstantBufferVariableType( const MiniReader &, MiniReader &typeReader, ConstantMetadata &constantMetadata ) { // Whether variable is a scalar, vector or matrix, see D3D10_SHADER_VARIABLE_CLASS std::uint16_t class_; typeReader.Read(class_); constantMetadata.Order = constantOrderFromShaderVariableClass( static_cast(class_) ); // Data format of the variable from the D3D10_SHADER_VARIABLE_TYPE enumeration std::uint16_t type; typeReader.Read(type); constantMetadata.Type = constantTypeFromShaderVariableType( static_cast(type) ); // Number of rows if this is a matrix (1 for scalars) std::uint16_t rows; typeReader.Read(rows); constantMetadata.RowCount = static_cast(rows); // Number of columns if this is a matrix (1 for scalars) // TODO: Check what happens in vectors std::uint16_t columns; typeReader.Read(columns); constantMetadata.ColumnCount = static_cast(columns); // Number of elements if this is a vector std::uint16_t elementCount; typeReader.Read(elementCount); if(constantMetadata.Order == ConstantOrder::Vector) { constantMetadata.ColumnCount = static_cast(elementCount); constantMetadata.RowCount = 1; } // Number of fields if this is a structure. Not exposed since structures aren't supported. std::uint16_t memberCount; typeReader.Read(memberCount); // Offset, in bytes, between the start of the parent structure and this variable. std::uint32_t memberOffset; typeReader.Read(memberOffset); // shader version > 5.0 // std::uint32_t unknown; // typeReader.Read(unknown); } // ------------------------------------------------------------------------------------------- // void HlslResourceDefinitionSerializer::readResourceBinding( const MiniReader &reader, MiniReader &resourceBindingReader, ResourceMetadata &resourceMetadata ) { // Offset of the name from the start of the chunk std::uint32_t nameOffset; resourceBindingReader.Read(nameOffset); // Name assigned to the resource by the user { MiniReader nameReader(reader); nameReader.Skip(nameOffset); nameReader.Read(resourceMetadata.Name); } // Type of resource, indicating whether it's a constant buffer, texture, etc. // Uses the D3D10_SHADER_INPUT_TYPE enumeration. std::uint32_t type; resourceBindingReader.Read(type); resourceMetadata.Type = resourceTypeFromShaderInputType( static_cast(type) ); // What's returned by the resource (I think) as a value from // the D3D11_RESOURCE_RETURN_TYPE enumeration. Not exposed. std::uint32_t returnType; resourceBindingReader.Read(returnType); // Dimensionality of the resource (from 1D buffer .. 3D texture array) as // a value from the D3D11_SRV_DIMENSION enumeration. std::uint32_t dimension; resourceBindingReader.Read(dimension); resourceMetadata.Order = resourceOrderFromDimension( static_cast(dimension) ); // Number of samples used for multi-sampling. Not exposed. std::uint32_t multipleSampleCount; resourceBindingReader.Read(multipleSampleCount); // Which slot the resource is bound to std::uint32_t slotIndex; resourceBindingReader.Read(slotIndex); resourceMetadata.SlotIndex = static_cast(slotIndex); // Number of slot the resource occupies std::uint32_t slotCount; resourceBindingReader.Read(slotCount); resourceMetadata.SlotCount = static_cast(slotCount); // Additional flags from the D3D10_SHADER_INPUT_FLAGS enumeration. Not exposed. std::uint32_t flags; resourceBindingReader.Read(flags); } // ------------------------------------------------------------------------------------------- // }}} // namespace Nuclex::Graphics::Introspection