| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- Shimon Schocken
- C++
- 이득우의 게임수학
- https://insightbook.co.kr/
- 주우석
- C#
- 이득우
- 알고리즘
- 백준
- unity6
- booksr.co.kr
- 데이터 통신과 컴퓨터 네트워크
- 김진홍 옮김
- 박기현
- hanbit.co.kr
- The Elements of Computing Systems 2/E
- 잡생각 정리글
- 게임 수학
- (주)책만
- C
- 메타버스
- 생능출판
- JavaScript
- Noam Nisan
- 밑바닥부터 만드는 컴퓨팅 시스템 2판
- 전공자를 위한 C언어 프로그래밍
- HANBIT Academy
- 입출력과 사칙연산
- BOJ
- 일기
- Today
- Total
cyphen156
CyphenEngine 개발기 #6 크로스플랫폼 : Linux로 포팅하기 본문
이번 글의 내용은 Windows로 구현했던 내용을 Linux에 맞도록 포팅하는 일에 대한 내용이다.
사실 그렇게 할게 많지는 않았다.
수정한것은 Platform에 종속된 하부 구현체 교체와, Dx11이 리눅스에선 지원되지 않기 위해 테스트를 위한 Vulkan이라는 렌더러를 개발해서 붙이는것 정도 였다.

1. 개발 환경 세팅하기
우선 실제 리눅스 환경을 구성하는 게 먼저였다.
Windows는 하위 시스템으로 Linux를 가상화하여 사용할 수 있게 해주는 WSL를 제공한다.
이 기능을 이용하기로 했다.
그리고 Windows와 동일하게 GUI와 그래픽스 환경을 지원하기 위한 선택을 해야 했는데,
X11과 Vulkan으로 선택하기로 했다.
우선 GUI 환경은 XServer를 통해 Linux에게 Window라는 GUI를 제공하는 라이브러리를 사용하기로 했다.
그리고 그래픽스는 OpenGLES와 Vulkan 중 고민을 했지만,
결론적으로 어차피 포팅 작업 자체는 내가 직접 코드를 치기보다 AI Agent의 어시스트를 받기로 결정했고,
무엇보다 Vulkan은 SDK 자체가 여러 플랫폼(Windows·Linux는 물론 macOS·Android까지)을 아우르도록 설계된 표준 API다. DirectX처럼 특정 OS에 묶인 API와 달리,
플랫폼마다 렌더러 내부를 처음부터 다시 세팅할 일이 적어진다.
그래서 Vulkan을 우선 도입하기로 했다.
2. 새로운 렌더러 모듈 구현체 : Vulkan
Dx11은 Linux에서 돌지 않는다.
그래서 Linux 실행을 화면까지 검증하려면 Linux에서도 도는 백엔드가 하나 필요했고, 그게 Vulkan 렌더러다.
다행히 이걸 새로 붙이는 비용은 크지 않았다.
지난 #2 브랜치에서 렌더러를 이미 DLL 경계로 떼어 놨기 때문이다.
엔진은 백엔드가 내부에서 뭘 하든 모른다.
GetRendererModuleApi 심볼 하나를 export하는 모듈이면 그만이다.
그러니 Vulkan 렌더러라는 건 결국 엔진 계약은 그대로 두고, 그 계약을 채우는 새 구현체 하나를 더 만드는 일이었다.
백엔드 API를 Vulkan으로 고른 것도 같은 맥락이다.
Dx11은 Windows에 묶인 API라, Linux로 가려면 렌더러 속을 통째로 다른 API로 다시 써야 한다.
반면 Vulkan은 SDK 자체가 크로스플랫폼 표준으로 설계돼 있어서,
렌더러 내부 Instance, device, swapchain, pipeline, 커맨드 버퍼는 플랫폼과 무관하게 한 번만 쓰면 된다.
플랫폼마다 갈라지는 건 창에 붙는 surface 생성 한 조각뿐이다.
즉 Windows에서 만든 Vulkan 렌더러 속은 Linux에서도 거의 그대로 재활용된다.
작업엔 원칙을 하나 세웠다.
Vulkan과 Linux를 동시에 디버깅하지 않는다.
새 백엔드(Vulkan)와 새 플랫폼(Linux)을 한꺼번에 켜면,
문제가 터졌을 때 그게 Vulkan 탓인지 Linux 탓인지 가릴 수가 없을것 같았다.
그래서 Vulkan은 익숙한 Windows에서 먼저 만들었다.
Vulkan SDK를 붙이고 Instance, surface, swapchain, render pass, pipeline, descriptor, 그리고 texture 업로드 경로까지 연결했다.
Dx11에서 하던 것과 똑같은 그림을 Vulkan으로 다시 그리는 셈이라,
손이 많이 가는 건 초기화 코드뿐이었다.
그리는 로직 자체는 이미 있는 RenderCommand를 Vulkan API로 번역하는 수준이다.
그리고 이 브랜치에서 제일 통쾌했던 순간은 CyphenRendererDx11.dll을 CyphenRendererVulkan.dll로 그냥 바꿔치기로 퉁쳐졌다는 것이다.
엔진 코드가 바뀐것은 모듈 디스크립터에 주입해주는 임시 하드코딩 변수 두개 수정 딱 그것 뿐이었다!.
Texture2D 로드, ResourceCommand 업로드, DrawTexturedQuad 제출 흐름을 그대로 유지한 채, 이번엔 Vulkan으로 화면에 텍스처를 띄웠다.
지난 글에서 "나중에 백엔드를 통째로 갈아끼울 수 있다"고 한 말이, 파일 하나 교체로 증명된 순간이었다.
한 가지 눈에 띈 건 출력이 상하로 뒤집혀 나온 것이었다.
이건 렌더링이 깨진 게 아니라
백엔드마다 클립 공간 Y축 방향이 달라서 생기는 좌표계·UV 매핑 문제라고 본다.
게임 수학때도 배웠지만 OpenGL계열은 모니터 좌하단을 원점으로,
Direct계열은 좌상단을 원점으로 좌표계를 설정하고 있기 때문이다.
원인이 분명하니 이 브랜치에선 굳이 손대지 않고 넘겼다.
검증은 Vulkan 창에 실제 텍스처가 뜨는 걸 확인했고,
1초 간격으로 캡처한 화면 해시를 비교해 두 텍스처가 번갈아 나오는 것까지 봤다.


