PHP FFI에서 GLFW를 통한 동적 OpenGL 로딩
PHP FFI 방식으로 OpenGL을 사용할 때, GLFW3 헤더 파일에서 상수와 typedef를 수동으로 복사하면 불필요한 보일러플레이트 코드가 많이 발생합니다. 우리는 #define 문을 PHP 상수로 변환하고, API 함수는 리소스 섹션에 그대로 삽입합니다.
변환 예시:
// glfw3.h
#define GLFW_VERSION_MAJOR 3
// glfw3.php
const GLFW_VERSION_MAJOR = 3;
// glfw3.h
GLFWAPI void glfwMakeContextCurrent(GLFWwindow* window);
// glfw3.php (in __halt_compiler())
void glfwMakeContextCurrent(GLFWwindow* window);
FFI 함수는 프록시 객체 메서드이자 포인터 역할을 동시에 수행합니다:
$glfwMakeContextCurrent = $glfw->glfwMakeContextCurrent;
$glfwMakeContextCurrent($window);
자동완성을 위한 절차적 스텁
타이핑과 IDE 지원을 위해 static 포인터 캐싱을 사용한 PHP 래퍼 함수를 생성합니다:
const GLFW_INSTANCE = FFI::cdef(...);
function glfwMakeContextCurrent(mixed ...$args): void {
static $function = GLFW_INSTANCE->glfwMakeContextCurrent;
$function(...$args);
}
이 접근 방식은 FFI 프록시 메서드 호출을 클로저로 대체하여 최소화합니다. 함수 주소가 정적이므로 성능이 유지됩니다.
대안(권장하지 않음):
- 첫 번째 인수로
$glfw전달 global $glfw사용
GLFW_INSTANCE 상수를 사용하면 메인 코드가 단순해집니다:
require 'src/glfw3.php';
if (!glfwInit()) exit(-1);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
$window = glfwCreateWindow(640, 480, 'Hello World', null, null);
opengl32.dll 없이 동적 OpenGL 로딩
OpenGL 함수는 플랫폼 의존적인 GetProcAddress 함수를 통해 동적으로 로드됩니다:
- Windows:
wglGetProcAddress - Linux:
glXGetProcAddressARB - Android:
eglGetProcAddress
GLFW는 이를 크로스 플랫폼 glfwGetProcAddress로 통합합니다:
function glClear(mixed ...$args): void {
static $function = GLFW_INSTANCE->cast(
'PFNGLCLEARPROC',
GLFW_INSTANCE->glfwGetProcAddress('glClear')
);
$function(...$args);
}
PFNGLCLEARPROC 같은 타입은 glcorearb.h에서 가져옵니다:
typedef void (*PFNGLCLEARPROC)(GLbitfield mask);
확장 지원(NV, AMD → ARB)은 동적으로 확인됩니다: 하드웨어가 사용 가능한 함수를 결정하고, 드라이버가 누락된 함수를 에뮬레이션합니다.
소스 코드에서 브리지 생성
glfw3.php(2만 줄 이상) 생성 자동화:
- ffi/preprocessor: C 헤더를 PHP 형식으로 변환, define 추출
- ffi/ide-helper-generator: 인수 타입이 포함된 스텁 생성
Ubuntu 24.04 호환성을 위해 GLFW 3.3을 선택했습니다. OpenGL 상수와 함수는 단일 파일로 통합되었으며, opengl.php는 제거되었습니다.
장점:
ext-glfw와 완전 호환- 수동 조정 없이 크로스 플랫폼 지원
- 컴파일 없이 자동완성 및 타이핑 지원
핵심 포인트
- GLFW_INSTANCE 글로벌 상수는 전역 변수 없이 빠른 FFI 접근 제공
- *PFNGLPROC** 타입(glcorearb.h)은 수동 시그니처 지정 없이 캐스팅 단순화
- glfwGetProcAddress가 플랫폼별(WGL/GLX/EGL) 복잡성 대체
- 소스에서 생성으로 2만 줄 이상의 코드 최신 상태 보장
- 성능: 정적 캐시로 FFI 메서드 오버헤드 최소화
다음 파트에서 버퍼와 셰이더로 삼각형을 그릴 준비가 완료되었습니다.
— Editorial Team
아직 댓글이 없습니다.