mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-20 00:02:55 +00:00
Add analyser for directx9 shaders to extract information about constants and other stuff
This commit is contained in:
parent
935e6ac060
commit
55ccbfca9e
246
src/ObjWriting/Shader/D3D9ShaderAnalyser.cpp
Normal file
246
src/ObjWriting/Shader/D3D9ShaderAnalyser.cpp
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
#include "D3D9ShaderAnalyser.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "Utils/FileUtils.h"
|
||||||
|
|
||||||
|
using namespace d3d9;
|
||||||
|
|
||||||
|
namespace d3d9
|
||||||
|
{
|
||||||
|
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/d3d9types/ne-d3d9types-_d3dshader_instruction_opcode_type
|
||||||
|
static constexpr uint32_t OPCODE_COMMENT = 0xFFFE;
|
||||||
|
static constexpr uint32_t OPCODE_END = 0xFFFF;
|
||||||
|
|
||||||
|
static constexpr uint32_t OPCODE_MASK = 0x0000FFFF;
|
||||||
|
|
||||||
|
static constexpr uint32_t COMMENT_SIZE_MASK = 0xFFFF0000;
|
||||||
|
static constexpr uint32_t COMMENT_SIZE_SHIFT = 16;
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxshader-constanttable
|
||||||
|
struct ConstantTable
|
||||||
|
{
|
||||||
|
uint32_t Size;
|
||||||
|
uint32_t Creator;
|
||||||
|
uint32_t Version;
|
||||||
|
uint32_t Constants;
|
||||||
|
uint32_t ConstantInfo;
|
||||||
|
uint32_t Flags;
|
||||||
|
uint32_t Target;
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxshader-constantinfo
|
||||||
|
struct ConstantInfo
|
||||||
|
{
|
||||||
|
uint32_t Name;
|
||||||
|
uint16_t RegisterSet;
|
||||||
|
uint16_t RegisterIndex;
|
||||||
|
uint16_t RegisterCount;
|
||||||
|
uint16_t Reserved;
|
||||||
|
uint32_t TypeInfo;
|
||||||
|
uint32_t DefaultValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxshader-typeinfo
|
||||||
|
struct TypeInfo
|
||||||
|
{
|
||||||
|
uint16_t Class;
|
||||||
|
uint16_t Type;
|
||||||
|
uint16_t Rows;
|
||||||
|
uint16_t Columns;
|
||||||
|
uint16_t Elements;
|
||||||
|
uint16_t StructMembers;
|
||||||
|
uint32_t StructMemberInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxshader-structmemberinfo
|
||||||
|
struct StructMemberInfo
|
||||||
|
{
|
||||||
|
uint32_t Name;
|
||||||
|
uint32_t TypeInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool PopulateVersionInfo(ShaderInfo& shaderInfo, const uint32_t* shaderByteCode, const size_t shaderByteCodeSize)
|
||||||
|
{
|
||||||
|
if (shaderByteCodeSize < sizeof(uint32_t))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto version = *shaderByteCode;
|
||||||
|
shaderInfo.m_version_minor = version & 0xFF;
|
||||||
|
shaderInfo.m_version_major = (version & 0xFF00) >> 8;
|
||||||
|
|
||||||
|
switch ((version & 0xFFFF0000) >> 16)
|
||||||
|
{
|
||||||
|
case 0x4658: // FX
|
||||||
|
case 0x5458: // TX
|
||||||
|
case 0x7ffe: // ?
|
||||||
|
case 0x7fff: // ?
|
||||||
|
shaderInfo.m_type = ShaderType::UNKNOWN; // Valid according to wine
|
||||||
|
return true;
|
||||||
|
case 0xfffe:
|
||||||
|
shaderInfo.m_type = ShaderType::VERTEX_SHADER;
|
||||||
|
return true;
|
||||||
|
case 0xffff:
|
||||||
|
shaderInfo.m_type = ShaderType::PIXEL_SHADER;
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FindComment(const uint32_t* shaderByteCode, const size_t shaderByteCodeSize, const uint32_t magic, const char*& commentStart, size_t& commentSize)
|
||||||
|
{
|
||||||
|
const uint32_t* currentPos = shaderByteCode + 1;
|
||||||
|
size_t currentOffset = sizeof(uint32_t);
|
||||||
|
while (*currentPos != OPCODE_END && (currentOffset + sizeof(uint32_t) - 1) < shaderByteCodeSize)
|
||||||
|
{
|
||||||
|
const auto currentValue = *currentPos;
|
||||||
|
if ((currentValue & OPCODE_MASK) == OPCODE_COMMENT)
|
||||||
|
{
|
||||||
|
assert(currentOffset + sizeof(uint32_t) < shaderByteCodeSize);
|
||||||
|
if (currentOffset + sizeof(uint32_t) >= shaderByteCodeSize)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto currentCommentSize = (currentValue & COMMENT_SIZE_MASK) >> COMMENT_SIZE_SHIFT;
|
||||||
|
|
||||||
|
if (currentPos[1] == magic)
|
||||||
|
{
|
||||||
|
commentStart = reinterpret_cast<const char*>(currentPos + 2);
|
||||||
|
commentSize = (currentCommentSize - 1) * sizeof(uint32_t);
|
||||||
|
return currentOffset + sizeof(uint32_t) * (currentCommentSize + 1) <= shaderByteCodeSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPos += currentCommentSize;
|
||||||
|
currentOffset += currentCommentSize * sizeof(uint32_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPos++;
|
||||||
|
currentOffset += sizeof(uint32_t);
|
||||||
|
assert((currentOffset + sizeof(uint32_t) - 1) < shaderByteCodeSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StringFitsInComment(const char* str, const char* commentStart, const size_t commentSize)
|
||||||
|
{
|
||||||
|
const auto strLen = strnlen(str, commentSize - (str - commentStart));
|
||||||
|
return str[strLen] == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PopulateShaderConstantFromConstantInfo(ShaderConstant& shaderConstant, const char* commentStart, const size_t commentSize, const ConstantInfo& constantInfo)
|
||||||
|
{
|
||||||
|
if (constantInfo.Name)
|
||||||
|
{
|
||||||
|
const auto* constantName = commentStart + constantInfo.Name;
|
||||||
|
if (!StringFitsInComment(constantName, commentStart, commentSize))
|
||||||
|
return false;
|
||||||
|
shaderConstant.m_name = std::string(constantName);
|
||||||
|
}
|
||||||
|
|
||||||
|
shaderConstant.m_register_set = static_cast<RegisterSet>(constantInfo.RegisterSet);
|
||||||
|
if (shaderConstant.m_register_set >= RegisterSet::MAX)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
shaderConstant.m_register_index = constantInfo.RegisterIndex;
|
||||||
|
shaderConstant.m_register_count = constantInfo.RegisterCount;
|
||||||
|
|
||||||
|
if(constantInfo.TypeInfo)
|
||||||
|
{
|
||||||
|
assert(commentStart + constantInfo.TypeInfo + sizeof(TypeInfo) <= commentStart + commentSize);
|
||||||
|
if (commentStart + constantInfo.TypeInfo + sizeof(TypeInfo) > commentStart + commentSize)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto* typeInfo = reinterpret_cast<const TypeInfo*>(commentStart + constantInfo.TypeInfo);
|
||||||
|
|
||||||
|
shaderConstant.m_class = static_cast<ParameterClass>(typeInfo->Class);
|
||||||
|
if (shaderConstant.m_class >= ParameterClass::MAX)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
shaderConstant.m_type = static_cast<ParameterType>(typeInfo->Type);
|
||||||
|
if (shaderConstant.m_type >= ParameterType::MAX)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
shaderConstant.m_type_rows = typeInfo->Rows;
|
||||||
|
shaderConstant.m_type_columns = typeInfo->Columns;
|
||||||
|
shaderConstant.m_type_elements = typeInfo->Elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PopulateShaderInfoFromConstantTable(ShaderInfo& shaderInfo, const char* commentStart, const size_t commentSize, const ConstantTable& constantTable)
|
||||||
|
{
|
||||||
|
if (constantTable.Size != sizeof(ConstantTable))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (constantTable.Creator)
|
||||||
|
{
|
||||||
|
const auto* creatorName = commentStart + constantTable.Creator;
|
||||||
|
if (!StringFitsInComment(creatorName, commentStart, commentSize))
|
||||||
|
return false;
|
||||||
|
shaderInfo.m_creator = std::string(creatorName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (constantTable.Target)
|
||||||
|
{
|
||||||
|
const auto* targetName = commentStart + constantTable.Target;
|
||||||
|
if (!StringFitsInComment(targetName, commentStart, commentSize))
|
||||||
|
return false;
|
||||||
|
shaderInfo.m_target = std::string(targetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (constantTable.Constants > 0 && constantTable.ConstantInfo)
|
||||||
|
{
|
||||||
|
assert(commentStart + constantTable.ConstantInfo + sizeof(ConstantInfo) * constantTable.Constants <= commentStart + commentSize);
|
||||||
|
if (commentStart + constantTable.ConstantInfo + sizeof(ConstantInfo) * constantTable.Constants > commentStart + commentSize)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto* constantInfos = reinterpret_cast<const ConstantInfo*>(commentStart + constantTable.ConstantInfo);
|
||||||
|
for (auto constantInfoIndex = 0u; constantInfoIndex < constantTable.Constants; constantInfoIndex++)
|
||||||
|
{
|
||||||
|
ShaderConstant constant;
|
||||||
|
if (!PopulateShaderConstantFromConstantInfo(constant, commentStart, commentSize, constantInfos[constantInfoIndex]))
|
||||||
|
return false;
|
||||||
|
shaderInfo.m_constants.emplace_back(std::move(constant));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PopulateShaderInfoFromShaderByteCode(ShaderInfo& shaderInfo, const uint32_t* shaderByteCode, const size_t shaderByteCodeSize)
|
||||||
|
{
|
||||||
|
if (!PopulateVersionInfo(shaderInfo, shaderByteCode, shaderByteCodeSize))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const char* constantTableComment;
|
||||||
|
size_t constantTableCommentSize;
|
||||||
|
if (!FindComment(shaderByteCode, shaderByteCodeSize, FileUtils::MakeMagic32('C', 'T', 'A', 'B'), constantTableComment, constantTableCommentSize))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (constantTableCommentSize < sizeof(ConstantTable))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto* constantTable = reinterpret_cast<const ConstantTable*>(constantTableComment);
|
||||||
|
if (!PopulateShaderInfoFromConstantTable(shaderInfo, constantTableComment, constantTableCommentSize, *constantTable))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ShaderInfo> ShaderAnalyser::GetShaderInfo(const uint32_t* shaderByteCode, const size_t shaderByteCodeSize)
|
||||||
|
{
|
||||||
|
if (shaderByteCode == nullptr || shaderByteCodeSize == 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto shaderInfo = std::make_unique<ShaderInfo>();
|
||||||
|
|
||||||
|
if (!PopulateShaderInfoFromShaderByteCode(*shaderInfo, shaderByteCode, shaderByteCodeSize))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return shaderInfo;
|
||||||
|
}
|
100
src/ObjWriting/Shader/D3D9ShaderAnalyser.h
Normal file
100
src/ObjWriting/Shader/D3D9ShaderAnalyser.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace d3d9
|
||||||
|
{
|
||||||
|
enum class ShaderType
|
||||||
|
{
|
||||||
|
UNKNOWN,
|
||||||
|
PIXEL_SHADER,
|
||||||
|
VERTEX_SHADER
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxregister-set
|
||||||
|
enum class RegisterSet
|
||||||
|
{
|
||||||
|
BOOL,
|
||||||
|
INT_4,
|
||||||
|
FLOAT_4,
|
||||||
|
SAMPLER,
|
||||||
|
|
||||||
|
// This entry only exist to mark the size of the enum and is not an actual valid value
|
||||||
|
MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxparameter-class
|
||||||
|
enum class ParameterClass
|
||||||
|
{
|
||||||
|
SCALAR,
|
||||||
|
VECTOR,
|
||||||
|
MATRIX_ROWS,
|
||||||
|
MATRIX_COLUMNS,
|
||||||
|
OBJECT,
|
||||||
|
STRUCT,
|
||||||
|
|
||||||
|
// This entry only exist to mark the size of the enum and is not an actual valid value
|
||||||
|
MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxparameter-type
|
||||||
|
enum class ParameterType
|
||||||
|
{
|
||||||
|
VOID,
|
||||||
|
BOOL,
|
||||||
|
INT,
|
||||||
|
FLOAT,
|
||||||
|
STRING,
|
||||||
|
TEXTURE,
|
||||||
|
TEXTURE_1D,
|
||||||
|
TEXTURE_2D,
|
||||||
|
TEXTURE_3D,
|
||||||
|
TEXTURE_CUBE,
|
||||||
|
SAMPLER,
|
||||||
|
SAMPLER_1D,
|
||||||
|
SAMPLER_2D,
|
||||||
|
SAMPLER_3D,
|
||||||
|
SAMPLER_CUBE,
|
||||||
|
PIXEL_SHADER,
|
||||||
|
VERTEX_SHADER,
|
||||||
|
PIXEL_FRAGMENT,
|
||||||
|
VERTEX_FRAGMENT,
|
||||||
|
UNSUPPORTED,
|
||||||
|
|
||||||
|
// This entry only exist to mark the size of the enum and is not an actual valid value
|
||||||
|
MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
class ShaderConstant
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string m_name;
|
||||||
|
RegisterSet m_register_set{};
|
||||||
|
unsigned m_register_index = 0;
|
||||||
|
unsigned m_register_count = 0;
|
||||||
|
ParameterClass m_class{};
|
||||||
|
ParameterType m_type{};
|
||||||
|
unsigned m_type_rows = 0;
|
||||||
|
unsigned m_type_columns = 0;
|
||||||
|
unsigned m_type_elements = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ShaderInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShaderType m_type = ShaderType::UNKNOWN;
|
||||||
|
unsigned m_version_major = 0;
|
||||||
|
unsigned m_version_minor = 0;
|
||||||
|
std::string m_creator;
|
||||||
|
std::string m_target;
|
||||||
|
std::vector<ShaderConstant> m_constants;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ShaderAnalyser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::unique_ptr<ShaderInfo> GetShaderInfo(const uint32_t* shaderByteCode, size_t shaderByteCodeSize);
|
||||||
|
};
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user