[Shader / HLSL] Shader Reflection & Define Macro를 이용한 Resource 관리 (2)

2021. 12. 19. 05:40·Shader

Shader Resource Struct / Hash Table

이전 글에서 해당 Resource 등록 과정에 대해 써놓았는데 내부적으로 사용하는 방식을 정리하려한다.

굳이 왜 해당 Resource에 대응하는 Class를 선언하여 Key값을 검색하는데에 사용하는가? 에 대한 의문이 들 수도 있는데

일단 이전에 사용하던 string Key값을 이용한 검색은 잘못된 Key를 입력했을 경우 RunTime에 반환이 잘못되거나 에러가 뜨는 상황이 자주 발생하여 실수를 최소화 하고싶어 이와 같은 방식으로 모든 Resource 관리를 변경하였다.

 

이제 내부 코드를 순차적으로 정리해보자.

/* 
# HashClass Create Define
* ClassName		-> Struct Name
* ResourceType	-> Struct Resource Type (eResourceType)
*/
#define CREATE_HASH_CLASS(ClassName, ResourceType)	\
struct ClassName : public HashClass<ClassName>	\
{	\
	static eResourceType GetType() { return ResourceType; }	\
};

/* 
# Resource Push HashTable Define
* ClassName		-> Struct Name
* ResourceType	-> Struct Resource Type (eResourceType)
*/
#define RESOURCE_PUSH(ClassName, ResourceType) static bool push_##ClassName = ShaderResourceHashTable::Get()->Push(ResourceType, #ClassName, typeid(ClassName).hash_code());

/* 
# Resource Push HashTable Overlap Check Define
* ResourceMask	-> Resource Define Mask
*/
#define RESOURCE_DEFINE(ResourceMask) static bool overlap_##ResourceMask = ShaderResourceHashTable::Get()->DefineCheck(ResourceMask);

// Template을 통해 들어오는 Class가 HashClass를 상속 받았는지 체크..
template<typename T>
using Enable_Check = typename std::enable_if<std::is_base_of<HashClass<T>, T>::value, bool>::type;

- CREATE_HASH_CLASS : Resource의 Base Macro. 매개변수로 들어오는 토큰 기준으로 해당 Struct 생성.

- RESOURCE_PUSH : Resource Struct Hash Code 등록 Macro.

- RESOURCE_DEFINE : Hash Code 등록 시 매번 Find 하는것을 막기 위해 현재 상태 업데이트하기 위한 Macro.

- Enable_Check : 위의 Macro를 통해 등록한 Resource를 찾을 경우 해당 Resource Struct가 들어올때만 체크하기 위해  사용.

 

/// <summary>
/// ConstantBuffer Resource Struct
/// </summary>
/// 
/// - Shader 내부의 ConstantBuffer Resource와 1:1 대응하는 Struct
/// - Shader에서 설정한 레지스터 번호와 버퍼가 일치하는 한개의 Constant Buffer
/// - D3DCompiler에서 현재 Shader에서 ConstantBuffer을 선언해 두어도 사용하지 않으면
///   Register Slot에 올리지 않는다..
/// 
/// - 주의점
///  1) 현재 struct의 이름과 변수 순서는 Shader 내부의 ConstantBuffer와 일치해야한다 (Struct Name을 통해 Constant Buffer를 찾기 때문)

///////////////////////////////////////////////////////////////////////////////////////////
// Deferred Constant Buffer
///////////////////////////////////////////////////////////////////////////////////////////

CONSTANT_BUFFER(cbMeshObject)
struct CB_MeshObject : public cbMeshObject
{
	DirectX::SimpleMath::Matrix gWorld;
	DirectX::SimpleMath::Matrix gWorldView;
	DirectX::SimpleMath::Matrix gWorldViewProj;
	DirectX::SimpleMath::Matrix gTexTransform;
	DirectX::SimpleMath::Matrix gShadowTransform;
};

...

/// Resource Hash 재등록 방지 Define
RESOURCE_DEFINE(DEFINE_CB)

- Constant Buffer의 경우 해당 Buffer와 동일한 크기의 구조체가 필요하므로 상속받아 사용.

 

#define DEFINE_CB				0x00000001
#define DEFINE_SS				0x00000010
#define DEFINE_SRV				0x00000100
#define DEFINE_UAV				0x00001000

///
/// 2021/11/08 1:22
/// SeoKyuHwang
/// 
/// # ShaderResourceHashTable Class
/// 
/// - ShaderResource Struct 기준 Hash Code 키값으로 설정하기 위한 Class..
/// - Shader Reflect Load 시 Description과 비교하기 위해 필요..
/// - Resource Struct 선언과 동시에 Hash Table에 올리기 위해 Define 활용..
/// - Define을 통해 해당 Resource Struct 선언과 동시에 Hash Table에 등록..

class ShaderResourceHashTable
{
public:
	static ShaderResourceHashTable* Get();

	static ShaderResourceHashTable* instance;

public:
	// ConstantBuffer Hash Table..
	std::unordered_map<std::string, Hash_Code> g_CBuffer_HashTable;
	// Sampler Hash Table..
	std::unordered_map<std::string, Hash_Code> g_Sampler_HashTable;
	// ShaderResourceView Hash Table..
	std::unordered_map<std::string, Hash_Code> g_SRV_HashTable;
	// UnorderedAccessView Hash Table..
	std::unordered_map<std::string, Hash_Code> g_UAV_HashTable;

public:
	// Hash Code Push 함수..
	bool Push(eResourceType type, std::string name, Hash_Code hash_code);

