init
This commit is contained in:
commit
81b612465e
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
.vscode/
|
||||
build/
|
111
CMakeLists.txt
Normal file
111
CMakeLists.txt
Normal file
|
@ -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)
|
10
Makefile
Normal file
10
Makefile
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
compile: build
|
||||
cmake --build build
|
||||
|
||||
build:
|
||||
mkdir build
|
||||
cmake -B build
|
||||
|
||||
t: compile
|
||||
sudo ./build/bin/SimpleEs
|
13
README.md
Normal file
13
README.md
Normal file
|
@ -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
|
88
src/color_test.c
Normal file
88
src/color_test.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/fb.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
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;
|
||||
}
|
175
src/demo.cpp
Normal file
175
src/demo.cpp
Normal file
|
@ -0,0 +1,175 @@
|
|||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
519
src/simple-es2.c
Normal file
519
src/simple-es2.c
Normal file
|
@ -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 <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <threads.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "GLES2/gl2.h"
|
||||
#include "GLES2/gl2ext.h"
|
||||
#include "GL/gl.h"
|
||||
|
||||
#include "EGL/egl.h"
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
// #include <xf86dri.h>
|
||||
// #include <xf86drmMode.h>
|
||||
#include <gbm.h>
|
||||
|
||||
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;
|
||||
}
|
674
src/triangle-es2.c
Normal file
674
src/triangle-es2.c
Normal file
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <threads.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "GLES2/gl2.h"
|
||||
#include "GLES2/gl2ext.h"
|
||||
|
||||
#include "EGL/egl.h"
|
||||
|
||||
// #define XORG_SHOW
|
||||
|
||||
#include <libdrm/drm.h>
|
||||
|
||||
#ifdef XORG_SHOW
|
||||
#include "X11/X.h"
|
||||
#include "X11/Xatom.h"
|
||||
#else
|
||||
#include <gbm.h>
|
||||
#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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user