나는 " 제한 "의 관점에서 성능을 생각하고 싶습니다 . 상당히 복잡하고 상호 연결된 시스템을 개념화하는 편리한 방법입니다. 성능 문제가 발생하면 "어떤 한계에 부딪 히고 있습니까?"라는 질문을합니다. (또는 : "CPU / GPU가 바인딩되어 있습니까?")
여러 수준으로 나눌 수 있습니다. 최상위 수준에는 CPU와 GPU가 있습니다. CPU 바운드 (GPU가 유휴 대기 중 CPU 대기) 또는 GPU 바운드 (CPU가 GPU 대기 중) 일 수 있습니다. 여기 주제에 대한 좋은 블로그 게시물이 있습니다.
더 세분화 할 수 있습니다. 온 CPU의 측면, 당신은 CPU의 캐시에 이미 데이터에 대한 모든 사이클을 사용하여 수 있습니다. 또는 메모리가 제한 되어 CPU가 유휴 상태가되어 주 메모리에서 데이터가 들어 오기를 기다리 므로 데이터 레이아웃을 최적화하십시오 . 당신은 그것을 아직도 더 나눌 수 있습니다.
내가 XNA에 대한 성능의 넓은 개요를하고있는 중이 야하지만 (내가 참조 형식 (의 할당 지적합니다 class
하지 struct
특히 X 박스 360에 - 일반적으로 저렴 사이클을 많이 구울 가비지 컬렉터를 게재 할 수있는 반면,) . 여기 참조 ) 자세한 내용은.
온 GPU의 측면, 나는 당신을 가리키는 의해 시작합니다 이 우수한 블로그 게시물 세부 정보를 많이 있습니다. 파이프 라인에 대한 미묘한 수준의 세부 정보 를 원하면 이 시리즈의 블로그 게시물을 읽으십시오 . ( 여기 더 간단한 것이 있습니다 ).
간단히 말해서, " 채우기 한도 "(백 버퍼에 쓸 수있는 픽셀 수-오버 버드 수), " 쉐이더 한도 "(쉐이더가 얼마나 복잡하고 " 텍스쳐 페치 / 텍스처 대역폭 제한 "(액세스 할 수있는 텍스처 데이터 양).
이제 우리는 CPU와 GPU가 상호 작용해야하는 곳 (다양한 API 및 드라이버를 통해)이 큰 문제에 직면했습니다. " 배치 한계 "및 " 대역폭 " 이 느슨하게 있습니다 . ( 앞서 언급 한 시리즈 중 하나 는 자세한 내용 을 다룹니다 .)
그러나 기본적으로 배치 ( 이미 알고 있듯이 )는 GraphicsDevice.Draw*
함수 중 하나를 호출 할 때마다 (또는 XNA의 일부가 이를 수행 할 때마다) 발생합니다 SpriteBatch
. 당신은 의심의 여지가 이미이 없다 읽으면서, 당신은 몇 천 개 얻을 수 * 프레임 당이의를. 이것은 CPU 한도이므로 다른 CPU 사용량과 경쟁합니다. 기본적으로 드라이버가 그리는 것에 대한 모든 것을 패키징하고 GPU로 전송하는 드라이버입니다.
그리고 GPU에 대한 대역폭 이 있습니다. 이것은 얼마나 많은 원시 데이터를 전송할 수 있는지입니다. 여기에는 렌더링 상태 및 셰이더 상수 / 매개 변수 설정 (월드 / 뷰 / 프로젝트 매트릭스와 같은 항목 포함)에서부터 DrawUser*
함수 사용시 정점에 이르는 모든 배치와 함께 제공되는 모든 상태 정보가 포함 됩니다. 또한 어떤 통화를 포함 SetData
하고 GetData
등 텍스처, 버텍스 버퍼에를
이 시점에서 호출 할 수있는 모든 것 SetData
(텍스처, 버텍스 및 인덱스 버퍼 등)뿐만 아니라 Effect
GPU 메모리에도 남아 있다고 말해야합니다 . 지속적으로 GPU로 다시 전송되지는 않습니다. 해당 데이터를 참조하는 그리기 명령은 해당 데이터에 대한 포인터와 함께 전송됩니다.
(또한 : 메인 스레드에서만 드로우 명령을 보낼 수 있지만 SetData
모든 스레드에서 할 수 있습니다 .)
XNA는 다소의 렌더링 상태 클래스 (물건을 복잡 BlendState
, DepthStencilState
등). 이 상태 데이터 는 드로우 콜마다 전송됩니다 (각 배치에서). 100 % 확신 할 수는 없지만 느리게 전송된다는 인상을 받고 있습니다 (변경되는 상태 만 전송 함). 어느 쪽이든, 상태 변화는 배치 비용에 비해 자유 지점까지 저렴합니다.
마지막으로 언급 할 것은 내부 GPU 파이프 라인 입니다. 여전히 읽어야하는 데이터에 쓰거나 여전히 써야하는 데이터를 읽음으로써 강제로 플러시하고 싶지 않습니다. 파이프 라인 플러시는 작업이 완료 될 때까지 대기하므로 데이터에 액세스 할 때 모든 것이 일관된 상태가됩니다.
주의해야 할 두 가지 특별한 경우는 다음과 같습니다. GetData
동적으로 호출 -특히 RenderTarget2D
GPU가 쓰고있는 것. 이것은 성능이 매우 나쁩니다.하지 마십시오.
다른 경우는 SetData
정점 / 인덱스 버퍼를 호출 하는 것입니다. 이 작업을 자주 수행해야하는 경우 DynamicVertexBuffer
(또한 DynamicIndexBuffer
)를 사용하십시오. 이를 통해 GPU는 자주 변경 될 것을 알 수 있으며 파이프 라인 플러시를 피하기 위해 내부적으로 버퍼링 마법을 수행 할 수 있습니다.
또한 동적 버퍼는 DrawUser*
메서드 보다 빠르지 만 필요한 최대 크기로 미리 할당해야합니다.
... 그리고 그것은 XNA 성능에 대해 내가 아는 모든 것입니다. :)