在 x11 系统上使用带有 GL/gl.h 和 GL/glx.h 的 opengl 绘制三角形
Drawing triangles with opengl with GL/gl.h and GL/glx.h on x11 System
我已阅读多个项目并将其拼凑在一起,以创建一个 x11 window 和 open gl 工作,预装 GL/gl.h 和 GL/glx.h .我遇到的问题是我想绘制到屏幕上的三角形没有显示。我认为我没有设置任何投影参数等,或者三角形没有绘制到我想要绘制的 space。
我确实得到了一个 window 并且我能够设置在我订阅事件掩码后触发的 xevents。按 'esc' 键将触发一个事件,该事件最终会调用 Shutdown()
并打破循环,释放 x11 和 gl 东西,最后退出程序。所以唯一不起作用的是绘图到屏幕的东西,这基本上是我程序的要点。
我该如何解决这个问题?
main.cpp:
#include <cstring>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysymdef.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <sys/time.h>
#include <unistd.h>
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define FPS 30
#define TEST_LOCAL
int shutdown = 0;
extern bool Initialize(int w, int h);
extern bool Update(float deltaTime);
extern void Render();
extern void HandleKeyboardEvents( XEvent );
extern void Resize(int w, int h);
extern void Shutdown();
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
#define SKIP_TICKS (1000 / FPS)
static double GetMilliseconds() {
static timeval s_tTimeVal;
gettimeofday(&s_tTimeVal, NULL);
double time = s_tTimeVal.tv_sec * 1000.0; // sec to ms
time += s_tTimeVal.tv_usec / 1000.0; // us to ms
return time;
}
static bool isExtensionSupported(const char *extList, const char *extension) {
return strstr(extList, extension) != 0;
}
int main(int argc, char** argv) {
Display* display;
Window window;
Screen* screen;
int screenId;
XEvent ev;
// Open the display
display = XOpenDisplay(NULL);
if (display == NULL) {
std::cout << "Could not open display\n";
return 1;
}
screen = DefaultScreenOfDisplay(display);
screenId = DefaultScreen(display);
// Check GLX version
GLint majorGLX, minorGLX = 0;
glXQueryVersion(display, &majorGLX, &minorGLX);
if (majorGLX <= 1 && minorGLX < 2) {
std::cout << "GLX 1.2 or greater is required.\n";
XCloseDisplay(display);
return 1;
}
GLint glxAttribs[] = {
GLX_X_RENDERABLE , True,
GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
GLX_RENDER_TYPE , GLX_RGBA_BIT,
GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
GLX_RED_SIZE , 8,
GLX_GREEN_SIZE , 8,
GLX_BLUE_SIZE , 8,
GLX_ALPHA_SIZE , 8,
GLX_DEPTH_SIZE , 24,
GLX_STENCIL_SIZE , 8,
GLX_DOUBLEBUFFER , True,
None
};
int fbcount;
GLXFBConfig* fbc = glXChooseFBConfig(display, screenId, glxAttribs, &fbcount);
if (fbc == 0) {
std::cout << "Failed to retrieve framebuffer.\n";
XCloseDisplay(display);
return 1;
}
// Pick the FB config/visual with the most samples per pixel
int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999;
for (int i = 0; i < fbcount; ++i) {
XVisualInfo *vi = glXGetVisualFromFBConfig( display, fbc[i] );
if ( vi != 0) {
int samp_buf, samples;
glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf );
glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLES , &samples );
if ( best_fbc < 0 || (samp_buf && samples > best_num_samp) ) {
best_fbc = i;
best_num_samp = samples;
}
if ( worst_fbc < 0 || !samp_buf || samples < worst_num_samp )
worst_fbc = i;
worst_num_samp = samples;
}
XFree( vi );
}
GLXFBConfig bestFbc = fbc[ best_fbc ];
XFree( fbc ); // Make sure to free this!
XVisualInfo* visual = glXGetVisualFromFBConfig( display, bestFbc );
if (visual == 0) {
std::cout << "Could not create correct visual window.\n";
XCloseDisplay(display);
return 1;
}
if (screenId != visual->screen) {
std::cout << "screenId(" << screenId << ") does not match visual->screen(" << visual->screen << ").\n";
XCloseDisplay(display);
return 1;
}
// Open the window
XSetWindowAttributes windowAttribs;
windowAttribs.border_pixel = BlackPixel(display, screenId);
windowAttribs.background_pixel = WhitePixel(display, screenId);
windowAttribs.override_redirect = True;
windowAttribs.colormap = XCreateColormap(display, RootWindow(display, screenId), visual->visual, AllocNone);
windowAttribs.event_mask = ExposureMask;
window = XCreateWindow(display, RootWindow(display, screenId), 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, visual->depth, InputOutput, visual->visual, CWBackPixel | CWColormap | CWBorderPixel | CWEventMask, &windowAttribs);
// Redirect Close
Atom atomWmDeleteWindow = XInternAtom(display, "WM_DELETE_WINDOW", False);
XSetWMProtocols(display, window, &atomWmDeleteWindow, 1);
// Create GLX OpenGL context
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" );
int context_attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 2,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
None
};
GLXContext context = 0;
const char *glxExts = glXQueryExtensionsString( display, screenId );
if (!isExtensionSupported( glxExts, "GLX_ARB_create_context")) {
std::cout << "GLX_ARB_create_context not supported\n";
context = glXCreateNewContext( display, bestFbc, GLX_RGBA_TYPE, 0, True );
}
else {
context = glXCreateContextAttribsARB( display, bestFbc, 0, true, context_attribs );
}
XSync( display, False );
// Verifying that context is a direct context
if (!glXIsDirect (display, context)) {
std::cout << "Indirect GLX rendering context obtained\n";
}
else {
std::cout << "Direct GLX rendering context obtained\n";
}
glXMakeCurrent(display, window, context);
std::cout << "GL Renderer: " << glGetString(GL_RENDERER) << "\n";
std::cout << "GL Version: " << glGetString(GL_VERSION) << "\n";
std::cout << "GLSL Version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << "\n";
if (!Initialize(WINDOW_WIDTH, WINDOW_HEIGHT)) {
glXDestroyContext(display, context);
XFree(visual);
XFreeColormap(display, windowAttribs.colormap);
XDestroyWindow(display, window);
XCloseDisplay(display);
return 1;
}
glMatrixMode( GL_PROJECTION );
glOrtho( 0, 640, 480, 0, -1, 1 );
XSelectInput( display, window, PointerMotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask );
// Show the window
XClearWindow(display, window);
XMapRaised(display, window);
double prevTime = GetMilliseconds();
double currentTime = GetMilliseconds();
double deltaTime = 0.0;
timeval time;
long sleepTime = 0;
gettimeofday(&time, NULL);
long nextGameTick = (time.tv_sec * 1000) + (time.tv_usec / 1000);
// Enter message loop
while (shutdown != 1) {
if (XPending(display) > 0) {
XNextEvent(display, &ev);
if (ev.type == Expose) {
XWindowAttributes attribs;
XGetWindowAttributes(display, window, &attribs);
Resize(attribs.width, attribs.height);
}
if (ev.type == ClientMessage) {
if (ev.xclient.data.l[0] == atomWmDeleteWindow) {
break;
}
}
else if (ev.type == DestroyNotify) {
break;
}
}
currentTime = GetMilliseconds();
deltaTime = double(currentTime - prevTime) * 0.001;
prevTime = currentTime;
if (!Update((float)deltaTime)) {
break;
}
HandleKeyboardEvents( ev );
Render();
// Present frame
glXSwapBuffers(display, window);
// Limit Framerate
gettimeofday(&time, NULL);
nextGameTick += SKIP_TICKS;
sleepTime = nextGameTick - ((time.tv_sec * 1000) + (time.tv_usec / 1000));
usleep((unsigned int)(sleepTime / 1000));
}
std::cout << "Shutting Down\n";
Shutdown();
// Cleanup GLX
glXDestroyContext(display, context);
// Cleanup X11
XFree(visual);
XFreeColormap(display, windowAttribs.colormap);
XDestroyWindow(display, window);
XCloseDisplay(display);
return 0;
}
#ifdef TEST_LOCAL
bool Initialize(int w, int h) {
glClearColor(0.5f, 0.6f, 0.7f, 1.0f);
glViewport(0, 0, w, h);
return true;
}
bool Update(float deltaTime) {
return true;
}
void HandleKeyboardEvents( XEvent ev ) {
int x, y;
switch ( ev.type ) {
case ButtonPress:
if ( ev.xbutton.button == 1 ) {
std::cout << "Left mouse down \n";
}
break;
case ButtonRelease:
if ( ev.xbutton.button == 1 ) {
std::cout << "Left mouse up \n";
}
break;
case KeyPress:
if ( ev.xkey.keycode == 9 ) { // ESC
Shutdown();
}
break;
case MotionNotify:
x = ev.xmotion.x;
y = ev.xmotion.y;
//std::cout << "Mouse X:" << x << ", Y: " << y << "\n";
break;
}
}
void Render() {
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_TRIANGLES);
glColor3f( 1.0f, 0.0f, 0.0f);
glVertex3f( 0.0f, -1.0f, 0.0f);
glColor3f( 1.0f, 0.0f, 0.0f);
glVertex3f(-1.0f, 1.0f, 0.0f);
glColor3f( 1.0f, 0.0f, 0.0f);
glVertex3f( 1.0f, 1.0f, 0.0f);
glEnd();
glFlush();
}
void Resize(int w, int h) {
glViewport(0, 0, w, h);
}
void Shutdown() {
shutdown = 1;
}
#endif
我编译:
g++ -g -Wall -o _build/main main.cpp -I/opt/x11/include -L/usr/x11/lib -lGL -lX11
OS:
Linux kali 5.9.0-kali4-amd64 #1 SMP Debian 5.9.11-1kali1 (2020-12-01) x86_64 GNU/Linux
您的代码不会渲染三角形,而是会在您的 glBegin
/glEnd
构造上生成 GL_INVALID_OPERATION
。原因就在这里:
int context_attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 2,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
None
};
根据 GLX_ARB_create_context
GLX 扩展规范(强调我的):
If version 3.2 or greater is requested, the context returned may implement any of the following versions:
- The requested profile of the requested version.
- The requested profile of any later version, so long as no features have been removed from that later version and profile.
通过您省略的 GLX_CONTEXT_PROFILE_MASK_ARB
属性请求配置文件,因此将应用默认值:
The default value for GLX_CONTEXT_PROFILE_MASK_ARB
is
GLX_CONTEXT_CORE_PROFILE_BIT_ARB
. All OpenGL 3.2 implementations are
required to implement the core profile, but implementation of the
compatibility profile is optional.
glBegin
/glEnd
绘图模式、fixed-function 管道、矩阵堆栈等遗留功能均已从核心配置文件中删除 OpenGL.
要将此代码发送到 运行,您有 3 个选项:
- 请求 GL 版本 <= 2.1。这将使您与旧版实现具有最大的兼容性。它基本上会产生与您根本不使用
GLX_ARB_create_context
扩展名相同的结果。
- 使用
GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
明确请求 GL 3.2(并删除 GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
)。这可能有效,也可能无效,具体取决于您的实施是否支持。
- 保持GL上下文为3.2核心,只写core-profile兼容代码。
选项 3 实际上是唯一在 2021 年有意义的选项。但是,它需要的设置代码比您目前拥有的要多得多。您将必须编写自己的着色器,并为顶点属性和相应的数据数组设置一个 VAO 和一个 VBO。
请注意,选项 3 也会破坏
with the preinstalled GL/gl.h and GL/glx.h.
你前提的一部分。您至少要放弃 gl.h
header 以支持由 GL loader.
生成的
我已阅读多个项目并将其拼凑在一起,以创建一个 x11 window 和 open gl 工作,预装 GL/gl.h 和 GL/glx.h .我遇到的问题是我想绘制到屏幕上的三角形没有显示。我认为我没有设置任何投影参数等,或者三角形没有绘制到我想要绘制的 space。
我确实得到了一个 window 并且我能够设置在我订阅事件掩码后触发的 xevents。按 'esc' 键将触发一个事件,该事件最终会调用 Shutdown()
并打破循环,释放 x11 和 gl 东西,最后退出程序。所以唯一不起作用的是绘图到屏幕的东西,这基本上是我程序的要点。
我该如何解决这个问题?
main.cpp:
#include <cstring>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysymdef.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <sys/time.h>
#include <unistd.h>
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define FPS 30
#define TEST_LOCAL
int shutdown = 0;
extern bool Initialize(int w, int h);
extern bool Update(float deltaTime);
extern void Render();
extern void HandleKeyboardEvents( XEvent );
extern void Resize(int w, int h);
extern void Shutdown();
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
#define SKIP_TICKS (1000 / FPS)
static double GetMilliseconds() {
static timeval s_tTimeVal;
gettimeofday(&s_tTimeVal, NULL);
double time = s_tTimeVal.tv_sec * 1000.0; // sec to ms
time += s_tTimeVal.tv_usec / 1000.0; // us to ms
return time;
}
static bool isExtensionSupported(const char *extList, const char *extension) {
return strstr(extList, extension) != 0;
}
int main(int argc, char** argv) {
Display* display;
Window window;
Screen* screen;
int screenId;
XEvent ev;
// Open the display
display = XOpenDisplay(NULL);
if (display == NULL) {
std::cout << "Could not open display\n";
return 1;
}
screen = DefaultScreenOfDisplay(display);
screenId = DefaultScreen(display);
// Check GLX version
GLint majorGLX, minorGLX = 0;
glXQueryVersion(display, &majorGLX, &minorGLX);
if (majorGLX <= 1 && minorGLX < 2) {
std::cout << "GLX 1.2 or greater is required.\n";
XCloseDisplay(display);
return 1;
}
GLint glxAttribs[] = {
GLX_X_RENDERABLE , True,
GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
GLX_RENDER_TYPE , GLX_RGBA_BIT,
GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
GLX_RED_SIZE , 8,
GLX_GREEN_SIZE , 8,
GLX_BLUE_SIZE , 8,
GLX_ALPHA_SIZE , 8,
GLX_DEPTH_SIZE , 24,
GLX_STENCIL_SIZE , 8,
GLX_DOUBLEBUFFER , True,
None
};
int fbcount;
GLXFBConfig* fbc = glXChooseFBConfig(display, screenId, glxAttribs, &fbcount);
if (fbc == 0) {
std::cout << "Failed to retrieve framebuffer.\n";
XCloseDisplay(display);
return 1;
}
// Pick the FB config/visual with the most samples per pixel
int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999;
for (int i = 0; i < fbcount; ++i) {
XVisualInfo *vi = glXGetVisualFromFBConfig( display, fbc[i] );
if ( vi != 0) {
int samp_buf, samples;
glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf );
glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLES , &samples );
if ( best_fbc < 0 || (samp_buf && samples > best_num_samp) ) {
best_fbc = i;
best_num_samp = samples;
}
if ( worst_fbc < 0 || !samp_buf || samples < worst_num_samp )
worst_fbc = i;
worst_num_samp = samples;
}
XFree( vi );
}
GLXFBConfig bestFbc = fbc[ best_fbc ];
XFree( fbc ); // Make sure to free this!
XVisualInfo* visual = glXGetVisualFromFBConfig( display, bestFbc );
if (visual == 0) {
std::cout << "Could not create correct visual window.\n";
XCloseDisplay(display);
return 1;
}
if (screenId != visual->screen) {
std::cout << "screenId(" << screenId << ") does not match visual->screen(" << visual->screen << ").\n";
XCloseDisplay(display);
return 1;
}
// Open the window
XSetWindowAttributes windowAttribs;
windowAttribs.border_pixel = BlackPixel(display, screenId);
windowAttribs.background_pixel = WhitePixel(display, screenId);
windowAttribs.override_redirect = True;
windowAttribs.colormap = XCreateColormap(display, RootWindow(display, screenId), visual->visual, AllocNone);
windowAttribs.event_mask = ExposureMask;
window = XCreateWindow(display, RootWindow(display, screenId), 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, visual->depth, InputOutput, visual->visual, CWBackPixel | CWColormap | CWBorderPixel | CWEventMask, &windowAttribs);
// Redirect Close
Atom atomWmDeleteWindow = XInternAtom(display, "WM_DELETE_WINDOW", False);
XSetWMProtocols(display, window, &atomWmDeleteWindow, 1);
// Create GLX OpenGL context
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" );
int context_attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 2,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
None
};
GLXContext context = 0;
const char *glxExts = glXQueryExtensionsString( display, screenId );
if (!isExtensionSupported( glxExts, "GLX_ARB_create_context")) {
std::cout << "GLX_ARB_create_context not supported\n";
context = glXCreateNewContext( display, bestFbc, GLX_RGBA_TYPE, 0, True );
}
else {
context = glXCreateContextAttribsARB( display, bestFbc, 0, true, context_attribs );
}
XSync( display, False );
// Verifying that context is a direct context
if (!glXIsDirect (display, context)) {
std::cout << "Indirect GLX rendering context obtained\n";
}
else {
std::cout << "Direct GLX rendering context obtained\n";
}
glXMakeCurrent(display, window, context);
std::cout << "GL Renderer: " << glGetString(GL_RENDERER) << "\n";
std::cout << "GL Version: " << glGetString(GL_VERSION) << "\n";
std::cout << "GLSL Version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << "\n";
if (!Initialize(WINDOW_WIDTH, WINDOW_HEIGHT)) {
glXDestroyContext(display, context);
XFree(visual);
XFreeColormap(display, windowAttribs.colormap);
XDestroyWindow(display, window);
XCloseDisplay(display);
return 1;
}
glMatrixMode( GL_PROJECTION );
glOrtho( 0, 640, 480, 0, -1, 1 );
XSelectInput( display, window, PointerMotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask );
// Show the window
XClearWindow(display, window);
XMapRaised(display, window);
double prevTime = GetMilliseconds();
double currentTime = GetMilliseconds();
double deltaTime = 0.0;
timeval time;
long sleepTime = 0;
gettimeofday(&time, NULL);
long nextGameTick = (time.tv_sec * 1000) + (time.tv_usec / 1000);
// Enter message loop
while (shutdown != 1) {
if (XPending(display) > 0) {
XNextEvent(display, &ev);
if (ev.type == Expose) {
XWindowAttributes attribs;
XGetWindowAttributes(display, window, &attribs);
Resize(attribs.width, attribs.height);
}
if (ev.type == ClientMessage) {
if (ev.xclient.data.l[0] == atomWmDeleteWindow) {
break;
}
}
else if (ev.type == DestroyNotify) {
break;
}
}
currentTime = GetMilliseconds();
deltaTime = double(currentTime - prevTime) * 0.001;
prevTime = currentTime;
if (!Update((float)deltaTime)) {
break;
}
HandleKeyboardEvents( ev );
Render();
// Present frame
glXSwapBuffers(display, window);
// Limit Framerate
gettimeofday(&time, NULL);
nextGameTick += SKIP_TICKS;
sleepTime = nextGameTick - ((time.tv_sec * 1000) + (time.tv_usec / 1000));
usleep((unsigned int)(sleepTime / 1000));
}
std::cout << "Shutting Down\n";
Shutdown();
// Cleanup GLX
glXDestroyContext(display, context);
// Cleanup X11
XFree(visual);
XFreeColormap(display, windowAttribs.colormap);
XDestroyWindow(display, window);
XCloseDisplay(display);
return 0;
}
#ifdef TEST_LOCAL
bool Initialize(int w, int h) {
glClearColor(0.5f, 0.6f, 0.7f, 1.0f);
glViewport(0, 0, w, h);
return true;
}
bool Update(float deltaTime) {
return true;
}
void HandleKeyboardEvents( XEvent ev ) {
int x, y;
switch ( ev.type ) {
case ButtonPress:
if ( ev.xbutton.button == 1 ) {
std::cout << "Left mouse down \n";
}
break;
case ButtonRelease:
if ( ev.xbutton.button == 1 ) {
std::cout << "Left mouse up \n";
}
break;
case KeyPress:
if ( ev.xkey.keycode == 9 ) { // ESC
Shutdown();
}
break;
case MotionNotify:
x = ev.xmotion.x;
y = ev.xmotion.y;
//std::cout << "Mouse X:" << x << ", Y: " << y << "\n";
break;
}
}
void Render() {
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_TRIANGLES);
glColor3f( 1.0f, 0.0f, 0.0f);
glVertex3f( 0.0f, -1.0f, 0.0f);
glColor3f( 1.0f, 0.0f, 0.0f);
glVertex3f(-1.0f, 1.0f, 0.0f);
glColor3f( 1.0f, 0.0f, 0.0f);
glVertex3f( 1.0f, 1.0f, 0.0f);
glEnd();
glFlush();
}
void Resize(int w, int h) {
glViewport(0, 0, w, h);
}
void Shutdown() {
shutdown = 1;
}
#endif
我编译:
g++ -g -Wall -o _build/main main.cpp -I/opt/x11/include -L/usr/x11/lib -lGL -lX11
OS:
Linux kali 5.9.0-kali4-amd64 #1 SMP Debian 5.9.11-1kali1 (2020-12-01) x86_64 GNU/Linux
您的代码不会渲染三角形,而是会在您的 glBegin
/glEnd
构造上生成 GL_INVALID_OPERATION
。原因就在这里:
int context_attribs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 2, GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, None };
根据 GLX_ARB_create_context
GLX 扩展规范(强调我的):
If version 3.2 or greater is requested, the context returned may implement any of the following versions:
- The requested profile of the requested version.
- The requested profile of any later version, so long as no features have been removed from that later version and profile.
通过您省略的 GLX_CONTEXT_PROFILE_MASK_ARB
属性请求配置文件,因此将应用默认值:
The default value for
GLX_CONTEXT_PROFILE_MASK_ARB
isGLX_CONTEXT_CORE_PROFILE_BIT_ARB
. All OpenGL 3.2 implementations are required to implement the core profile, but implementation of the compatibility profile is optional.
glBegin
/glEnd
绘图模式、fixed-function 管道、矩阵堆栈等遗留功能均已从核心配置文件中删除 OpenGL.
要将此代码发送到 运行,您有 3 个选项:
- 请求 GL 版本 <= 2.1。这将使您与旧版实现具有最大的兼容性。它基本上会产生与您根本不使用
GLX_ARB_create_context
扩展名相同的结果。 - 使用
GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
明确请求 GL 3.2(并删除GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
)。这可能有效,也可能无效,具体取决于您的实施是否支持。 - 保持GL上下文为3.2核心,只写core-profile兼容代码。
选项 3 实际上是唯一在 2021 年有意义的选项。但是,它需要的设置代码比您目前拥有的要多得多。您将必须编写自己的着色器,并为顶点属性和相应的数据数组设置一个 VAO 和一个 VBO。
请注意,选项 3 也会破坏
with the preinstalled GL/gl.h and GL/glx.h.
你前提的一部分。您至少要放弃 gl.h
header 以支持由 GL loader.