mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-25 16:48:11 +00:00
egl: implement selecting opengl3 contexts
This commit is contained in:
parent
786b2fb9f1
commit
5d2ddf7664
4 changed files with 217 additions and 58 deletions
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include "gstglcontext_egl.h"
|
#include "gstglcontext_egl.h"
|
||||||
#include <gst/gl/egl/gstegl.h>
|
#include <gst/gl/egl/gstegl.h>
|
||||||
|
#include "../utils/opengl_versions.h"
|
||||||
|
|
||||||
#if GST_GL_HAVE_WINDOW_X11
|
#if GST_GL_HAVE_WINDOW_X11
|
||||||
#include "../x11/gstglwindow_x11.h"
|
#include "../x11/gstglwindow_x11.h"
|
||||||
|
@ -171,19 +172,36 @@ gst_gl_context_egl_choose_format (GstGLContext * context, GError ** error)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_gl_context_egl_choose_config (GstGLContextEGL * egl,
|
gst_gl_context_egl_choose_config (GstGLContextEGL * egl, GstGLAPI gl_api,
|
||||||
GstGLContext * other_context, GError ** error)
|
gint major, GError ** error)
|
||||||
{
|
{
|
||||||
|
gboolean create_context;
|
||||||
EGLint numConfigs;
|
EGLint numConfigs;
|
||||||
gint i = 0;
|
gint i = 0;
|
||||||
EGLint config_attrib[20];
|
EGLint config_attrib[20];
|
||||||
|
|
||||||
|
create_context =
|
||||||
|
gst_gl_check_extension ("EGL_KHR_create_context", egl->egl_exts);
|
||||||
|
/* silence unused warnings */
|
||||||
|
(void) create_context;
|
||||||
|
|
||||||
config_attrib[i++] = EGL_SURFACE_TYPE;
|
config_attrib[i++] = EGL_SURFACE_TYPE;
|
||||||
config_attrib[i++] = EGL_WINDOW_BIT;
|
config_attrib[i++] = EGL_WINDOW_BIT;
|
||||||
config_attrib[i++] = EGL_RENDERABLE_TYPE;
|
config_attrib[i++] = EGL_RENDERABLE_TYPE;
|
||||||
if (egl->gl_api & GST_GL_API_GLES2)
|
if (gl_api & GST_GL_API_GLES2) {
|
||||||
config_attrib[i++] = EGL_OPENGL_ES2_BIT;
|
if (major == 3) {
|
||||||
else
|
#if defined(EGL_KHR_create_context)
|
||||||
|
if (create_context) {
|
||||||
|
config_attrib[i++] = EGL_OPENGL_ES3_BIT_KHR;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
config_attrib[i++] = EGL_OPENGL_ES2_BIT;
|
||||||
|
}
|
||||||
|
} else
|
||||||
config_attrib[i++] = EGL_OPENGL_BIT;
|
config_attrib[i++] = EGL_OPENGL_BIT;
|
||||||
#if defined(USE_EGL_RPI) && GST_GL_HAVE_WINDOW_WAYLAND
|
#if defined(USE_EGL_RPI) && GST_GL_HAVE_WINDOW_WAYLAND
|
||||||
/* The configurations with a=0 seems to be buggy whereas
|
/* The configurations with a=0 seems to be buggy whereas
|
||||||
|
@ -218,6 +236,71 @@ failure:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static EGLContext
|
||||||
|
_create_context_with_flags (GstGLContextEGL * egl, EGLContext share_context,
|
||||||
|
GstGLAPI gl_api, gint major, gint minor, gint contextFlags,
|
||||||
|
gint profileMask)
|
||||||
|
{
|
||||||
|
gboolean create_context;
|
||||||
|
#define N_ATTRIBS 20
|
||||||
|
gint attribs[N_ATTRIBS];
|
||||||
|
gint n = 0;
|
||||||
|
|
||||||
|
/* fail creation of apis/versions/flags that require EGL_KHR_create_context
|
||||||
|
* if the extension doesn't exist, namely:0
|
||||||
|
*
|
||||||
|
* - profile mask
|
||||||
|
* - context flags
|
||||||
|
* - GL3 > 3.1
|
||||||
|
* - GLES2 && minor > 0
|
||||||
|
*/
|
||||||
|
create_context =
|
||||||
|
gst_gl_check_extension ("EGL_KHR_create_context", egl->egl_exts);
|
||||||
|
(void) create_context;
|
||||||
|
if (!create_context && (profileMask || contextFlags
|
||||||
|
|| ((gl_api & GST_GL_API_OPENGL3)
|
||||||
|
&& GST_GL_CHECK_GL_VERSION (major, minor, 3, 2))
|
||||||
|
|| ((gl_api & GST_GL_API_GLES2) && minor > 0))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (egl, "attempting to create OpenGL%s context version %d.%d "
|
||||||
|
"flags %x profile %x", gl_api & GST_GL_API_GLES2 ? " ES" : "", major,
|
||||||
|
minor, contextFlags, profileMask);
|
||||||
|
|
||||||
|
#if defined(EGL_KHR_create_context)
|
||||||
|
if (create_context) {
|
||||||
|
if (major) {
|
||||||
|
attribs[n++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
|
||||||
|
attribs[n++] = major;
|
||||||
|
}
|
||||||
|
if (minor) {
|
||||||
|
attribs[n++] = EGL_CONTEXT_MINOR_VERSION_KHR;
|
||||||
|
attribs[n++] = minor;
|
||||||
|
}
|
||||||
|
if (contextFlags) {
|
||||||
|
attribs[n++] = EGL_CONTEXT_FLAGS_KHR;
|
||||||
|
attribs[n++] = contextFlags;
|
||||||
|
}
|
||||||
|
if (profileMask) {
|
||||||
|
attribs[n++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
|
||||||
|
attribs[n++] = profileMask;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
attribs[n++] = EGL_CONTEXT_CLIENT_VERSION;
|
||||||
|
attribs[n++] = major;
|
||||||
|
}
|
||||||
|
attribs[n++] = EGL_NONE;
|
||||||
|
|
||||||
|
g_assert (n < N_ATTRIBS);
|
||||||
|
#undef N_ATTRIBS
|
||||||
|
|
||||||
|
return eglCreateContext (egl->egl_display, egl->egl_config, share_context,
|
||||||
|
attribs);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_gl_context_egl_create_context (GstGLContext * context,
|
gst_gl_context_egl_create_context (GstGLContext * context,
|
||||||
GstGLAPI gl_api, GstGLContext * other_context, GError ** error)
|
GstGLAPI gl_api, GstGLContext * other_context, GError ** error)
|
||||||
|
@ -225,11 +308,8 @@ gst_gl_context_egl_create_context (GstGLContext * context,
|
||||||
GstGLContextEGL *egl;
|
GstGLContextEGL *egl;
|
||||||
GstGLWindow *window = NULL;
|
GstGLWindow *window = NULL;
|
||||||
EGLNativeWindowType window_handle = (EGLNativeWindowType) 0;
|
EGLNativeWindowType window_handle = (EGLNativeWindowType) 0;
|
||||||
gint i = 0;
|
|
||||||
EGLint context_attrib[5];
|
|
||||||
EGLint majorVersion;
|
EGLint majorVersion;
|
||||||
EGLint minorVersion;
|
EGLint minorVersion;
|
||||||
const gchar *egl_exts;
|
|
||||||
gboolean need_surface = TRUE;
|
gboolean need_surface = TRUE;
|
||||||
guintptr external_gl_context = 0;
|
guintptr external_gl_context = 0;
|
||||||
GstGLDisplay *display;
|
GstGLDisplay *display;
|
||||||
|
@ -249,7 +329,8 @@ gst_gl_context_egl_create_context (GstGLContext * context,
|
||||||
external_gl_context = gst_gl_context_get_gl_context (other_context);
|
external_gl_context = gst_gl_context_get_gl_context (other_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((gl_api & (GST_GL_API_OPENGL | GST_GL_API_GLES2)) == GST_GL_API_NONE) {
|
if ((gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2)) ==
|
||||||
|
GST_GL_API_NONE) {
|
||||||
g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API,
|
g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API,
|
||||||
"EGL supports opengl or gles2");
|
"EGL supports opengl or gles2");
|
||||||
goto failure;
|
goto failure;
|
||||||
|
@ -291,7 +372,12 @@ gst_gl_context_egl_create_context (GstGLContext * context,
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gl_api & GST_GL_API_OPENGL) {
|
egl->egl_exts = eglQueryString (egl->egl_display, EGL_EXTENSIONS);
|
||||||
|
|
||||||
|
if (gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3)) {
|
||||||
|
GstGLAPI chosen_gl_api = 0;
|
||||||
|
gint i;
|
||||||
|
|
||||||
/* egl + opengl only available with EGL 1.4+ */
|
/* egl + opengl only available with EGL 1.4+ */
|
||||||
if (majorVersion == 1 && minorVersion <= 3) {
|
if (majorVersion == 1 && minorVersion <= 3) {
|
||||||
if ((gl_api & ~GST_GL_API_OPENGL) == GST_GL_API_NONE) {
|
if ((gl_api & ~GST_GL_API_OPENGL) == GST_GL_API_NONE) {
|
||||||
|
@ -321,9 +407,66 @@ gst_gl_context_egl_create_context (GstGLContext * context,
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_INFO ("Using OpenGL");
|
GST_INFO ("Bound OpenGL");
|
||||||
egl->gl_api = GST_GL_API_OPENGL;
|
|
||||||
|
/* api, version only matters for gles */
|
||||||
|
if (!gst_gl_context_egl_choose_config (egl, GST_GL_API_OPENGL, 0, error)) {
|
||||||
|
g_assert (error == NULL || *error != NULL);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (opengl_versions); i++) {
|
||||||
|
gint profileMask = 0;
|
||||||
|
gint contextFlags = 0;
|
||||||
|
|
||||||
|
if (GST_GL_CHECK_GL_VERSION (opengl_versions[i].major,
|
||||||
|
opengl_versions[i].minor, 3, 2)) {
|
||||||
|
/* skip gl3 contexts if requested */
|
||||||
|
if ((gl_api & GST_GL_API_OPENGL3) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
chosen_gl_api = GST_GL_API_OPENGL3;
|
||||||
|
#if defined(EGL_KHR_create_context)
|
||||||
|
profileMask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
|
||||||
|
contextFlags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
|
||||||
|
#endif
|
||||||
|
} else if (opengl_versions[i].major == 3 && opengl_versions[i].minor == 1) {
|
||||||
|
/* skip 3.1, the implementation is free to give us either a core or a
|
||||||
|
* compatibility context (we have no say) */
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
/* skip legacy contexts if requested */
|
||||||
|
if ((gl_api & GST_GL_API_OPENGL) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
chosen_gl_api = GST_GL_API_OPENGL;
|
||||||
|
}
|
||||||
|
|
||||||
|
egl->egl_context =
|
||||||
|
_create_context_with_flags (egl, (EGLContext) external_gl_context,
|
||||||
|
chosen_gl_api, opengl_versions[i].major,
|
||||||
|
opengl_versions[i].minor, contextFlags, profileMask);
|
||||||
|
|
||||||
|
if (egl->egl_context)
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if defined(EGL_KHR_create_context)
|
||||||
|
profileMask &= ~EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
|
||||||
|
|
||||||
|
egl->egl_context =
|
||||||
|
_create_context_with_flags (egl, (EGLContext) external_gl_context,
|
||||||
|
chosen_gl_api, opengl_versions[i].major,
|
||||||
|
opengl_versions[i].minor, contextFlags, profileMask);
|
||||||
|
|
||||||
|
if (egl->egl_context)
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
egl->gl_api = chosen_gl_api;
|
||||||
} else if (gl_api & GST_GL_API_GLES2) {
|
} else if (gl_api & GST_GL_API_GLES2) {
|
||||||
|
gint i;
|
||||||
|
|
||||||
try_gles2:
|
try_gles2:
|
||||||
if (!eglBindAPI (EGL_OPENGL_ES_API)) {
|
if (!eglBindAPI (EGL_OPENGL_ES_API)) {
|
||||||
g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
|
g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
|
||||||
|
@ -332,52 +475,43 @@ gst_gl_context_egl_create_context (GstGLContext * context,
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_INFO ("Using OpenGL|ES 2.0");
|
GST_INFO ("Bound OpenGL|ES");
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (gles2_versions); i++) {
|
||||||
|
gint profileMask = 0;
|
||||||
|
gint contextFlags = 0;
|
||||||
|
|
||||||
|
if (!gst_gl_context_egl_choose_config (egl, GST_GL_API_GLES2,
|
||||||
|
gles2_versions[i].major, error)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#if defined(EGL_KHR_create_context)
|
||||||
|
/* try a debug context */
|
||||||
|
contextFlags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
|
||||||
|
|
||||||
|
egl->egl_context =
|
||||||
|
_create_context_with_flags (egl, (EGLContext) external_gl_context,
|
||||||
|
GST_GL_API_GLES2, gles2_versions[i].major,
|
||||||
|
gles2_versions[i].minor, contextFlags, profileMask);
|
||||||
|
|
||||||
|
if (egl->egl_context)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* try without a debug context */
|
||||||
|
contextFlags &= ~EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
egl->egl_context =
|
||||||
|
_create_context_with_flags (egl, (EGLContext) external_gl_context,
|
||||||
|
GST_GL_API_GLES2, gles2_versions[i].major,
|
||||||
|
gles2_versions[i].minor, contextFlags, profileMask);
|
||||||
|
|
||||||
|
if (egl->egl_context)
|
||||||
|
break;
|
||||||
|
}
|
||||||
egl->gl_api = GST_GL_API_GLES2;
|
egl->gl_api = GST_GL_API_GLES2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gst_gl_context_egl_choose_config (egl, other_context, error)) {
|
|
||||||
g_assert (error == NULL || *error != NULL);
|
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
|
|
||||||
egl_exts = eglQueryString (egl->egl_display, EGL_EXTENSIONS);
|
|
||||||
|
|
||||||
GST_DEBUG ("about to create gl context");
|
|
||||||
|
|
||||||
if (egl->gl_api & GST_GL_API_GLES2) {
|
|
||||||
context_attrib[i++] = EGL_CONTEXT_CLIENT_VERSION;
|
|
||||||
context_attrib[i++] = 2;
|
|
||||||
}
|
|
||||||
#if !defined(GST_DISABLE_GST_DEBUG) && defined(EGL_KHR_create_context)
|
|
||||||
if (gst_gl_check_extension ("EGL_KHR_create_context", egl_exts)) {
|
|
||||||
context_attrib[i++] = EGL_CONTEXT_FLAGS_KHR;
|
|
||||||
context_attrib[i++] = EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
context_attrib[i++] = EGL_NONE;
|
|
||||||
|
|
||||||
egl->egl_context =
|
|
||||||
eglCreateContext (egl->egl_display, egl->egl_config,
|
|
||||||
(EGLContext) external_gl_context, context_attrib);
|
|
||||||
|
|
||||||
#ifdef EGL_KHR_create_context
|
|
||||||
if (egl->egl_context == EGL_NO_CONTEXT && egl->gl_api & GST_GL_API_GLES2
|
|
||||||
&& eglGetError () != EGL_SUCCESS) {
|
|
||||||
/* try without EGL_CONTEXT_FLAGS flags as it was added to
|
|
||||||
* EGL_KHR_create_context for gles contexts */
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < G_N_ELEMENTS (context_attrib); i++) {
|
|
||||||
if (context_attrib[i] == EGL_CONTEXT_FLAGS_KHR ||
|
|
||||||
context_attrib[i] == EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR)
|
|
||||||
context_attrib[i] = EGL_NONE;
|
|
||||||
}
|
|
||||||
egl->egl_context =
|
|
||||||
eglCreateContext (egl->egl_display, egl->egl_config,
|
|
||||||
(EGLContext) external_gl_context, context_attrib);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (egl->egl_context != EGL_NO_CONTEXT) {
|
if (egl->egl_context != EGL_NO_CONTEXT) {
|
||||||
GST_INFO ("gl context created: %" G_GUINTPTR_FORMAT,
|
GST_INFO ("gl context created: %" G_GUINTPTR_FORMAT,
|
||||||
(guintptr) egl->egl_context);
|
(guintptr) egl->egl_context);
|
||||||
|
@ -427,7 +561,8 @@ gst_gl_context_egl_create_context (GstGLContext * context,
|
||||||
window_handle, NULL);
|
window_handle, NULL);
|
||||||
/* Store window handle for later comparision */
|
/* Store window handle for later comparision */
|
||||||
egl->window_handle = window_handle;
|
egl->window_handle = window_handle;
|
||||||
} else if (!gst_gl_check_extension ("EGL_KHR_surfaceless_context", egl_exts)) {
|
} else if (!gst_gl_check_extension ("EGL_KHR_surfaceless_context",
|
||||||
|
egl->egl_exts)) {
|
||||||
EGLint surface_attrib[7];
|
EGLint surface_attrib[7];
|
||||||
gint j = 0;
|
gint j = 0;
|
||||||
|
|
||||||
|
@ -468,7 +603,7 @@ gst_gl_context_egl_create_context (GstGLContext * context,
|
||||||
"eglCreateImage");
|
"eglCreateImage");
|
||||||
egl->eglDestroyImage = gst_gl_context_get_proc_address (context,
|
egl->eglDestroyImage = gst_gl_context_get_proc_address (context,
|
||||||
"eglDestroyImage");
|
"eglDestroyImage");
|
||||||
} else if (gst_gl_check_extension ("EGL_KHR_image_base", egl_exts)) {
|
} else if (gst_gl_check_extension ("EGL_KHR_image_base", egl->egl_exts)) {
|
||||||
egl->eglCreateImage = gst_gl_context_get_proc_address (context,
|
egl->eglCreateImage = gst_gl_context_get_proc_address (context,
|
||||||
"eglCreateImageKHR");
|
"eglCreateImageKHR");
|
||||||
egl->eglDestroyImage = gst_gl_context_get_proc_address (context,
|
egl->eglDestroyImage = gst_gl_context_get_proc_address (context,
|
||||||
|
@ -585,7 +720,13 @@ gst_gl_context_egl_swap_buffers (GstGLContext * context)
|
||||||
|
|
||||||
egl = GST_GL_CONTEXT_EGL (context);
|
egl = GST_GL_CONTEXT_EGL (context);
|
||||||
|
|
||||||
eglSwapBuffers (egl->egl_display, egl->egl_surface);
|
if (!eglSwapBuffers (egl->egl_display, egl->egl_surface)) {
|
||||||
|
EGLint err = eglGetError ();
|
||||||
|
|
||||||
|
if (err == EGL_CONTEXT_LOST) {
|
||||||
|
gst_gl_context_lost_context (context);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstGLAPI
|
static GstGLAPI
|
||||||
|
|
|
@ -48,6 +48,8 @@ struct _GstGLContextEGL {
|
||||||
|
|
||||||
GstGLAPI gl_api;
|
GstGLAPI gl_api;
|
||||||
|
|
||||||
|
const gchar *egl_exts;
|
||||||
|
|
||||||
EGLImageKHR (*eglCreateImage) (EGLDisplay dpy, EGLContext ctx, EGLenum target,
|
EGLImageKHR (*eglCreateImage) (EGLDisplay dpy, EGLContext ctx, EGLenum target,
|
||||||
EGLClientBuffer buffer, const EGLint *attrib_list);
|
EGLClientBuffer buffer, const EGLint *attrib_list);
|
||||||
EGLBoolean (*eglDestroyImage) (EGLDisplay dpy, EGLImageKHR image);
|
EGLBoolean (*eglDestroyImage) (EGLDisplay dpy, EGLImageKHR image);
|
||||||
|
|
|
@ -1388,6 +1388,12 @@ failure:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_gl_context_lost_context (GstGLContext * context)
|
||||||
|
{
|
||||||
|
/* do stuff */
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_gl_context_get_gl_context:
|
* gst_gl_context_get_gl_context:
|
||||||
* @context: a #GstGLContext:
|
* @context: a #GstGLContext:
|
||||||
|
|
|
@ -48,6 +48,16 @@ static const struct { int major, minor; } opengl_versions[] = {
|
||||||
|
|
||||||
{0, 0} /* end of list */
|
{0, 0} /* end of list */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct { int major, minor; } gles2_versions[] = {
|
||||||
|
{3, 2},
|
||||||
|
{3, 1},
|
||||||
|
{3, 0},
|
||||||
|
|
||||||
|
{2, 0},
|
||||||
|
|
||||||
|
{0, 0} /* end of list */
|
||||||
|
};
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
#endif /* _OPENGL_VERSIONS_H_ */
|
#endif /* _OPENGL_VERSIONS_H_ */
|
||||||
|
|
Loading…
Reference in a new issue