부울을 압축하여 D3D 상수 버퍼에 정렬 할 수없는 이유는 무엇입니까?


9

좋아, 부울을 포장하고 hlsl 상수 버퍼에 맞추는 데 어려움을 겪고 있으며 왜 그런지 잘 모르겠습니다.

hlsl의 버퍼는 다음과 같습니다

cbuffer MaterialBuffer : register(b1) {
    float3 materialDiffuseAlbedo;
    float  materialSpecularExponent;
    float3 materialSpecularAlbedo;
    bool isTextured;
};

그리고 여기에 C ++

struct GeometryBufferPass_MaterialBuffer {
    XMFLOAT3 diffuse;
    float specularExponent;
    XMFLOAT3 specular;
    bool isTextured;
};

나는 부울을 옮기고 모든 종류의 방식으로 구조체를 패딩하지 않고 시도했습니다. 이를 수행하는 올바른 방법은 무엇입니까?


무엇이 문제의 원인입니까?
MichaelHouse

부울은 셰이더가 텍스처를 샘플링해야하는지 여부를 결정하는 데 사용됩니다. 이 방법으로 텍스처와 텍스처되지 않은 오브젝트를 동일한 쉐이더로 렌더링 할 수 있습니다. 부울은 단순히 조건문에 사용됩니다. 모든 객체를 동일하게 취급하기 때문에 올바른 데이터를 얻지 못합니다. 내 스카이 스피어가 현재 텍스처가있는 유일한 것이므로 올바르지 않습니다.
KlashnikovKid

다른 값은 작동하지만 부울은 작동하지 않습니까? 셰이더에 사용할 수있는 디버거 중 하나를 사용하여 무엇이 들어가고 있는지 보셨습니까?
MichaelHouse

2
bool 값을 char에 저장하십시오. true의 경우 1로, false의 경우 0으로 저장하십시오. 테스트를 위해서만, 그리고 bool은 어쨌든 C ++에서 1 바이트입니다.
Gustavo Maciel

3
부울의 크기는 구현에 따라 다릅니다. 일부 플랫폼에서는 int와 동일한 크기입니다. stackoverflow.com/questions/5067492/…
Tetrad

답변:


9

효율성을 위해 상수 버퍼는 값이 GPU 레지스터에 걸 치지 않도록 매핑됩니다 . 각 레지스터는 크기가 4 바이트 (16 바이트)이므로 상수 버퍼 구조는 GPU에서 그 배수 여야합니다. 데이터 매핑의 편의를 위해 C ++ 구조를 적절하게 채워야합니다 (이는 항상 확장 성이 좋지는 않습니다).

따라서 문제는 HLSL 부울이 4 바이트이지만 CPU 측 (특정 구현에서)에는 1 바이트라는 것입니다. 이로 인해 C ++ 구조가 올바르게 정렬되지 않습니다. 부울 값의 중요한 비트 (0 또는 1)는 값의 최하위 바이트에 저장되며 크기가 위치와 일치하지 않기 때문에 메모리의 해당 바이트 수는 CPU 및 GPU 버전 구조에서 다릅니다.

적절한 패딩을 수동으로 삽입하고 적절한 16 바이트 정렬을 보장하거나 정수와 같이 적절한 크기의 유형을 사용하면 문제가 해결됩니다. 이 스레드 는 대략 같은 문제에 대한보다 심층적 인 토론을 포함하고 있기 때문에 유용 할 수 있습니다.


1
"다음 isTextured레지스터로 넘어 가야 하므로 동일한 레지스터에 맞습니다. 따라서 다음 레지스터에 완전히 충돌합니다." 두 번째 레지스터는 specular처음 세 구성 요소로 구성되며 isTextured마지막 구성 요소 는 다음 레지스터에 충돌 할 필요가 없다는 것을 알 수 있습니까? 1 바이트 대 4 바이트 부울 길이는 분명히 중요하지만 둘 다 specular동일한 레지스터에 적합 합니다.
Nathan Reed

당신이 올바른지; 레지스터의 크기와 유형의 크기를 혼동하고 매핑의 잘못된 표현을 생각해 냈습니다. 유일한 문제는 메모리에서 관련 바이트의 위치입니다. 이에 따라 답변을 조정했습니다.

철저한 답변을 받아들입니다. 당신이 언급했듯이, 그것은 큰 / 작은 엔디안 문제이며 int를 사용하여 해결되었습니다.
KlashnikovKid

3

좋아, 약간의 독서를하고 hlsl bool이 본질적으로 32 비트 정수라는 것을 알았습니다. 그래서 방금 C ++ 구조체에서 int를 사용하여 문제를 해결했습니다.

struct GeometryBufferPass_MaterialBuffer {
    XMFLOAT3 diffuse;
    float specularExponent;
    XMFLOAT3 specular;
    int isTextured;
};

부울 유형을 유지하지 않고 컴파일러 측에서 int를 사용하는 이유는 무엇입니까? 의미를 유지하기 위해.
구스타보 메이 엘

그래, 내가 위에서하는 일이야. 구조체 CPU 측에 정수를 사용하고 상수 버퍼 GPU 측에 부울을 사용했습니다.
KlashnikovKid

0

float, bool 및 int는 특히 여러 항목의 엔디안에 필요하지 않습니다.

int 또는 float로 전환하면 여기에 나열된 일부 예에서 XMFLOAT3 항목간에 정렬되므로 올바르게 참조됩니다. 그러나 int, float (없음 XM 유형)에 대해 구조에서 배열 또는 여러 항목을 선언 해야하는 경우 GPU 값이 CPU 구조에 설정된 값과 일치하지 않을 수 있습니다.

조명 유형에 사용될 int 유형의 배열을 추가 할 때 확실히했습니다.

내가 찾은 가장 쉬운 방법은 16으로 정렬되는 XM 유형을 고수하는 것입니다.이 요소는 낭비되는 요소 / 바이트가 필요하지만 엔디안을 정렬합니다. EG XMINT4를 사용하고 첫 번째 요소 .x를 값으로 사용했거나 필요에 따라 다른 요소를 다른 목적으로 사용하지만 이름이 잘못되었습니다 (댓글을 작성하십시오). 참고 : XMINT2 배열도 논리적 순서가 아닙니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.