From 349b2e1977176b70bf88534c21d0475f7441806a Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 31 Mar 2012 00:33:53 +0200 Subject: [PATCH] gl_common: add OpenGL 3.x context creation Also add a bunch of GL functions to the function loader, which will be needed by vo_gl3. Remove some unused legacy GL functions from the loader. Use the proper name for glGetProgramivARB. glGetProgramiv is a different and incompatible function. The ARB variant is used for ARB shaders, while the proper one is for GLSL. --- libvo/gl_common.c | 436 ++++++++++++++++++++++++++++++++++++++++++------------ libvo/gl_common.h | 103 ++++++++++--- 2 files changed, 421 insertions(+), 118 deletions(-) diff --git a/libvo/gl_common.c b/libvo/gl_common.c index 4c7c1c5fc8..e2e2c2b010 100644 --- a/libvo/gl_common.c +++ b/libvo/gl_common.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include "talloc.h" #include "gl_common.h" @@ -48,6 +49,31 @@ //! \defgroup glgeneral OpenGL general helper functions +// GLU has this as gluErrorString (we don't use GLU, as it is legacy-OpenGL) +static const char *gl_error_to_string(GLenum error) +{ + switch (error) { + case GL_INVALID_ENUM: return "INVALID_ENUM"; + case GL_INVALID_VALUE: return "INVALID_VALUE"; + case GL_INVALID_OPERATION: return "INVALID_OPERATION"; + case GL_INVALID_FRAMEBUFFER_OPERATION: + return "INVALID_FRAMEBUFFER_OPERATION"; + case GL_OUT_OF_MEMORY: return "OUT_OF_MEMORY"; + default: return "unknown"; + } +} + +void glCheckError(GL *gl, const char *info) +{ + for (;;) { + GLenum error = gl->GetError(); + if (error == GL_NO_ERROR) + break; + mp_msg(MSGT_VO, MSGL_ERR, "[gl] %s: OpenGL error %s.\n", info, + gl_error_to_string(error)); + } +} + //! \defgroup glcontext OpenGL context management helper functions //! \defgroup gltexture OpenGL texture handling helper functions @@ -295,44 +321,28 @@ typedef struct { const char *extstr; const char *funcnames[7]; void *fallback; + bool is_gl3; } extfunc_desc_t; #define DEF_FUNC_DESC(name) \ - {offsetof(GL, name), NULL, {"gl" # name, NULL}, gl ## name} + {offsetof(GL, name), NULL, {"gl" # name}, gl ## name} #define DEF_EXT_FUNCS(...) __VA_ARGS__ #define DEF_EXT_DESC(name, ext, funcnames) \ {offsetof(GL, name), ext, {DEF_EXT_FUNCS funcnames}} +// These are mostly handled the same, but needed because at least the MESA +// headers don't define any function prototypes for these. +#define DEF_GL3_DESC(name) \ + {offsetof(GL, name), NULL, {"gl" # name}, NULL, .is_gl3 = true} static const extfunc_desc_t extfuncs[] = { // these aren't extension functions but we query them anyway to allow // different "backends" with one binary - DEF_FUNC_DESC(Begin), - DEF_FUNC_DESC(End), DEF_FUNC_DESC(Viewport), - DEF_FUNC_DESC(MatrixMode), - DEF_FUNC_DESC(LoadIdentity), - DEF_FUNC_DESC(Translated), - DEF_FUNC_DESC(Scaled), - DEF_FUNC_DESC(Ortho), - DEF_FUNC_DESC(Frustum), - DEF_FUNC_DESC(PushMatrix), - DEF_FUNC_DESC(PopMatrix), DEF_FUNC_DESC(Clear), - DEF_FUNC_DESC(GenLists), - DEF_FUNC_DESC(DeleteLists), - DEF_FUNC_DESC(NewList), - DEF_FUNC_DESC(EndList), - DEF_FUNC_DESC(CallList), - DEF_FUNC_DESC(CallLists), DEF_FUNC_DESC(GenTextures), DEF_FUNC_DESC(DeleteTextures), - DEF_FUNC_DESC(TexEnvf), DEF_FUNC_DESC(TexEnvi), - DEF_FUNC_DESC(Color4ub), - DEF_FUNC_DESC(Color4f), DEF_FUNC_DESC(ClearColor), - DEF_FUNC_DESC(ClearDepth), - DEF_FUNC_DESC(DepthFunc), DEF_FUNC_DESC(Enable), DEF_FUNC_DESC(Disable), DEF_FUNC_DESC(DrawBuffer), @@ -348,25 +358,43 @@ static const extfunc_desc_t extfuncs[] = { DEF_FUNC_DESC(TexParameteri), DEF_FUNC_DESC(TexParameterf), DEF_FUNC_DESC(TexParameterfv), - DEF_FUNC_DESC(TexCoord2f), - DEF_FUNC_DESC(TexCoord2fv), - DEF_FUNC_DESC(Vertex2f), - DEF_FUNC_DESC(Vertex3f), - DEF_FUNC_DESC(Normal3f), - DEF_FUNC_DESC(Lightfv), - DEF_FUNC_DESC(ColorMaterial), - DEF_FUNC_DESC(ShadeModel), DEF_FUNC_DESC(GetIntegerv), + DEF_FUNC_DESC(GetBooleanv), DEF_FUNC_DESC(ColorMask), DEF_FUNC_DESC(ReadPixels), DEF_FUNC_DESC(ReadBuffer), + DEF_FUNC_DESC(DrawArrays), + DEF_FUNC_DESC(GetString), + DEF_FUNC_DESC(GetError), + + // legacy GL functions (1.x - 2.x) + DEF_FUNC_DESC(Begin), + DEF_FUNC_DESC(End), + DEF_FUNC_DESC(MatrixMode), + DEF_FUNC_DESC(LoadIdentity), + DEF_FUNC_DESC(Translated), + DEF_FUNC_DESC(Scaled), + DEF_FUNC_DESC(Ortho), + DEF_FUNC_DESC(PushMatrix), + DEF_FUNC_DESC(PopMatrix), + DEF_FUNC_DESC(GenLists), + DEF_FUNC_DESC(DeleteLists), + DEF_FUNC_DESC(NewList), + DEF_FUNC_DESC(EndList), + DEF_FUNC_DESC(CallList), + DEF_FUNC_DESC(CallLists), + DEF_FUNC_DESC(Color4ub), + DEF_FUNC_DESC(Color4f), + DEF_FUNC_DESC(TexCoord2f), + DEF_FUNC_DESC(TexCoord2fv), + DEF_FUNC_DESC(Vertex2f), DEF_FUNC_DESC(VertexPointer), DEF_FUNC_DESC(ColorPointer), DEF_FUNC_DESC(TexCoordPointer), - DEF_FUNC_DESC(DrawArrays), DEF_FUNC_DESC(EnableClientState), DEF_FUNC_DESC(DisableClientState), + // OpenGL extension functions DEF_EXT_DESC(GenBuffers, NULL, ("glGenBuffers", "glGenBuffersARB")), DEF_EXT_DESC(DeleteBuffers, NULL, @@ -379,18 +407,6 @@ static const extfunc_desc_t extfuncs[] = { ("glUnmapBuffer", "glUnmapBufferARB")), DEF_EXT_DESC(BufferData, NULL, ("glBufferData", "glBufferDataARB")), - DEF_EXT_DESC(BeginFragmentShader, "ATI_fragment_shader", - ("glBeginFragmentShaderATI")), - DEF_EXT_DESC(EndFragmentShader, "ATI_fragment_shader", - ("glEndFragmentShaderATI")), - DEF_EXT_DESC(SampleMap, "ATI_fragment_shader", - ("glSampleMapATI")), - DEF_EXT_DESC(ColorFragmentOp2, "ATI_fragment_shader", - ("glColorFragmentOp2ATI")), - DEF_EXT_DESC(ColorFragmentOp3, "ATI_fragment_shader", - ("glColorFragmentOp3ATI")), - DEF_EXT_DESC(SetFragmentShaderConstant, "ATI_fragment_shader", - ("glSetFragmentShaderConstantATI")), DEF_EXT_DESC(ActiveTexture, NULL, ("glActiveTexture", "glActiveTextureARB")), DEF_EXT_DESC(BindTexture, NULL, @@ -405,7 +421,7 @@ static const extfunc_desc_t extfuncs[] = { ("glBindProgramARB")), DEF_EXT_DESC(ProgramString, "_program", ("glProgramStringARB")), - DEF_EXT_DESC(GetProgramiv, "_program", + DEF_EXT_DESC(GetProgramivARB, "_program", ("glGetProgramivARB")), DEF_EXT_DESC(ProgramEnvParameter4f, "_program", ("glProgramEnvParameter4fARB")), @@ -414,6 +430,64 @@ static const extfunc_desc_t extfuncs[] = { "wglSwapInterval", "wglSwapIntervalEXT")), DEF_EXT_DESC(TexImage3D, NULL, ("glTexImage3D")), + + // ancient ATI extensions + DEF_EXT_DESC(BeginFragmentShader, "ATI_fragment_shader", + ("glBeginFragmentShaderATI")), + DEF_EXT_DESC(EndFragmentShader, "ATI_fragment_shader", + ("glEndFragmentShaderATI")), + DEF_EXT_DESC(SampleMap, "ATI_fragment_shader", + ("glSampleMapATI")), + DEF_EXT_DESC(ColorFragmentOp2, "ATI_fragment_shader", + ("glColorFragmentOp2ATI")), + DEF_EXT_DESC(ColorFragmentOp3, "ATI_fragment_shader", + ("glColorFragmentOp3ATI")), + DEF_EXT_DESC(SetFragmentShaderConstant, "ATI_fragment_shader", + ("glSetFragmentShaderConstantATI")), + + // GL 3, possibly in GL 2.x as well in form of extensions + DEF_GL3_DESC(GenBuffers), + DEF_GL3_DESC(DeleteBuffers), + DEF_GL3_DESC(BindBuffer), + DEF_GL3_DESC(MapBuffer), + DEF_GL3_DESC(UnmapBuffer), + DEF_GL3_DESC(BufferData), + DEF_GL3_DESC(ActiveTexture), + DEF_GL3_DESC(BindTexture), + DEF_GL3_DESC(GenVertexArrays), + DEF_GL3_DESC(BindVertexArray), + DEF_GL3_DESC(GetAttribLocation), + DEF_GL3_DESC(EnableVertexAttribArray), + DEF_GL3_DESC(DisableVertexAttribArray), + DEF_GL3_DESC(VertexAttribPointer), + DEF_GL3_DESC(DeleteVertexArrays), + DEF_GL3_DESC(UseProgram), + DEF_GL3_DESC(GetUniformLocation), + DEF_GL3_DESC(CompileShader), + DEF_GL3_DESC(CreateProgram), + DEF_GL3_DESC(CreateShader), + DEF_GL3_DESC(ShaderSource), + DEF_GL3_DESC(LinkProgram), + DEF_GL3_DESC(AttachShader), + DEF_GL3_DESC(DeleteShader), + DEF_GL3_DESC(DeleteProgram), + DEF_GL3_DESC(GetShaderInfoLog), + DEF_GL3_DESC(GetShaderiv), + DEF_GL3_DESC(GetProgramInfoLog), + DEF_GL3_DESC(GetProgramiv), + DEF_GL3_DESC(GetStringi), + DEF_GL3_DESC(BindAttribLocation), + DEF_GL3_DESC(BindFramebuffer), + DEF_GL3_DESC(GenFramebuffers), + DEF_GL3_DESC(DeleteFramebuffers), + DEF_GL3_DESC(CheckFramebufferStatus), + DEF_GL3_DESC(FramebufferTexture2D), + DEF_GL3_DESC(Uniform1f), + DEF_GL3_DESC(Uniform3f), + DEF_GL3_DESC(Uniform1i), + DEF_GL3_DESC(UniformMatrix3fv), + DEF_GL3_DESC(UniformMatrix4x3fv), + {-1} }; @@ -423,43 +497,53 @@ static const extfunc_desc_t extfuncs[] = { * \param ext2 an extra extension string */ static void getFunctions(GL *gl, void *(*getProcAddress)(const GLubyte *), - const char *ext2) + const char *ext2, bool is_gl3) { const extfunc_desc_t *dsc; - const char *extensions; - char *allexts; + char *allexts = talloc_strdup(NULL, ext2 ? ext2 : ""); + + *gl = (GL) {0}; if (!getProcAddress) getProcAddress = (void *)getdladdr; - // special case, we need glGetString before starting to find the other functions - gl->GetString = getProcAddress("glGetString"); - if (!gl->GetString) - gl->GetString = glGetString; - - extensions = (const char *)gl->GetString(GL_EXTENSIONS); - if (!extensions) - extensions = ""; - if (!ext2) - ext2 = ""; - allexts = malloc(strlen(extensions) + strlen(ext2) + 2); - strcpy(allexts, extensions); - strcat(allexts, " "); - strcat(allexts, ext2); + if (is_gl3) { + gl->GetStringi = getProcAddress("glGetStringi"); + gl->GetIntegerv = getProcAddress("glGetIntegerv"); + + if (!(gl->GetStringi && gl->GetIntegerv)) + return; + + GLint exts; + gl->GetIntegerv(GL_NUM_EXTENSIONS, &exts); + for (int n = 0; n < exts; n++) { + allexts = talloc_asprintf_append(allexts, " %s", + gl->GetStringi(GL_EXTENSIONS, n)); + } + } else { + gl->GetString = getProcAddress("glGetString"); + if (!gl->GetString) + gl->GetString = glGetString; + const char *ext = (char*)gl->GetString(GL_EXTENSIONS); + allexts = talloc_asprintf_append(allexts, " %s", ext); + } + mp_msg(MSGT_VO, MSGL_DBG2, "OpenGL extensions string:\n%s\n", allexts); for (dsc = extfuncs; dsc->offset >= 0; dsc++) { void *ptr = NULL; - int i; if (!dsc->extstr || strstr(allexts, dsc->extstr)) { - for (i = 0; !ptr && dsc->funcnames[i]; i++) + for (int i = 0; !ptr && dsc->funcnames[i]; i++) ptr = getProcAddress((const GLubyte *)dsc->funcnames[i]); } if (!ptr) ptr = dsc->fallback; + if (!ptr && !dsc->extstr && (!dsc->is_gl3 || is_gl3)) + mp_msg(MSGT_VO, MSGL_WARN, "[gl] OpenGL function not found: %s\n", + dsc->funcnames[0]); void **funcptr = (void**)(((char*)gl) + dsc->offset); *funcptr = ptr; } - free(allexts); + talloc_free(allexts); } /** @@ -1276,12 +1360,12 @@ int loadGPUProgram(GL *gl, GLenum target, char *prog) gl->GetString(GL_PROGRAM_ERROR_STRING), &prog[err]); return 0; } - if (!gl->GetProgramiv || !mp_msg_test(MSGT_VO, MSGL_DBG2)) + if (!gl->GetProgramivARB || !mp_msg_test(MSGT_VO, MSGL_DBG2)) return 1; mp_msg(MSGT_VO, MSGL_V, "[gl] Program statistics:\n"); for (i = 0; progstats[i].name; i++) { - gl->GetProgramiv(target, progstats[i].cur, &cur); - gl->GetProgramiv(target, progstats[i].max, &max); + gl->GetProgramivARB(target, progstats[i].cur, &cur); + gl->GetProgramivARB(target, progstats[i].max, &max); mp_msg(MSGT_VO, MSGL_V, "[gl] %s: %i/%i\n", progstats[i].name, cur, max); } @@ -1695,7 +1779,7 @@ static int create_window_cocoa(struct MPGLContext *ctx, uint32_t d_width, static int setGlWindow_cocoa(MPGLContext *ctx) { vo_cocoa_change_attributes(ctx->vo); - getFunctions(ctx->gl, (void *)vo_cocoa_glgetaddr, NULL); + getFunctions(ctx->gl, (void *)vo_cocoa_glgetaddr, NULL, false); if (!ctx->gl->SwapInterval) ctx->gl->SwapInterval = vo_cocoa_swap_interval; return SET_WINDOW_OK; @@ -1804,7 +1888,7 @@ static int setGlWindow_w32(MPGLContext *ctx) wglDeleteContext(*context); *context = new_context; *vinfo = new_vinfo; - getFunctions(gl, w32gpa, NULL); + getFunctions(ctx->gl, w32gpa, NULL, false); // and inform that reinit is neccessary res = SET_WINDOW_REINIT; @@ -1899,19 +1983,26 @@ static XVisualInfo *getWindowVisualInfo(MPGLContext *ctx, Window win) return XGetVisualInfo(ctx->vo->x11->display, VisualIDMask, &vinfo_template, &tmp); } -static void appendstr(char **dst, const char *str) +static char *get_glx_exts(MPGLContext *ctx) { - int newsize; - char *newstr; - if (!str) - return; - newsize = strlen(*dst) + 1 + strlen(str) + 1; - newstr = realloc(*dst, newsize); - if (!newstr) - return; - *dst = newstr; - strcat(*dst, " "); - strcat(*dst, str); + Display *display = ctx->vo->x11->display; + const char *(*glXExtStr)(Display *, int); + char *glxstr = talloc_strdup(NULL, ""); + + glXExtStr = getdladdr("glXQueryExtensionsString"); + if (glXExtStr) + glxstr = talloc_asprintf_append(glxstr, " %s", + glXExtStr(display, ctx->vo->x11->screen)); + glXExtStr = getdladdr("glXGetClientString"); + if (glXExtStr) + glxstr = talloc_asprintf_append(glxstr, " %s", + glXExtStr(display, GLX_EXTENSIONS)); + glXExtStr = getdladdr("glXGetServerString"); + if (glXExtStr) + glxstr = talloc_asprintf_append(glxstr, " %s", + glXExtStr(display, GLX_EXTENSIONS)); + + return glxstr; } /** @@ -1974,8 +2065,6 @@ static int setGlWindow_x11(MPGLContext *ctx) vo_x11_update_geometry(ctx->vo, 1); if (!keep_context) { void *(*getProcAddress)(const GLubyte *); - const char *(*glXExtStr)(Display *, int); - char *glxstr = strdup(""); if (*context) glXDestroyContext(display, *context); *context = new_context; @@ -1985,25 +2074,19 @@ static int setGlWindow_x11(MPGLContext *ctx) getProcAddress = getdladdr("glXGetProcAddress"); if (!getProcAddress) getProcAddress = getdladdr("glXGetProcAddressARB"); - glXExtStr = getdladdr("glXQueryExtensionsString"); - if (glXExtStr) - appendstr(&glxstr, glXExtStr(display, DefaultScreen(display))); - glXExtStr = getdladdr("glXGetClientString"); - if (glXExtStr) - appendstr(&glxstr, glXExtStr(display, GLX_EXTENSIONS)); - glXExtStr = getdladdr("glXGetServerString"); - if (glXExtStr) - appendstr(&glxstr, glXExtStr(display, GLX_EXTENSIONS)); - - getFunctions(gl, getProcAddress, glxstr); + + char *glxstr = get_glx_exts(ctx); + + getFunctions(gl, getProcAddress, glxstr, false); if (!gl->GenPrograms && gl->GetString && getProcAddress && strstr(gl->GetString(GL_EXTENSIONS), "GL_ARB_vertex_program")) { mp_msg(MSGT_VO, MSGL_WARN, "Broken glXGetProcAddress detected, trying workaround\n"); - getFunctions(gl, NULL, glxstr); + getFunctions(gl, NULL, glxstr, false); } - free(glxstr); + + talloc_free(glxstr); // and inform that reinit is neccessary return SET_WINDOW_REINIT; @@ -2011,6 +2094,146 @@ static int setGlWindow_x11(MPGLContext *ctx) return SET_WINDOW_OK; } +// The GL3 initialization code roughly follows/copies from: +// http://www.opengl.org/wiki/Tutorial:_OpenGL_3.0_Context_Creation_(GLX) +// but also uses some of the old code. + +static GLXFBConfig select_fb_config(struct vo *vo, const int *attribs) +{ + int fbcount; + GLXFBConfig *fbc = glXChooseFBConfig(vo->x11->display, vo->x11->screen, + attribs, &fbcount); + if (!fbc) + return NULL; + + // The list in fbc is sorted (so that the first element is the best). + GLXFBConfig fbconfig = fbc[0]; + + XFree(fbc); + + return fbconfig; +} + +typedef GLXContext (*glXCreateContextAttribsARBProc) + (Display*, GLXFBConfig, GLXContext, Bool, const int*); + +static int create_window_x11_gl3(struct MPGLContext *ctx, int gl_flags, + int gl_version, uint32_t d_width, + uint32_t d_height, uint32_t flags) +{ + struct vo *vo = ctx->vo; + + if (ctx->context.x11) { + // GL context and window already exist. + // Only update window geometry etc. + Colormap colormap = XCreateColormap(vo->x11->display, vo->x11->rootwin, + ctx->vinfo.x11->visual, AllocNone); + vo_x11_create_vo_window(vo, ctx->vinfo.x11, vo->dx, vo->dy, d_width, + d_height, flags, colormap, "gl"); + XFreeColormap(vo->x11->display, colormap); + return SET_WINDOW_OK; + } + + int glx_major, glx_minor; + + // FBConfigs were added in GLX version 1.3. + if (!glXQueryVersion(vo->x11->display, &glx_major, &glx_minor) || + (MPGL_VER(glx_major, glx_minor) < MPGL_VER(1, 3))) + { + mp_msg(MSGT_VO, MSGL_ERR, "[gl] GLX version older than 1.3.\n"); + return SET_WINDOW_FAILED; + } + + const int glx_attribs_stereo_value_idx = 1; // index of GLX_STEREO + 1 + int glx_attribs[] = { + GLX_STEREO, False, + GLX_X_RENDERABLE, True, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DOUBLEBUFFER, True, + None + }; + GLXFBConfig fbc = NULL; + if (flags & VOFLAG_STEREO) { + glx_attribs[glx_attribs_stereo_value_idx] = True; + fbc = select_fb_config(vo, glx_attribs); + if (!fbc) { + mp_msg(MSGT_VO, MSGL_ERR, "[gl] Could not find a stereo visual," + " 3D will probably not work!\n"); + glx_attribs[glx_attribs_stereo_value_idx] = False; + } + } + if (!fbc) + fbc = select_fb_config(vo, glx_attribs); + if (!fbc) { + mp_msg(MSGT_VO, MSGL_ERR, "[gl] no GLX support present\n"); + return SET_WINDOW_FAILED; + } + + glXGetFBConfigAttrib(vo->x11->display, fbc, GLX_RED_SIZE, &ctx->depth_r); + glXGetFBConfigAttrib(vo->x11->display, fbc, GLX_GREEN_SIZE, &ctx->depth_g); + glXGetFBConfigAttrib(vo->x11->display, fbc, GLX_BLUE_SIZE, &ctx->depth_b); + + XVisualInfo *vinfo = glXGetVisualFromFBConfig(vo->x11->display, fbc); + mp_msg(MSGT_VO, MSGL_V, "[gl] GLX chose visual with ID 0x%x\n", + (int)vinfo->visualid); + Colormap colormap = XCreateColormap(vo->x11->display, vo->x11->rootwin, + vinfo->visual, AllocNone); + vo_x11_create_vo_window(vo, vinfo, vo->dx, vo->dy, d_width, d_height, + flags, colormap, "gl"); + XFreeColormap(vo->x11->display, colormap); + + glXCreateContextAttribsARBProc glXCreateContextAttribsARB = + (glXCreateContextAttribsARBProc) + glXGetProcAddressARB((const GLubyte *)"glXCreateContextAttribsARB"); + + char *glxstr = get_glx_exts(ctx); + bool have_ctx_ext = !!strstr(glxstr, "GLX_ARB_create_context"); + + if (!(have_ctx_ext && glXCreateContextAttribsARB)) + { + XFree(vinfo); + talloc_free(glxstr); + return SET_WINDOW_FAILED; + } + + int context_attribs[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, MPGL_VER_GET_MAJOR(gl_version), + GLX_CONTEXT_MINOR_VERSION_ARB, MPGL_VER_GET_MINOR(gl_version), + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB + | (gl_flags & MPGLFLAG_DEBUG ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), + None + }; + GLXContext context = glXCreateContextAttribsARB(vo->x11->display, fbc, 0, + True, context_attribs); + if (!context) { + mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GLX context!\n"); + XFree(vinfo); + talloc_free(glxstr); + return SET_WINDOW_FAILED; + } + + // set context + if (!glXMakeCurrent(vo->x11->display, vo->x11->window, context)) { + mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GLX context!\n"); + glXDestroyContext(vo->x11->display, context); + XFree(vinfo); + talloc_free(glxstr); + return SET_WINDOW_FAILED; + } + + ctx->vinfo.x11 = vinfo; + ctx->context.x11 = context; + + getFunctions(ctx->gl, (void *)glXGetProcAddress, glxstr, true); + + talloc_free(glxstr); + + return SET_WINDOW_REINIT; +} + /** * \brief free the VisualInfo and GLXContext of an OpenGL context. * \ingroup glcontext @@ -2065,7 +2288,7 @@ static int setGlWindow_sdl(MPGLContext *ctx) if (sdl_set_mode(0, SDL_OPENGL | SDL_RESIZABLE) < 0) return SET_WINDOW_FAILED; SDL_GL_LoadLibrary(NULL); - getFunctions(ctx->gl, sdlgpa, NULL); + getFunctions(ctx->gl, sdlgpa, NULL, false); return SET_WINDOW_OK; } @@ -2176,6 +2399,7 @@ MPGLContext *init_mpglcontext(enum MPGLType type, struct vo *vo) case GLTYPE_X11: ctx->create_window = create_window_x11; ctx->setGlWindow = setGlWindow_x11; + ctx->create_window_gl3 = create_window_x11_gl3; ctx->releaseGlContext = releaseGlContext_x11; ctx->swapGlBuffers = swapGlBuffers_x11; ctx->update_xinerama_info = update_xinerama_info; @@ -2207,6 +2431,24 @@ MPGLContext *init_mpglcontext(enum MPGLType type, struct vo *vo) return NULL; } +int create_mpglcontext(struct MPGLContext *ctx, int gl_flags, int gl_version, + uint32_t d_width, uint32_t d_height, uint32_t flags) +{ + if (gl_version < MPGL_VER(3, 0)) { + if (ctx->create_window(ctx, d_width, d_height, flags) < 0) + return SET_WINDOW_FAILED; + return ctx->setGlWindow(ctx); + } else { + if (!ctx->create_window_gl3) { + mp_msg(MSGT_VO, MSGL_ERR, "[gl] OpenGL 3.x context creation not " + "implemented.\n"); + return SET_WINDOW_FAILED; + } + return ctx->create_window_gl3(ctx, gl_flags, gl_version, d_width, + d_height, flags); + } +} + void uninit_mpglcontext(MPGLContext *ctx) { if (!ctx) diff --git a/libvo/gl_common.h b/libvo/gl_common.h index 5c33db25bf..9646c5214a 100644 --- a/libvo/gl_common.h +++ b/libvo/gl_common.h @@ -270,6 +270,7 @@ void glDrawTex(GL *gl, GLfloat x, GLfloat y, GLfloat w, GLfloat h, GLfloat tx, GLfloat ty, GLfloat tw, GLfloat th, int sx, int sy, int rect_tex, int is_yv12, int flip); int loadGPUProgram(GL *gl, GLenum target, char *prog); +void glCheckError(GL *gl, const char *info); /** \addtogroup glconversion * \{ */ @@ -374,10 +375,20 @@ enum MPGLType { GLTYPE_SDL, }; +enum { + MPGLFLAG_DEBUG = 1, +}; + +#define MPGL_VER(major, minor) (((major) << 16) | (minor)) +#define MPGL_VER_GET_MAJOR(ver) ((ver) >> 16) +#define MPGL_VER_GET_MINOR(ver) ((ver) & ((1 << 16) - 1)) + typedef struct MPGLContext { GL *gl; enum MPGLType type; struct vo *vo; + // Bit size of each component in the created framebuffer. 0 if unknown. + int depth_r, depth_g, depth_b; union { int w32; #ifdef CONFIG_GL_X11 @@ -397,11 +408,19 @@ typedef struct MPGLContext { int (*setGlWindow)(struct MPGLContext *); void (*releaseGlContext)(struct MPGLContext *); void (*swapGlBuffers)(struct MPGLContext *); - void (*update_xinerama_info)(struct vo *vo); - void (*border)(struct vo *vo); int (*check_events)(struct vo *vo); void (*fullscreen)(struct vo *vo); + // only available if GL3 context creation is supported + // gl_flags: bitfield of MPGLFLAG_* constants + // gl_version: requested OpenGL version number (use MPGL_VER()) + // return value is one of the SET_WINDOW_* constants + int (*create_window_gl3)(struct MPGLContext *ctx, int gl_flags, + int gl_version, uint32_t d_width, + uint32_t d_height, uint32_t flags); + // optional void (*ontop)(struct vo *vo); + void (*border)(struct vo *vo); + void (*update_xinerama_info)(struct vo *vo); } MPGLContext; int mpgl_find_backend(const char *name); @@ -409,6 +428,10 @@ int mpgl_find_backend(const char *name); MPGLContext *init_mpglcontext(enum MPGLType type, struct vo *vo); void uninit_mpglcontext(MPGLContext *ctx); +// calls create_window_gl3 or create_window+setGlWindow +int create_mpglcontext(struct MPGLContext *ctx, int gl_flags, int gl_version, + uint32_t d_width, uint32_t d_height, uint32_t flags); + //function pointers loaded from the OpenGL library struct GL { void (GLAPIENTRY *Begin)(GLenum); @@ -419,7 +442,6 @@ struct GL { void (GLAPIENTRY *Translated)(double, double, double); void (GLAPIENTRY *Scaled)(double, double, double); void (GLAPIENTRY *Ortho)(double, double, double, double, double,double); - void (GLAPIENTRY *Frustum)(double, double, double, double, double, double); void (GLAPIENTRY *PushMatrix)(void); void (GLAPIENTRY *PopMatrix)(void); void (GLAPIENTRY *Clear)(GLbitfield); @@ -431,13 +453,10 @@ struct GL { void (GLAPIENTRY *CallLists)(GLsizei, GLenum, const GLvoid *); void (GLAPIENTRY *GenTextures)(GLsizei, GLuint *); void (GLAPIENTRY *DeleteTextures)(GLsizei, const GLuint *); - void (GLAPIENTRY *TexEnvf)(GLenum, GLenum, GLfloat); void (GLAPIENTRY *TexEnvi)(GLenum, GLenum, GLint); void (GLAPIENTRY *Color4ub)(GLubyte, GLubyte, GLubyte, GLubyte); void (GLAPIENTRY *Color4f)(GLfloat, GLfloat, GLfloat, GLfloat); void (GLAPIENTRY *ClearColor)(GLclampf, GLclampf, GLclampf, GLclampf); - void (GLAPIENTRY *ClearDepth)(GLclampd); - void (GLAPIENTRY *DepthFunc)(GLenum); void (GLAPIENTRY *Enable)(GLenum); void (GLAPIENTRY *Disable)(GLenum); const GLubyte *(GLAPIENTRY * GetString)(GLenum); @@ -461,12 +480,8 @@ struct GL { void (GLAPIENTRY *TexCoord2f)(GLfloat, GLfloat); void (GLAPIENTRY *TexCoord2fv)(const GLfloat *); void (GLAPIENTRY *Vertex2f)(GLfloat, GLfloat); - void (GLAPIENTRY *Vertex3f)(GLfloat, GLfloat, GLfloat); - void (GLAPIENTRY *Normal3f)(GLfloat, GLfloat, GLfloat); - void (GLAPIENTRY *Lightfv)(GLenum, GLenum, const GLfloat *); - void (GLAPIENTRY *ColorMaterial)(GLenum, GLenum); - void (GLAPIENTRY *ShadeModel)(GLenum); void (GLAPIENTRY *GetIntegerv)(GLenum, GLint *); + void (GLAPIENTRY *GetBooleanv)(GLenum, GLboolean *); void (GLAPIENTRY *ColorMask)(GLboolean, GLboolean, GLboolean, GLboolean); void (GLAPIENTRY *ReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid *); @@ -477,6 +492,7 @@ struct GL { void (GLAPIENTRY *DrawArrays)(GLenum, GLint, GLsizei); void (GLAPIENTRY *EnableClientState)(GLenum); void (GLAPIENTRY *DisableClientState)(GLenum); + GLenum (GLAPIENTRY *GetError)(void); // OpenGL extension functions @@ -486,15 +502,6 @@ struct GL { GLvoid * (GLAPIENTRY * MapBuffer)(GLenum, GLenum); GLboolean (GLAPIENTRY *UnmapBuffer)(GLenum); void (GLAPIENTRY *BufferData)(GLenum, intptr_t, const GLvoid *, GLenum); - void (GLAPIENTRY *BeginFragmentShader)(void); - void (GLAPIENTRY *EndFragmentShader)(void); - void (GLAPIENTRY *SampleMap)(GLuint, GLuint, GLenum); - void (GLAPIENTRY *ColorFragmentOp2)(GLenum, GLuint, GLuint, GLuint, GLuint, - GLuint, GLuint, GLuint, GLuint, GLuint); - void (GLAPIENTRY *ColorFragmentOp3)(GLenum, GLuint, GLuint, GLuint, GLuint, - GLuint, GLuint, GLuint, GLuint, GLuint, - GLuint, GLuint, GLuint); - void (GLAPIENTRY *SetFragmentShaderConstant)(GLuint, const GLfloat *); void (GLAPIENTRY *ActiveTexture)(GLenum); void (GLAPIENTRY *BindTexture)(GLenum, GLuint); void (GLAPIENTRY *MultiTexCoord2f)(GLenum, GLfloat, GLfloat); @@ -502,13 +509,67 @@ struct GL { void (GLAPIENTRY *DeletePrograms)(GLsizei, const GLuint *); void (GLAPIENTRY *BindProgram)(GLenum, GLuint); void (GLAPIENTRY *ProgramString)(GLenum, GLenum, GLsizei, const GLvoid *); - void (GLAPIENTRY *GetProgramiv)(GLenum, GLenum, GLint *); + void (GLAPIENTRY *GetProgramivARB)(GLenum, GLenum, GLint *); void (GLAPIENTRY *ProgramEnvParameter4f)(GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat); int (GLAPIENTRY *SwapInterval)(int); void (GLAPIENTRY *TexImage3D)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *); + + // ancient ATI extensions + void (GLAPIENTRY *BeginFragmentShader)(void); + void (GLAPIENTRY *EndFragmentShader)(void); + void (GLAPIENTRY *SampleMap)(GLuint, GLuint, GLenum); + void (GLAPIENTRY *ColorFragmentOp2)(GLenum, GLuint, GLuint, GLuint, GLuint, + GLuint, GLuint, GLuint, GLuint, GLuint); + void (GLAPIENTRY *ColorFragmentOp3)(GLenum, GLuint, GLuint, GLuint, GLuint, + GLuint, GLuint, GLuint, GLuint, GLuint, + GLuint, GLuint, GLuint); + void (GLAPIENTRY *SetFragmentShaderConstant)(GLuint, const GLfloat *); + + + // GL 3, possibly in GL 2.x as well in form of extensions + void (GLAPIENTRY *GenVertexArrays)(GLsizei, GLuint *); + void (GLAPIENTRY *BindVertexArray)(GLuint); + GLint (GLAPIENTRY *GetAttribLocation)(GLuint, const GLchar *); + void (GLAPIENTRY *EnableVertexAttribArray)(GLuint); + void (GLAPIENTRY *DisableVertexAttribArray)(GLuint); + void (GLAPIENTRY *VertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, + GLsizei, const GLvoid *); + void (GLAPIENTRY *DeleteVertexArrays)(GLsizei, const GLuint *); + void (GLAPIENTRY *UseProgram)(GLuint); + GLint (GLAPIENTRY *GetUniformLocation)(GLuint, const GLchar *); + void (GLAPIENTRY *CompileShader)(GLuint); + GLuint (GLAPIENTRY *CreateProgram)(void); + GLuint (GLAPIENTRY *CreateShader)(GLenum); + void (GLAPIENTRY *ShaderSource)(GLuint, GLsizei, const GLchar **, + const GLint *); + void (GLAPIENTRY *LinkProgram)(GLuint); + void (GLAPIENTRY *AttachShader)(GLuint, GLuint); + void (GLAPIENTRY *DeleteShader)(GLuint); + void (GLAPIENTRY *DeleteProgram)(GLuint); + void (GLAPIENTRY *GetShaderInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *); + void (GLAPIENTRY *GetShaderiv)(GLuint, GLenum, GLint *); + void (GLAPIENTRY *GetProgramInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *); + void (GLAPIENTRY *GetProgramiv)(GLenum, GLenum, GLint *); + const GLubyte* (GLAPIENTRY *GetStringi)(GLenum, GLuint); + void (GLAPIENTRY *BindAttribLocation)(GLuint, GLuint, const GLchar *); + void (GLAPIENTRY *BindFramebuffer)(GLenum, GLuint); + void (GLAPIENTRY *GenFramebuffers)(GLsizei, GLuint *); + void (GLAPIENTRY *DeleteFramebuffers)(GLsizei, const GLuint *); + GLenum (GLAPIENTRY *CheckFramebufferStatus)(GLenum); + void (GLAPIENTRY *FramebufferTexture2D)(GLenum, GLenum, GLenum, GLuint, + GLint); + + void (GLAPIENTRY *Uniform1f)(GLint, GLfloat); + void (GLAPIENTRY *Uniform3f)(GLint, GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY *Uniform1i)(GLint, GLint); + void (GLAPIENTRY *UniformMatrix3fv)(GLint, GLsizei, GLboolean, + const GLfloat *); + void (GLAPIENTRY *UniformMatrix4x3fv)(GLint, GLsizei, GLboolean, + const GLfloat *); + }; #endif /* MPLAYER_GL_COMMON_H */ -- 2.11.4.GIT