Shader Resource 등록 방식 및 사용
- 이어서 실질적으로 Resource가 등록되고 사용하는 방식에 대해 정리해보려 한다.
이전에 설명해둔 방식을 토대로 HashCode를 Key값으로 두고 구현을 하였다.
/// ConstantBuffer Reflection
// Shader ConstantBuffer..
for (unsigned int cbindex = 0; cbindex < shaderDesc.ConstantBuffers; cbindex++)
{
ID3D11ShaderReflectionConstantBuffer* cBuffer = pReflector->GetConstantBufferByIndex(cbindex);
D3D11_SHADER_BUFFER_DESC bufferDesc;
if (SUCCEEDED(cBuffer->GetDesc(&bufferDesc)))
{
ID3D11Buffer* cBuffer = nullptr;
CD3D11_BUFFER_DESC cBufferDesc(bufferDesc.Size, D3D11_BIND_CONSTANT_BUFFER);
// 현재 읽은 ConstantBuffer Register Slot Check..
D3D11_SHADER_INPUT_BIND_DESC bindDesc;
pReflector->GetResourceBindingDescByName(bufferDesc.Name, &bindDesc);
// 해당 Constant Buffer 생성..
HR(g_Device->CreateBuffer(&cBufferDesc, nullptr, &cBuffer));
// Constant Buffer Hash Code..
hash_key = resource_table->FindHashCode(eResourceType::CB, bufferDesc.Name);
// Constant Buffer Register Slot Number..
cbuffer_register_slot = bindDesc.BindPoint;
// Key (Constant Buffer HashCode) && Value (Register Slot, Constant Buffer)
m_ConstantBufferList.insert(std::make_pair(hash_key, new ConstantBuffer(bindDesc.Name, cbuffer_register_slot, &cBuffer)));
}
}
/// Shader Resource Reflection
// Shader Resource..
for (unsigned int rsindex = 0; rsindex < shaderDesc.BoundResources; rsindex++)
{
D3D11_SHADER_INPUT_BIND_DESC bindDesc;
pReflector->GetResourceBindingDesc(rsindex, &bindDesc);
// Resource Type에 맞는 해당 List에 삽입..
switch (bindDesc.Type)
{
case D3D_SIT_TEXTURE:
{
// SRV Hash Code..
hash_key = resource_table->FindHashCode(eResourceType::SRV, bindDesc.Name);
// SRV Register Slot Number..
srv_register_slot = bindDesc.BindPoint;
// SRV 추가..
m_SRVList.insert(std::make_pair(hash_key, new ShaderResourceBuffer(bindDesc.Name, srv_register_slot)));
}
break;
case D3D_SIT_SAMPLER:
{
// Sampler Hash Code..
hash_key = resource_table->FindHashCode(eResourceType::SS, bindDesc.Name);
// Sampler Register Slot Number..
sampler_register_slot = bindDesc.BindPoint;
// Sampler 추가..
m_SamplerList.insert(std::make_pair(hash_key, new SamplerBuffer(bindDesc.Name, sampler_register_slot)));
}
break;
case D3D_SIT_UAV_RWTYPED:
{
// UAV Hash Code..
hash_key = resource_table->FindHashCode(eResourceType::UAV, bindDesc.Name);
// UAV Register Slot Number..
uav_register_slot = bindDesc.BindPoint;
// UAV 추가..
m_UAVList.insert(std::make_pair(hash_key, new UnorderedAccessBuffer(bindDesc.Name, uav_register_slot)));
}
break;
default:
break;
}
}
위의 과정은 Shader Reflection을 통해 Shader Load하는 과정 중 일부이다.
현재 Shader 내부에서 Binding 되는 Contant Buffer, Sampler State, ShaderResourceView, UnorderedAccessView의 Binding Point와 해당 Resource의 Name을 갖고올 수 있으므로 이전에 해당 Resource와 동일한 이름의 Struct를 선언과 동시에 Hash Table에 등록해 놨으므로 해당 Name을 통해 Hash Code를 받아 Key값으로 등록 하는 과정이다.
// Template을 통해 들어오는 Class가 HashClass를 상속 받았는지 체크..
template<typename T>
using Enable_Check = typename std::enable_if<std::is_base_of<HashClass<T>, T>::value, bool>::type;
// Shader Data Set..
template<typename T, Enable_Check<T>>
inline void ShaderBase::ConstantBufferCopy(T* cBuffer)
{
// 해당 Value 찾기..
std::unordered_map<Hash_Code, ConstantBuffer*>::iterator it = m_ConstantBufferList.find(T::GetHashCode());
// 해당 Key에 대한 Value가 없다면..
if (it == m_ConstantBufferList.end()) return;
// Update Buffer Get..
ID3D11Buffer* buffer = it->second->cBuffer.Get();
// Mapping SubResource Data..
D3D11_MAPPED_SUBRESOURCE mappedResource;
ZeroMemory(&mappedResource, sizeof(D3D11_MAPPED_SUBRESOURCE));
// GPU Access Lock Buffer Data..
g_DeviceContext->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
// Copy Resource Data..
memcpy((T*)mappedResource.pData, cBuffer, sizeof(T));
// GPU Access UnLock Buffer Data..
g_DeviceContext->Unmap(buffer, 0);
}
// Constant Buffer Set..
CB_MeshObject objectBuf;
objectBuf.gWorld = world;
objectBuf.gWorldView = world * view;
objectBuf.gWorldViewProj = world * viewproj;
objectBuf.gShadowTransform = world * shadowTrans;
m_MeshVS->ConstantBufferCopy(&objectBuf);
Constant Buffer 설정을 예로들면, Template를 통해 들어오는 Class가 해당 Hash Code를 반환해주는 Base Class를
상속받았는지 체크하여 조건에 맞다면 해당 Resource를 찾아 설정하는 방식이다.
Resource 등록 방식의 장점
- Shader를 Load 한 후 해당 Resource와 1:1 매칭 시켜주는 작업을 줄일 수 있다.
- Resource Class가 아닌 다른 Class가 들어오는것을 미리 방지 할 수 있다.
- String의 비교하는 비용을 줄일 수 있다.
- 해당 Resource를 찾을때 이름이 틀리는 것을 미리 방지 할 수 있다. (String의 경우 체크가 실행되야 알 수 있지만, 현재는 이름이
다르면 컴파일 자체가 되지 않는다.)
Resource 등록 방식의 단점
- 현재 모든 Graphic Resource는 실수를 줄이기 위해 위와 같은 방식을 사용하는데, 매번 필요한 Resource가 생길때마다
선언을 해주어야 하는 불편함이 있다.
- 해당 Resource의 Buffer 세부 정보 설정에 따른 구분을 해주어야 하는 귀찮음이 있을 수 있다.
'Shader' 카테고리의 다른 글
[Shader / HLSL] HLSL Semantic (0) | 2022.02.02 |
---|---|
[Shader / HLSL] Shader Reflection & Define Macro Resource Hash Table 을 이용한 Resource 동기화 (0) | 2022.01.17 |
[Shader / HLSL] Shader Reflection & Define Macro를 이용한 Resource 관리 (2) (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 |