3. 리눅스 구현 채우기
렌더러가 준비됐으니, 이제 그 아래 플랫폼 바닥을 Linux용으로 채울 차례다.
여기서부터가 이번 브랜치의 본체인데, 사실 채워야 할 목록은 내가 뽑을 필요도 없었다.
#2 마지막에 "Linux에서 컴파일된다"까지 맞춰 뒀기 때문에,
빠진 플랫폼 구현은 링크 단계에서 링커가 알아서 목록으로 뽑아 줬다.
컴파일은 되는데 링크가 안 되는 상태, 그게 시작점이었다.
채운 건 전부 Platform에 종속된 하부 구현체다. Windows 구현과 같은 이름에 속만 다른 것들이다.
PlatformFile Win32 파일 API → POSIX fd (open/read/write/seek/close)
stat/mkdir/opendir, 재귀 삭제는 lstat로 심링크 안 따라감
PlatformTime Windows 타이머 → clock_gettime
ModuleLoader LoadLibrary → dlopen / dlsym / dlclose
JpegCodec WIC → libjpeg-turbo(turbojpeg)
Launch Win32 window → X11 window + engine thread + shutdown pipe
지난 글에서 "LoadLibrary를 dlopen으로 바꿀 땐 Platform 구현만 갈아 끼우면 된다"고 했던 게 이 표 그대로다.
ModuleLoader 위 계층 (어떤 모듈인지, 버전이 맞는지 판단하는 곳)은 한 줄도 건드리지 않았다.
딱 한 군데, 예상보다 조금 더 손이 간 건 경로 처리였다.
막상 Linux를 채우려니 경로 변환 책임이 여기저기 애매하게 걸쳐 있어서,
PlatformFile이 경로 규칙을 직접 알지 않도록 native facade를 하나 끼워 정리했다.
PlatformPath ToPlatformPath 단방향 (역방향은 제거, Path::Normalize가 담당)
LinuxPath PlatformPath + LinuxString을 묶는 native path facade
FileHandle native fd를 숨기는 opaque 값 (RAII는 FileStream이 담당)
검증은 WSL Linux에서 엔진을 실행해 CoreIoTests PASS=69 FAIL=0을 확인했다.
다만 이 시점의 실행은 Core IO까지만 도달하고 렌더러 단계에서 멈췄다.
앞서 만든 Vulkan 모듈이 아직 Linux용 .so로는 빌드되지 않았기 때문이다.
그 마지막 연결이 다음 단계다.
4. 빌드
이제 Windows에서 만든 Vulkan 모듈을 Linux .so로 빌드해 붙이면 된다.
빌드 시스템은 이미 #2_7에서 준비해 뒀다.
Windows 프로덕션은 손수 만든 .vcxproj / .sln으로 그대로 두고, Linux 빌드는 CMake 전용으로 병존시키는 구조다.
여기서 손댄 건 전부 "Windows에선 안 걸리는데 Linux에선 걸리는" 것들이다.
export 매크로 __declspec(dllexport) (Windows 전용) → visibility default (.so)
PlatformDefine 기반 공통 헤더로 통일
surface 생성 vkCreateWin32SurfaceKHR → vkCreateXlibSurfaceKHR (X11 Display + Window)
native context Launch가 HINSTANCE/HWND(Win) · Display/Window(Linux)를
LaunchContext에 담아 renderer 모듈 ABI로 전달
산출물 규격 CyphenRendererVulkan.so (ModuleLoader 파일명 규칙에 맞춤)
$ORIGIN RPATH, SPIR-V shader 출력 배치
모듈 export 매크로를 공통 헤더로 뺀 게 핵심이다.
Windows의 __declspec과 Linux의 visibility를 한 곳에서 갈라 두니,
모듈 entrypoint를 내보내는 규칙이 두 플랫폼에서 하나로 맞춰졌다.
surface 생성도 입력 계약(native render context + 창 정보)은 똑같이 두고,
그 안에서 Win32냐 Xlib냐만 갈라지게 했다.
섹션 2에서 말한 "플랫폼마다 갈라지는 한 조각"이 바로 여기다.
검증은 이렇다.
cmake -S . -B .../Linux_Vulkan_Debug -G Ninja -DCMAKE_BUILD_TYPE=Debug ... configure 성공
cmake --build ... 빌드 성공
Binaries/Linux/x64/Debug 산출물:
CyphenEngine, CyphenRendererVulkan.so, TexturedQuad.vert/frag.spv
nm -D CyphenRendererVulkan.so | grep GetRendererModuleApi → export 확인
vulkaninfo --summary → Vulkan Instance 1.4.341, VK_KHR_xlib_surface 지원
Linux GUI 실행:
CoreIoTests PASS=69 FAIL=0
ModuleTests PASS=34 FAIL=0
→ .so 로드, Vulkan surface/swapchain/pipeline 초기화, 리소스 출력 정상
3번에서 Core IO 다음에 멈췄던 실행이, 이제 렌더러 모듈을 넘어 X11 창에 텍스처를 띄우며 끝까지 돌았다.
정리하며
이번 브랜치의 결론을 추리면 이렇다.
- WSL2 + X11 + Vulkan으로 Linux 개발 환경을 세웠다.
- Dx11이 Linux에 없으니, 테스트용 Vulkan 렌더러를 새 모듈 구현체로 만들었다. Vulkan SDK가 크로스플랫폼 표준이라 렌더러 속은 한 번만 쓰면 됐고, Windows에서 먼저 검증한 뒤 Dx11.dll ↔ Vulkan.dll 교체로 증명했다.
- 포팅해야 할 목록은 내가 뽑은 게 아니라 링커가 뽑아 줬다 — "Linux에서 컴파일된다"를 경계로 잡아 둔 값이다.
- Platform 하부 구현체를 Linux용으로 갈아 끼웠다 — POSIX fd, clock_gettime, dlopen, turbojpeg, X11 Launch. 같은 이름, 다른 속.
- export 매크로·Xlib surface·.so 산출물 규격 등 플랫폼 경계만 손봐 Linux 빌드를 완성했다.
- CoreIoTests 69/69, ModuleTests 34/34, Linux GUI에서 Vulkan 파이프라인 초기화 확인.
화면에 뜬 건 여전히 텍스처 몇 장이다.
하지만 이번엔 Windows가 아니라 Linux 위에서, DX11이 아니라 Vulkan으로 떴다.
그리고 그걸 위해 갈아 끼운 건 Platform 밑 구현체 몇 개와 테스트용 렌더러 하나뿐이었다.
포팅이 이 정도로 끝났다는 게,
#1·#2에서 판 바닥이 옳았다는 증거다.
세 브랜치로 잡았던 리팩토링 로드맵은 여기서 최소 목표에 닿았다.
다음은 이 위에 진짜 콘텐츠를 올릴 차례다.
다음 #4 브랜치에서는 2D 월드의 개장을 목표로 한다.
금방 돌아올수 있다면 좋겟네
'프로젝트 > CyphenEngine' 카테고리의 다른 글
| Transform 활용 방법에 대한 고민 (0) | 2026.07.16 |
|---|---|
| CyphenEngine 개발기 #5 Renderer 모듈화 : DirectX11로 이미지 렌더하기 (0) | 2026.07.03 |
| CyphenEngine 개발기 #4 엔진 구조 리팩토링 (0) | 2026.07.02 |
| 자체엔진 개발 중간 기록 : Dx11.dll -> Vulkan.dll 렌더러 모듈 교체 테스트 (0) | 2026.07.01 |
| 저장용 리눅스 명령어 (0) | 2026.06.29 |
