- M1·M2 계열 GPU에서 OpenGL ES 3.1 애플리케이션을 표준대로 실행할 수 있는 Linux용 드라이버가 제공됨
- Asahi Linux의 역공학 기반 무료·오픈소스 드라이버는 M1·M2 그래픽 하드웨어에서 Khronos 적합성 테스트를 통과한 유일한 OpenGL ES 3.1 구현임
- 인증은 공식 테스트 통과와 Khronos 제출, 30일 검토 기간을 거치며 M1, M1 Pro/Max/Ultra, M2, M2 Pro/Max 항목이 등록됨
- OpenGL ES 3.1은 6월의 실험적 OpenGL ES 3.0·OpenGL 3.1 지원을 갱신하고, 컴퓨트 셰이더와 이미지 원자 연산을 추가함
- M1에는 이미지 원자 연산 전용 명령이 없어 주소 계산으로 우회했으며, 이후 비트 인터리브 명령을 찾아 10개 명령을 1개로 줄임
M1·M2용 OpenGL ES 3.1 적합성 인증
- M1·M2 계열 GPU용 OpenGL ES 3.1 적합성 인증 드라이버가 제공됨
- OpenGL ES 3.1 애플리케이션과 호환됨
- Linux 설치로 사용할 수 있음
- 기존 Asahi Linux 사용자는 배포판별 업그레이드 명령으로 최신 드라이버를 받을 수 있음
- Fedora:
dnf upgrade - Arch:
pacman -Syu
- Fedora:
- 역공학 기반 무료·오픈소스 그래픽 드라이버는 asahi/mesa에 공개되어 있음
- 이 드라이버는 M1·M2 계열 그래픽 하드웨어에서 세계에서 유일한 OpenGL ES 3.1 적합성 인증 구현임
- 수만 개 테스트를 통과해 정확성을 입증함
- 업계 표준 기구의 인정을 받음
Khronos 절차와 등록된 칩 계열
- 적합성 인증을 받으려면 구현체가 공식 적합성 테스트 스위트를 통과해야 함
- 테스트 스위트는 명세의 모든 기능을 검증하도록 설계됨
- 테스트 결과는 표준화 기구 Khronos에 제출됨
- 30일 검토 기간 동안 문제가 없으면 적합성 인증 구현이 됨
- Khronos 웹사이트에는 다음 드라이버가 적합성 인증 구현으로 등록됨
- 이번 성과는 OpenGL ES에만 머물지 않음
- M1용 그래픽 표준 전체에서 첫 적합성 인증 구현에 해당함
제조사 드라이버와 표준 API의 간극
- 제조사의 M1 드라이버는 Vulkan, OpenGL, OpenGL ES를 포함한 어떤 표준 그래픽 API에서도 적합성 인증을 받지 못함
- Linux를 사용하지 않는 M1·M2 환경에서는 표준 기반 애플리케이션이 동작한다는 보장이 없음
- Vulkan 사례에서 MoltenVK는 독점 드라이버 위에 Vulkan 일부를 계층화함
- 해당 독점 드라이버에는 핵심 기능이 빠져 있음
- 유효한 Vulkan 애플리케이션이 깨질 수 있음
- M1·M2 컴퓨터를 Linux로 전환하지 않은 개발자와 사용자 모두에게 장애가 됨
- Asahi Linux 드라이버 개발은 표준 소프트웨어가 M1 전용 해킹이나 포팅 없이 실행되는 것을 목표로 함
- 독점 드라이버, 독점 API, 표준 구현 거부에 만족하지 않음
- 명세에 맞는 오픈 표준 구현을 생태계의 바람직한 방향으로 봄
OpenGL ES 3.1의 핵심 추가 기능
- OpenGL ES 3.1은 6월에 제공된 실험적 OpenGL ES 3.0 및 OpenGL 3.1을 갱신함
- 주요 추가 기능은 컴퓨트 셰이더임
- 그래픽 애플리케이션 안에서 일반 계산을 가속하는 데 주로 사용됨
- 3D 게임은 물리 시뮬레이션을 컴퓨트 셰이더에서 실행할 수 있음
- 시뮬레이션 결과를 렌더링에 바로 사용하면 GPU와 CPU 물리 시뮬레이션 사이 동기화로 생기는 정지를 줄일 수 있음
- 그 결과 게임이 더 빠르게 실행될 수 있음
이미지 원자 연산이 필요한 이유
- OpenGL ES의 이전 버전은 애플리케이션이 화면 표시를 위해 이미지를 읽을 수 있게 했음
- ES 3.1은 애플리케이션이 보통 컴퓨트 셰이더에서 이미지에 쓰기를 할 수 있게 함
- 이미지 처리 알고리듬을 고정 기능 3D 파이프라인에 맞춰야 하는 제약이 줄어듦
- GPU는 수천 개 스레드를 동시에 실행하는 대규모 병렬 구조임
- 두 스레드가 같은 위치에 쓰면 실행 순서에 따라 결과가 달라짐
- 이 상황이 경쟁 조건임
- 원자적 메모리 접근은 경쟁 조건을 다루는 기본 해법임
- 메모리 서브시스템의 특수 하드웨어가 선택된 연산에 대해 스레드 순서와 무관하게 일관된 결과를 보장함
- 최신 그래픽 하드웨어는 덧셈 같은 여러 원자 연산을 지원함
- OpenGL ES 확장 OES_shader_image_atomic은 이미지 픽셀에 대한 원자 연산을 추가함
- 이 확장은 ES 3.2에서 필수임
- 예를 들어 컴퓨트 셰이더가 픽셀
(10, 20)의 값을 원자적으로 증가시킬 수 있음
M1에서 이미지 원자 연산을 구현한 방식
- 다른 GPU는 이미지 원자 연산 전용 명령을 제공해 드라이버 구현이 단순함
- M1에는 이미지 원자 연산 전용 하드웨어 명령이 없음
- 비이미지 원자 연산은 있음
- 비원자 이미지 기능도 있음
- 그래서 픽셀에 원자 연산을 직접 수행하지 않고, 픽셀의 메모리 주소를 계산한 뒤 해당 주소에 일반 원자 연산을 수행함
- 이미지가 선형으로 메모리에 배치되어 있다면 주소 계산은 단순함
- Y 좌표에 행당 바이트 수인 stride를 곱함
- X 좌표에 픽셀당 바이트 수를 곱함
- 두 값을 더해 첫 픽셀 기준 바이트 오프셋을 구함
- 첫 픽셀 주소에 오프셋을 더해 최종 주소를 얻음
- 실제 이미지는 보통 선형으로 배치되지 않음
- 현대 그래픽 하드웨어는 캐시 효율을 높이기 위해 X·Y 좌표를 인터리브함
- 메모리의 픽셀 배치는 행 단위가 아니라 나선형에 가까운 곡선을 따름
비트 인터리브 최적화와 숨은 명령 탐색
- X·Y 좌표를 인터리브할 때 한 비트씩 마스킹하고 시프트하는 방식은 비효율적임
- 잘 알려진 비트 조작 알고리듬은 비트 그룹을 섞어 문제를 병렬화함
- 셰이더 코드에서 이 알고리듬을 구현하면 성능이 개선됨
- 실제로는 각 좌표의 하위 7비트 이하만 인터리브됨
- X·Y 좌표를 32비트 레지스터의 하위·상위 16비트에 넣어 32비트 명령으로 동시에 처리할 수 있음
- 명령 수를 절반으로 줄일 수 있음
- GPU의 shift-and-add 결합 명령도 활용함
- 이 기법을 합치면 M1 GPU 어셈블리 10개 명령으로 인터리브를 수행할 수 있었음
- 이후 전용 비트 인터리브 명령 가능성을 검토함
- PowerVR에는
shfl셔플 명령이 있음 - M1 GPU는 PowerVR에서 가져온 요소가 있어 유사 명령이 있을 가능성을 검토함
- 독점 컴파일러가 테스트 셰이더 컴파일 시 해당 명령을 사용하지 않아, 컴파일 결과 관찰만으로는 역공학이 어려웠음
- PowerVR에는
추측과 검증으로 확인한 인터리브 명령
- Dougall Johnson은 이미 알려진 명령 인코딩을 바탕으로 후보를 추정함
- 비트 반전 명령에는 연산을 지정하는 2비트 필드가 있고 값은
01임- 설정된 비트 수 세기 명령은
10 - 첫 번째 설정 비트 찾기 명령은
11 - 알려진 복잡한 비트 조작 명령은 이 세 값을 사용함
- 설정된 비트 수 세기 명령은
- 남은 값
00이 관측되지 않은 미지의 값임- 인터리브 명령이 존재한다면 비트 반전 명령과 비슷하되 연산 코드가
00일 가능성을 검토함
- 인터리브 명령이 존재한다면 비트 반전 명령과 비슷하되 연산 코드가
- 세 개의 알려진 명령은 입력 소스가 하나뿐이지만, 인터리브 명령에는 두 소스가 필요함
- M1 GPU 명령은 보통 소스 위치를 일관되게 인코딩함
- 두 소스 산술 명령에서 두 번째 소스가 있을 위치에 빈 공간이 있어, 그 위치를 두 번째 소스로 추정함
- 검증은 컴파일러를 수정해 곱셈 같은 2소스 정수 연산을 추정한 인터리브 인코딩으로 바꾸는 방식으로 진행됨
- 컴퓨트 셰이더에서 해당 연산을 사용함
- 테스트 셰이더는 가능한 입력마다 미지의 명령이 인터리브 결과를 반환하는지 확인함
- 명령은 두 개의 16비트 소스를 받기 때문에 약 40억 개 입력이 있음
- M1 GPU는 드라이버의 새 컴퓨트 지원으로 모든 입력을 1초 미만에 확인함
- 최종적으로 10개 명령짜리 벡터화 어셈블리를 1개 인터리브 명령으로 대체함
- 이 방식은 빠르고 적합성 테스트도 통과함