commit 81b612465e0e82689b466f7e56d6c93cb5a988dd Author: Uziel Date: Sun Sep 29 09:19:42 2024 +0000 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e524d79 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.vscode/ +build/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d5bff15 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,111 @@ +SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON) + +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +#项目名称 +PROJECT(Triangle-ES2) + +#dubug 模式-----------------------it's very import for Debug +set(CMAKE_BUILD_TYPE "Debug") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -fPIC -pipe -g -O0 -Wall -W -D_REENTRANT -D__VXWORKS__") + +#编译宏定义 +#ADD_DEFINITIONS(-D_MWV207_OS_=106) +#ADD_DEFINITIONS(-DXORG_SHOW=1) + +# 添加头文件 +include_directories( + "/usr/local/include" +) + +# 设置第三方库的查找目录,LINUX必须放在前面,后面会找不到,原因未知 +link_directories( + "/usr/lib" + "/usr/local/lib" + #"/usr/lib/mali-g5x/" + ) + + + +# 增加头文件库 +#include_directories( "/usr/lib/gcc/aarch64-linux-gnu/9/include" ) + +# 查找指定目录下的所有*.h头文件,并将文件列表保存到指定变量 +#file(GLOB_RECURSE JPG_Include "./jpgLib_prj/src/*.h") +# 查找指定目录下的所有*.c源文件,并将文件列表保存到指定变量 +#file(GLOB_RECURSE JPG_SRC "./jpgLib_prj/src/*.c") + +# 添加指定目录下的所有头文件和源文件,并将文件列表保存到指定变量 + +set(Triangle_SRC src/triangle-es2.c) + + + + +# 将指定目录下的头文件和源文件放到指定目录下 +source_group("src" FILES ${Triangle_SRC}) + + +# 编译成可执行文件 +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/build/bin) + +add_executable(TriangleEsDemo ${Triangle_SRC}) + +# 查找对应的第三方库 +#find_library(OPENGL_LIBRARY GL "OpenGL library") +#find_library(GLU_LIBRARY GLU "GLU library" ) + +set(DEP_LIBS + dl + gbm + m + pthread + EGL + GLESv2 + GL + OpenGL + #X11 +) + +# 链接第三方库和自己工程生成的库 +target_link_libraries(TriangleEsDemo + ${DEP_LIBS} + ) + + +add_executable(SimpleEs src/simple-es2.c) + +# 查找对应的第三方库 +#find_library(OPENGL_LIBRARY GL "OpenGL library") +#find_library(GLU_LIBRARY GLU "GLU library" ) + + +# 链接第三方库和自己工程生成的库 +target_link_libraries(SimpleEs + ${DEP_LIBS} + ) + + +add_executable(color_test src/color_test.c) + +target_link_libraries(color_test + dl + ) + +# # demo +# add_executable(demo src/demo.cpp) + +# # 链接第三方库和自己工程生成的库 +# target_link_libraries(demo +# -Wl,--start-group +# #stdc++ +# glut +# dl +# m +# pthread +# X11 +# EGL +# GLESv2 +# OpenGL +# GL +# -Wl,--end-group) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a4da8ac --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ + +compile: build + cmake --build build + +build: + mkdir build + cmake -B build + +t: compile + sudo ./build/bin/SimpleEs \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d677381 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ + + +使用gbm实现opengles在drm上画图。 + +| Syntax | Description | +| ----------- | ----------- | +| color_test.c | 直接刷写fb的像素值 | +| simple-es2.c | 使用GBM + pbuffer离屏渲染,并写入文件 | +| triangle-es2.c | 使用GBM + surface渲染opengles到屏幕 | + +依赖 + +libgbm-dev, libopengles-dev \ No newline at end of file diff --git a/src/color_test.c b/src/color_test.c new file mode 100644 index 0000000..63e9706 --- /dev/null +++ b/src/color_test.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned int color_t; /* 根据实际情况修改,此处为unsigned short是565的屏 */ + +static struct fb_var_screeninfo __g_vinfo; /* 显示信息 */ +static void *__gp_frame; /* 虚拟屏幕首地址 */ + +int framebuffer_init(void) { + int fd = 0; + fd = open("/dev/fb0", O_RDWR); + if (fd == -1) { + perror("fail to open /dev/fb0\n"); + return -1; + } + + ioctl(fd, FBIOGET_VSCREENINFO, &__g_vinfo); /* 获取显示信息 */ + printf("bits_per_pixel = %d\n", __g_vinfo.bits_per_pixel); /* 一个像素点对应的位数,如果值为16则为565格式输出,如果值为32则为888格式输出 */ + printf("xres_virtual = %d\n", __g_vinfo.xres_virtual); /* 虚拟x轴像素点数 */ + printf("yres_virtual = %d\n", __g_vinfo.yres_virtual); /* 虚拟y轴像素点数 */ + printf("xres = %d\n", __g_vinfo.xres); /* x轴像素点数 */ + printf("yres = %d\n", __g_vinfo.yres); /* y轴像素点数 */ + + __gp_frame = mmap(NULL, /* 映射区的开始地址,为NULL表示由系统决定映射区的起始地址 */ + __g_vinfo.xres_virtual * __g_vinfo.yres_virtual + * __g_vinfo.bits_per_pixel / 8, /* 映射区大小 */ + PROT_WRITE | PROT_READ, /* 内存保护标志(可读可写) */ + MAP_SHARED, /* 映射对象类型(与其他进程共享) */ + fd, /* 有效的文件描述符 */ + 0); /* 被映射内容的偏移量 */ + if (__gp_frame == NULL) { + perror("fail to mmap\n"); + return -1; + } + return 0; +} + +#define BYTE(data, loc) (((data)>> (loc*8))&0xFF) + +void full_screen(color_t color) { + printf("test write fb: 0x%08x\n", color); + + int i; + int bpp = __g_vinfo.bits_per_pixel / 8; + unsigned char *p = __gp_frame; + + for (i = 0; i < __g_vinfo.xres_virtual * __g_vinfo.yres_virtual; i++) { + + for (size_t j = 0; j < bpp; j++) + { + p[j] = BYTE(color, j); + } + + p += bpp; + } +} + +int main() { + if (framebuffer_init()) { + return -1; + } + + while (1) { + // full_screen(0x001F); + // sleep(2); + // full_screen(0x07E0); + // sleep(2); + // full_screen(0xF800); + // sleep(2); + full_screen(0x0000FF); + sleep(2); + full_screen(0x00FF00); + sleep(2); + full_screen(0xFF0000); + sleep(2); + full_screen(0x00); + sleep(2); + full_screen(0xFFFFFF); + sleep(2); + } + return 0; +} \ No newline at end of file diff --git a/src/demo.cpp b/src/demo.cpp new file mode 100644 index 0000000..2914bd5 --- /dev/null +++ b/src/demo.cpp @@ -0,0 +1,175 @@ +#include +#include +#include +#include +#include + +// Shader sources +const GLchar* vertexSource = + "attribute vec4 position; \n" + "void main() \n" + "{ \n" + " gl_Position = position; \n" + "} \n"; + +const GLchar* fragmentSource = + "void main() \n" + "{ \n" + " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); \n" + "} \n"; + +void checkGLError(const char* stmt, const char* fname, int line) { + GLenum err = glGetError(); + if (err != GL_NO_ERROR) { + fprintf(stderr, "OpenGL error %08x, at %s:%i - for %s\n", err, fname, line, stmt); + exit(1); + } +} + +#define GL_CHECK(stmt) do { \ + stmt; \ + checkGLError(#stmt, __FILE__, __LINE__); \ + } while (0) + +typedef EGLDisplay (*PFNEGLGETPLATFORMDISPLAYEXTPROC)(EGLenum, void*, const EGLint*); + +int main() { + // 1. Initialize EGL + EGLDisplay display; + EGLConfig config; + EGLContext context; + EGLint numConfigs; + EGLint configAttribs[] = { + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_BLUE_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_RED_SIZE, 8, + EGL_DEPTH_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE + }; + + // Get function pointer to eglGetPlatformDisplayEXT + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = + (PFNEGLGETPLATFORMDISPLAYEXTPROC) eglGetProcAddress("eglGetPlatformDisplayEXT"); + + if (!eglGetPlatformDisplayEXT) { + fprintf(stderr, "Error: eglGetPlatformDisplayEXT() not found.\n"); + return 1; + } + + // Use surfaceless platform + display = eglGetPlatformDisplayEXT(EGL_PLATFORM_SURFACELESS_MESA, EGL_DEFAULT_DISPLAY, NULL); + if (display == EGL_NO_DISPLAY) { + fprintf(stderr, "Error: eglGetPlatformDisplayEXT() failed.\n"); + return 1; + } + + if (!eglInitialize(display, NULL, NULL)) { + fprintf(stderr, "Error: eglInitialize() failed.\n"); + return 1; + } + + if (!eglChooseConfig(display, configAttribs, &config, 1, &numConfigs)) { + fprintf(stderr, "Error: eglChooseConfig() failed.\n"); + return 1; + } + + EGLint contextAttribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); + if (context == EGL_NO_CONTEXT) { + fprintf(stderr, "Error: eglCreateContext() failed.\n"); + return 1; + } + + if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, context)) { + fprintf(stderr, "Error: eglMakeCurrent() failed.\n"); + return 1; + } + + // 2. Create and compile shaders + GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); + GL_CHECK(glShaderSource(vertexShader, 1, &vertexSource, NULL)); + GL_CHECK(glCompileShader(vertexShader)); + + GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + GL_CHECK(glShaderSource(fragmentShader, 1, &fragmentSource, NULL)); + GL_CHECK(glCompileShader(fragmentShader)); + + // 3. Link shaders to create a program + GLuint shaderProgram = glCreateProgram(); + GL_CHECK(glAttachShader(shaderProgram, vertexShader)); + GL_CHECK(glAttachShader(shaderProgram, fragmentShader)); + GL_CHECK(glLinkProgram(shaderProgram)); + GL_CHECK(glUseProgram(shaderProgram)); + + // 4. Define vertices for a triangle + GLfloat vertices[] = { + 0.0f, 0.5f, + -0.5f, -0.5f, + 0.5f, -0.5f, + }; + + GLuint VBO; + GL_CHECK(glGenBuffers(1, &VBO)); + + GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, VBO)); + GL_CHECK(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW)); + + GLint posAttrib = glGetAttribLocation(shaderProgram, "position"); + GL_CHECK(glEnableVertexAttribArray(posAttrib)); + GL_CHECK(glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0)); + + // 5. Create FBO + GLuint fbo, texture; + GL_CHECK(glGenFramebuffers(1, &fbo)); + GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, fbo)); + + GL_CHECK(glGenTextures(1, &texture)); + GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture)); + GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL)); + GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); + GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); + + GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0)); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + fprintf(stderr, "Error: Framebuffer is not complete.\n"); + return 1; + } + + // 6. Render to the FBO + GL_CHECK(glViewport(0, 0, 800, 600)); + GL_CHECK(glClearColor(0.0, 0.0, 1.0, 1.0)); + GL_CHECK(glClear(GL_COLOR_BUFFER_BIT)); + + GL_CHECK(glDrawArrays(GL_TRIANGLES, 0, 3)); + + // 7. Read pixels from the FBO + GLubyte *pixels = (GLubyte *)malloc(800 * 600 * 3); + GL_CHECK(glReadPixels(0, 0, 800, 600, GL_RGB, GL_UNSIGNED_BYTE, pixels)); + + // 8. Clean up + GL_CHECK(glDeleteFramebuffers(1, &fbo)); + GL_CHECK(glDeleteTextures(1, &texture)); + GL_CHECK(glDeleteProgram(shaderProgram)); + GL_CHECK(glDeleteShader(vertexShader)); + GL_CHECK(glDeleteShader(fragmentShader)); + GL_CHECK(glDeleteBuffers(1, &VBO)); + + eglDestroyContext(display, context); + eglTerminate(display); + + // Use `pixels` as needed + // For example, save it to a file, process it, etc. + // Don't forget to free the memory once done + free(pixels); + + printf("Rendering completed successfully.\n"); + + return 0; +} + diff --git a/src/simple-es2.c b/src/simple-es2.c new file mode 100644 index 0000000..43fedf1 --- /dev/null +++ b/src/simple-es2.c @@ -0,0 +1,519 @@ +/* + * This code was created by Jeff Molofee '99 + * (ported to Linux by Ti Leggett '01) + * (ported to i.mx51, i.mx31 and x11 by Freescale '10) + * If you've found this code useful, please let him know. + * + * Visit Jeff at http://nehe.gamedev.net/ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "GLES2/gl2.h" +#include "GLES2/gl2ext.h" +#include "GL/gl.h" + +#include "EGL/egl.h" +#include + +// #include +// #include +#include + +int device; +struct gbm_device *gbmDevice; +struct gbm_surface *gbmSurface; + +EGLDisplay egldisplay; +EGLConfig eglconfig; +EGLSurface eglsurface; +EGLContext eglcontext; + + +GLuint framebuffer; +GLuint renderbuffer; + +// 定义纹理对象的标识符 +GLuint texId; + + +GLuint g_hShaderProgram = 0; +GLuint g_hModelViewMatrixLoc = 0; +GLuint g_hProjMatrixLoc = 0; +GLuint g_hVertexLoc = 0; +GLuint g_hColorLoc = 1; + +#define ASSERT_EQ(exp1, exp2) do { auto e1 = (exp1);auto e2 = (exp2);\ + if((e1) != (e2)) { \ + printf("assert value: %p, %p\n", e1, e2); \ + __assert_fail (#exp1 "==" #exp2, __FILE__, __LINE__, __ASSERT_FUNCTION); \ +}}while(0) + +#define CHECK_NULL(exp1) do { auto e1 = (exp1);\ + if(!(e1)) { \ + printf("check " #exp1 " is %p\n", e1); \ +}}while(0) + +//-------------------------------------------------------------------------------------- +// Name: g_strVertexShader / g_strFragmentShader +// Desc: The vertex and fragment shader programs +//-------------------------------------------------------------------------------------- +const char* g_strVertexShader = +"uniform mat4 g_matModelView; \n" +"uniform mat4 g_matProj; \n" +" \n" +"attribute vec4 g_vPosition; \n" +"attribute vec3 g_vColor; \n" +" \n" +"varying vec3 g_vVSColor; \n" +" \n" +"void main() \n" +"{ \n" +" vec4 vPositionES = g_matModelView * g_vPosition; \n" +" gl_Position = g_matProj * vPositionES; \n" +" g_vVSColor = g_vColor; \n" +"} \n"; + + +const char* g_strFragmentShader = +"#ifdef GL_FRAGMENT_PRECISION_HIGH \n" +" precision highp float; \n" +"#else \n" +" precision mediump float; \n" +"#endif \n" +" \n" +"varying vec3 g_vVSColor; \n" +" \n" +"void main() \n" +"{ \n" +" gl_FragColor = vec4( g_vVSColor, 1.0 ); \n" +"} \n"; + + +float matModelView[16] = {0}; +float matProj[16] = {0}; + +// Define vertice for a 4-sided pyramid +float VertexPositions[] = +{ + 0.0f,1.0f, 0.0f, + -1.0f,-1.0f, 0.0f, + +1.0f,-1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + -1.0f,1.0f, 0.0f, + 1.0f, -1.0, 0.0f +}; + +void render(float w, float h) +{ + + // Clear the colorbuffer and depth-buffer + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + glViewport(0, 0, w, h); +#if 1 + // Build a perspective projection matrix + matProj[ 0] = cosf( 0.5f ) / sinf( 0.5f ); + matProj[ 5] = matProj[0] * (w/h) ; + matProj[10] = -( 10.0f ) / ( 9.0f ); + matProj[11] = -1.0f; + matProj[14] = -( 10.0f ) / ( 9.0f ); + + glViewport(0, 0, w, h); + + // Rotate and translate the model view matrix + matModelView[ 0] = 1.0; + matModelView[ 2] = 0.0f; + matModelView[ 5] = 1.0f; + matModelView[ 8] = 0.0f; + matModelView[10] = 0.0f; + matModelView[14] = -4.0f;//translation Z + matModelView[15] = 1.0f; + + glUniformMatrix4fv( g_hModelViewMatrixLoc, 1, 0, matModelView ); + glUniformMatrix4fv( g_hProjMatrixLoc, 1, 0, matProj ); + + // Bind the vertex attributes + glVertexAttribPointer( g_hVertexLoc, 3, GL_FLOAT, 0, 0, VertexPositions ); + glEnableVertexAttribArray( g_hVertexLoc ); + + glDrawArrays( GL_TRIANGLES, 0, 3 ); + + // Cleanup + glDisableVertexAttribArray( g_hVertexLoc ); +#endif +} + +static int matchConfigToVisual(EGLDisplay display, EGLint visualId, EGLConfig* configs, int count) +{ + EGLint id; + EGLint suf_type; + for (int i = 0; i < count; ++i) + { + eglGetConfigAttrib(display, configs[i], EGL_SURFACE_TYPE, &suf_type); + printf("suf_type: 0x%x\n", suf_type); + if (!eglGetConfigAttrib(display, configs[i], EGL_NATIVE_VISUAL_ID, &id)) + continue; + if (id == visualId) + return i; + } + return -1; +} + + +EGLDisplay gbm_init(const char* devicePath) { + device = open(devicePath, O_RDWR | O_CLOEXEC); + gbmDevice = gbm_create_device(device); + CHECK_NULL(gbmDevice); + // gbmSurface = gbm_surface_create(gbmDevice, 600, 800, GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + // CHECK_NULL(gbmSurface); + + return eglGetDisplay(gbmDevice); +} +void fbo_test() { + + + int width = 800; + int height = 600; + + // 创建并绑定帧缓冲对象 + glGenFramebuffers(1, &framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + + // 创建并绑定渲染缓冲对象用于深度和模板信息 + glGenRenderbuffers(1, &renderbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); + + // 分配存储空间 + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); + + // 将渲染缓冲对象附着到帧缓冲的深度和模板附着点 + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer); + + // 创建并绑定纹理对象用于颜色附着点 + glGenTextures(1, &texId); + glBindTexture(GL_TEXTURE_2D, texId); + + // 分配存储空间 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + // 设置纹理参数 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // automatic mipmap generation included in OpenGL v1.4 + + // 将纹理对象附着到帧缓冲的颜色附着点 + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0); + + // 检查 FBO 完整性 + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + // 处理错误 + printf("glCheckFramebufferStatus2 error : 0x%x\n", status); + } + + + // glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); +} + +int init(void) +{ + // if ((egldisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY) + // { + // fprintf(stderr, "Failed to get EGL display! \n"); + // // return EXIT_FAILURE; + // } + + egldisplay = gbm_init("/dev/dri/card0"); + + int major=-1, minor=-1; + eglInitialize(egldisplay, &major, &minor); + printf("Initialized EGL version: %d.%d\n", major, minor); + ASSERT_EQ(eglGetError(), EGL_SUCCESS); + eglBindAPI(EGL_OPENGL_ES_API); + + EGLint count = 0; + EGLint numConfigs = 0; + eglGetConfigs(egldisplay, NULL, 0, &count); + EGLConfig* configs = malloc(count * sizeof(configs)); + + static const EGLint configAttribs[] = { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, + // EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_NONE + }; + + if (!eglChooseConfig(egldisplay, configAttribs, configs, count, &numConfigs)) + { + fprintf(stderr, "Failed to get EGL configs! Error: 0x%x\n", eglGetError()); + eglTerminate(egldisplay); + return EXIT_FAILURE; + } + + + int configIndex = matchConfigToVisual(egldisplay, GBM_FORMAT_XRGB8888, configs, numConfigs); + if (configIndex < 0) + { + fprintf(stderr, "Failed to find matching EGL config! Error: 0x%x\n", eglGetError()); + eglTerminate(egldisplay); + gbm_device_destroy(gbmDevice); + return EXIT_FAILURE; + } + + printf("configIndex: %d, numConfigs: %d\n", configIndex, numConfigs); + + static const EGLint contextAttribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 3, + EGL_NONE }; + + EGLContext context = eglCreateContext(egldisplay, configs[configIndex], EGL_NO_CONTEXT, contextAttribs); + if (context == EGL_NO_CONTEXT) + { + fprintf(stderr, "Failed to create EGL context! Error: 0x%x\n", eglGetError()); + eglTerminate(egldisplay); + gbm_device_destroy(gbmDevice); + return EXIT_FAILURE; + } + + // No rendering, no surface, just compute + // static EGLint attribList[] = { + // EGL_RENDER_BUFFER, EGL_BACK_BUFFER, + // EGL_WIDTH, 300, + // EGL_HEIGHT, 300, + // EGL_NONE}; + // eglsurface = eglCreateWindowSurface(egldisplay, configs[configIndex], (EGLNativeWindowType)(0), NULL); + // auto ret = eglGetError(); + // printf("eglCreateWindowSurface: result: 0x%x\n", ret); + // if(eglsurface == EGL_NO_SURFACE) + // { + // switch(ret) + // { + // case EGL_BAD_ALLOC: + // // Not enough resources available. Handle and recover + // printf("BgRender::CreateGlesEnv Not enough resources available\n"); + // break; + // case EGL_BAD_CONFIG: + // // Verify that provided EGLConfig is valid + // printf("BgRender::CreateGlesEnv provided EGLConfig is invalid\n"); + // break; + // case EGL_BAD_PARAMETER: + // // Verify that the EGL_WIDTH and EGL_HEIGHT are + // // non-negative values + // printf("BgRender::CreateGlesEnv provided EGL_WIDTH and EGL_HEIGHT is invalid\n"); + // break; + // case EGL_BAD_MATCH: + // // Check window and EGLConfig attributes to determine + // // compatibility and pbuffer-texture parameters + // printf("BgRender::CreateGlesEnv Check window and EGLConfig attributes\n"); + // break; + // } + // } + + // free(configs); + eglsurface = EGL_NO_SURFACE; + eglMakeCurrent(egldisplay, eglsurface, eglsurface, context); + + + { + //1、查看显卡、GLSL和OpenGL的信息 + printf("OpenGL information:\n"); + printf(" version: \"%s\"\n", glGetString(GL_VERSION)); + printf(" shading language version: \"%s\"\n", glGetString(GL_SHADING_LANGUAGE_VERSION)); + printf(" vendor: \"%s\"\n", glGetString(GL_VENDOR)); + printf(" renderer: \"%s\"\n", glGetString(GL_RENDERER)); + // printf(" extensions: \"%s\"\n", glGetString(GL_EXTENSIONS)); + printf("===================================\n"); + + // Compile the shaders + GLuint hVertexShader = glCreateShader( GL_VERTEX_SHADER ); + glShaderSource( hVertexShader, 1, &g_strVertexShader, NULL ); + glCompileShader( hVertexShader ); + + // Check for compile success + GLint nCompileResult = 0; + glGetShaderiv( hVertexShader, GL_COMPILE_STATUS, &nCompileResult ); + printf("compile opengl shader result: %d\n", nCompileResult); + if( 0 == nCompileResult ) + { + char strLog[1024] = {0}; + GLint nLength; + glGetShaderInfoLog( hVertexShader, 1024, &nLength, strLog ); + printf("compile opengl shader failed: %s\n", strLog); + return 0; + } + + GLuint hFragmentShader = glCreateShader( GL_FRAGMENT_SHADER ); + glShaderSource( hFragmentShader, 1, &g_strFragmentShader, NULL ); + glCompileShader( hFragmentShader ); + + // Check for compile success + glGetShaderiv( hFragmentShader, GL_COMPILE_STATUS, &nCompileResult ); + if( 0 == nCompileResult ) + { + char strLog[1024]; + GLint nLength; + glGetShaderInfoLog( hFragmentShader, 1024, &nLength, strLog ); + return 0; + } + + // Attach the individual shaders to the common shader program + g_hShaderProgram = glCreateProgram(); + glAttachShader( g_hShaderProgram, hVertexShader ); + glAttachShader( g_hShaderProgram, hFragmentShader ); + + // Init attributes BEFORE linking + glBindAttribLocation( g_hShaderProgram, g_hVertexLoc, "g_vPosition" ); + + // Link the vertex shader and fragment shader together + glLinkProgram( g_hShaderProgram ); + + // Check for link success + GLint nLinkResult = 0; + glGetProgramiv( g_hShaderProgram, GL_LINK_STATUS, &nLinkResult ); + if( 0 == nLinkResult ) + { + char strLog[1024]; + GLint nLength; + glGetProgramInfoLog( g_hShaderProgram, 1024, &nLength, strLog ); + return 0; + } + + // Get uniform locations + g_hModelViewMatrixLoc = glGetUniformLocation( g_hShaderProgram, "g_matModelView" ); + g_hProjMatrixLoc = glGetUniformLocation( g_hShaderProgram, "g_matProj" ); + + glDeleteShader( hVertexShader ); + glDeleteShader( hFragmentShader ); + + // Set the shader program + glUseProgram( g_hShaderProgram ); + + // Clear the colorbuffer and depth-buffer + glClearColor( 0.0f, 0.0f, 0.5f, 1.0f ); + + // Set some state + glEnable( GL_DEPTH_TEST ); + + } + + return 0; +} + +void Cleanup() +{ + +} + +void resize(int w, int h) +{ + // Build a perspective projection matrix + matProj[ 0] = cosf( 0.5f ) / sinf( 0.5f ); + matProj[ 5] = matProj[0] * (w/h) ; + matProj[10] = -( 10.0f ) / ( 9.0f ); + matProj[11] = -1.0f; + matProj[14] = -( 10.0f ) / ( 9.0f ); + + glViewport(0, 0, w, h); +} + +void deinit(void) +{ + printf("Cleaning up...\n"); + eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + assert(eglGetError() == EGL_SUCCESS); + eglDestroyContext(egldisplay, eglcontext); + eglDestroySurface(egldisplay, eglsurface); + eglTerminate(egldisplay); + assert(eglGetError() == EGL_SUCCESS); + eglReleaseThread(); +} + +// int event_handle(void* arg) { +// printf("start event loop\n"); + +// while (1) { +// XEvent xevent; +// // XWindowEvent(x_display, win, StructureNotifyMask, &xevent); +// XNextEvent(x_display, &xevent); +// if (xevent.type == DestroyNotify) { +// printf("DestroyNotify \n"); +// break; +// } +// } +// return 0; +// } + +void handle_sig(int sig) { + printf("recieve sig: %d\n", sig); +} + +void init_signal() { + signal(SIGUSR1, handle_sig); + signal(SIGUSR2, handle_sig); + signal(37, handle_sig); +} + +void writeToFile(const char* filename, unsigned char* data, long dataLen) { + FILE* file = fopen(filename, "wb"); + if (file) { + fwrite(data, 1, dataLen, file); + fclose(file); + } +} + +int main (void) +{ + EGLint width = 800; + EGLint height = 600; + + // init_signal(); + init(); + + // eglQuerySurface(egldisplay, eglsurface, EGL_WIDTH, &width); + // eglQuerySurface(egldisplay, eglsurface, EGL_HEIGHT, &height); + + printf("w=%d h=%d\n",width,height); + + // thrd_t thr; + // thrd_create(&thr, event_handle, NULL); + + unsigned char* buffer = (unsigned char*)malloc(width * height * 4); + fbo_test(); + while (1) { + + glBindTexture(GL_TEXTURE_2D, texId); + glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + + // glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + render(width,height); + // glBindFramebuffer(GL_FRAMEBUFFER, 0); + printf("glReadPixels start \n"); + glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer); + glReadPixels( 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + printf("glReadPixels end \n"); + writeToFile("image.rgba", buffer, width * height * 4); + // eglSwapBuffers(egldisplay, eglsurface); + sleep(1); + } + + free(buffer); + deinit(); + + return 0; +} diff --git a/src/triangle-es2.c b/src/triangle-es2.c new file mode 100644 index 0000000..b220e02 --- /dev/null +++ b/src/triangle-es2.c @@ -0,0 +1,674 @@ +/* + * This code was created by Jeff Molofee '99 + * (ported to Linux by Ti Leggett '01) + * (ported to i.mx51, i.mx31 and x11 by Freescale '10) + * If you've found this code useful, please let him know. + * + * Visit Jeff at http://nehe.gamedev.net/ + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "GLES2/gl2.h" +#include "GLES2/gl2ext.h" + +#include "EGL/egl.h" + +// #define XORG_SHOW + +#include + +#ifdef XORG_SHOW +#include "X11/X.h" +#include "X11/Xatom.h" +#else +#include +#endif + +Display *x_display; +Window win; + +int device; +struct gbm_device *gbmDevice; +struct gbm_surface *gbmSurface; +struct gbm_bo * gbmBo; + +int fb_id; +int dumb_handle; + +int g_stop; + +#ifdef XORG_SHOW +#define USE_FORMAT 0x34325258 +#else +#define USE_GBM_FORMAT GBM_FORMAT_XRGB8888 +#define USE_FORMAT USE_GBM_FORMAT +#endif + +EGLDisplay egldisplay; +EGLConfig eglconfig; +EGLSurface eglsurface; +EGLContext eglcontext; + + +GLuint g_hShaderProgram = 0; +GLuint g_hModelViewMatrixLoc = 0; +GLuint g_hProjMatrixLoc = 0; +GLuint g_hVertexLoc = 0; +GLuint g_hColorLoc = 1; +GLuint g_hVColor = 0; + +#define ASSERT_EQ(exp1, exp2) do { auto e1 = (exp1);auto e2 = (exp2);\ + if((e1) != (e2)) { \ + printf("assert value: %p, %p\n", e1, e2); \ + __assert_fail (#exp1 "==" #exp2, __FILE__, __LINE__, __ASSERT_FUNCTION); \ +}}while(0) + + +//-------------------------------------------------------------------------------------- +// Name: g_strVertexShader / g_strFragmentShader +// Desc: The vertex and fragment shader programs +//-------------------------------------------------------------------------------------- +const char* g_strVertexShader = +"uniform mat4 g_matModelView; \n" +"uniform mat4 g_matProj; \n" +" \n" +"attribute vec4 g_vPosition; \n" +"attribute vec3 g_vColor; \n" +" \n" +"varying vec3 g_vVSColor; \n" +" \n" +"void main() \n" +"{ \n" +" vec4 vPositionES = g_matModelView * g_vPosition; \n" +" gl_Position = g_matProj * vPositionES; \n" +" g_vVSColor = g_vColor; \n" +"} \n"; + + +const char* g_strFragmentShader = +"#ifdef GL_FRAGMENT_PRECISION_HIGH \n" +" precision highp float; \n" +"#else \n" +" precision mediump float; \n" +"#endif \n" +" \n" +"varying vec3 g_vVSColor; \n" +" \n" +"void main() \n" +"{ \n" +" gl_FragColor = vec4( g_vVSColor, 1.0 ); \n" +"} \n"; + + +float matModelView[16] = {0}; +float matProj[16] = {0}; +float color[4] = {0, 0, 0, 0}; + +// Define vertice for a 4-sided pyramid +float VertexPositions[] = +{ + 0.0f,1.0f, 0.0f, + -1.0f,-1.0f, 0.0f, + +1.0f,-1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + -1.0f,1.0f, 0.0f, + 1.0f, -1.0, 0.0f +}; + +void render(float w, float h, unsigned int framenum) +{ + + // Clear the colorbuffer and depth-buffer + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + glViewport(0, 0, w, h); +#if 1 + // Build a perspective projection matrix + matProj[ 0] = cosf( 0.5f ) / sinf( 0.5f ); + matProj[ 5] = matProj[0] * (w/h) ; + matProj[10] = -( 10.0f ) / ( 9.0f ); + matProj[11] = -1.0f; + matProj[14] = -( 10.0f ) / ( 9.0f ); + + glViewport(0, 0, w, h); + + float zTransDelta = sinf((framenum%200) /200.0 * M_PI); + + // Rotate and translate the model view matrix + matModelView[ 0] = 1.0f; + matModelView[ 2] = 0.1f; + matModelView[ 5] = 1.0f; + matModelView[ 8] = 0.0f; + matModelView[10] = 0.0f; + matModelView[14] = -5.0f + zTransDelta;//translation Z + matModelView[15] = 1.0f; + + color[0] = sinf(((framenum%400) /400.0) * M_PI); + // color[1] = sinf(((framenum%300) /300.0) * M_PI); + // color[2] = sinf(((framenum%200) /200.0) * M_PI); + // color[3] = sinf((framenum%500) /500.0 * M_PI); + + glUniformMatrix4fv( g_hModelViewMatrixLoc, 1, 0, matModelView ); + glUniformMatrix4fv( g_hProjMatrixLoc, 1, 0, matProj ); + glVertexAttrib4fv(g_hVColor, color); + + // Bind the vertex attributes + glVertexAttribPointer( g_hVertexLoc, 3, GL_FLOAT, 0, 0, VertexPositions ); + glEnableVertexAttribArray( g_hVertexLoc ); + + glDrawArrays( GL_TRIANGLES, 0, 3 ); + + // Cleanup + glDisableVertexAttribArray( g_hVertexLoc ); +#endif +} + +#ifndef XORG_SHOW + +#define drm_ioctl(fd, _IOCTL_NAME, ...) \ + { int __ret; \ + __ret=ioctl(fd, _IOCTL_NAME, __VA_ARGS__);\ + if (__ret) { \ + printf( "ioctl:" #_IOCTL_NAME " failed:%d\n", __ret); \ + return __ret;\ + }} + +#define memzero(_p) (memset((_p), 0, sizeof(*(_p)))) + +static int mode_get_cap(int fd, int cap) { + struct drm_get_cap get_cap; + get_cap.capability = cap; + drm_ioctl(fd, DRM_IOCTL_GET_CAP, &get_cap); + + return get_cap.value; +} + +int modeset_import_fd(int dumb, int fd) { + struct drm_prime_handle prime_handle; + memzero(&prime_handle); + prime_handle.handle = dumb_handle; + // prime_handle.fd = fd; + prime_handle.flags = DRM_RDWR; + drm_ioctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime_handle); + printf("prime_handle : %d, newfd:%d flags:%x\n", prime_handle.fd, prime_handle.handle, prime_handle.flags); + + return prime_handle.fd; +} + +int modeset_fd(int fd) { + int width = 1280; + int height = 1024; + int bpp = 32; + + int buffer_v = mode_get_cap(fd, DRM_CAP_DUMB_BUFFER); + printf("buffer_v :0x%x\n", buffer_v); + + int prime_v = mode_get_cap(fd, DRM_CAP_PRIME); + printf("prime_v :0x%x\n", prime_v); + + + // struct drm_mode_create_dumb create_dumb; + // memzero(&create_dumb); + // create_dumb.width = width; + // create_dumb.height = height; + // create_dumb.bpp = bpp; + // create_dumb.pitch = width * bpp/8; + // create_dumb.size = create_dumb.pitch * height; + // drm_ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb); + // dumb_handle = create_dumb.handle; + // printf("create_dumb handle:0x%x\n", dumb_handle); + + + // struct drm_mode_map_dumb map_dumb; + // map_dumb.handle = dumb_handle; + // drm_ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb); + + return 0; +} + +int modeset_clean(int fd) { + // struct drm_mode_destroy_dumb destroy_dumb; + // destroy_dumb.handle = dumb_handle; + ioctl(fd, DRM_IOCTL_MODE_RMFB, fb_id); + // drm_ioctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb); + + ioctl(fd, DRM_IOCTL_DROP_MASTER); + + return 0; +} + +int gbm_mode_set() { + if (gbmBo) { + return 0; + } + gbmBo = gbm_surface_lock_front_buffer(gbmSurface); + union gbm_bo_handle bo_handle = gbm_bo_get_handle(gbmBo); + printf("gbm bo handle: %d\n", bo_handle); + dumb_handle = bo_handle.u32; + gbm_surface_release_buffer(gbmSurface, gbmBo); + + int fd = device; + int width = gbm_bo_get_width(gbmBo); + int height = gbm_bo_get_height(gbmBo); + int bpp = gbm_bo_get_bpp(gbmBo); + int i; + + struct drm_mode_fb_cmd fb_cmd; + memzero(&fb_cmd); + fb_cmd.width = width; + fb_cmd.height = height; + fb_cmd.bpp = bpp; + fb_cmd.depth = 24; + fb_cmd.pitch = width * bpp/8; + fb_cmd.handle = dumb_handle; + drm_ioctl(fd, DRM_IOCTL_MODE_ADDFB, &fb_cmd); + fb_id = fb_cmd.fb_id; + printf("add_fb fb_id: %d\n", fb_id); + + struct drm_mode_card_res drm_mode_card_res; + memzero(&drm_mode_card_res); + drm_ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &drm_mode_card_res); + + drm_mode_card_res.connector_id_ptr = calloc(1, sizeof(uint32_t)); + drm_mode_card_res.crtc_id_ptr = calloc(1, sizeof(uint32_t)); + drm_mode_card_res.fb_id_ptr = calloc(1, sizeof(uint32_t)); + drm_mode_card_res.count_encoders = 0; + // drm_mode_card_res.encoder_id_ptr = calloc(1, sizeof(uint32_t)); + drm_ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &drm_mode_card_res); + + printf("res count_connectors:%d, count_crtcs:%d, count_fbs:%d, crtc_ptr:0x%x\n", + drm_mode_card_res.count_connectors, drm_mode_card_res.count_crtcs, drm_mode_card_res.count_fbs, drm_mode_card_res.crtc_id_ptr); + printf("crtc data:[ %d]\n", ((uint32_t*)drm_mode_card_res.crtc_id_ptr)[0]); + uint32_t crtc_id = ((uint32_t*)drm_mode_card_res.crtc_id_ptr)[0]; + uint32_t conn_id = ((uint32_t*)drm_mode_card_res.connector_id_ptr)[0]; + + + struct drm_mode_get_connector get_connector; + memzero(&get_connector); + get_connector.connector_id = conn_id; + drm_ioctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &get_connector); + printf("get_connector modes count: %d\n", get_connector.count_modes); + + get_connector.connector_id = conn_id; + get_connector.count_encoders = 0; + get_connector.count_props = 0; + struct drm_mode_modeinfo *modes = calloc(get_connector.count_modes, sizeof(struct drm_mode_modeinfo)); + + get_connector.modes_ptr = modes; + drm_ioctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &get_connector); + + for (i = 0; i < get_connector.count_modes; i++) { + printf("get_connector mode[%d] : '%s' -> (%d, %d, %d)\n", i, modes[i].name, modes[i].hdisplay, modes[i].vdisplay, modes[i].vrefresh); + if (modes[i].hdisplay == width && modes[i].vdisplay == height) { + printf("match gbm size (%d, %d)\n", width, height); + break; + } + } + + if (i == get_connector.count_modes) { + printf("nothing match gbm size (%d, %d)\n", width, height); + return -1; + } + + ioctl(fd, DRM_IOCTL_SET_MASTER); + + struct drm_mode_crtc mode_crtc; + memzero(&mode_crtc); + mode_crtc.count_connectors = drm_mode_card_res.count_connectors; + mode_crtc.set_connectors_ptr = drm_mode_card_res.connector_id_ptr; + mode_crtc.crtc_id = crtc_id; + mode_crtc.fb_id = fb_id; + mode_crtc.mode_valid = 1; + memcpy(&mode_crtc.mode, modes+i, sizeof(struct drm_mode_modeinfo)); + drm_ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &mode_crtc); + + + return 0; +} + +EGLDisplay gbm_init(const char* devicePath) { + device = open(devicePath, O_RDWR | O_CLOEXEC); + modeset_fd(device); + + gbmDevice = gbm_create_device(device); + if (!gbmDevice) { + printf("gbm device is null!\n"); + } + // int gbm_fd = gbm_device_get_fd(gbmDevice); + // printf("gbm_fd: %d, card0 fd:%d\n", gbm_fd, device); + gbmSurface = gbm_surface_create(gbmDevice, 1280, 1024, USE_GBM_FORMAT, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + if (!gbmSurface) { + printf("gbm surface is null!\n"); + } + + return eglGetDisplay(gbmDevice); +} + +EGLDisplay gbm_uninit() { + if (gbmSurface) + gbm_surface_destroy(gbmSurface); + // if (gbmBo) + // gbm_bo_destroy(gbmBo); + gbm_device_destroy(gbmDevice); + + modeset_clean(device); + return 0; +} +#endif + +void print_glinfo() { + printf("OpenGL information:\n"); + printf(" version: \"%s\"\n", glGetString(GL_VERSION)); + printf(" shading language version: \"%s\"\n", glGetString(GL_SHADING_LANGUAGE_VERSION)); + printf(" vendor: \"%s\"\n", glGetString(GL_VENDOR)); + printf(" renderer: \"%s\"\n", glGetString(GL_RENDERER)); + // printf(" extensions: \"%s\"\n", glGetString(GL_EXTENSIONS)); + printf("===================================\n"); +} + +static int matchConfigToVisual(EGLDisplay display, EGLint visualId, EGLConfig* configs, int count) +{ + EGLint id = 0; + EGLint suf_type; + int retId = -1; + for (int i = 0; i < count; ++i) + { + // eglGetConfigAttrib(display, configs[i], EGL_SURFACE_TYPE, &suf_type); + // printf("suf_type: 0x%x\n", suf_type); + // eglGetConfigAttrib(display, configs[i], EGL_NATIVE_VISUAL_TYPE, &suf_type); + // printf("native_visual_type: 0x%x\n", suf_type); + + if (!eglGetConfigAttrib(display, configs[i], EGL_NATIVE_VISUAL_ID, &id)) + continue; + + // printf("visualid: 0x%x, str:%.*s\n", id, 4, &id); + if (id == visualId) { + retId = i; + break; + } + + } + return retId; +} + +int init(void) +{ + + +#ifdef XORG_SHOW + x_display = XOpenDisplay (NULL); + if (!x_display) { + printf("XOpenDisplay failed!\n"); + return 1; + } + Window root = DefaultRootWindow( x_display ); + + XSetWindowAttributes swa; + swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask | StructureNotifyMask; + win = XCreateWindow ( // create a window with the provided parameters + x_display, root, + 0, 0, 1000, 1000, 0, + CopyFromParent, InputOutput, + CopyFromParent, CWEventMask, + &swa ); + + XSetWindowAttributes xattr; + xattr.override_redirect = False; + XChangeWindowAttributes( x_display, win, CWOverrideRedirect, &xattr ); + + XMapWindow ( x_display , win); // make the window visible on the screen + XStoreName ( x_display , win , "GL test"); // give the window a name + + XSelectInput(x_display, win, StructureNotifyMask); + egldisplay = eglGetDisplay((EGLNativeDisplayType)x_display); + +#else + egldisplay = gbm_init("/dev/dri/card0"); +#endif + int majo, mino; + eglInitialize(egldisplay, &majo, &mino); + printf("egl ver: %d.%d\n", majo, mino); + ASSERT_EQ(eglGetError(), EGL_SUCCESS); + eglBindAPI(EGL_OPENGL_ES_API); + + + static const EGLint s_configAttribs[] = + { + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_RED_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_NONE + }; + + EGLint count = 0; + EGLint numConfigs = 0; + eglGetConfigs(egldisplay, NULL, 0, &count); + EGLConfig* configs = malloc(count * sizeof(EGLConfig)); + + eglChooseConfig(egldisplay, s_configAttribs, configs, count, &numConfigs); + ASSERT_EQ(eglGetError(), EGL_SUCCESS); + printf("configs num: %d\n", numConfigs); + + int indexCfg = matchConfigToVisual(egldisplay, USE_FORMAT, configs, numConfigs); + printf("configs indexCfg: %d\n", indexCfg); + if (indexCfg < 0) { + indexCfg = 1; + } + + eglconfig = configs[indexCfg]; + + EGLint ContextAttribList[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE }; + eglcontext = eglCreateContext( egldisplay, eglconfig, EGL_NO_CONTEXT, ContextAttribList ); + ASSERT_EQ(eglGetError(), EGL_SUCCESS); + + +#ifdef XORG_SHOW + EGLint win_attrlist[] = { + EGL_NONE, + }; + eglsurface = eglCreateWindowSurface(egldisplay, eglconfig, (EGLNativeWindowType)(win), win_attrlist); +#else + EGLint win_attrlist[] = { + EGL_NONE + }; + eglsurface = eglCreateWindowSurface(egldisplay, eglconfig, (EGLNativeWindowType)(gbmSurface), win_attrlist); +#endif + ASSERT_EQ(eglGetError(), EGL_SUCCESS); + if (eglsurface == EGL_NO_SURFACE) { + int e = eglGetError(); + printf("EGL_NO_SURFACE ! error_num: %p\n", e); + return -1; + } + + eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglcontext); + ASSERT_EQ(eglGetError(), EGL_SUCCESS); + + + print_glinfo(); + + { + // Compile the shaders + GLuint hVertexShader = glCreateShader( GL_VERTEX_SHADER ); + glShaderSource( hVertexShader, 1, &g_strVertexShader, NULL ); + glCompileShader( hVertexShader ); + + // Check for compile success + GLint nCompileResult = 0; + glGetShaderiv( hVertexShader, GL_COMPILE_STATUS, &nCompileResult ); + if( 0 == nCompileResult ) + { + char strLog[1024]; + GLint nLength; + glGetShaderInfoLog( hVertexShader, 1024, &nLength, strLog ); + return 0; + } + + GLuint hFragmentShader = glCreateShader( GL_FRAGMENT_SHADER ); + glShaderSource( hFragmentShader, 1, &g_strFragmentShader, NULL ); + glCompileShader( hFragmentShader ); + + // Check for compile success + glGetShaderiv( hFragmentShader, GL_COMPILE_STATUS, &nCompileResult ); + if( 0 == nCompileResult ) + { + char strLog[1024]; + GLint nLength; + glGetShaderInfoLog( hFragmentShader, 1024, &nLength, strLog ); + return 0; + } + + // Attach the individual shaders to the common shader program + g_hShaderProgram = glCreateProgram(); + glAttachShader( g_hShaderProgram, hVertexShader ); + glAttachShader( g_hShaderProgram, hFragmentShader ); + + // Init attributes BEFORE linking + glBindAttribLocation( g_hShaderProgram, g_hVertexLoc, "g_vPosition" ); + + // Link the vertex shader and fragment shader together + glLinkProgram( g_hShaderProgram ); + + // Check for link success + GLint nLinkResult = 0; + glGetProgramiv( g_hShaderProgram, GL_LINK_STATUS, &nLinkResult ); + if( 0 == nLinkResult ) + { + char strLog[1024]; + GLint nLength; + glGetProgramInfoLog( g_hShaderProgram, 1024, &nLength, strLog ); + return 0; + } + + // Get uniform locations + g_hModelViewMatrixLoc = glGetUniformLocation( g_hShaderProgram, "g_matModelView" ); + g_hProjMatrixLoc = glGetUniformLocation( g_hShaderProgram, "g_matProj" ); + g_hVColor = glGetAttribLocation( g_hShaderProgram, "g_vColor" ); + + + glDeleteShader( hVertexShader ); + glDeleteShader( hFragmentShader ); + + // Set the shader program + glUseProgram( g_hShaderProgram ); + + // Clear the colorbuffer and depth-buffer + glClearColor( 0.0f, 0.0f, 0.5f, 1.0f ); + + // Set some state + glEnable( GL_DEPTH_TEST ); + + } + + return 0; +} + +void resize(int w, int h) +{ + // Build a perspective projection matrix + matProj[ 0] = cosf( 0.5f ) / sinf( 0.5f ); + matProj[ 5] = matProj[0] * (w/h) ; + matProj[10] = -( 10.0f ) / ( 9.0f ); + matProj[11] = -1.0f; + matProj[14] = -( 10.0f ) / ( 9.0f ); + + glViewport(0, 0, w, h); +} + +void deinit(void) +{ + printf("Cleaning up...\n"); + eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + assert(eglGetError() == EGL_SUCCESS); + eglDestroyContext(egldisplay, eglcontext); + eglDestroySurface(egldisplay, eglsurface); + eglTerminate(egldisplay); + assert(eglGetError() == EGL_SUCCESS); + eglReleaseThread(); +#ifndef XORG_SHOW + gbm_uninit(); +#endif +} + +int event_handle(void* arg) { + printf("start event loop\n"); +#ifdef XORG_SHOW + while (1) { + XEvent xevent; + // XWindowEvent(x_display, win, StructureNotifyMask, &xevent); + XNextEvent(x_display, &xevent); + if (xevent.type == DestroyNotify) { + printf("DestroyNotify \n"); + break; + } + } +#endif + return 0; +} + +void handle_sig(int sig) { + printf("recieve sig: %d\n", sig); + g_stop = 1; +} + +void init_signal() { + signal(SIGABRT, handle_sig); + signal(SIGHUP, handle_sig); + signal(SIGINT, handle_sig); +} + + +int main (void) +{ + EGLint width = 600; + EGLint height = 600; + int ret; + ret = init(); + if (ret) { + return ret; + } + init_signal(); + + eglQuerySurface(egldisplay, eglsurface, EGL_WIDTH, &width); + eglQuerySurface(egldisplay, eglsurface, EGL_HEIGHT, &height); + + printf("w=%d h=%d\n",width,height); + + thrd_t thr; + thrd_create(&thr, event_handle, NULL); + + unsigned int framenum = 0; + while (!g_stop) { + render(width, height, framenum); + eglSwapBuffers(egldisplay, eglsurface); + + #ifndef XORG_SHOW + gbm_mode_set(); + #endif + + usleep(1*1000); + framenum++; + + if (!(framenum%100)) { + printf("frame num:%d\n", framenum); + } + if (framenum > 100000) { + break; + } + } + + deinit(); + + return 0; +}