IF 문에 하나 대신 두 개의 셰이더 사용


9

비교적 큰 opengl ES 1.1 소스를 ES 2.0으로 이식하는 작업을 해왔습니다.

OpenGL ES 2.0 (모든 것이 쉐이더를 사용함)에서 주전자를 세 번 그려보고 싶습니다.

  1. 균일 한 색상을 가진 첫 번째 색상 (ala glColor4f).

  2. 두 번째는 정점 별 색상입니다 (찻 주전자에는 정점 색상 배열도 있음)

  3. 세 번째는 정점 별 텍스처

  4. 그리고 정점마다의 질감과 색상을 가진 네 번째 것일 수도 있습니다. 그리고 아마도 5 번째 법선이 될 것입니다.

내가 아는 한 구현과 관련하여 두 가지 선택이 있습니다. 첫 번째는 동작을 변경하도록 설정된 유니폼을 사용하여 위의 모든 항목을 지원하는 셰이더를 만드는 것입니다 (예 : 단일 색상 유니폼 또는 정점 별 색상 유니폼 사용).

두 번째 선택은 상황에 따라 다른 셰이더를 만드는 것입니다. 일부 사용자 지정 셰이더 사전 처리를 사용하면 그렇게 복잡하지 않지만 드로잉 객체간에 셰이더를 전환 할 때의 성능 비용이 문제입니다. 나는 그것이 사소한 것이 아니라는 것을 읽었습니다.

내 말은,이 문제를 해결하는 가장 좋은 방법은 둘 다 구축하고 측정하는 것이지만 입력을 듣는 것이 좋습니다.

답변:


10

분기의 성능 비용도 사소하게 작을 수는 없습니다. 귀하의 경우에 그려지는 모든 정점과 조각은 쉐이더를 통해 동일한 경로를 취하므로 현대 데스크탑 하드웨어에서는 나쁘지 않을 것이지만 ES2를 사용하고 있습니다. 데스크탑 하드웨어.

분기와 최악의 경우는 다음과 같습니다.

  • 분기의 양쪽이 평가됩니다.
  • "mix"또는 "step"명령어는 셰이더 컴파일러에 의해 생성되어 사용할 측을 결정하기 위해 코드에 삽입됩니다.

그리고이 모든 추가 명령은 사용자가 그리는 각 정점 또는 조각에 대해 실행됩니다. 이는 셰이더 변경 비용에 대비하여 수백만 개의 추가 지침을 고려해야 할 가능성이 있습니다.

Apple의 " iOS 용 OpenGL ES 프로그래밍 안내서 "(대상 하드웨어를 대표 할 수 있음)는 분기에 대해 다음과 같이 말합니다.

분기 방지

3D 그래픽 프로세서에서 병렬로 작업을 실행하는 기능을 줄일 수 있으므로 브랜치는 셰이더로 사용하지 않는 것이 좋습니다. 셰이더가 분기를 사용해야하는 경우 다음 권장 사항을 따르십시오.

  • 최상의 성능 : 셰이더가 컴파일 될 때 알려진 상수의 분기.
  • 허용 가능 : 균일 한 변수에 분기합니다.
  • 잠재적으로 느림 : 셰이더 내에서 계산 된 값을 분기합니다.

노브와 레버가 많은 대형 셰이더를 만드는 대신 특정 렌더링 작업에 특화된 더 작은 셰이더를 만듭니다. 셰이더의 브랜치 수를 줄이고 생성하는 셰이더 수를 늘리는 것 사이에는 상충 관계가 있습니다. 다른 옵션을 테스트하고 가장 빠른 솔루션을 선택하십시오.

여기 "허용 가능"슬롯에 만족한다고해도 4 가지 또는 5 가지 경우 중 하나를 선택해야한다는 사실을 고려해야합니다. 대상 하드웨어의 명령어 수 제한을 알고 위의 Apple 링크에서 다시 인용하여 해당 하드웨어를 초과하지 않도록하십시오.

이러한 한계를 초과 할 경우 소프트웨어 폴백을 구현하기 위해 OpenGL ES 구현이 필요하지 않습니다. 대신, 셰이더는 단순히 컴파일 또는 링크에 실패합니다.

이 중 어느 것도 분기가 귀하의 필요에 가장 적합한 솔루션 이 아니라고 말하는 것은 아닙니다 . 두 가지 접근 방식을 모두 프로파일 링해야한다는 사실을 올바르게 확인 했으므로 이것이 최종 권장 사항입니다. 그러나 셰이더가 더욱 복잡 해짐에 따라 분기 기반 솔루션이 몇 가지 셰이더 변경보다 훨씬 높은 오버 헤드를 제공 할 수 있습니다.


3

셰이더 바인딩 비용은 사소한 것이 아니지만 동일한 셰이더를 사용하는 모든 객체를 일괄 처리하지 않고 수천 개의 항목을 렌더링하지 않으면 병목 현상이 발생하지 않습니다.

이것이 이것이 모바일 장치에 적용되는지 확실하지 않지만 조건이 일정하고 균일 한 경우 GPU가 끔찍하게 느리지 않습니다. 둘 다 유효합니다. 둘 다 과거에 사용되었으며 앞으로도 계속 사용됩니다. 귀하의 경우에 더 깨끗하다고 ​​생각되는 것을 선택하십시오.

또한 이것을 달성하는 몇 가지 다른 방법이 있습니다 : "Uber-shaders"와 OpenGL 쉐이더 프로그램이 연결되는 방식에 대한 약간의 속임수.

"우버 셰이더"는 기본적으로 분기를 제외한 첫 번째 선택이지만 여러 셰이더가 있습니다. 대신 사용하는 if- 문을, 당신은 전처리 사용 #define, #ifdef, #else, #endif, 적절한 등 다양한 버전, 컴파일 #define당신이 필요에들.

vec4 color;
#ifdef PER_VERTEX_COLOR
color = in_color;
#else
color = obj_color;
#endif

셰이더를 별도의 기능으로 나눌 수도 있습니다. 모든 함수에 대한 프로토 타입을 정의하고 호출하는 하나의 셰이더를 만들고 적절한 구현을 포함하는 추가 셰이더를 연결하십시오. 모든 셰이더를 수정하지 않고도 모든 객체에서 필터링이 수행되는 방식을 쉽게 교체 할 수 있도록 섀도 매핑에이 트릭을 사용했습니다.

//ins, outs, uniforms

float getShadowCoefficient();

void main()
{
    //shading stuff goes here

    gl_FragColor = color * getShadowCoefficient();
}

그런 다음, getShadowCoefficient()필요한 유니폼 등 을 정의하는 다른 여러 셰이더 파일을 가질 수 있습니다 . 예를 들어, 다음을 shadow_none.glsl포함합니다.

float getShadowCoefficient()
{
    return 1;
}

그리고 shadow_simple.glsl포함합니다 (CSM을 구현하는 셰이더에서 단순화 됨).

in vec4 eye_position;

uniform sampler2DShadow shad_tex;
uniform mat4 shad_mat;

float getShadowCoefficient()
{
    vec4 shad_coord = shad_mat * eye_position;
    return texture(shad_tex, shad_coord).x;
}

다른 shadow_*셰이더 를 연결하여 음영을 원하는지 여부를 간단히 선택할 수 있습니다 . 이 솔루션에는 더 많은 오버 헤드가있을 수 있지만 GLSL 컴파일러는이를 수행하는 다른 방법과 비교하여 추가 오버 헤드를 최적화하기에 충분하다고 생각하고 싶습니다. 나는 이것에 대한 테스트를 실행하지 않았지만 그것이 내가 좋아하는 방법입니다.

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