brunch

You can make anything
by writing

C.S.Lewis

by 상윤 Jun 13. 2018

용어 2. ICD

장치 독립적인 표준의 제공

컴퓨터로 수행하는 작업들 중에서 시각적 표현을 위한 모든 작업들의 총칭을 그래픽스라 하고 그런 작업들을 그래픽 렌더링, 짧게 줄여서 그냥 렌더링이라고 한다. 이를 수행하기 위해선 나름대로 복잡한 작업들을 수행해야 하는데, 이러한 작업들을 수행하기엔 CPU가 너무 비싼 자원인 것이 문제가 되었다. 온갖 분기 예측 기법을 위해 동원된 방식들은 하나 하나의 논리적인 수행을 처리하는데 집중되어 있는데, 그에 반해 렌더링을 위해 필요한 수행 방식은 논리적으로 복잡하지 않고 수식의 계산에만 치중하는 차이가 있다.


이러한 계산 작업들을 일련의 흐름으로 엮어 처리할 수 있도록 파이프라인을 구성하고 이를 수행하고자 값싼 여러 개의 프로세싱 유닛들을 모아 만들어낸 것이 우리가 흔히 부르는 그래픽 카드다. 또한 이 그래픽 카드가 작업을 수행할 수 있도록 렌더링을 위한 데이터를 입력하고 파이프라인을 조작, 제어할 수 있는 렌더링 API들이 사용됨으로써 우리는 컴퓨터를 통해 계산된, 영상 자료와 같은 시각적 표현의 결과물들을 볼 수 있게 되었다.


그래픽 카드는 여러 렌더링 API를 통해 제어될 수 있는데, 이는 그래픽 카드의 드라이버가 렌더링 API들에 대한 구현을 제공하기 때문이다. 달리 말하면, 그래픽 카드가 지원하지 않는 렌더링 API는 사용할 수 없다는 의미이다. 예를 들어, AMD의 특정 그래픽카드들, 특히 랩탑에 탑재되는 모빌리티 버전의 그래픽 카드들은 한 때 렌더링 API의 대표격인 DirectX와 OpenGL, 둘 모두를 지원하지 않고 대중적으로 많이 사용되는 DirectX만을 지원하는 카드를 내놨었다. 또 다른 예로써 최근 많은 제조사들이 협력하여 개발하고 있는 API인 Vulkan에 대한 지원 여부를 들 수 있다. 이를 사용하기 위해선, 글을 쓰는 현재 시점에서 가급적 최신 버전의 그래픽 드라이버가 필요하다. 그러나 오래 전에 출시된 그래픽 카드는 특정 버전의 이후의 드라이버를 사용할 수 없도록 제조사가 지원을 중단했을 수 있다. 그렇다면 그래픽 카드가 Vulkan API를 구동할 수 없기 때문에 Vulkan을 통해 개발된 게임을 실행하는 것 또한 당연히 불가능하다.


요즘 대부분의 그래픽 카드들은 DirectX와 OpenGL, Vulkan과 같은 다양한 렌더링 API 뿐만 아니라 GPGPU와 같은 병렬 처리를 위한 API, 비디오 압축 처리를 위한 API 등을 제공한다. 그렇다면, 반대로 하나의 렌더링 API에서 여러 개의 그래픽 카드들을 사용하는 것은 가능할까? 여러 개의 그래픽 카드를 설치하고 이를 제어하는 기술에 대한 것은 오래 전부터 많은 관심을 받아왔다. 특히 NVIDIA나 AMD는 자사의 카드를 2개 이상 다중 GPU를 설치하는 기술에 대해 각각 NVIDIA SLI, AMD CrossFire라는 이름을 붙여 지원하고 있다. 이들 기술을 이용하면 단일 카드를 이용하는 것보다는 확연한 성능 향상을 얻을 수 있다. 그러나 오늘의 관심은 이 부분이 아니다. 서로 다른 제조사가 만든 그래픽 카드를 설치하여 사용하는 경우는 어떻게 될까 하는 것이 바로 오늘 다룰 주제다.


렌더링 API를 이용하여 그래픽 카드에 명령을 내릴 때, 렌더링 API는 그 자체는 어떤 그래픽 카드가 사용되는지 관심이 없다. 해당 API 수준에선 명령이 어떤 그래픽 카드에 전달될 것인지에 대한 부분은 추상화시키고 어떻게 렌더링 할지에만 관심을 두기 때문이다. 그러나 실제로 이를 연결하는 과정이 없인 그래픽 카드에 명령을 전달할 수조차 없을 것이다. 만일 장치가 시스템에 오로지 하나만 연결될 수 있다고 가정한다면 그러한 연결은 당연히 단 하나의 대상으로 연결하는 것으로 고민을 끝낼 수 있을 것이다. 하지만 그런 대상이 여럿일 경우는 어떤 것을 선택해야 하는지 결정해야 한다. 여기서 한 발짝 더 들어가면, 그런 선택을 누가 해야하는지도 논의되어야 한다.


