This post is from a low-reputation account and contains an unverified outbound link. Be cautious before clicking external links.
검색해서 발견한 것인데 표준 path의 위치에 libEGL과 libGLESv2들의 공유 object가 없어서 아래와 같이 symbolic link로 연결해 보았습니다.
cd /usr/lib/arm-linux-gnueabihf
sudo ln -s tegra-egl/libEGL.so.1 libEGL.so
sudo ln -s tegra-egl/libGLESv2.so.2 libGLESv2.so
표준적으로는 EGL과 GLES2의 header가 없기때문에, Khronos OpenGL ES Registry(http://www.khronos.org/registry/gles/ )로부터 다운로드 합니다. 다운로드 한 파일들은 바로 프로그램과 같은 장소에 디렉토리 구성이 있는 것처럼 배치했습니다.사용한 프로그램은 이렇습니다.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include "EGL/egl.h"
#include "GLES2/gl2.h"
#include <sys/time.h>
static Display* xdisp;
static Window window;
EGLDisplay eglDisplay;
EGLContext eglContext;
EGLSurface eglSurface;
static GLuint shaderProgram;
void initializeEGL();
void terminateEGL();
void mainloop();
GLuint createShaderProgram();
int main() {
xdisp = XOpenDisplay( NULL );
if( xdisp == NULL ) { return -1; }
Window rootWin = DefaultRootWindow( xdisp );
int screen = DefaultScreen( xdisp );
unsigned long white = WhitePixel( xdisp, screen );
unsigned long black = BlackPixel( xdisp, screen );
window = XCreateSimpleWindow( xdisp, rootWin, 100, 100, 640, 480, 2, black, white );
XSelectInput( xdisp, window, KeyPressMask|ButtonPressMask|UnmapNotify );
Atom atom, atom2;
atom = XInternAtom( xdisp, "WM_DELETE_WINDOW", False );
XSetWMProtocols( xdisp, window, &atom, 1 );
atom2 = XInternAtom( xdisp, "WM_PROTOCOLS", False );
XMapWindow( xdisp, window );
XFlush( xdisp );
initializeEGL();
shaderProgram = createShaderProgram();
XEvent evt;
bool isFinish = false;
int frameCount = 0;
timeval t0, t1;
gettimeofday( &t0, NULL );
const int countSecond = 5;
do {
while( XPending( xdisp ) ) {
XNextEvent( xdisp, &evt );
switch( evt.type ) {
case ClientMessage:
if( evt.xclient.message_type == atom2 && evt.xclient.data.l[0] == atom ) {
XFlush( xdisp );
isFinish = true;
}
break;
case KeyPress:
isFinish = true;
break;
}
}
mainloop();
frameCount++;
gettimeofday( &t1, NULL );
if( t1.tv_sec * 1000000 + t1.tv_usec - t0.tv_sec * 1000000 - t0.tv_usec > countSecond * 1000000 ) {
printf( "FPS: %.2f\n", frameCount / (float)countSecond );
gettimeofday( &t0, NULL );
frameCount = 0;
}
} while( !isFinish );
glDeleteProgram( shaderProgram );
terminateEGL();
XDestroyWindow( xdisp, window );
XCloseDisplay( xdisp );
return 0;
}
void initializeEGL() {
eglDisplay = eglGetDisplay( (EGLNativeDisplayType) xdisp );
if( eglDisplay == EGL_NO_DISPLAY ) {
fprintf( stderr, "NO EGL DISPLAY\n" );
return;
}
if( !eglInitialize( eglDisplay, NULL, NULL ) ) {
fprintf( stderr, "Unable to initialize EGL\n" );
return;
}
EGLint attr[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE,
};
EGLConfig cfg;
EGLint numConfigs = 0;
if( !eglChooseConfig( eglDisplay, attr, &cfg, 1, &numConfigs )) {
fprintf( stderr, "Failed to choose config.\n" );
return;
}
eglSurface =eglCreateWindowSurface( eglDisplay, cfg, window, NULL );
if( eglSurface == EGL_NO_SURFACE ) {
return;
}
EGLint ctxAttr[] = {
EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE,
};
eglContext = eglCreateContext( eglDisplay, cfg, EGL_NO_CONTEXT, ctxAttr );
if( eglContext == EGL_NO_CONTEXT ) {
fprintf( stderr, "Unable to create EGL context. (%d).\n", eglGetError() );
return;
}
eglMakeCurrent( eglDisplay, eglSurface, eglSurface, eglContext );
printf( "GL_RENDERER: %s\n", (char*)glGetString( GL_RENDERER ) );
printf( "GL_VENDOR: %s\n", (char*)glGetString( GL_VENDOR ) );
printf( "GL_VERSION: %s\n", (char*)glGetString( GL_VERSION ) );
printf( "EGL_VENDOR : %s\n", eglQueryString( eglDisplay, EGL_VENDOR ) );
printf( "EGL_VERSION: %s\n", eglQueryString( eglDisplay, EGL_VERSION ) );
printf( "EGL_CLIENT_APIS : %s\n", eglQueryString( eglDisplay, EGL_CLIENT_APIS ) );
eglSwapInterval( eglDisplay, 0 );
}
void terminateEGL() {
eglDestroyContext( eglDisplay, eglContext );
eglDestroySurface( eglDisplay, eglSurface );
eglTerminate( eglDisplay );
}
static GLchar srcVertexShader[] =
"attribute vec4 position0;\n"
"attribute vec4 color0;\n"
"varying vec4 vsout_color0;\n"
"uniform float theta;\n"
"void main() {\n"
" gl_Position = position0;\n"
" gl_Position.x = position0.x * cos(theta) - position0.y * sin(theta);\n"
" gl_Position.y = position0.x * sin(theta) + position0.y * cos(theta);\n"
" vsout_color0 = color0;\n"
"}";
static GLchar srcFragmentShader[] =
"precision mediump float;\n"
"varying vec4 vsout_color0;\n"
"void main() {\n"
" gl_FragColor = vsout_color0;\n"
"}";
void checkCompiled( GLuint shader ) {
GLint status;
glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
if( status != GL_TRUE ) {
GLint length;
glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &length );
if( length ) {
char* buf = (char*)malloc( length );
glGetShaderInfoLog( shader, length, NULL, buf );
fprintf( stderr, "CompiledLog: %s\n", buf );
free( buf );
}
exit( EXIT_FAILURE );
}
}
GLuint createShaderProgram() {
GLuint shaderVS = glCreateShader( GL_VERTEX_SHADER );
GLuint shaderFS = glCreateShader( GL_FRAGMENT_SHADER );
GLsizei length;
GLchar* vsSources[] = {
srcVertexShader,
};
GLchar* fsSources[] = {
srcFragmentShader,
};
glShaderSource( shaderVS, 1, (GLchar**) &vsSources, NULL );
glCompileShader( shaderVS );
checkCompiled( shaderVS );
glShaderSource( shaderFS, 1, (GLchar**) &fsSources, NULL );
glCompileShader( shaderFS );
checkCompiled( shaderFS );
GLuint program;
program = glCreateProgram();
glAttachShader( program, shaderVS );
glAttachShader( program, shaderFS );
glLinkProgram( program );
return program;
}
void mainloop() {
static unsigned int count = 0;
float v = sinf( count * 0.001f ) + 1;
v *= 0.5f;
glClearColor( 0.25f, 0.25f, v, 0.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUseProgram( shaderProgram );
GLint locPos = glGetAttribLocation( shaderProgram, "position0" );
GLint locColor = glGetAttribLocation( shaderProgram, "color0" );
float vertices[] = {
0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
};
GLint stride = sizeof(float)*7;
glVertexAttribPointer( locPos, 3, GL_FLOAT, false, stride, &vertices[0] );
glVertexAttribPointer( locColor, 4, GL_FLOAT, false, stride, &vertices[3] );
glEnableVertexAttribArray( locPos );
glEnableVertexAttribArray( locColor );
glUniform1f( glGetUniformLocation( shaderProgram, "theta" ), count*0.001f );
glDrawArrays( GL_TRIANGLES, 0, 3 );
eglSwapBuffers( eglDisplay, eglSurface );
count++;
}
이 프로그램을 실행하면 다음과 같이 됩니다.
GL_RENDERER: GK20A/AXIGL_VENDOR: NVIDIA CorporationGL_VERSION: OpenGL ES 3.0 19.3EGL_VENDOR : NVIDIAEGL_VERSION: 1.4EGL_CLIENT_APIS : OpenGL_ES OpenGLFPS: 262.60FPS: 177.60FPS: 155.40FPS: 167.00FPS: 169.40FPS: 257.00FPS: 269.20FPS: 177.00
이 버전에서는 이미 OpenGL ES 3.0의 Context로 되어 있는 것 같습니다.GLESv2의 라이브러리를 link해서, 프로그램 중에는 ES 2.0을 지정할 예정이었지만, 좀 이상한 상태입니다.