为什么写这篇博客
我在linux下想使用Glad + EGL来实现一个程序,对Glad的学习使用基本都是通过LearnOpenGL这个网站,由于其中使用的窗口库是glfw,当我将窗口库换成EGL碰到很多问题,所以写一篇博客记录一下,怕以后忘记,是我第一次写,也希望能帮助到大家。最后回贴上代码。
Glad
Glad不过多介绍,可以帮助我们更方便的使用openGL。
由于要我要使用EGL,偶然在glad文件生成网站发现可以生成EGL的glad封装库,目前还没尝试去使用。
EGL
一个窗口库,需要和平台窗口连接才能使用,比如我在Linux,就和linux的X11创建的窗口进行连接(linux下应该有很多创建窗口的方法,这一块我不太清楚)
第一问:gladLoadGLLoader
我一开始以为这个函数和glfw有关,所以直接删掉了,后来排查问题的时候发现想要使用glad就必须要先调用这个函数。在glfw中是:
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)
那么EGL怎么办呢?一开始各种网上冲浪搜索,都不知道冲到那个洋去了,其实很简单:
gladLoadGLLoader((GLADloadproc)eglGetProcAddress)
哈哈!!!
第二问:GLSL 3.30 is not supported. Supported versions are: 1.00 ES,3.00ES
因为我是根据learnOpenGL网站上写的,那个网站上用的就是GLSL 3.30,这一下好了,不支持,我一搜这个问题,有人说是openGL版本的问题,也没有个解决办法,后面仔细一想,这不对啊。我从learnOpenGL网站上复制的代码能运行,上面用的就是3.3啊。关于这个问题,个人觉得是跟窗口的平台、gladLoadGLLoader函数有关,因为使用glfw的时候,就可以正常使用。
那我是怎么解决的呢
先学习一下ES 3.0,了解和GLSL3.30有什么区别
,可参考:
https://www.jianshu.com/p/2ce67644eae8
最后发现着色器的写法有些不一样。
第三问:编译能通过,运行的时候出现Segmentation fault
我第一次出现这个问题是执行到glCreateShader这个函数这里(通过gdb调试),此函数生成一个着色器,但是我的着色器是从learnOpenGL上复制的,就是vertexShaderSource 和 fragmentShaderSource ,我不明白为什么会生成失败,现在发现是由于版本的问题的,各个版本的这个写法好像有些不一样,这一块还不太清楚。
代码
#include <glad/glad.h>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <sys/time.h>
#include <X11/Xlib.h>
#include <EGL/egl.h>
using namespace std;
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
const char *vertexShaderSource = "#version 300 es\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char *fragmentShaderSource = "#version 300 es\n"
"precision mediump float; \n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
int main()
{
// in the first part the program opens a connection to the X11 window manager
Display* x_display = XOpenDisplay ( NULL ); // open the standard display (the primary screen)
if ( x_display == NULL ) {
cerr << "cannot connect to X server" << endl;
return 1;
}
Window root = DefaultRootWindow( x_display ); // get the root window (usually the whole screen)
XSetWindowAttributes swa;
swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask;
Window win = XCreateWindow ( // create a window with the provided parameters
x_display, root,
0, 0, 800, 480, 0,
CopyFromParent, InputOutput,
CopyFromParent, CWEventMask,
&swa );
/* 选择一种感兴趣的事件进行监听 */
XSelectInput(x_display, win, ExposureMask | KeyPressMask);
/* 显示窗口 */
XMapWindow(x_display, win);
/// the egl part //
EGLDisplay egl_display;
EGLContext egl_context;
EGLSurface egl_surface;
egl_display = eglGetDisplay( (EGLNativeDisplayType) x_display );
if ( egl_display == EGL_NO_DISPLAY ) {
cerr << "Got no EGL display." << endl;
return 1;
}
if ( !eglInitialize( egl_display, NULL, NULL ) ) {
cerr << "Unable to initialize EGL" << endl;
return 1;
}
EGLint attr[] = { // some attributes to set up our egl-interface
EGL_BUFFER_SIZE, 16,
EGL_RENDERABLE_TYPE,
EGL_OPENGL_ES2_BIT,
EGL_NONE
};
EGLConfig ecfg;
EGLint num_config;
if ( !eglChooseConfig( egl_display, attr, &ecfg, 1, &num_config ) ) {
cerr << "Failed to choose config (eglError: " << eglGetError() << ")" << endl;
return 1;
}
if ( num_config != 1 ) {
cerr << "Didn't get exactly one config, but " << num_config << endl;
return 1;
}
egl_surface = eglCreateWindowSurface ( egl_display, ecfg, win, NULL );
if ( egl_surface == EGL_NO_SURFACE ) {
cerr << "Unable to create EGL surface (eglError: " << eglGetError() << ")" << endl;
return 1;
}
// egl-contexts collect all state descriptions needed required for operation
EGLint ctxattr[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
egl_context = eglCreateContext ( egl_display, ecfg, EGL_NO_CONTEXT, ctxattr );
if ( egl_context == EGL_NO_CONTEXT ) {
cerr << "Unable to create EGL context (eglError: " << eglGetError() << ")" << endl;
return 1;
}
eglMakeCurrent( egl_display, egl_surface, egl_surface, egl_context );
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)eglGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// build and compile our shader program
// ------------------------------------
// vertex shader
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// check for shader compile errors
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// fragment shader
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// check for shader compile errors
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// link shaders
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// check for linking errors
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
float vertices[] = {
-0.5f, -0.5f, 0.0f, // left
0.5f, -0.5f, 0.0f, // right
0.0f, 0.5f, 0.0f // top
};
glUseProgram(shaderProgram);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(0);
XEvent xev;
bool quit = false;
while ( !quit ) { // the main loop
XNextEvent(x_display, &xev);
if ( xev.type == KeyPress ) quit = true;
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// draw our first triangle
glUseProgram(shaderProgram);
glDrawArrays(GL_TRIANGLES, 0, 3);
eglSwapBuffers ( egl_display, egl_surface ); // get the rendered buffer to the screen
}
eglDestroyContext ( egl_display, egl_context );
eglDestroySurface ( egl_display, egl_surface );
eglTerminate ( egl_display );
XDestroyWindow ( x_display, win );
XCloseDisplay ( x_display );
glDeleteProgram(shaderProgram);
return 0;
}