특정 상태 변경의 실제 비용은 많은 요인에 따라 다르므로 일반적인 대답은 거의 불가능합니다.
첫째, 모든 상태 변경은 잠재적으로 CPU 비용과 GPU 비용을 모두 가질 수 있습니다. 드라이버 및 그래픽 API에 따라 CPU 비용은 기본 스레드 또는 배경 스레드에 전적으로 지불 될 수 있습니다.
둘째, GPU 비용은 비행 작업량에 따라 달라질 수 있습니다. 최신 GPU는 파이프 라인이 매우 많으며 한 번에 많은 작업을 수행하는 것을 좋아하며, 가장 큰 속도 저하는 파이프 라인을 정지시켜 현재 비행중인 모든 것이 상태가 변경되기 전에 은퇴해야한다는 것입니다. 파이프 라인이 멈추는 원인은 무엇입니까? 글쎄, 그것은 당신의 GPU에 달려 있습니다!
여기서 성능을 이해하기 위해 실제로 알아야 할 것은 상태 변경을 처리하기 위해 드라이버와 GPU가 무엇을해야 하는가입니다. 이것은 물론 GPU 및 ISV가 공개적으로 공유하지 않는 세부 사항에 따라 다릅니다. 그러나 몇 가지 일반적인 원칙이 있습니다.
GPU는 일반적으로 프론트 엔드와 백엔드로 나뉩니다. 프론트 엔드는 드라이버가 생성 한 일련의 명령을 처리하는 반면 백엔드는 모든 실제 작업을 처리합니다. 이전에 말했듯이 백엔드는 많은 작업을 수행하는 것을 좋아하지만 해당 작업에 대한 정보를 저장하려면 정보가 필요합니다 (아마도 프론트 엔드에 의해 채워짐). 충분히 작은 배치를 걷어 작업을 추적하는 모든 실리콘을 사용하는 경우, 사용하지 않는 마력이 많이 있더라도 프론트 엔드가 정지해야합니다. 따라서 원리는 다음과 같습니다 . 상태 변경 (및 작은 그리기)이 많을수록 GPU 백엔드가 굶어 질 가능성이 높습니다 .
드로우가 실제로 처리되는 동안 기본적으로 쉐이더 프로그램을 실행하는 것입니다. 쉐이더 프로그램은 유니폼, 버텍스 버퍼 데이터, 텍스처뿐만 아니라 쉐이더 단위에 버텍스 버퍼 및 당신의 질감이 있습니다. 그리고 GPU는 이러한 메모리 액세스 앞에 캐시를 가지고 있습니다. 따라서 GPU에서 새로운 유니폼이나 새로운 텍스처 / 버퍼 바인딩을 던질 때마다 처음 읽을 때 캐시 누락이 발생할 수 있습니다. 또 다른 원칙 : 대부분의 상태 변경으로 인해 GPU 캐시 미스가 발생합니다. (이것은 상수 버퍼를 직접 관리 할 때 가장 의미가 있습니다. 드로우간에 일정한 버퍼를 동일하게 유지하면 GPU에서 캐시에 머무를 가능성이 높습니다.)
셰이더 리소스의 상태 변경 비용의 큰 부분은 CPU 측입니다. 새로운 상수 버퍼를 설정할 때마다 드라이버는 해당 상수 버퍼의 내용을 GPU의 명령 스트림으로 복사 할 가능성이 높습니다. 단일 유니폼을 설정하면 드라이버가 뒤에서 큰 상수 버퍼로 전환 할 가능성이 높으므로 상수 버퍼에서 해당 유니폼의 오프셋을 찾아 값을 복사 한 다음 상수 버퍼를 표시해야합니다 다음 그리기 호출 전에 명령 스트림으로 복사 될 수 있습니다. 새 텍스처 나 정점 버퍼를 바인딩하면 드라이버가 해당 리소스에 대한 제어 구조를 복사하고있을 수 있습니다. 또한 멀티 태스킹 OS에서 개별 GPU를 사용하는 경우 드라이버는 사용하는 모든 리소스와 커널 사용을 시작하기 위해 사용하는 모든 리소스를 추적해야합니다. GPU 메모리 관리자는 그리기가 발생할 때 해당 리소스의 메모리가 GPU의 VRAM에 상주하도록 보장 할 수 있습니다. 원리:상태가 변경되면 드라이버가 메모리를 섞어 GPU에 대한 최소 명령 스트림을 생성합니다.
현재 셰이더를 변경하면 GPU 캐시 미스가 발생할 수 있습니다 (명령 캐시도 있습니다). 원칙적으로, CPU 작업은 "쉐이더 사용"이라는 명령 스트림에 새로운 명령을 넣는 것으로 제한되어야합니다. 그러나 실제로는 처리해야 할 쉐이더 컴파일이 엉망입니다. GPU 드라이버는 셰이더를 미리 만든 경우에도 종종 셰이더를 느리게 컴파일합니다. 그러나이 주제와 더 관련이 있지만 일부 상태는 GPU 하드웨어에서 기본적으로 지원되지 않고 대신 셰이더 프로그램으로 컴파일됩니다. 가장 일반적인 예로는 정점 형식이 있습니다. 이러한 형식은 칩에서 별도의 상태가 아닌 정점 셰이더로 컴파일 될 수 있습니다. 따라서 이전에 특정 정점 셰이더와 함께 사용하지 않은 정점 형식을 사용하는 경우 이제 셰이더를 패치하고 셰이더 프로그램을 GPU에 복사하기 위해 많은 CPU 비용을 지불하고있을 수 있습니다. 또한 드라이버 및 셰이더 컴파일러는 셰이더 프로그램의 실행을 최적화하기 위해 모든 종류의 작업을 수행 할 수 있습니다. 이는 유니폼 및 리소스 제어 구조의 메모리 레이아웃을 최적화하여 인접한 메모리 또는 셰이더 레지스터에 잘 압축되도록하는 것을 의미합니다. 따라서 셰이더를 변경하면 드라이버가 파이프 라인에 이미 바인딩 된 모든 것을보고 새 셰이더에 대해 완전히 다른 형식으로 다시 압축 한 다음이를 명령 스트림에 복사 할 수 있습니다. 원리: 이는 유니폼 및 리소스 제어 구조의 메모리 레이아웃을 최적화하여 인접한 메모리 또는 셰이더 레지스터에 잘 압축되도록하는 것을 의미합니다. 따라서 셰이더를 변경하면 드라이버가 파이프 라인에 이미 바인딩 된 모든 것을보고 새 셰이더에 대해 완전히 다른 형식으로 다시 압축 한 다음 명령 스트림에 복사합니다. 원리: 이는 유니폼 및 리소스 제어 구조의 메모리 레이아웃을 최적화하여 인접한 메모리 또는 셰이더 레지스터에 잘 압축되도록하는 것을 의미합니다. 따라서 셰이더를 변경하면 드라이버가 파이프 라인에 이미 바인딩 된 모든 것을보고 새 셰이더에 대해 완전히 다른 형식으로 다시 압축 한 다음 명령 스트림에 복사합니다. 원리:셰이더를 변경하면 많은 CPU 메모리 셔플 링이 발생할 수 있습니다.
프레임 버퍼 변경은 아마도 구현에 따라 달라 지지만 일반적으로 GPU에서 꽤 비쌉니다. GPU가 동시에 다른 렌더 대상에 대한 다중 드로우 콜을 처리하지 못할 수 있으므로 두 드로우 콜 사이의 파이프 라인을 중단해야 할 수 있습니다. 나중에 렌더링 대상을 읽을 수 있도록 캐시를 비워야 할 수도 있습니다. 도면 중에 연기 된 작업을 해결해야 할 수도 있습니다. 깊이 버퍼, MSAA 렌더 타겟 등과 함께 별도의 데이터 구조를 축적하는 것이 매우 일반적입니다. 렌더 타겟에서 전환 할 때 마무리해야 할 수도 있습니다. 타일 기반 GPU에있는 경우 많은 모바일 GPU와 마찬가지로 프레임 버퍼에서 전환 할 때 상당히 많은 양의 실제 음영 처리 작업을 수행해야 할 수도 있습니다.) 원칙 :렌더 타겟 변경은 GPU에서 비쌉니다.
나는 그것이 매우 혼란 스럽지만 불행히도 세부 정보가 공개되지 않기 때문에 너무 구체적으로 표현하기가 어렵지만, 당신이 어떤 주를 부를 때 실제로 진행되고있는 것들에 대한 반 정도의 개요가 있기를 바라고 있습니다. 선호하는 그래픽 API에서 기능을 변경합니다.