From f7f78f74373df057f39d5fc4c4906c76a9000287 Mon Sep 17 00:00:00 2001 From: Stanislav Vorobiov Date: Mon, 24 Feb 2014 22:11:31 +0400 Subject: [PATCH] VIGS/YaGL: Support OpenGL 3.1+ core on windows On windows we use WGL_ARB_create_context for that Change-Id: Ib032f4dc45d36d50b1af440f71d8d97ba5eb950a --- hw/vigs/vigs_gl_backend_wgl.c | 161 +++++++++++++- hw/yagl/yagl_drivers/egl_wgl/yagl_egl_wgl.c | 242 ++++++++++++++++++++- hw/yagl/yagl_drivers/gles_ogl/yagl_gles_ogl.c | 7 +- .../yagl_drivers/gles_ogl/yagl_gles_ogl_macros.h | 3 +- 4 files changed, 403 insertions(+), 10 deletions(-) diff --git a/hw/vigs/vigs_gl_backend_wgl.c b/hw/vigs/vigs_gl_backend_wgl.c index 4f6ea92..a775202 100644 --- a/hw/vigs/vigs_gl_backend_wgl.c +++ b/hw/vigs/vigs_gl_backend_wgl.c @@ -109,6 +109,9 @@ struct vigs_gl_backend_wgl PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB; PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB; + /* WGL_ARB_create_context */ + PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; + HWND win; HDC dc; HPBUFFERARB sfc; @@ -119,6 +122,130 @@ struct vigs_gl_backend_wgl HGLRC read_pixels_ctx; }; +static bool vigs_gl_backend_wgl_check_gl_version(struct vigs_gl_backend_wgl *gl_backend_wgl, + bool *is_gl_2) +{ + int config_attribs[] = { + WGL_SUPPORT_OPENGL_ARB, TRUE, + WGL_DOUBLE_BUFFER_ARB, TRUE, + WGL_DRAW_TO_PBUFFER_ARB, TRUE, + WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, + WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, + WGL_RED_BITS_ARB, 8, + WGL_GREEN_BITS_ARB, 8, + WGL_BLUE_BITS_ARB, 8, + WGL_ALPHA_BITS_ARB, 8, + WGL_COLOR_BITS_ARB, 32, + WGL_DEPTH_BITS_ARB, 24, + WGL_STENCIL_BITS_ARB, 8, + 0, + }; + int ctx_attribs[] = + { + WGL_CONTEXT_MAJOR_VERSION_ARB, 3, + WGL_CONTEXT_MINOR_VERSION_ARB, 1, + WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + 0 + }; + bool res = false; + const char *tmp; + HWND win; + HDC dc; + int config_id = 0; + UINT n = 0; + PIXELFORMATDESCRIPTOR pix_fmt; + HGLRC ctx; + + tmp = getenv("GL_VERSION"); + + if (tmp) { + if (strcmp(tmp, "2") == 0) { + VIGS_LOG_INFO("GL_VERSION forces OpenGL version to 2.1"); + *is_gl_2 = true; + res = true; + } else if (strcmp(tmp, "3_1") == 0) { + VIGS_LOG_INFO("GL_VERSION forces OpenGL version to 3.1"); + *is_gl_2 = false; + res = true; + } else if (strcmp(tmp, "3_1_es3") == 0) { + VIGS_LOG_INFO("GL_VERSION forces OpenGL version to 3.1 ES3"); + *is_gl_2 = false; + res = true; + } else if (strcmp(tmp, "3_2") == 0) { + VIGS_LOG_INFO("GL_VERSION forces OpenGL version to 3.2"); + *is_gl_2 = false; + res = true; + } else { + VIGS_LOG_CRITICAL("Bad GL_VERSION value = %s", tmp); + } + + goto out1; + } + + win = CreateWindow(VIGS_WGL_WIN_CLASS, "VIGSWin", + WS_DISABLED | WS_POPUP, + 0, 0, 1, 1, NULL, NULL, 0, 0); + + if (!win) { + VIGS_LOG_ERROR("CreateWindow failed"); + goto out1; + } + + dc = GetDC(win); + if (!dc) { + VIGS_LOG_ERROR("GetDC failed"); + goto out2; + } + + if (!gl_backend_wgl->wglChoosePixelFormatARB(dc, + config_attribs, + NULL, + 1, + &config_id, + &n) || (n == 0)) { + VIGS_LOG_ERROR("wglChoosePixelFormatARB failed"); + goto out3; + } + + if (!DescribePixelFormat(dc, + config_id, + sizeof(PIXELFORMATDESCRIPTOR), + &pix_fmt)) { + VIGS_LOG_ERROR("DescribePixelFormat failed"); + goto out3; + } + + if (!SetPixelFormat(dc, + config_id, + &pix_fmt)) { + VIGS_LOG_ERROR("SetPixelFormat failed"); + goto out3; + } + + ctx = gl_backend_wgl->wglCreateContextAttribsARB(dc, + NULL, + ctx_attribs); + + *is_gl_2 = (ctx == NULL); + res = true; + + if (ctx) { + VIGS_LOG_INFO("Using OpenGL 3.1+ core"); + } else { + VIGS_LOG_INFO("wglCreateContextAttribsARB failed, using OpenGL 2.1"); + } + + gl_backend_wgl->wglDeleteContext(ctx); + +out3: + ReleaseDC(win, dc); +out2: + DestroyWindow(win); +out1: + + return res; +} + static int vigs_gl_backend_wgl_choose_config(struct vigs_gl_backend_wgl *gl_backend_wgl) { const int config_attribs[] = { @@ -199,14 +326,28 @@ static bool vigs_gl_backend_wgl_create_context(struct vigs_gl_backend_wgl *gl_ba HGLRC share_ctx, HGLRC *ctx) { - *ctx = gl_backend_wgl->wglCreateContext(gl_backend_wgl->dc); + int attribs[] = + { + WGL_CONTEXT_MAJOR_VERSION_ARB, 3, + WGL_CONTEXT_MINOR_VERSION_ARB, 1, + WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + 0 + }; + + if (gl_backend_wgl->base.is_gl_2) { + *ctx = gl_backend_wgl->wglCreateContext(gl_backend_wgl->dc); + } else { + *ctx = gl_backend_wgl->wglCreateContextAttribsARB(gl_backend_wgl->dc, + share_ctx, + attribs); + } if (!*ctx) { - VIGS_LOG_CRITICAL("wglCreateContext failed"); + VIGS_LOG_CRITICAL("wglCreateContextAttribsARB/wglCreateContext failed"); return false; } - if (share_ctx) { + if (share_ctx && gl_backend_wgl->base.is_gl_2) { if (!gl_backend_wgl->wglShareLists(share_ctx, *ctx)) { VIGS_LOG_CRITICAL("wglShareLists failed"); gl_backend_wgl->wglDeleteContext(*ctx); @@ -417,6 +558,7 @@ struct vigs_backend *vigs_gl_backend_create(void *display) VIGS_WGL_GET_EXT_PROC(WGL_ARB_pbuffer, PFNWGLRELEASEPBUFFERDCARBPROC, wglReleasePbufferDCARB); VIGS_WGL_GET_EXT_PROC(WGL_ARB_pbuffer, PFNWGLDESTROYPBUFFERARBPROC, wglDestroyPbufferARB); VIGS_WGL_GET_EXT_PROC(WGL_ARB_pixel_format, PFNWGLCHOOSEPIXELFORMATARBPROC, wglChoosePixelFormatARB); + VIGS_WGL_GET_EXT_PROC(WGL_ARB_create_context, PFNWGLCREATECONTEXTATTRIBSARBPROC, wglCreateContextAttribsARB); VIGS_GL_GET_PROC(GenTextures, glGenTextures); VIGS_GL_GET_PROC(DeleteTextures, glDeleteTextures); @@ -480,6 +622,17 @@ struct vigs_backend *vigs_gl_backend_create(void *display) VIGS_GL_GET_PROC_OPTIONAL(MapBufferRange, glMapBufferRange); + if (!vigs_gl_backend_wgl_check_gl_version(gl_backend_wgl, + &gl_backend_wgl->base.is_gl_2)) { + goto fail; + } + + if (!gl_backend_wgl->base.is_gl_2) { + VIGS_GL_GET_PROC(GenVertexArrays, glGenVertexArrays); + VIGS_GL_GET_PROC(BindVertexArray, glBindVertexArray); + VIGS_GL_GET_PROC(DeleteVertexArrays, glDeleteVertexArrays); + } + gl_backend_wgl->wglMakeCurrent(NULL, NULL); gl_backend_wgl->wglDeleteContext(tmp_ctx); tmp_ctx = NULL; @@ -504,8 +657,6 @@ struct vigs_backend *vigs_gl_backend_create(void *display) goto fail; } - gl_backend_wgl->base.is_gl_2 = true; - config_id = vigs_gl_backend_wgl_choose_config(gl_backend_wgl); if (!config_id) { diff --git a/hw/yagl/yagl_drivers/egl_wgl/yagl_egl_wgl.c b/hw/yagl/yagl_drivers/egl_wgl/yagl_egl_wgl.c index 98d621d..f6d673e 100644 --- a/hw/yagl/yagl_drivers/egl_wgl/yagl_egl_wgl.c +++ b/hw/yagl/yagl_drivers/egl_wgl/yagl_egl_wgl.c @@ -115,6 +115,9 @@ typedef struct YaglEglWglDriver { PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB; PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB; PFNWGLMAKECONTEXTCURRENTARBPROC wglMakeContextCurrentARB; + + /* WGL_ARB_create_context */ + PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; } YaglEglWglDriver; static inline HWND yagl_egl_wgl_dummy_win_create(void) @@ -123,6 +126,221 @@ static inline HWND yagl_egl_wgl_dummy_win_create(void) WS_DISABLED | WS_POPUP, 0, 0, 1, 1, NULL, NULL, 0, 0); } +static bool yagl_egl_wgl_get_gl_version(YaglEglWglDriver *egl_wgl, + yagl_gl_version *version) +{ + int config_attribs[] = { + WGL_SUPPORT_OPENGL_ARB, TRUE, + WGL_DOUBLE_BUFFER_ARB, TRUE, + WGL_DRAW_TO_PBUFFER_ARB, TRUE, + WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, + WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, + WGL_RED_BITS_ARB, 8, + WGL_GREEN_BITS_ARB, 8, + WGL_BLUE_BITS_ARB, 8, + WGL_ALPHA_BITS_ARB, 8, + WGL_COLOR_BITS_ARB, 32, + WGL_DEPTH_BITS_ARB, 24, + WGL_STENCIL_BITS_ARB, 8, + 0, + }; + int ctx_attribs[] = + { + WGL_CONTEXT_MAJOR_VERSION_ARB, 3, + WGL_CONTEXT_MINOR_VERSION_ARB, 1, + WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + 0 + }; + int pbuff_attribs[] = + { + WGL_PBUFFER_LARGEST_ARB, FALSE, + WGL_TEXTURE_TARGET_ARB, WGL_NO_TEXTURE_ARB, + WGL_TEXTURE_FORMAT_ARB, WGL_NO_TEXTURE_ARB, + 0 + }; + bool res = false; + const char *tmp; + HWND win; + HDC dc; + int config_id = 0; + UINT n = 0; + PIXELFORMATDESCRIPTOR pix_fmt; + HGLRC ctx; + HPBUFFERARB pbuffer; + HDC pbuffer_dc; + const GLubyte *(GLAPIENTRY *GetStringi)(GLenum, GLuint) = NULL; + void (GLAPIENTRY *GetIntegerv)(GLenum, GLint*) = NULL; + GLint i, num_extensions = 0; + GLint major = 0, minor = 0; + + YAGL_EGL_WGL_ENTER(yagl_egl_wgl_get_gl_version, NULL); + + tmp = getenv("GL_VERSION"); + + if (tmp) { + if (strcmp(tmp, "2") == 0) { + YAGL_LOG_INFO("GL_VERSION forces OpenGL version to 2.1"); + *version = yagl_gl_2; + res = true; + } else if (strcmp(tmp, "3_1") == 0) { + YAGL_LOG_INFO("GL_VERSION forces OpenGL version to 3.1"); + *version = yagl_gl_3_1; + res = true; + } else if (strcmp(tmp, "3_1_es3") == 0) { + YAGL_LOG_INFO("GL_VERSION forces OpenGL version to 3.1 ES3"); + *version = yagl_gl_3_1_es3; + res = true; + } else if (strcmp(tmp, "3_2") == 0) { + YAGL_LOG_INFO("GL_VERSION forces OpenGL version to 3.2"); + *version = yagl_gl_3_2; + res = true; + } else { + YAGL_LOG_CRITICAL("Bad GL_VERSION value = %s", tmp); + } + + goto out1; + } + + win = yagl_egl_wgl_dummy_win_create(); + if (!win) { + YAGL_LOG_ERROR("CreateWindow failed"); + goto out1; + } + + dc = GetDC(win); + if (!dc) { + YAGL_LOG_ERROR("GetDC failed"); + goto out2; + } + + if (!egl_wgl->wglChoosePixelFormatARB(dc, + config_attribs, + NULL, + 1, + &config_id, + &n) || (n == 0)) { + YAGL_LOG_ERROR("wglChoosePixelFormatARB failed"); + goto out3; + } + + if (!DescribePixelFormat(dc, + config_id, + sizeof(PIXELFORMATDESCRIPTOR), + &pix_fmt)) { + YAGL_LOG_ERROR("DescribePixelFormat failed"); + goto out3; + } + + if (!SetPixelFormat(dc, + config_id, + &pix_fmt)) { + YAGL_LOG_ERROR("SetPixelFormat failed"); + goto out3; + } + + ctx = egl_wgl->wglCreateContextAttribsARB(dc, + NULL, + ctx_attribs); + + if (!ctx) { + YAGL_LOG_INFO("wglCreateContextAttribsARB failed, using OpenGL 2.1"); + *version = yagl_gl_2; + res = true; + goto out3; + } + + pbuffer = egl_wgl->wglCreatePbufferARB(dc, config_id, + 1, 1, pbuff_attribs); + + if (!pbuffer) { + YAGL_LOG_ERROR("wglCreatePbufferARB failed"); + goto out4; + } + + pbuffer_dc = egl_wgl->wglGetPbufferDCARB(pbuffer); + + if (!pbuffer_dc) { + YAGL_LOG_ERROR("wglGetPbufferDCARB failed"); + goto out5; + } + + if (!egl_wgl->wglMakeCurrent(pbuffer_dc, ctx)) { + YAGL_LOG_ERROR("wglMakeCurrent failed"); + goto out6; + } + + GetStringi = yagl_dyn_lib_get_ogl_procaddr(egl_wgl->base.dyn_lib, + "glGetStringi"); + + if (!GetStringi) { + YAGL_LOG_ERROR("Unable to get symbol: %s", + yagl_dyn_lib_get_error(egl_wgl->base.dyn_lib)); + goto out7; + } + + GetIntegerv = yagl_dyn_lib_get_ogl_procaddr(egl_wgl->base.dyn_lib, + "glGetIntegerv"); + + if (!GetIntegerv) { + YAGL_LOG_ERROR("Unable to get symbol: %s", + yagl_dyn_lib_get_error(egl_wgl->base.dyn_lib)); + goto out7; + } + + GetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); + + for (i = 0; i < num_extensions; ++i) { + tmp = (const char*)GetStringi(GL_EXTENSIONS, i); + if (strcmp(tmp, "GL_ARB_ES3_compatibility") == 0) { + YAGL_LOG_INFO("GL_ARB_ES3_compatibility supported, using OpenGL 3.1 ES3"); + *version = yagl_gl_3_1_es3; + res = true; + goto out7; + } + } + + /* + * No GL_ARB_ES3_compatibility, so we need at least OpenGL 3.2 to be + * able to patch shaders and run them with GLSL 1.50. + */ + + GetIntegerv(GL_MAJOR_VERSION, &major); + GetIntegerv(GL_MINOR_VERSION, &minor); + + if ((major > 3) || + ((major == 3) && (minor >= 2))) { + YAGL_LOG_INFO("GL_ARB_ES3_compatibility not supported, using OpenGL 3.2"); + *version = yagl_gl_3_2; + res = true; + goto out7; + } + + YAGL_LOG_INFO("GL_ARB_ES3_compatibility not supported, OpenGL 3.2 not supported, using OpenGL 3.1"); + *version = yagl_gl_3_1; + res = true; + +out7: + egl_wgl->wglMakeCurrent(NULL, NULL); +out6: + egl_wgl->wglReleasePbufferDCARB(pbuffer, pbuffer_dc); +out5: + egl_wgl->wglDestroyPbufferARB(pbuffer); +out4: + egl_wgl->wglDeleteContext(ctx); +out3: + ReleaseDC(win, dc); +out2: + DestroyWindow(win); +out1: + if (res) { + YAGL_LOG_FUNC_EXIT("%d, version = %u", res, *version); + } else { + YAGL_LOG_FUNC_EXIT("%d", res); + } + + return res; +} + static inline bool yagl_egl_wgl_dc_set_def_pixfmt(HDC dc) { INT pixfmt_idx; @@ -505,6 +723,13 @@ static EGLContext yagl_egl_wgl_context_create(struct yagl_egl_driver *driver, { YaglEglWglDriver *egl_wgl = (YaglEglWglDriver *)(driver); YaglEglWglDpy *dpy = (YaglEglWglDpy *)egl_dpy; + int attribs[] = + { + WGL_CONTEXT_MAJOR_VERSION_ARB, 3, + WGL_CONTEXT_MINOR_VERSION_ARB, 1, + WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + 0 + }; HGLRC egl_wgl_ctx; HDC dc; @@ -518,12 +743,20 @@ static EGLContext yagl_egl_wgl_context_create(struct yagl_egl_driver *driver, goto fail; } - egl_wgl_ctx = egl_wgl->wglCreateContext(dc); + if ((egl_wgl->base.gl_version > yagl_gl_2) && (version != 1)) { + egl_wgl_ctx = egl_wgl->wglCreateContextAttribsARB(dc, + share_context, + attribs); + } else { + egl_wgl_ctx = egl_wgl->wglCreateContext(dc); + } + if (!egl_wgl_ctx) { goto fail; } - if (share_context != EGL_NO_CONTEXT) { + if ((share_context != EGL_NO_CONTEXT) && + ((egl_wgl->base.gl_version <= yagl_gl_2) || (version == 1))) { if(!egl_wgl->wglShareLists((HGLRC)share_context, egl_wgl_ctx)) { egl_wgl->wglDeleteContext(egl_wgl_ctx); @@ -828,6 +1061,7 @@ static bool yagl_egl_wgl_init_ext(YaglEglWglDriver *egl_wgl) YAGL_EGL_WGL_GET_EXT_PROC(WGL_ARB_pbuffer, wglDestroyPbufferARB, PFNWGLDESTROYPBUFFERARBPROC); YAGL_EGL_WGL_GET_EXT_PROC(WGL_ARB_pixel_format, wglChoosePixelFormatARB, PFNWGLCHOOSEPIXELFORMATARBPROC); YAGL_EGL_WGL_GET_EXT_PROC(WGL_ARB_make_current_read, wglMakeContextCurrentARB, PFNWGLMAKECONTEXTCURRENTARBPROC); + YAGL_EGL_WGL_GET_EXT_PROC(WGL_ARB_create_context, wglCreateContextAttribsARB, PFNWGLCREATECONTEXTATTRIBSARBPROC); ext_initialized = true; @@ -920,6 +1154,10 @@ struct yagl_egl_driver *yagl_egl_driver_create(void *display) goto fail; } + if (!yagl_egl_wgl_get_gl_version(egl_wgl, &egl_wgl->base.gl_version)) { + goto fail; + } + YAGL_LOG_FUNC_EXIT("EGL WGL driver created (%p)", egl_driver); return egl_driver; diff --git a/hw/yagl/yagl_drivers/gles_ogl/yagl_gles_ogl.c b/hw/yagl/yagl_drivers/gles_ogl/yagl_gles_ogl.c index 660f2af..dd549c8 100644 --- a/hw/yagl/yagl_drivers/gles_ogl/yagl_gles_ogl.c +++ b/hw/yagl/yagl_drivers/gles_ogl/yagl_gles_ogl.c @@ -242,6 +242,11 @@ struct yagl_gles_driver *yagl_gles_ogl_create(struct yagl_dyn_lib *dyn_lib, YAGL_GLES_OGL_GET_PROC(driver, GenVertexArrays, glGenVertexArrays); YAGL_GLES_OGL_GET_PROC(driver, BindVertexArray, glBindVertexArray); YAGL_GLES_OGL_GET_PROC(driver, DeleteVertexArrays, glDeleteVertexArrays); + } else { + YAGL_GLES_OGL_GET_PROC_OPT(driver, MapBufferRange, glMapBufferRange); + } + + if (gl_version >= yagl_gl_3_1_es3) { YAGL_GLES_OGL_GET_PROC(driver, GetActiveUniformsiv, glGetActiveUniformsiv); YAGL_GLES_OGL_GET_PROC(driver, GetUniformIndices, glGetUniformIndices); YAGL_GLES_OGL_GET_PROC(driver, GetUniformBlockIndex, glGetUniformBlockIndex); @@ -305,8 +310,6 @@ struct yagl_gles_driver *yagl_gles_ogl_create(struct yagl_dyn_lib *dyn_lib, YAGL_GLES_OGL_GET_PROC(driver, ClearBufferfv, glClearBufferfv); YAGL_GLES_OGL_GET_PROC(driver, GetFragDataLocation, glGetFragDataLocation); YAGL_GLES_OGL_GET_PROC(driver, DrawRangeElements, glDrawRangeElements); - } else { - YAGL_GLES_OGL_GET_PROC_OPT(driver, MapBufferRange, glMapBufferRange); } driver->destroy = &yagl_gles_ogl_destroy; diff --git a/hw/yagl/yagl_drivers/gles_ogl/yagl_gles_ogl_macros.h b/hw/yagl/yagl_drivers/gles_ogl/yagl_gles_ogl_macros.h index d3a0267..8f76bbd 100644 --- a/hw/yagl/yagl_drivers/gles_ogl/yagl_gles_ogl_macros.h +++ b/hw/yagl/yagl_drivers/gles_ogl/yagl_gles_ogl_macros.h @@ -41,7 +41,8 @@ do { \ *(void**)(&driver->func) = yagl_dyn_lib_get_ogl_procaddr(dyn_lib, #sym); \ if (!driver->func) { \ - YAGL_LOG_ERROR("Unable to get symbol: %s", \ + YAGL_LOG_ERROR("Unable to get symbol \"%s\": %s", \ + #sym, \ yagl_dyn_lib_get_error(dyn_lib)); \ goto fail; \ } \ -- 2.7.4