	// 해당 Hash Code 반환 함수..
	size_t FindHashCode(eResourceType type, std::string cBufName);

	bool DefineCheck(Define_Mask nowDefine);

	// Hash Table Reset 함수..
	void Destroy();

private:
	// Hash Code Push Check 함수..
	bool CheckHashCode(std::unordered_map<std::string, Hash_Code>& table, std::string name, Hash_Code hash_code);

	Define_Mask DEFINE_MASK = 0x00000000;
};

bool ShaderResourceHashTable::Push(eResourceType type, std::string name, Hash_Code hash_code)
{
	// 해당 Resource Type에 따른 Hash Code 등록..
	switch (type)
	{
	case eResourceType::CB:
	{
		if (DEFINE_MASK & DEFINE_CB)
			return false;
		else
			return CheckHashCode(g_CBuffer_HashTable, name, hash_code);
	}
	case eResourceType::SS:
	{
		if (DEFINE_MASK & DEFINE_SS)
			return false;
		else
			return CheckHashCode(g_Sampler_HashTable, name, hash_code);
	}
	case eResourceType::SRV:
	{
		if (DEFINE_MASK & DEFINE_SRV)
			return false;
		else
			return CheckHashCode(g_SRV_HashTable, name, hash_code);
	}
	case eResourceType::UAV:
	{
		if (DEFINE_MASK & DEFINE_UAV)
			return false;
		else
			return CheckHashCode(g_UAV_HashTable, name, hash_code);
	}
	default:
		break;
	}

	return true;
}

size_t ShaderResourceHashTable::FindHashCode(eResourceType type, std::string cBufName)
{
	std::unordered_map<std::string, Hash_Code>::iterator cHash;
	
	// Resource Type에 따른 Hash Code 반환..
	switch (type)
	{
	case eResourceType::CB:
	{
		cHash = g_CBuffer_HashTable.find(cBufName);
	
		if (cHash == g_CBuffer_HashTable.end())
		{
			return 0;
		}
	}
	break;
	case eResourceType::SS:
	{
		cHash = g_Sampler_HashTable.find(cBufName);
	
		if (cHash == g_Sampler_HashTable.end())
		{
			return 0;
		}
	}
	break;
	case eResourceType::SRV:
	{
		cHash = g_SRV_HashTable.find(cBufName);
	
		if (cHash == g_SRV_HashTable.end())
		{
			return 0;
		}
	}
	break;
	case eResourceType::UAV:
	{
		cHash = g_UAV_HashTable.find(cBufName);
	
		if (cHash == g_UAV_HashTable.end())
		{
			return 0;
		}
	}
	break;
	default:
		return 0;
	}
	
	return cHash->second;
}

bool ShaderResourceHashTable::DefineCheck(Define_Mask nowDefine)
{
	DEFINE_MASK |= nowDefine;

	return true;
}

bool ShaderResourceHashTable::CheckHashCode(std::unordered_map<std::string, Hash_Code>& table, std::string name, Hash_Code hash_code)
{
	// 해당 Resource가 등록된 상태가 아니라면 Hash_Code 등록..
	if (table.find(name) == table.end())
	{
		table.insert(std::make_pair(name, hash_code));
	}

	return true;
}

- 해당 선언한 Struct의 Name과 Hash_Code가 올라갈 Hash Table List Class.

 

이어서 다음글에서 해당 Hash Table과 Struct를 이용한 Resource 등록에 관한 정리를 해야겠다.

'Shader' 카테고리의 다른 글

[Shader / HLSL] Shader Reflection & Define Macro Resource Hash Table 을 이용한 Resource 동기화  (0) 2022.01.17
[Shader / HLSL] Shader Reflection & Define Macro를 이용한 Resource 관리 (3)  (0) 2021.12.19
[Shader / HLSL] Shader Reflection & Define Macro를 이용한 Resource 관리 (1)  (0) 2021.12.19
[Shader / HLSL] RunTime Compile Shader / Shader Macro  (0) 2021.12.19
[Shader / HLSL] Shader Reflection  (0) 2021.12.18
'Shader' 카테고리의 다른 글
  • [Shader / HLSL] Shader Reflection & Define Macro Resource Hash Table 을 이용한 Resource 동기화
  • [Shader / HLSL] Shader Reflection & Define Macro를 이용한 Resource 관리 (3)
  • [Shader / HLSL] Shader Reflection & Define Macro를 이용한 Resource 관리 (1)
  • [Shader / HLSL] RunTime Compile Shader / Shader Macro
KyuHwang
KyuHwang
  • KyuHwang
    DirectX Engine
    KyuHwang
  • 전체
    오늘
    어제
    • 분류 전체보기 (50)
      • C++ (4)
      • CS (0)
      • Graphics (32)
      • DLL (2)
      • Shader (7)
      • Project (4)
      • ETC (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • YouTube
  • 공지사항

  • 인기 글

  • 태그

    C ++
    bc format
    shader
    rigging chain
    Define Macro
    Shader Resource 관리
    animation constraint
    Order Independent Transparency
    RunTime Compile Shader
    Alpha Blending
    Return Type Operator
    Define Function
    DLL Interface
    Directx11
    animation retargeting
    Shader Macro
    Project
    std::enable_if
    dll
    Shader Reflection
    texture block compression
    DirectX 2D
    Hash Code
    Win API
    Explicit Linking
    mobile format
    std::is_base_of
    hlsl
    Implicit Linking
    nvtt
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
KyuHwang
[Shader / HLSL] Shader Reflection & Define Macro를 이용한 Resource 관리 (2)
상단으로

티스토리툴바