
시리즈 마지막 편입니다. 1편 Weylus 미러링, 2편 evdi 가상 모니터, 3편 COSMIC 용 Sunshine 에 이어, 이제 둘을 합쳐 폰을 진짜 확장 모니터로 써 봤습니다. 결과부터 말하면 동작은 했고, 숫자 하나 때문에 결론은 다른 곳에서 났습니다.
1단계: 가상 모니터를 가볍게
2편에서 1920x1080@60 가상 모니터는 키 입력이 씹힐 만큼 무거웠습니다. 복사할 양을 줄이려고 EDID 를 1280x720@30 으로 새로 만들었습니다(720p 타이밍 1650x750, 픽셀 클럭 37.125MHz). 30Hz 를 받도록 EDID 의 주파수 허용 범위도 24Hz 까지 넓혔습니다.
가상 모니터만 켜 둔 상태에서 컴포지터 CPU 는 9.4% 에서 12.3% 로 조금 올랐고, dmabuf 오류는 없었습니다. 여기까지는 좋아 보였습니다.
2단계: 가상 모니터는 다른 포맷으로 온다
Sunshine 이 가상 모니터를 고르자 협상이 다시 실패했습니다. 덤프해 보니 COSMIC 은 가상 모니터를 RGBA 공유 메모리 방식 하나로만 보냈습니다(GPU 버퍼 없음). Sunshine 의 공유 메모리 목록에는 RGBA 가 없습니다. 3편의 끼움 라이브러리에 세 가지를 더했습니다.
- 연결 요청을 프레임레이트 후보(60, 30)마다 복제하고, BGRA 요청마다 RGBA 사본을 맨 뒤에 붙인다.
- 협상 결과를 Sunshine 에 넘기는 콜백(param_changed)을 감싸, RGBA 를 BGRA 로 알린다. 함정: 협상된 Format 의 값은 Choice(None) 로 한 번 감싸여 와서, 처음엔 포맷 속성을 찾지 못했습니다.
- 그래도 화면이 검었습니다. Sunshine 은 GPU 버퍼를 쓸 수 있는 시스템이면 VAAPI 인코더를 "GPU 버퍼 전용"으로 만들어, 메모리 프레임을 가져오다 실패했습니다(Couldn't import RGB Image 0x300C).
3단계: dlsym 을 가로채 "dmabuf 없음"이라고 답하기
Sunshine 은 EGL 함수를 dlopen + dlsym 으로 불러옵니다. 그래서 끼움 라이브러리에서 dlsym 을 가로채, dmabuf 포맷 질의(eglQueryDmaBufFormatsEXT)에 0개로 답하게 했습니다. 그러면 VAAPI 가 메모리 프레임을 GPU 에 올려 인코딩하는 경로로 만들어집니다.
- dlsym 을 가로챌 때는 원래 함수로 꼬리 호출(jmp) 로 넘겨야 합니다. 그래야 glibc 가 RTLD_NEXT 를 판단할 때 쓰는 호출 위치가 원래 호출자로 유지됩니다. 역어셈블로 jmp 인 것을 확인했습니다.
- 이 기능은 가상 모니터가 켜져 있을 때만 켭니다. 노트북 화면만 보낼 때는 빠른 GPU 버퍼 경로를 그대로 씁니다.
4단계: 뒤바뀐 색 바로잡기
화면이 나왔지만 빨강과 파랑이 바뀌어 있었습니다. RGBA 바이트를 BGRA 라고 속였으니 예상된 결과입니다. Sunshine 은 메모리 프레임을 glTexSubImage2D(..., GL_BGRA, ...) 로 올리는데, 이 함수도 이미 가로채고 있던 eglGetProcAddress 를 통해 받아 가므로 래퍼를 돌려줘 GL_BGRA 를 GL_RGBA 로 바꿨습니다. 색이 정상으로 돌아왔고, 폰에 노트북 옆 두 번째 화면이 떴습니다.
그런데: 숫자를 쟀다
가상 모니터로 창을 옮기고 스트리밍하는 동안 부하를 쟀습니다.
| 항목 | 값 |
|---|---|
| 컴포지터(cosmic-comp) | 373% (코어 약 3.7개, 켜기 전 9.4%) |
| Sunshine / vmon | 11.2% / 4.6% |
| dmabuf·EGL 오류 | 5분간 52건 |
| CPU 압박(PSI, 10초 평균) | 21% |
스트리밍 프로그램들은 가벼웠습니다. 무거운 건 컴포지터였습니다. 가상 장치(evdi)로는 GPU 버퍼를 넘기지 못해, 가상 모니터에 그릴 게 생기자 CPU 경로의 부담이 확 커졌습니다. 해상도와 주사율을 낮춰도 이 구조는 그대로입니다.
결론과 시리즈 정리
- 미러링: Weylus(브라우저, 앱 설치 없음) 또는 Sunshine + Moonlight(GPU 인코딩, 더 가벼움). 바로 쓸 만합니다.
- 확장: 소프트웨어만으로도 가능은 합니다. 하지만 이 노트북(COSMIC, 하이브리드 GPU)에서는 컴포지터가 코어 3.7개를 써서 상시 사용은 어렵습니다.
- 현실적인 확장: 몇천 원짜리 HDMI 더미 플러그입니다. 진짜 GPU 출력이라 CPU 경로를 타지 않고, 이번에 만든 Sunshine 보정(60fps 협상, 포털 신호)은 그대로 쓰입니다.
하루짜리 실험에서 남은 교훈은 셋입니다. 인식된다와 쓸 수 있다는 다르다. 실패하지 않는 실패는 양쪽 값을 덤프해야 보인다. 그리고 결론은 체감이 아니라 측정한 숫자로 내린다.