Merge pull request #126 from Laupetin/feature/dx11-shader-parsing

feat: use parameter names from dx11 shaders to resolve material hashes
This commit is contained in:
Jan 2024-02-24 13:41:09 +01:00 committed by GitHub
commit 99632f5d98
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 1500 additions and 26 deletions

View File

@ -0,0 +1,685 @@
#include "D3D11ShaderAnalyser.h"
#include "Utils/FileUtils.h"
#include <cstring>
using namespace d3d11;
namespace d3d11
{
BoundResource::BoundResource()
: m_type(BoundResourceType::UNKNOWN),
m_return_type(BoundResourceReturnType::UNKNOWN),
m_dimension(BoundResourceDimension::UNKNOWN),
m_num_samples(0u),
m_bind_point(0u),
m_bind_count(0u),
m_flags(0u)
{
}
ConstantBuffer::ConstantBuffer()
: m_size(0u),
m_flags(0u),
m_type(ConstantBufferType::UNKNOWN)
{
}
ConstantBufferVariable::ConstantBufferVariable()
: m_offset(0u),
m_size(0u),
m_flags(0u)
{
}
static constexpr auto TAG_RDEF = FileUtils::MakeMagic32('R', 'D', 'E', 'F');
static constexpr auto TAG_SHDR = FileUtils::MakeMagic32('S', 'H', 'D', 'R');
static constexpr auto VERSION_5_0 = 0x500;
static constexpr auto VERSION_5_1 = 0x501;
static constexpr auto TARGET_VERSION_MASK = 0xFFFF;
static constexpr auto CHUNK_TABLE_OFFSET = 28u;
struct FileRdefHeader
{
uint32_t constantBufferCount;
uint32_t constantBufferOffset;
uint32_t boundResourceCount;
uint32_t boundResourceOffset;
uint32_t target;
uint32_t flags;
uint32_t creatorOffset;
};
struct FileRdefExtraHeader_5_0
{
// Wine project does not seem to know what this is
uint32_t unknown[8];
};
static_assert(sizeof(FileRdefHeader) == 28);
static_assert(sizeof(FileRdefExtraHeader_5_0) == 32);
// https://learn.microsoft.com/en-us/windows/win32/api/d3dcommon/ne-d3dcommon-d3d_shader_input_type
enum D3D_SHADER_INPUT_TYPE : uint32_t
{
D3D_SIT_CBUFFER = 0,
D3D_SIT_TBUFFER,
D3D_SIT_TEXTURE,
D3D_SIT_SAMPLER,
D3D_SIT_UAV_RWTYPED,
D3D_SIT_STRUCTURED,
D3D_SIT_UAV_RWSTRUCTURED,
D3D_SIT_BYTEADDRESS,
D3D_SIT_UAV_RWBYTEADDRESS,
D3D_SIT_UAV_APPEND_STRUCTURED,
D3D_SIT_UAV_CONSUME_STRUCTURED,
D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER,
D3D_SIT_RTACCELERATIONSTRUCTURE,
D3D_SIT_UAV_FEEDBACKTEXTURE,
D3D10_SIT_CBUFFER,
D3D10_SIT_TBUFFER,
D3D10_SIT_TEXTURE,
D3D10_SIT_SAMPLER,
D3D11_SIT_UAV_RWTYPED,
D3D11_SIT_STRUCTURED,
D3D11_SIT_UAV_RWSTRUCTURED,
D3D11_SIT_BYTEADDRESS,
D3D11_SIT_UAV_RWBYTEADDRESS,
D3D11_SIT_UAV_APPEND_STRUCTURED,
D3D11_SIT_UAV_CONSUME_STRUCTURED,
D3D11_SIT_UAV_RWSTRUCTURED_WITH_COUNTER
};
// https://learn.microsoft.com/en-us/windows/win32/api/d3dcommon/ne-d3dcommon-d3d_resource_return_type
enum D3D_RESOURCE_RETURN_TYPE : uint32_t
{
D3D_RETURN_TYPE_UNORM = 1,
D3D_RETURN_TYPE_SNORM = 2,
D3D_RETURN_TYPE_SINT = 3,
D3D_RETURN_TYPE_UINT = 4,
D3D_RETURN_TYPE_FLOAT = 5,
D3D_RETURN_TYPE_MIXED = 6,
D3D_RETURN_TYPE_DOUBLE = 7,
D3D_RETURN_TYPE_CONTINUED = 8,
D3D10_RETURN_TYPE_UNORM,
D3D10_RETURN_TYPE_SNORM,
D3D10_RETURN_TYPE_SINT,
D3D10_RETURN_TYPE_UINT,
D3D10_RETURN_TYPE_FLOAT,
D3D10_RETURN_TYPE_MIXED,
D3D11_RETURN_TYPE_UNORM,
D3D11_RETURN_TYPE_SNORM,
D3D11_RETURN_TYPE_SINT,
D3D11_RETURN_TYPE_UINT,
D3D11_RETURN_TYPE_FLOAT,
D3D11_RETURN_TYPE_MIXED,
D3D11_RETURN_TYPE_DOUBLE,
D3D11_RETURN_TYPE_CONTINUED
};
// https://learn.microsoft.com/en-us/windows/win32/api/d3dcommon/ne-d3dcommon-d3d_srv_dimension
enum D3D_SRV_DIMENSION : uint32_t
{
D3D_SRV_DIMENSION_UNKNOWN = 0,
D3D_SRV_DIMENSION_BUFFER = 1,
D3D_SRV_DIMENSION_TEXTURE1D = 2,
D3D_SRV_DIMENSION_TEXTURE1DARRAY = 3,
D3D_SRV_DIMENSION_TEXTURE2D = 4,
D3D_SRV_DIMENSION_TEXTURE2DARRAY = 5,
D3D_SRV_DIMENSION_TEXTURE2DMS = 6,
D3D_SRV_DIMENSION_TEXTURE2DMSARRAY = 7,
D3D_SRV_DIMENSION_TEXTURE3D = 8,
D3D_SRV_DIMENSION_TEXTURECUBE = 9,
D3D_SRV_DIMENSION_TEXTURECUBEARRAY = 10,
D3D_SRV_DIMENSION_BUFFEREX = 11,
D3D10_SRV_DIMENSION_UNKNOWN,
D3D10_SRV_DIMENSION_BUFFER,
D3D10_SRV_DIMENSION_TEXTURE1D,
D3D10_SRV_DIMENSION_TEXTURE1DARRAY,
D3D10_SRV_DIMENSION_TEXTURE2D,
D3D10_SRV_DIMENSION_TEXTURE2DARRAY,
D3D10_SRV_DIMENSION_TEXTURE2DMS,
D3D10_SRV_DIMENSION_TEXTURE2DMSARRAY,
D3D10_SRV_DIMENSION_TEXTURE3D,
D3D10_SRV_DIMENSION_TEXTURECUBE,
D3D10_1_SRV_DIMENSION_UNKNOWN,
D3D10_1_SRV_DIMENSION_BUFFER,
D3D10_1_SRV_DIMENSION_TEXTURE1D,
D3D10_1_SRV_DIMENSION_TEXTURE1DARRAY,
D3D10_1_SRV_DIMENSION_TEXTURE2D,
D3D10_1_SRV_DIMENSION_TEXTURE2DARRAY,
D3D10_1_SRV_DIMENSION_TEXTURE2DMS,
D3D10_1_SRV_DIMENSION_TEXTURE2DMSARRAY,
D3D10_1_SRV_DIMENSION_TEXTURE3D,
D3D10_1_SRV_DIMENSION_TEXTURECUBE,
D3D10_1_SRV_DIMENSION_TEXTURECUBEARRAY,
D3D11_SRV_DIMENSION_UNKNOWN,
D3D11_SRV_DIMENSION_BUFFER,
D3D11_SRV_DIMENSION_TEXTURE1D,
D3D11_SRV_DIMENSION_TEXTURE1DARRAY,
D3D11_SRV_DIMENSION_TEXTURE2D,
D3D11_SRV_DIMENSION_TEXTURE2DARRAY,
D3D11_SRV_DIMENSION_TEXTURE2DMS,
D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY,
D3D11_SRV_DIMENSION_TEXTURE3D,
D3D11_SRV_DIMENSION_TEXTURECUBE,
D3D11_SRV_DIMENSION_TEXTURECUBEARRAY,
D3D11_SRV_DIMENSION_BUFFEREX
};
struct FileBoundResource
{
uint32_t nameOffset;
D3D_SHADER_INPUT_TYPE type;
D3D_RESOURCE_RETURN_TYPE returnType;
D3D_SRV_DIMENSION dimension;
uint32_t numSamples;
uint32_t bindPoint;
uint32_t bindCount;
uint32_t uFlags;
};
struct FileBoundResource_5_1 : FileBoundResource
{
uint32_t space;
uint32_t uID;
};
static_assert(sizeof(FileBoundResource) == 32);
static_assert(sizeof(FileBoundResource_5_1) == 40);
// https://learn.microsoft.com/en-us/windows/win32/api/d3dcommon/ne-d3dcommon-d3d_cbuffer_type
enum D3D_CBUFFER_TYPE : uint32_t
{
D3D_CT_CBUFFER = 0,
D3D_CT_TBUFFER,
D3D_CT_INTERFACE_POINTERS,
D3D_CT_RESOURCE_BIND_INFO,
D3D10_CT_CBUFFER,
D3D10_CT_TBUFFER,
D3D11_CT_CBUFFER,
D3D11_CT_TBUFFER,
D3D11_CT_INTERFACE_POINTERS,
D3D11_CT_RESOURCE_BIND_INFO
};
struct FileConstantBuffer
{
uint32_t nameOffset;
uint32_t variableCount;
uint32_t variableOffset;
uint32_t size;
uint32_t flags;
D3D_CBUFFER_TYPE type;
};
struct FileConstantBufferVariable
{
uint32_t nameOffset;
uint32_t startOffset;
uint32_t size;
uint32_t flags;
uint32_t typeOffset;
uint32_t defaultValueOffset;
};
struct FileConstantBufferVariable_5_0 : FileConstantBufferVariable
{
// Wine project does not seem to know what this is
uint32_t unknown[4];
};
static_assert(sizeof(FileConstantBufferVariable) == 24);
static_assert(sizeof(FileConstantBufferVariable_5_0) == 40);
enum FileProgramType : uint32_t
{
D3D10_SB_PIXEL_SHADER = 0,
D3D10_SB_VERTEX_SHADER = 1,
D3D10_SB_GEOMETRY_SHADER = 2,
// D3D11 Shaders
D3D11_SB_HULL_SHADER = 3,
D3D11_SB_DOMAIN_SHADER = 4,
D3D11_SB_COMPUTE_SHADER = 5,
D3D11_SB_RESERVED0 = 0xFFF0
};
struct FileShaderHeader
{
uint32_t versionMinor : 4;
uint32_t versionMajor : 4;
uint32_t unused : 8;
FileProgramType programType : 16;
};
static_assert(sizeof(FileShaderHeader) == 4);
uint32_t ReadU32(const uint8_t*& ptr)
{
const auto result = *reinterpret_cast<const uint32_t*>(ptr);
ptr += sizeof(uint32_t);
return result;
}
bool FindChunk(const uint32_t magic, const uint8_t* byteCode, const size_t byteCodeSize, size_t& chunkOffset, size_t& chunkSize)
{
if (byteCodeSize < CHUNK_TABLE_OFFSET + sizeof(uint32_t))
return false;
const auto* ptr = byteCode + CHUNK_TABLE_OFFSET;
const auto chunkCount = ReadU32(ptr);
if (byteCodeSize < (ptr - byteCode) + chunkCount * sizeof(uint32_t))
return false;
for (auto chunkIndex = 0u; chunkIndex < chunkCount; chunkIndex++)
{
const auto currentChunkOffset = ReadU32(ptr);
if (byteCodeSize < currentChunkOffset + sizeof(uint32_t) * 2)
return false;
const auto currentChunkTag = *reinterpret_cast<const uint32_t*>(byteCode + currentChunkOffset + 0);
const auto currentChunkSize = *reinterpret_cast<const uint32_t*>(byteCode + currentChunkOffset + 4);
if (byteCodeSize < currentChunkOffset + sizeof(uint32_t) * 2 + currentChunkSize)
return false;
if (currentChunkTag == magic)
{
chunkOffset = currentChunkOffset + 8;
chunkSize = currentChunkSize;
return true;
}
}
return false;
}
bool StringFitsInChunk(const char* str, const uint8_t* shaderByteCode, const size_t shaderByteCodeSize)
{
const auto strLen = strnlen(str, shaderByteCodeSize - (reinterpret_cast<const uint8_t*>(str) - shaderByteCode));
return str[strLen] == '\0';
}
BoundResourceType GetType(const D3D_SHADER_INPUT_TYPE type)
{
switch (type)
{
case D3D_SIT_CBUFFER:
case D3D10_SIT_CBUFFER:
return BoundResourceType::CBUFFER;
case D3D_SIT_TBUFFER:
case D3D10_SIT_TBUFFER:
return BoundResourceType::TBUFFER;
case D3D_SIT_TEXTURE:
case D3D10_SIT_TEXTURE:
return BoundResourceType::TEXTURE;
case D3D_SIT_SAMPLER:
case D3D10_SIT_SAMPLER:
return BoundResourceType::SAMPLER;
default:
return BoundResourceType::UNKNOWN;
}
}
BoundResourceReturnType GetReturnType(const D3D_RESOURCE_RETURN_TYPE returnType)
{
switch (returnType)
{
case D3D_RETURN_TYPE_UNORM:
case D3D10_RETURN_TYPE_UNORM:
case D3D11_RETURN_TYPE_UNORM:
return BoundResourceReturnType::UNORM;
case D3D_RETURN_TYPE_SNORM:
case D3D10_RETURN_TYPE_SNORM:
case D3D11_RETURN_TYPE_SNORM:
return BoundResourceReturnType::SNORM;
case D3D_RETURN_TYPE_SINT:
case D3D10_RETURN_TYPE_SINT:
case D3D11_RETURN_TYPE_SINT:
return BoundResourceReturnType::SINT;
case D3D_RETURN_TYPE_UINT:
case D3D10_RETURN_TYPE_UINT:
case D3D11_RETURN_TYPE_UINT:
return BoundResourceReturnType::UINT;
case D3D_RETURN_TYPE_FLOAT:
case D3D10_RETURN_TYPE_FLOAT:
case D3D11_RETURN_TYPE_FLOAT:
return BoundResourceReturnType::FLOAT;
case D3D_RETURN_TYPE_MIXED:
case D3D10_RETURN_TYPE_MIXED:
case D3D11_RETURN_TYPE_MIXED:
return BoundResourceReturnType::MIXED;
case D3D_RETURN_TYPE_DOUBLE:
case D3D11_RETURN_TYPE_DOUBLE:
return BoundResourceReturnType::DOUBLE;
case D3D_RETURN_TYPE_CONTINUED:
case D3D11_RETURN_TYPE_CONTINUED:
return BoundResourceReturnType::CONTINUED;
default:
return BoundResourceReturnType::UNKNOWN;
}
}
BoundResourceDimension GetDimension(const D3D_SRV_DIMENSION dimension)
{
switch (dimension)
{
case D3D_SRV_DIMENSION_BUFFER:
case D3D10_SRV_DIMENSION_BUFFER:
case D3D10_1_SRV_DIMENSION_BUFFER:
case D3D11_SRV_DIMENSION_BUFFER:
return BoundResourceDimension::BUFFER;
case D3D_SRV_DIMENSION_TEXTURE1D:
case D3D10_SRV_DIMENSION_TEXTURE1D:
case D3D10_1_SRV_DIMENSION_TEXTURE1D:
case D3D11_SRV_DIMENSION_TEXTURE1D:
return BoundResourceDimension::TEXTURE_1D;
case D3D_SRV_DIMENSION_TEXTURE1DARRAY:
case D3D10_SRV_DIMENSION_TEXTURE1DARRAY:
case D3D10_1_SRV_DIMENSION_TEXTURE1DARRAY:
case D3D11_SRV_DIMENSION_TEXTURE1DARRAY:
return BoundResourceDimension::TEXTURE_1D_ARRAY;
case D3D_SRV_DIMENSION_TEXTURE2D:
case D3D10_SRV_DIMENSION_TEXTURE2D:
case D3D10_1_SRV_DIMENSION_TEXTURE2D:
case D3D11_SRV_DIMENSION_TEXTURE2D:
return BoundResourceDimension::TEXTURE_2D;
case D3D_SRV_DIMENSION_TEXTURE2DARRAY:
case D3D10_SRV_DIMENSION_TEXTURE2DARRAY:
case D3D10_1_SRV_DIMENSION_TEXTURE2DARRAY:
case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
return BoundResourceDimension::TEXTURE_2D_ARRAY;
case D3D_SRV_DIMENSION_TEXTURE2DMS:
case D3D10_SRV_DIMENSION_TEXTURE2DMS:
case D3D10_1_SRV_DIMENSION_TEXTURE2DMS:
case D3D11_SRV_DIMENSION_TEXTURE2DMS:
return BoundResourceDimension::TEXTURE_2D_MS;
case D3D_SRV_DIMENSION_TEXTURE2DMSARRAY:
case D3D10_SRV_DIMENSION_TEXTURE2DMSARRAY:
case D3D10_1_SRV_DIMENSION_TEXTURE2DMSARRAY:
case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY:
return BoundResourceDimension::TEXTURE_2D_MS_ARRAY;
case D3D_SRV_DIMENSION_TEXTURE3D:
case D3D10_SRV_DIMENSION_TEXTURE3D:
case D3D10_1_SRV_DIMENSION_TEXTURE3D:
case D3D11_SRV_DIMENSION_TEXTURE3D:
return BoundResourceDimension::TEXTURE_3D;
case D3D_SRV_DIMENSION_TEXTURECUBE:
case D3D10_SRV_DIMENSION_TEXTURECUBE:
case D3D10_1_SRV_DIMENSION_TEXTURECUBE:
case D3D11_SRV_DIMENSION_TEXTURECUBE:
return BoundResourceDimension::TEXTURE_CUBE;
case D3D_SRV_DIMENSION_TEXTURECUBEARRAY:
case D3D10_1_SRV_DIMENSION_TEXTURECUBEARRAY:
case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY:
return BoundResourceDimension::TEXTURE_CUBE_ARRAY;
case D3D_SRV_DIMENSION_BUFFEREX:
case D3D11_SRV_DIMENSION_BUFFEREX:
return BoundResourceDimension::BUFFER_EX;
default:
return BoundResourceDimension::UNKNOWN;
}
}
bool PopulateBoundResource(BoundResource& boundResource,
const FileBoundResource& fileBoundResource,
const uint8_t* shaderByteCode,
const size_t shaderByteCodeSize,
const size_t chunkOffset)
{
const auto nameString = reinterpret_cast<const char*>(shaderByteCode + chunkOffset + fileBoundResource.nameOffset);
if (!StringFitsInChunk(nameString, shaderByteCode, shaderByteCodeSize))
return false;
boundResource.m_name = std::string(nameString);
boundResource.m_type = GetType(fileBoundResource.type);
boundResource.m_return_type = GetReturnType(fileBoundResource.returnType);
boundResource.m_dimension = GetDimension(fileBoundResource.dimension);
boundResource.m_num_samples = fileBoundResource.numSamples;
boundResource.m_bind_point = fileBoundResource.bindPoint;
boundResource.m_bind_count = fileBoundResource.bindCount;
boundResource.m_flags = fileBoundResource.uFlags;
return true;
}
bool PopulateConstantBufferVariable(ConstantBufferVariable& constantBufferVariable,
const FileConstantBufferVariable& fileConstantBufferVariable,
const uint8_t* shaderByteCode,
const size_t shaderByteCodeSize,
const size_t chunkOffset,
const size_t chunkSize)
{
const auto nameString = reinterpret_cast<const char*>(shaderByteCode + chunkOffset + fileConstantBufferVariable.nameOffset);
if (!StringFitsInChunk(nameString, shaderByteCode, shaderByteCodeSize))
return false;
constantBufferVariable.m_name = std::string(nameString);
constantBufferVariable.m_offset = fileConstantBufferVariable.startOffset;
constantBufferVariable.m_size = fileConstantBufferVariable.size;
constantBufferVariable.m_flags = fileConstantBufferVariable.flags;
return true;
}
ConstantBufferType GetType(const D3D_CBUFFER_TYPE type)
{
switch (type)
{
case D3D_CT_CBUFFER:
case D3D10_CT_CBUFFER:
case D3D11_CT_CBUFFER:
return ConstantBufferType::CBUFFER;
case D3D_CT_TBUFFER:
case D3D10_CT_TBUFFER:
case D3D11_CT_TBUFFER:
return ConstantBufferType::TBUFFER;
case D3D_CT_INTERFACE_POINTERS:
case D3D11_CT_INTERFACE_POINTERS:
return ConstantBufferType::INTERFACE_POINTERS;
case D3D_CT_RESOURCE_BIND_INFO:
case D3D11_CT_RESOURCE_BIND_INFO:
return ConstantBufferType::RESOURCE_BIND_INFO;
default:
return ConstantBufferType::UNKNOWN;
}
}
bool PopulateConstantBuffer(ConstantBuffer& constantBuffer,
const FileConstantBuffer& fileConstantBuffer,
const uint8_t* shaderByteCode,
const size_t shaderByteCodeSize,
const size_t chunkOffset,
const size_t chunkSize,
const unsigned targetVersion)
{
const auto nameString = reinterpret_cast<const char*>(shaderByteCode + chunkOffset + fileConstantBuffer.nameOffset);
if (!StringFitsInChunk(nameString, shaderByteCode, shaderByteCodeSize))
return false;
constantBuffer.m_name = std::string(nameString);
constantBuffer.m_size = fileConstantBuffer.size;
constantBuffer.m_flags = fileConstantBuffer.flags;
constantBuffer.m_type = GetType(fileConstantBuffer.type);
if (targetVersion < VERSION_5_0)
{
const auto* variables = reinterpret_cast<const FileConstantBufferVariable*>(shaderByteCode + chunkOffset + fileConstantBuffer.variableOffset);
if (fileConstantBuffer.variableOffset + sizeof(FileConstantBufferVariable) * fileConstantBuffer.variableCount > chunkSize)
return false;
for (auto variableIndex = 0u; variableIndex < fileConstantBuffer.variableCount; variableIndex++)
{
const auto& fileVariable = variables[variableIndex];
ConstantBufferVariable variable;
if (!PopulateConstantBufferVariable(variable, fileVariable, shaderByteCode, shaderByteCodeSize, chunkOffset, chunkSize))
return false;
constantBuffer.m_variables.emplace_back(std::move(variable));
}
}
else
{
const auto* variables = reinterpret_cast<const FileConstantBufferVariable_5_0*>(shaderByteCode + chunkOffset + fileConstantBuffer.variableOffset);
if (fileConstantBuffer.variableOffset + sizeof(FileConstantBufferVariable_5_0) * fileConstantBuffer.variableCount > chunkSize)
return false;
for (auto variableIndex = 0u; variableIndex < fileConstantBuffer.variableCount; variableIndex++)
{
const auto& fileVariable = variables[variableIndex];
ConstantBufferVariable variable;
if (!PopulateConstantBufferVariable(variable, fileVariable, shaderByteCode, shaderByteCodeSize, chunkOffset, chunkSize))
return false;
constantBuffer.m_variables.emplace_back(std::move(variable));
}
}
return true;
}
bool PopulateShaderInfoFromRdef(ShaderInfo& shaderInfo, const uint8_t* shaderByteCode, const size_t shaderByteCodeSize)
{
size_t chunkOffset, chunkSize;
if (!FindChunk(TAG_RDEF, shaderByteCode, shaderByteCodeSize, chunkOffset, chunkSize))
return false;
if (sizeof(FileRdefHeader) > chunkSize)
return false;
const auto* header = reinterpret_cast<const FileRdefHeader*>(shaderByteCode + chunkOffset);
const auto targetVersion = header->target & TARGET_VERSION_MASK;
const auto creatorString = reinterpret_cast<const char*>(shaderByteCode + chunkOffset + header->creatorOffset);
if (!StringFitsInChunk(creatorString, shaderByteCode, shaderByteCodeSize))
return false;
shaderInfo.m_creator = std::string(creatorString);
if (targetVersion < VERSION_5_1)
{
const auto* boundResources = reinterpret_cast<const FileBoundResource*>(shaderByteCode + chunkOffset + header->boundResourceOffset);
if (header->boundResourceOffset + sizeof(FileBoundResource) * header->boundResourceCount > chunkSize)
return false;
for (auto boundResourceIndex = 0u; boundResourceIndex < header->boundResourceCount; boundResourceIndex++)
{
const auto& fileBoundResource = boundResources[boundResourceIndex];
BoundResource boundResource;
PopulateBoundResource(boundResource, fileBoundResource, shaderByteCode, shaderByteCodeSize, chunkOffset);
shaderInfo.m_bound_resources.emplace_back(std::move(boundResource));
}
}
else
{
const auto* boundResources = reinterpret_cast<const FileBoundResource_5_1*>(shaderByteCode + chunkOffset + header->boundResourceOffset);
if (header->boundResourceOffset + sizeof(FileBoundResource_5_1) * header->boundResourceCount > chunkSize)
return false;
for (auto boundResourceIndex = 0u; boundResourceIndex < header->boundResourceCount; boundResourceIndex++)
{
const auto& fileBoundResource = boundResources[boundResourceIndex];
BoundResource boundResource;
if (!PopulateBoundResource(boundResource, fileBoundResource, shaderByteCode, shaderByteCodeSize, chunkOffset))
return false;
shaderInfo.m_bound_resources.emplace_back(std::move(boundResource));
}
}
const auto* constantBuffers = reinterpret_cast<const FileConstantBuffer*>(shaderByteCode + chunkOffset + header->constantBufferOffset);
if (header->constantBufferOffset + sizeof(FileConstantBuffer) * header->constantBufferCount > chunkSize)
return false;
for (auto constantBufferIndex = 0u; constantBufferIndex < header->constantBufferCount; constantBufferIndex++)
{
const auto& fileConstantBuffer = constantBuffers[constantBufferIndex];
ConstantBuffer constantBuffer;
if (!PopulateConstantBuffer(constantBuffer, fileConstantBuffer, shaderByteCode, shaderByteCodeSize, chunkOffset, chunkSize, targetVersion))
return false;
shaderInfo.m_constant_buffers.emplace_back(std::move(constantBuffer));
}
return true;
}
ShaderType GetShaderType(const FileProgramType programType)
{
switch (programType)
{
case D3D10_SB_PIXEL_SHADER:
return ShaderType::PIXEL_SHADER;
case D3D10_SB_VERTEX_SHADER:
return ShaderType::VERTEX_SHADER;
case D3D10_SB_GEOMETRY_SHADER:
return ShaderType::GEOMETRY_SHADER;
case D3D11_SB_HULL_SHADER:
return ShaderType::HULL_SHADER;
case D3D11_SB_DOMAIN_SHADER:
return ShaderType::DOMAIN_SHADER;
case D3D11_SB_COMPUTE_SHADER:
return ShaderType::COMPUTE_SHADER;
default:
return ShaderType::UNKNOWN;
}
}
bool PopulateShaderInfoFromShdr(ShaderInfo& shaderInfo, const uint8_t* shaderByteCode, const size_t shaderByteCodeSize)
{
size_t chunkOffset, chunkSize;
if (!FindChunk(TAG_SHDR, shaderByteCode, shaderByteCodeSize, chunkOffset, chunkSize))
return false;
if (sizeof(FileShaderHeader) > chunkSize)
return false;
const auto* header = reinterpret_cast<const FileShaderHeader*>(shaderByteCode + chunkOffset);
shaderInfo.m_version_major = header->versionMajor;
shaderInfo.m_version_minor = header->versionMinor;
shaderInfo.m_type = GetShaderType(header->programType);
return true;
}
bool PopulateShaderInfoFromBytes(ShaderInfo& shaderInfo, const uint8_t* shaderByteCode, const size_t shaderByteCodeSize)
{
if (!PopulateShaderInfoFromRdef(shaderInfo, shaderByteCode, shaderByteCodeSize))
return false;
if (!PopulateShaderInfoFromShdr(shaderInfo, shaderByteCode, shaderByteCodeSize))
return false;
return true;
}
} // namespace d3d11
std::unique_ptr<ShaderInfo> ShaderAnalyser::GetShaderInfo(const uint8_t* shader, const size_t shaderSize)
{
if (shader == nullptr || shaderSize == 0)
return nullptr;
auto shaderInfo = std::make_unique<ShaderInfo>();
if (!PopulateShaderInfoFromBytes(*shaderInfo, shader, shaderSize))
return nullptr;
return shaderInfo;
}