이런 문제에 대한 대답이 바로 Installable Client Driver, ICD다. 우선 용어의 의미부터 명확히 하기 위해 무슨 의미로 installable과 client라 이름 붙었는지 이해할 필요가 있다. Client의 의미를 먼저 살펴보자. 앞서 계속 언급한 렌더링 API라는 용어는 OpenGL, DirectX 등 렌더링을 위한 API에 대한 분류를 흔히 일컫는 용어다. 하지만 해당 API의 입장에서 보았을 때 그 자신의 역할은 그래픽 카드에 명령을 요청하는 것이다. 그래픽 카드는 이러한 요청을 받아 처리한뒤 그 결과를 제공한다. 이와 같이 요청을 주고 받는 관계는 클라이언트-서버의 관계로 볼 수 있다. 렌더링 API는 CPU에서 GPU에게 렌더링 명령을 요청하는 API이기 때문에 이러한 의미에서 클라이언트 API라 한다.


Installable에 대해선, 비(非) ICD에 대해 먼저 따져보는 것이 이해하는데 수월할 것이다. 비 ICD인 경우, 여러 그래픽 카드가 설치된 상태에서 특정 그래픽 드라이버가 설치되면 그 외의 다른 그래픽 카드에 대한 드라이버는 동시에 시스템 상에서 구동될 수 없다. 이와 달리 여러 드라이버가 동시에 시스템에 설치되어 구동될 수 있는 것을 installable이라 한다. 이와 같은 의미들에 따라, ICD란 한 시스템에서 여러 그래픽 카드가 구동될 수 있도록 하는 드라이버라는 것을 의미한다. 단, 이는 체계적으로 통일된 개념이 아니라, 각각의 API가 저마다 지원하는 개념이기 때문에 OpenGL ICD, OpenCL ICD, Vulkan ICD 와 같이 각각의 API가 개별적으로 ICD를 지원해야만 한다. 또한 이는 운영 체제에 따라서 같은 API 에서도 달라질 수 있다.


ICD를 조금 더 이해해보기 위해 CPU의 내장 그래픽 기능과 그래픽 카드를 같이 사용하는 예를 살펴 보자. 이런 상황은 최근 들어선 굉장히 흔하다. 좀 더 구체적인 상황으로써 Intel의 CPU와 AMD의 그래픽 카드를 사용하는 상황을 가정해보자. 각각의 장치에 대해 그래픽 드라이버를 설치하면 저마다 이용 가능한 렌더링 API에 대한 라이브러리 또한 시스템에 설치된다. 두 장치가 모두 특정 렌더링 API에 대한 기능을 사용할 수 있다면, 이는 다행스럽게도 해당 렌더링 API가 ICD를 지원하는 것이다.


그렇다면 과연 렌더링 명령을 내렸을 때 어떤 장치를 통해서 렌더링 작업을 수행하게 될까? 이런 상황에선 각 벤더 별로 제공하는 ICD에 대해서 중간층에서 조절할 수 있는 개체가 개입하게 된다. 이 개체는 어떤 장치를 사용할 것인지 결정해주는 역할을 한다. 이런 중간자를 대개 ICD 로더라고 부르는데, 이 ICD 로더는 렌더링 API에서 그 존재에 대하여 개념적으로 명시할 수도 있고, 그렇지 않으면 운영 체제가 그 역할을 수행하는 모듈을 직접 제공해야 할 수도 있다.


렌더링 API에 대한 ICD가 드라이버 차원에서 지원되고 또한 그 ICD를 제어하는 ICD 로더가 있다면 각 드라이버의 렌더링 API에 대한 ICD의 구현 라이브러리를 로더가 런타임에 확인 및 로드하게 된다. 이러한 과정을 장치 조회(Device enumeration)이라고 하며, 이 과정에서 각각의 드라이버 구현에선 저마다 자기 제조사의, 제어 가능한 그래픽 카드가 존재하는지 질의한다. 그 결과에 따라 특정 그래픽 카드의 사용 가능 여부를 확인할 수 있다. 장치 조회는 우리가 그래픽 카드를 바꿔 설치하는 경우, 새 카드의 그래픽 드라이버를 시스템에 추가적으로 설치하면서 실제 그래픽 카드의 수와 ICD의 수가 차이가 나기 때문에 반드시 필요한 과정이다. 지금 예로 드는 상황에선, GPU를 AMD에서 NVIDIA 카드로 교체했다고 볼 수 있다. 그럴 경우 ICD는 Intel, AMD, NVIDIA 세 제조사의 드라이버 모두가 설치된 반면, 실제 그래픽 장치는 Intel, NVIDIA 둘 뿐이기 때문에, AMD에 대한 ICD 라이브러리를 사용한다면 문제가 발생할 것이다.