View File

@ -0,0 +1,136 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
namespace d3d11
{
enum class ShaderType
{
UNKNOWN,
PIXEL_SHADER,
VERTEX_SHADER,
GEOMETRY_SHADER,
HULL_SHADER,
DOMAIN_SHADER,
COMPUTE_SHADER
};
class ConstantBufferVariable
{
public:
ConstantBufferVariable();
~ConstantBufferVariable() = default;
ConstantBufferVariable(const ConstantBufferVariable& other) = default;
ConstantBufferVariable(ConstantBufferVariable&& other) noexcept = default;
ConstantBufferVariable& operator=(const ConstantBufferVariable& other) = default;
ConstantBufferVariable& operator=(ConstantBufferVariable&& other) noexcept = default;
std::string m_name;
unsigned m_offset;
unsigned m_size;
unsigned m_flags;
};
enum class ConstantBufferType
{
UNKNOWN,
CBUFFER,
TBUFFER,
INTERFACE_POINTERS,
RESOURCE_BIND_INFO,
};
class ConstantBuffer
{
public:
ConstantBuffer();
~ConstantBuffer() = default;
ConstantBuffer(const ConstantBuffer& other) = default;
ConstantBuffer(ConstantBuffer&& other) noexcept = default;
ConstantBuffer& operator=(const ConstantBuffer& other) = default;
ConstantBuffer& operator=(ConstantBuffer&& other) noexcept = default;
std::string m_name;
unsigned m_size;
unsigned m_flags;
ConstantBufferType m_type;
std::vector<ConstantBufferVariable> m_variables;
};
enum class BoundResourceType
{
UNKNOWN,
CBUFFER,
TBUFFER,
TEXTURE,
SAMPLER
};
enum class BoundResourceReturnType
{
UNKNOWN,
UNORM,
SNORM,
SINT,
UINT,
FLOAT,
MIXED,
DOUBLE,
CONTINUED,
};
enum class BoundResourceDimension
{
UNKNOWN,
BUFFER,
TEXTURE_1D,
TEXTURE_1D_ARRAY,
TEXTURE_2D,
TEXTURE_2D_ARRAY,
TEXTURE_2D_MS,
TEXTURE_2D_MS_ARRAY,
TEXTURE_3D,
TEXTURE_CUBE,
TEXTURE_CUBE_ARRAY,
BUFFER_EX,
};
class BoundResource
{
public:
BoundResource();
~BoundResource() = default;
BoundResource(const BoundResource& other) = default;
BoundResource(BoundResource&& other) noexcept = default;
BoundResource& operator=(const BoundResource& other) = default;
BoundResource& operator=(BoundResource&& other) noexcept = default;
std::string m_name;
BoundResourceType m_type;
BoundResourceReturnType m_return_type;
BoundResourceDimension m_dimension;
unsigned m_num_samples;
unsigned m_bind_point;
unsigned m_bind_count;
unsigned m_flags;
};
class ShaderInfo
{
public:
ShaderType m_type = ShaderType::UNKNOWN;
unsigned m_version_major = 0;
unsigned m_version_minor = 0;
std::string m_creator;
std::vector<ConstantBuffer> m_constant_buffers;
std::vector<BoundResource> m_bound_resources;
};
class ShaderAnalyser
{
public:
static std::unique_ptr<ShaderInfo> GetShaderInfo(const uint8_t* shader, size_t shaderSize);
};
} // namespace d3d11

View File

@ -1,12 +1,17 @@
#include "AssetDumperMaterial.h"
#include "Game/T6/CommonT6.h"
#include "Game/T6/GameAssetPoolT6.h"
#include "Game/T6/GameT6.h"
#include "Game/T6/MaterialConstantsT6.h"
#include "Game/T6/TechsetConstantsT6.h"
#include "ObjWriting.h"
#include "Shader/D3D11ShaderAnalyser.h"
#include <cassert>
#include <nlohmann/json.hpp>
#include <sstream>
#include <unordered_set>
using namespace T6;
using namespace nlohmann;
@ -18,17 +23,647 @@ namespace T6::material
Common::R_HashString(strValue, 0), strValue \
}
std::unordered_map<unsigned, std::string> knownHashes{
KNOWN_HASH("colorMap"),
KNOWN_HASH("normalMap"),
KNOWN_HASH("specularMap"),
static constexpr const char* SAMPLER_STR = "Sampler";
static constexpr const char* GLOBALS_CBUFFER_NAME = "$Globals";
static constexpr const char* PER_OBJECT_CONSTS_CBUFFER_NAME = "PerObjectConsts";
const char* KNOWN_CONSTANT_NAMES[]{
"AngularVelocityScale",
"AnimSpeed",
"Background",
"BackgroundColor",
"BackgroundNoise",
"BakedLightingIntensity",
"BloodBrightness",
"BloodIntensity",
"BlurAmount",
"CapWidth",
"Char_Size",
"Char_Width",
"Coarseness",
"Color",
"ColorAmount",
"ColorBias",
"Color_Map_Noise",
"Color_Map_Scale",
"Color_Map_Size_Scale",
"DDXScale",
"DDYScale",
"DarkenAmount",
"DarkenPower",
"Detail_Amount",
"Detail_Normal_Tile",
"Diffuse_Normal_Height_Facing",
"Dimensions",
"DispersionAmount",
"Dolly",
"EdgeColor",
"EdgeHarshness",
"EdgeIntensity",
"EdgeMaxDist",
"EdgeMinDist",
"EdgeSize",
"Edge_Color_Multiplier",
"Emissive_Amount",
"EnemiesColor",
"Exposure",
"FPS",
"Fade_Distance",
"Fill_Direction",
"Fill_Direction2",
"FirstFrame",
"FlareIntensity",
"FlareScale",
"FlattenEdges",
"Flicker_Max",
"Flicker_Min",
"Flicker_Seed",
"Flicker_Speed",
"Font_Color",
"Gamma",
"GlossAmount",
"Gloss_Amount",
"Glow_Alt_Color",
"Glow_Color",
"Glow_Falloff",
"GradientColor",
"GradientMax",
"GradientMin",
"Grain_Amount",
"Grain_Color",
"Grid",
"Hardness",
"Heart_Rate_Offset",
"Heart_Rate_Scale",
"Highlight_1_Brightness",
"Highlight_1_Sharpness",
"Highlight_2_Brightness",
"Highlight_2_Sharpness",
"Highlight_2_Size",
"Hightlight_1_Size",
"Holo_Scale",
"LastFrame",
"Layer1Alpha",
"Layer1Depth",
"Layer1Offset",
"Layer1OffsetBobbleDelay",
"Layer1OffsetBobbleSpeedAndSize",
"Layer1Origin",
"Layer1Rotation",
"Layer1Scale",
"Layer1ScaleBobbleDelay",
"Layer1ScaleBobbleSpeedAndSize",
"Layer1Scroll",
"Layer2Alpha",
"Layer2Depth",
"Layer2Offset",
"Layer2OffsetBobbleDelay",
"Layer2OffsetBobbleSpeedAndSize",
"Layer2Origin",
"Layer2Rotation",
"Layer2Scale",
"Layer2ScaleBobbleDelay",
"Layer2ScaleBobbleSpeedAndSize",
"Layer2Scroll",
"Layer3Alpha",
"Layer3Depth",
"Layer3Offset",
"Layer3Origin",
"Layer3Rotation",
"Layer3Scale",
"Layer3Scroll",
"Layer4Alpha",
"Layer4Depth",
"Layer4Offset",
"Layer4Origin",
"Layer4Rotation",
"Layer4Scale",
"Layer4Scroll",
"LineColor",
"LineNoise",
"LineWidth",
"MaxDepth",
"MaxFlickerColor",
"MaxPulseDepth",
"MaxResolution",
"Max_Color",
"Maximum_Distance",
"Midlayer_Depth",
"MinDepth",
"MinFlickerColor",
"MinResolution",
"MinStatic",
"MinVelocityFraction",
"Min_Color",
"Min_Player_Intensity",
"MomentumColor",
"NegativeColor",
"NoisePower",
"Noise_Scale",
"NormalHeightMultiplier",
"Normal_Detail_Height",
"Normal_Detail_Scale",
"Normal_Map_Size_Scale",
"Normal_Variance_Scale",
"NumFrames",
"Outline_Lookup_Scale",
"OverallAmount",
"OverallBrightness",
"Overlay_Color",
"P1",
"P2",
"Padding",
"Player_Color_Multiplier",
"Player_Lookup_Scale",
"PositiveColor",
"Power",
"PulseColor",
"PulseInterval",
"PulseTime",
"Pulse_Color_Multiplier",
"Pulse_Lookup_Scale",
"Radius",
"ReflectionAmount",
"Reflection_Amount",
"Reflection_Blur",
"Reticle_Alt_Color",
"Reticle_Color",
"Row_Chars_",
"Scale",
"ScanlineColor",
"ScanlineIntensity",
"ScanlineOffset",
"ScanlinePower",
"ScanlineSpeed",
"ScatterAmount",
"ScatterSize",
"SceneNoise",
"SparkleBrightness",
"SparkleDensity",
"SparklePower",
"SparkleProbeAmount",
"SparkleScale",
"SparkleSpecAmount",
"SparkleWash",
"SpecGloss_Map_Size_Scale",
"SpecularAmount",
"SpecularColor",
"Specular_Amount",
"Specular_Decay_Threshold",
"Speed",
"StaticAmount",
"StaticLookupSpeed",
"StaticLookupX",
"StaticScale",
"Static_Size",
"Static_amount",
"TearLookupMaxX",
"TearLookupMinX",
"TearLookupSpeed",
"TearMultiplier",
"TearPower",
"Thickness",
"TickMarkColorAndHarshness",
"Tint",
"VelocityScale",
"VignetteMultiplier",
"VignettePower",
"WarpAmount",
"WarpHeight",
"WarpScale",
"WarpSpeed",
"WashOut",
"WashoutMultiply",
"WaterDirection",
"WaterHeight",
"WaterRefraction",
"WaterScale1",
"WaterScale2",
"WaterSpeed1",
"WaterSpeed2",
"Zoom",
"alphaDissolveParms",
"alphaRevealParms",
"alphaRevealParms1",
"alphaRevealParms2",
"alphaRevealParms3",
"alphaRevealParms4",
"clipSpaceLookupOffset",
"clipSpaceLookupScale",
"cloudsFeather",
"cloudsHeights",
"cloudsUVMad1",
"cloudsUVMad2",
"cloudsUVMul1",
"cloudsUVMul2",
"codeMeshArg",
"colorDetailScale",
"colorObjMax",
"colorObjMaxBaseBlend",
"colorObjMin",
"colorObjMinBaseBlend",
"colorTint",
"debugBumpmap",
"debugPerformance",
"detailScale",
"detailScale1",
"detailScale2",
"detailScale3",
"detailScale4",
"distortionScale",
"dofEquationScene",
"dofEquationViewModelAndFarBlur",
"dofLerpBias",
"dofLerpDownBias",
"dofLerpDownScale",
"dofLerpScale",
"dofLerpUpBias",
"dofLerpUpScale",
"dofRowDelta",
"eyeOffsetParms",
"falloffBeginColor",
"falloffEndColor",
"falloffParms",
"featherParms",
"flagParams",
"framebufferRead",
"gameTime",
"hdrAmount",
"inverseTransposeWorldMatrix",
"inverseTransposeWorldViewMatrix",
"inverseWorldMatrix",
"inverseWorldViewMatrix",
"motionblurDirectionAndMagnitude",
"occlusionAmount",
"occlusionAmount1",
"occlusionAmount2",
"occlusionAmount3",
"occlusionAmount4",
"particleCloudColor",
"particleCloudMatrix",
"particleCloudVelWorld",
"resizeParams1",
"resizeParams2",
"scaleRGB",
"scriptVector0",
"scriptVector1",
"scriptVector2",
"scriptVector3",
"scriptVector4",
"scriptVector5",
"scriptVector6",
"scriptVector7",
"skyBoxCloudWeights",
"skyBoxRotationSize",
"skyColorParms",
"spotLightWeight",
"treeCanopyLightingParms",
"treeCanopyScatterColor",
"treeCanopySwayParms",
"ui3dUVSetup0",
"ui3dUVSetup1",
"ui3dUVSetup2",
"ui3dUVSetup3",
"ui3dUVSetup4",
"ui3dUVSetup5",
"uvAnimParms",
"uvScroll",
"viewMatrix",
"weaponParam0",
"weaponParam1",
"weaponParam2",
"weaponParam3",
"weaponParam4",
"weaponParam5",
"weaponParam6",
"weaponParam7",
"weaponParam8",
"weaponParam9",
"worldViewMatrix",
"worldViewProjectionMatrix",
};
const char* KNOWN_TEXTURE_DEF_NAMES[]{
"AddMap",
"Blip_Mask",
"BlockNoise",
"CS_Z_buffer",
"Camo_Detail_Map",
"Color_Map",
"CompassMap",
"Detail_Map",
"Diffuse",
"Diffuse_Map",
"DpadTexture",
"FontTextutre",
"Grain_Map",
"GridTexture",
"GrimeMap",
"Heart_Rate_Image",
"Hologram_Diffuse",
"Image",
"Layer1Map",
"Layer2Map",
"Layer3Map",
"Layer4Map",
"Lookup",
"Lookup2",
"LookupMap",
"Mask",
"Noise",
"Noise_Texture",
"NormalDetailMap",
"Normal_Detail_Map",
"Normal_Map",
"Overlay_Map",
"Reflection_Mask",
"Reveal_Map",
"Rim_Color_Mask",
"Rim_Specular_Mask",
"Rim_Occlusion_Mask",
"Scanline",
"SparkleMap",
"SpecularAndGloss",
"SpecularAndGloss2",
"Specular_Color_Map",
"Specular_Gloss_Map",
"Specular_Map",
"SpotShadowSamplerState",
"SpotShadowState",
"SpriteMap",
"Static",
"StaticMap",
"Static_Noise_Map",
"SunShadowSamplerState",
"SunShadowState",
"Surface_Normal_Map",
"ThermalMapMask",
"Thermal_Gradient",
"Thermal_Map",
"TickMarkMaterial",
"Tile",
"WarpMap",
"WaterNormalMap",
"Weapon_Normal_Map",
"Weapon_Specular_Map",
"Wireframe",
"ZBuffer_Map",
"attenuation",
"attenuationSampler",
"baseLut2D",
"baseLut2DSampler",
"cinematicA",
"cinematicASampler",
"cinematicCb",
"cinematicCbSampler",
"cinematicCr",
"cinematicCrSampler",
"cinematicY",
"cinematicYSampler",
"codeTexture0",
"codeTexture1",
"codeTexture2",
"color",
"colorDetailMap",
"colorDetailMapSampler",
"colorMap",
"colorMap1",
"colorMap2",
"colorMap2D",
"colorMapPostSun",
"colorMapPostSunSampler",
"colorMapSampler",
"colorMapSampler1",
"colorMapSampler2",
"colorSampler",
"detailMap",
"detailMapSampler",
"dlightAttenuation",
"dlightAttenuationSampler",
"floatZ",
"floatZSampler",
"imageSampler",
"lightmapSamplerSecondary",
"lightmapSecondary",
"lut2D",
"lut2DSampler",
"lut3D",
"lut3DSampler",
"missileCam",
"missileCamSampler",
"modelLighting",
"modelLightingSampler",
"normalMap",
"normalMap1",
"normalMap2",
"normalMapSampler",
"normalMapSampler1",
"normalMapSampler2",
"occlusionMap",
"occlusionMapSampler",
"occMap",
"occMapSampler",
"outdoorMap",
"outdoorMapSampler",
"radiantDiffuseMap",
"rawFloatZ",
"rawFloatZSampler",
"reflectionProbe",
"reflectionProbeSampler",
"shadowmapSamplerSpot",
"shadowmapSamplerSun",
"shadowmapSpot",
"shadowmapSun",
"sonarColor",
"sonarColorSampler",
"sonarDepth",
"sonarDepthSampler",
"source",
"specularMap",
"specularMap1",
"specularMap2",
"specularMapSampler",
"specularMapSampler1",
"specularMapSampler2",
"stencil",
"stencilSampler",
"ui3d",
"ui3dSampler",
};
class MaterialConstantZoneState final : public IZoneAssetDumperState
{
public:
void ExtractNamesFromZone()
{
if (ObjWriting::Configuration.Verbose)
std::cout << "Building material constant name lookup...\n";
const auto begin = std::chrono::high_resolution_clock::now();
AddStaticKnownNames();
for (const auto* zone : g_GameT6.GetZones())
{
const auto* t6AssetPools = dynamic_cast<const GameAssetPoolT6*>(zone->m_pools.get());
if (!t6AssetPools)
return;
for (const auto* techniqueSetInfo : *t6AssetPools->m_technique_set)
{
const auto* techniqueSet = techniqueSetInfo->Asset();
for (const auto* technique : techniqueSet->techniques)
{
if (technique)
ExtractNamesFromTechnique(technique);
}
}
}
const auto end = std::chrono::high_resolution_clock::now();
if (ObjWriting::Configuration.Verbose)
{
const auto durationInMs = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
std::cout << "Built material constant name lookup in " << durationInMs.count() << "ms: " << m_constant_names_from_shaders.size()
<< " constant names; " << m_texture_def_names_from_shaders.size() << " texture def names\n";
}
}
bool GetConstantName(const unsigned hash, std::string& constantName) const
{
const auto existingConstantName = m_constant_names_from_shaders.find(hash);
if (existingConstantName != m_constant_names_from_shaders.end())
{
constantName = existingConstantName->second;
return true;
}
return false;
}
bool GetTextureDefName(const unsigned hash, std::string& textureDefName) const
{
const auto existingTextureDefName = m_texture_def_names_from_shaders.find(hash);
if (existingTextureDefName != m_texture_def_names_from_shaders.end())
{
textureDefName = existingTextureDefName->second;
return true;
}
return false;
}
private:
void ExtractNamesFromTechnique(const MaterialTechnique* technique)
{
const auto existingTechnique = m_dumped_techniques.find(technique);
if (existingTechnique != m_dumped_techniques.end())
return;
m_dumped_techniques.emplace(technique);
for (auto passIndex = 0u; passIndex < technique->passCount; passIndex++)
{
const auto& pass = technique->passArray[passIndex];
if (pass.vertexShader && pass.vertexShader->prog.loadDef.program)
ExtractNamesFromShader(pass.vertexShader->prog.loadDef.program, pass.vertexShader->prog.loadDef.programSize);
if (pass.pixelShader && pass.pixelShader->prog.loadDef.program)
ExtractNamesFromShader(pass.pixelShader->prog.loadDef.program, pass.pixelShader->prog.loadDef.programSize);
}
}
void ExtractNamesFromShader(const char* shader, const size_t shaderSize)
{
const auto shaderInfo = d3d11::ShaderAnalyser::GetShaderInfo(reinterpret_cast<const uint8_t*>(shader), shaderSize);
if (!shaderInfo)
return;
const auto globalsConstantBuffer = std::find_if(shaderInfo->m_constant_buffers.cbegin(),
shaderInfo->m_constant_buffers.cend(),
[](const d3d11::ConstantBuffer& constantBuffer)
{
return constantBuffer.m_name == GLOBALS_CBUFFER_NAME;
});
const auto perObjectConsts = std::find_if(shaderInfo->m_constant_buffers.cbegin(),
shaderInfo->m_constant_buffers.cend(),
[](const d3d11::ConstantBuffer& constantBuffer)
{
return constantBuffer.m_name == PER_OBJECT_CONSTS_CBUFFER_NAME;
});
if (globalsConstantBuffer != shaderInfo->m_constant_buffers.end())
{
for (const auto& variable : globalsConstantBuffer->m_variables)
AddConstantName(variable.m_name);
}
if (perObjectConsts != shaderInfo->m_constant_buffers.end())
{
for (const auto& variable : perObjectConsts->m_variables)
AddConstantName(variable.m_name);
}
for (const auto& boundResource : shaderInfo->m_bound_resources)
{
if (boundResource.m_type == d3d11::BoundResourceType::SAMPLER || boundResource.m_type == d3d11::BoundResourceType::TEXTURE)
{
if (AddTextureDefName(boundResource.m_name))
{
const auto samplerPos = boundResource.m_name.rfind(SAMPLER_STR);
if (samplerPos != std::string::npos)
{
auto nameWithoutSamplerStr = boundResource.m_name;
nameWithoutSamplerStr.erase(samplerPos, std::char_traits<char>::length(SAMPLER_STR));
AddTextureDefName(std::move(nameWithoutSamplerStr));
}
}
}
}
}
void AddStaticKnownNames()
{
for (const auto* knownConstantName : KNOWN_CONSTANT_NAMES)
AddConstantName(knownConstantName);
for (const auto* knownTextureDefName : KNOWN_TEXTURE_DEF_NAMES)
AddTextureDefName(knownTextureDefName);
}
void AddConstantName(std::string constantName)
{
const auto hash = Common::R_HashString(constantName.c_str(), 0);
if (m_constant_names_from_shaders.find(hash) != m_constant_names_from_shaders.end())
return;
m_constant_names_from_shaders.emplace(hash, std::move(constantName));
}
bool AddTextureDefName(std::string textureDefName)
{
const auto hash = Common::R_HashString(textureDefName.c_str(), 0);
if (m_texture_def_names_from_shaders.find(hash) != m_texture_def_names_from_shaders.end())
return false;
m_texture_def_names_from_shaders.emplace(hash, std::move(textureDefName));
return true;
}
std::unordered_set<const MaterialTechnique*> m_dumped_techniques;
std::unordered_map<unsigned, std::string> m_constant_names_from_shaders;
std::unordered_map<unsigned, std::string> m_texture_def_names_from_shaders;
};
class JsonDumper
{
public:
explicit JsonDumper(std::ostream& stream)
: m_stream(stream)
explicit JsonDumper(AssetDumpingContext& context, std::ostream& stream)
: m_stream(stream),
m_material_constants(*context.GetZoneAssetDumperState<MaterialConstantZoneState>())
{
}
@ -61,8 +696,9 @@ namespace T6::material
j[key] = nullptr;
}
static void MaterialToJson(json& jRoot, const Material* material)
void MaterialToJson(json& jRoot, const Material* material) const
{
MaterialInfoToJson(jRoot, material);
StateBitsEntryToJson(jRoot, material);
jRoot["stateFlags"] = material->stateFlags;
@ -128,7 +764,7 @@ namespace T6::material
jRoot["techniqueSet"] = nullptr;
}
static void TextureTableToJson(json& jRoot, const Material* material)
void TextureTableToJson(json& jRoot, const Material* material) const
{
json jTextures = json::array();
if (material->textureTable)
@ -143,19 +779,19 @@ namespace T6::material
jRoot["textures"] = std::move(jTextures);
}
static void TextureDefToJson(json& jTexture, const MaterialTextureDef* textureDef)
void TextureDefToJson(json& jTexture, const MaterialTextureDef* textureDef) const
{
const auto knownHash = knownHashes.find(textureDef->nameHash);
if (knownHash == knownHashes.end())
std::string textureDefName;
if (m_material_constants.GetTextureDefName(textureDef->nameHash, textureDefName))
{
jTexture["name"] = textureDefName;
}
else
{
jTexture["nameHash"] = textureDef->nameHash;
jTexture["nameStart"] = std::string(1u, textureDef->nameStart);
jTexture["nameEnd"] = std::string(1u, textureDef->nameEnd);
}
else
{
jTexture["name"] = knownHash->second;
}
JsonEnumEntry(jTexture, "semantic", textureDef->semantic, textureSemanticNames);
jTexture["isMatureContent"] = textureDef->isMatureContent;
@ -179,7 +815,7 @@ namespace T6::material
jSamplerState["clampW"] = samplerState.clampW ? true : false;
}
static void ConstantTableToJson(json& jRoot, const Material* material)
void ConstantTableToJson(json& jRoot, const Material* material) const
{
json jConstants = json::array();
if (material->constantTable)
@ -194,26 +830,31 @@ namespace T6::material
jRoot["constants"] = std::move(jConstants);
}
static void ConstantDefToJson(json& jConstant, const MaterialConstantDef* textureDef)
void ConstantDefToJson(json& jConstant, const MaterialConstantDef* constantDef) const
{
const auto fragmentLength = strnlen(textureDef->name, std::extent_v<decltype(MaterialConstantDef::name)>);
const std::string nameFragment(textureDef->name, fragmentLength);
const auto fragmentLength = strnlen(constantDef->name, std::extent_v<decltype(MaterialConstantDef::name)>);
const std::string nameFragment(constantDef->name, fragmentLength);
std::string knownConstantName;
if (fragmentLength < std::extent_v<decltype(MaterialConstantDef::name)> || Common::R_HashString(nameFragment.c_str(), 0) == textureDef->nameHash)
if (fragmentLength < std::extent_v<decltype(MaterialConstantDef::name)> || Common::R_HashString(nameFragment.c_str(), 0) == constantDef->nameHash)
{
jConstant["name"] = nameFragment;
}
else if (m_material_constants.GetConstantName(constantDef->nameHash, knownConstantName))
{
jConstant["name"] = knownConstantName;
}
else
{
jConstant["nameHash"] = textureDef->nameHash;
jConstant["nameHash"] = constantDef->nameHash;
jConstant["nameFragment"] = nameFragment;
}
json jLiteral;
jLiteral.push_back(textureDef->literal.v[0]);
jLiteral.push_back(textureDef->literal.v[1]);
jLiteral.push_back(textureDef->literal.v[2]);
jLiteral.push_back(textureDef->literal.v[3]);
jLiteral.push_back(constantDef->literal.v[0]);
jLiteral.push_back(constantDef->literal.v[1]);
jLiteral.push_back(constantDef->literal.v[2]);
jLiteral.push_back(constantDef->literal.v[3]);
jConstant["literal"] = std::move(jLiteral);
}
@ -324,6 +965,7 @@ namespace T6::material
}
std::ostream& m_stream;
const MaterialConstantZoneState& m_material_constants;
};
} // namespace T6::material
@ -357,6 +999,14 @@ void AssetDumperMaterial::DumpAsset(AssetDumpingContext& context, XAssetInfo<Mat
if (!assetFile)
return;
const material::JsonDumper dumper(*assetFile);
const material::JsonDumper dumper(context, *assetFile);
dumper.Dump(asset->Asset());
}
void AssetDumperMaterial::DumpPool(AssetDumpingContext& context, AssetPool<Material>* pool)
{
auto* materialConstantState = context.GetZoneAssetDumperState<material::MaterialConstantZoneState>();
materialConstantState->ExtractNamesFromZone();
AbstractAssetDumper<Material>::DumpPool(context, pool);
}

View File

@ -14,5 +14,8 @@ namespace T6
protected:
bool ShouldDump(XAssetInfo<Material>* asset) override;
void DumpAsset(AssetDumpingContext& context, XAssetInfo<Material>* asset) override;
public:
void DumpPool(AssetDumpingContext& context, AssetPool<Material>* pool) override;
};
} // namespace T6