조회 과정을 통해 사용 가능한 장치를 파악하였으면, 렌더링 API에서 제공하는 장치에 대한 추상화를 진행한다. 구체적으로, Vulkan에선 위의 조회 과정을 VkPhysicalDevice라는 객체와 그와 관련된 함수군을 통해 제공하며, 특정 VkPhysicalDevice로부터 VkDevice라는 논리 장치에 대한 객체를 획득함으로써 이후의 모든 Vulkan API에 대한 사용 방식을 실제 그래픽 카드로부터 분리시킨다. EGL은 이와 같은 장치 지원에 대하여 EGLDevice라는 개념을 NVIDIA에서 EGL 확장으로 제안하였다. 이를 이용하여 장치에 대한 조회까지는 가능한데(Unix 계열 NVIDIA 드라이버에 한함) 획득한 장치 객체를 EGL API에 대한 실행 주체인 EGLDisplay 객체와 연결하여 획득하는 과정에 대한 구체적인 방안은 아직 제안된 표준이 없는 것으로 보인다.


(이와 관련해서는 수차례 찾긴 해봤는데 현재 어떤 논의들이 오가고 있는지 확인하지 못했다. 다만 EGL을 제공해야하는 입장에서, 이를 EGLDisplay를 얻는 함수의 기능에 대한 확장으로 제공할 것을 고려하고 있다. 물론 다른 표준 구현자들 또한 여러 방식으로 고려하고 있을 것이란 생각에 아직은 초기 계획만 하고 있다. 그에 대해선 확인되는대로 글을 추가할 예정이나 혹시라도 관련한 정보를 알고 계신 분이 이 글을 보신다면 댓글로 알려주시길 바란다!)


장치에 대한 추상화가 진행되고 나면 렌더링 API에 대한 호출은 위에서도 언급했듯 오롯이 렌더링에 관련된 개념으로만 진행되며, 어떤 ICD의 구현을 수행하는지는 내부적으로 연결된 흐름에 따라 처리될 뿐이다. 세부적으로 살펴보자면, 장치를 추상화한 객체에서 특정 렌더링 함수를 호출하는 것은 일종의 프록시와 같은 연결 방식을 거친다고 볼 수 있다. 호출된 함수 내부에선 장치가 무엇이었는지에 따라 미리 준비된, 실제 구현에 대한 함수를 추가적으로 호출할 뿐이다. 그를 통해 특정 그래픽 드라이버가 제공한, 실질적인 함수의 구현으로 진입하게 되고 그제서야 그래픽 카드에 전달할 명령을 구성한다.


말로만 길게 써서 잘 안 읽히거나 와닿지 않을 수도 있겠다. 하지만 특별히 어려운 개념이 아닌 것만은 분명하며, 그저 장치와 시스템 간의 관계를 독립시킨 개념이라고만 생각해도 충분하다. 실제로 이와 같은 기능에 대한 제공 당사자가 아닌 경우는 특별히 이해할 필요도 없는 부분일 수도 있다. 다만, 장치에 대한 실질적인 사용 권한을 획득하거나 사용하도록 요청하는 방식은 파악해두는 것이 고성능의 장치를 설치해두고도 사용하지 못하는 불상사를 피할 수는 있을 것이다. 물론 이는 각각의 API들마다 제공하는 방식이 다르기 때문에 저마다 파악해야한다. 


자, 그럼 ICD에 대한 설명과 정리는 이것으로 충분할 것으로 보인다. 대체적으로 뭉뚱그려서 설명하다보니 각각의 API들에 대해 구체적인 부분은 생략이 된 부분도 있지만 크게 개념적으로 이해하는데 문제가 되진 않을 것이다. 혹시라도 더 자세한 내용이 궁금하면 구글링만으로도 충분히 잘 설명한 자료들이 많이 나타나니까 확인해봐도 좋을 것이다. 오늘도 글이 쓰다보니 많이 길어진 것 같아 여기서 이만 맺는다.

작가의 이전글 용어 1. EGL
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari