static bool vigs_gl_backend_wgl_create_surface(struct vigs_gl_backend_wgl *gl_backend_wgl,
                                               int config_id,
                                               HPBUFFERARB *sfc,
                                               HDC *sfc_dc)
{
    int surface_attribs[] = {
        WGL_PBUFFER_LARGEST_ARB, FALSE,
        WGL_TEXTURE_TARGET_ARB, WGL_NO_TEXTURE_ARB,
        WGL_TEXTURE_FORMAT_ARB, WGL_NO_TEXTURE_ARB,
        0
    };

    *sfc = gl_backend_wgl->wglCreatePbufferARB(gl_backend_wgl->dc, config_id,
                                               1, 1, surface_attribs);

    if (!*sfc) {
        VIGS_LOG_CRITICAL("wglCreatePbufferARB failed");
        return false;
    }

    *sfc_dc = gl_backend_wgl->wglGetPbufferDCARB(*sfc);

    if (!*sfc_dc) {
        VIGS_LOG_CRITICAL("wglGetPbufferDCARB failed");
        return false;
    }

    return true;
}
static bool vigs_gl_backend_wgl_read_pixels_make_current(struct vigs_gl_backend *gl_backend,
                                                         bool enable)
{
    struct vigs_gl_backend_wgl *gl_backend_wgl =
        (struct vigs_gl_backend_wgl*)gl_backend;

    if (enable) {
        if (!gl_backend_wgl->wglMakeCurrent(gl_backend_wgl->read_pixels_sfc_dc, gl_backend_wgl->read_pixels_ctx)) {
            VIGS_LOG_CRITICAL("wglMakeCurrent failed");
            return false;
        }
    } else {
        if (!gl_backend_wgl->wglMakeCurrent(NULL, NULL)) {
            VIGS_LOG_CRITICAL("wglMakeCurrent failed");
            return false;
        }
    }

    return true;
}
static bool vigs_gl_backend_wgl_create_context(struct vigs_gl_backend_wgl *gl_backend_wgl,
                                               HGLRC share_ctx,
                                               HGLRC *ctx)
{
    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("wglCreateContextAttribsARB/wglCreateContext failed");
        return false;
    }

    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);
            *ctx = NULL;
            return false;
        }
    }

    return true;
}
Exemple #4
0
static void vigs_io_write(void *opaque, hwaddr offset,
                          uint64_t value, unsigned size)
{
    VIGSState *s = opaque;

    switch (offset) {
    case VIGS_REG_EXEC:
        vigs_server_dispatch(s->server, value);
        break;
    case VIGS_REG_CON:
        if (((s->reg_con & VIGS_REG_CON_VBLANK_ENABLE) == 0) &&
            (value & VIGS_REG_CON_VBLANK_ENABLE)) {
            VIGS_LOG_DEBUG("VBLANK On");
        } else if (((value & VIGS_REG_CON_VBLANK_ENABLE) == 0) &&
                   (s->reg_con & VIGS_REG_CON_VBLANK_ENABLE)) {
            VIGS_LOG_DEBUG("VBLANK Off");
        }

        s->reg_con = value & VIGS_REG_CON_MASK;

        vigs_update_irq(s);
        break;
    case VIGS_REG_INT:
        if (value & VIGS_REG_INT_VBLANK_PENDING) {
            value &= ~VIGS_REG_INT_VBLANK_PENDING;
        } else {
            value |= (s->reg_int & VIGS_REG_INT_VBLANK_PENDING);
        }

        if (value & VIGS_REG_INT_FENCE_ACK_PENDING) {
            value &= ~VIGS_REG_INT_FENCE_ACK_PENDING;
        } else {
            value |= (s->reg_int & VIGS_REG_INT_FENCE_ACK_PENDING);
        }

        s->reg_int = value & VIGS_REG_INT_MASK;

        vigs_update_irq(s);
        break;
    default:
        VIGS_LOG_CRITICAL("Bad register 0x%X write", (uint32_t)offset);
        break;
    }
}
Exemple #5
0
static uint64_t vigs_io_read(void *opaque, hwaddr offset,
                             unsigned size)
{
    VIGSState *s = opaque;

    switch (offset) {
    case VIGS_REG_CON:
        return s->reg_con;
    case VIGS_REG_INT:
        return s->reg_int;
    case VIGS_REG_FENCE_LOWER:
        return vigs_fenceman_get_lower(s->fenceman);
    case VIGS_REG_FENCE_UPPER:
        return vigs_fenceman_get_upper(s->fenceman);
    default:
        VIGS_LOG_CRITICAL("Bad register 0x%X read", (uint32_t)offset);
        break;
    }

    return 0;
}
struct vigs_backend *vigs_gl_backend_create(void *display)
{
    WNDCLASSEXA vigs_win_class;
    HWND tmp_win = NULL;
    HDC tmp_dc = NULL;
    HGLRC tmp_ctx = NULL;
    int config_id = 0;
    PIXELFORMATDESCRIPTOR tmp_pixfmt = {
        .nSize = sizeof(PIXELFORMATDESCRIPTOR),
        .nVersion = 1,
        .dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
        .iPixelType = PFD_TYPE_RGBA,
        .cColorBits = 32,
        .cDepthBits = 24,
        .cStencilBits = 8,
        .iLayerType = PFD_MAIN_PLANE,
    };
    const char *ext_str = NULL;
    struct vigs_gl_backend_wgl *gl_backend_wgl = NULL;

    vigs_win_class.cbSize = sizeof(WNDCLASSEXA);
    vigs_win_class.style = 0;
    vigs_win_class.lpfnWndProc = &DefWindowProcA;
    vigs_win_class.cbClsExtra = 0;
    vigs_win_class.cbWndExtra = 0;
    vigs_win_class.hInstance = NULL;
    vigs_win_class.hIcon = NULL;
    vigs_win_class.hCursor = NULL;
    vigs_win_class.hbrBackground = NULL;
    vigs_win_class.lpszMenuName =  NULL;
    vigs_win_class.lpszClassName = VIGS_WGL_WIN_CLASS;
    vigs_win_class.hIconSm = NULL;

    if (!RegisterClassExA(&vigs_win_class)) {
        VIGS_LOG_CRITICAL("Unable to register window class");
        return NULL;
    }

    gl_backend_wgl = g_malloc0(sizeof(*gl_backend_wgl));

    vigs_backend_init(&gl_backend_wgl->base.base,
                      &gl_backend_wgl->base.ws_info.base);

    gl_backend_wgl->handle = LoadLibraryA("opengl32");

    if (!gl_backend_wgl->handle) {
        VIGS_LOG_CRITICAL("Unable to load opengl32.dll");
        goto fail;
    }

    VIGS_WGL_GET_PROC(PFNWGLCREATECONTEXTPROC, wglCreateContext, fail);
    VIGS_WGL_GET_PROC(PFNWGLDELETECONTEXTPROC, wglDeleteContext, fail);
    VIGS_WGL_GET_PROC(PFNWGLGETPROCADDRESSPROC, wglGetProcAddress, fail);
    VIGS_WGL_GET_PROC(PFNWGLMAKECURRENTPROC, wglMakeCurrent, fail);
    VIGS_WGL_GET_PROC(PFNWGLGETCURRENTCONTEXTPROC, wglGetCurrentContext, fail);
    VIGS_WGL_GET_PROC(PFNWGLSHARELISTSPROC, wglShareLists, fail);

    tmp_win = CreateWindow(VIGS_WGL_WIN_CLASS, "VIGSWin",
                           WS_DISABLED | WS_POPUP,
                           0, 0, 1, 1, NULL, NULL, 0, 0);

    if (!tmp_win) {
        VIGS_LOG_CRITICAL("Unable to create window");
        goto fail;
    }

    tmp_dc = GetDC(tmp_win);

    if (!tmp_dc) {
        VIGS_LOG_CRITICAL("Unable to get window DC");
        goto fail;
    }

    config_id = ChoosePixelFormat(tmp_dc, &tmp_pixfmt);

    if (!config_id) {
        VIGS_LOG_CRITICAL("ChoosePixelFormat failed");
        goto fail;
    }

    if (!SetPixelFormat(tmp_dc, config_id, &tmp_pixfmt)) {
        VIGS_LOG_CRITICAL("SetPixelFormat failed");
        goto fail;
    }

    tmp_ctx = gl_backend_wgl->wglCreateContext(tmp_dc);
    if (!tmp_ctx) {
        VIGS_LOG_CRITICAL("wglCreateContext failed");
        goto fail;
    }

    if (!gl_backend_wgl->wglMakeCurrent(tmp_dc, tmp_ctx)) {
        VIGS_LOG_CRITICAL("wglMakeCurrent failed");
        goto fail;
    }

    /*
     * WGL extensions couldn't be queried by glGetString(), we need to use
     * wglGetExtensionsStringARB or wglGetExtensionsStringEXT for this, which
     * themselves are extensions
     */
    gl_backend_wgl->wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
        gl_backend_wgl->wglGetProcAddress((LPCSTR)"wglGetExtensionsStringARB");
    gl_backend_wgl->wglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)
        gl_backend_wgl->wglGetProcAddress((LPCSTR)"wglGetExtensionsStringEXT");

    if (gl_backend_wgl->wglGetExtensionsStringARB) {
        ext_str = gl_backend_wgl->wglGetExtensionsStringARB(tmp_dc);
    } else if (gl_backend_wgl->wglGetExtensionsStringEXT) {
        ext_str = gl_backend_wgl->wglGetExtensionsStringEXT();
    }

    if (!ext_str) {
        VIGS_LOG_CRITICAL("Unable to obtain WGL extension string");
        goto fail;
    }

    VIGS_WGL_GET_EXT_PROC(WGL_ARB_pbuffer, PFNWGLCREATEPBUFFERARBPROC, wglCreatePbufferARB);
    VIGS_WGL_GET_EXT_PROC(WGL_ARB_pbuffer, PFNWGLGETPBUFFERDCARBPROC, wglGetPbufferDCARB);
    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);
    VIGS_GL_GET_PROC(BindTexture, glBindTexture);
    VIGS_GL_GET_PROC(CullFace, glCullFace);
    VIGS_GL_GET_PROC(TexParameterf, glTexParameterf);
    VIGS_GL_GET_PROC(TexParameterfv, glTexParameterfv);
    VIGS_GL_GET_PROC(TexParameteri, glTexParameteri);
    VIGS_GL_GET_PROC(TexParameteriv, glTexParameteriv);
    VIGS_GL_GET_PROC(TexImage2D, glTexImage2D);
    VIGS_GL_GET_PROC(TexSubImage2D, glTexSubImage2D);
    VIGS_GL_GET_PROC(Clear, glClear);
    VIGS_GL_GET_PROC(ClearColor, glClearColor);
    VIGS_GL_GET_PROC(Disable, glDisable);
    VIGS_GL_GET_PROC(Enable, glEnable);
    VIGS_GL_GET_PROC(Finish, glFinish);
    VIGS_GL_GET_PROC(Flush, glFlush);
    VIGS_GL_GET_PROC(PixelStorei, glPixelStorei);
    VIGS_GL_GET_PROC(ReadPixels, glReadPixels);
    VIGS_GL_GET_PROC(Viewport, glViewport);
    VIGS_GL_GET_PROC(GetIntegerv, glGetIntegerv);
    VIGS_GL_GET_PROC(GetString, glGetString);
    VIGS_GL_GET_PROC(DrawArrays, glDrawArrays);
    VIGS_GL_GET_PROC(GenBuffers, glGenBuffers);
    VIGS_GL_GET_PROC(DeleteBuffers, glDeleteBuffers);
    VIGS_GL_GET_PROC(BindBuffer, glBindBuffer);
    VIGS_GL_GET_PROC(BufferData, glBufferData);
    VIGS_GL_GET_PROC(BufferSubData, glBufferSubData);
    VIGS_GL_GET_PROC(MapBuffer, glMapBuffer);
    VIGS_GL_GET_PROC(UnmapBuffer, glUnmapBuffer);
    VIGS_GL_GET_PROC(CreateProgram, glCreateProgram);
    VIGS_GL_GET_PROC(CreateShader, glCreateShader);
    VIGS_GL_GET_PROC(CompileShader, glCompileShader);
    VIGS_GL_GET_PROC(AttachShader, glAttachShader);
    VIGS_GL_GET_PROC(LinkProgram, glLinkProgram);
    VIGS_GL_GET_PROC(GetProgramiv, glGetProgramiv);
    VIGS_GL_GET_PROC(GetProgramInfoLog, glGetProgramInfoLog);
    VIGS_GL_GET_PROC(GetShaderiv, glGetShaderiv);
    VIGS_GL_GET_PROC(GetShaderInfoLog, glGetShaderInfoLog);
    VIGS_GL_GET_PROC(DetachShader, glDetachShader);
    VIGS_GL_GET_PROC(DeleteProgram, glDeleteProgram);
    VIGS_GL_GET_PROC(DeleteShader, glDeleteShader);
    VIGS_GL_GET_PROC(DisableVertexAttribArray, glDisableVertexAttribArray);
    VIGS_GL_GET_PROC(EnableVertexAttribArray, glEnableVertexAttribArray);
    VIGS_GL_GET_PROC(ShaderSource, glShaderSource);
    VIGS_GL_GET_PROC(UseProgram, glUseProgram);
    VIGS_GL_GET_PROC(GetAttribLocation, glGetAttribLocation);
    VIGS_GL_GET_PROC(GetUniformLocation, glGetUniformLocation);
    VIGS_GL_GET_PROC(VertexAttribPointer, glVertexAttribPointer);
    VIGS_GL_GET_PROC(Uniform2fv, glUniform2fv);
    VIGS_GL_GET_PROC(Uniform4fv, glUniform4fv);
    VIGS_GL_GET_PROC(UniformMatrix4fv, glUniformMatrix4fv);

    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(GenFramebuffers, glGenFramebuffersEXT);
        VIGS_GL_GET_PROC(GenRenderbuffers, glGenRenderbuffersEXT);
        VIGS_GL_GET_PROC(DeleteFramebuffers, glDeleteFramebuffersEXT);
        VIGS_GL_GET_PROC(DeleteRenderbuffers, glDeleteRenderbuffersEXT);
        VIGS_GL_GET_PROC(BindFramebuffer, glBindFramebufferEXT);
        VIGS_GL_GET_PROC(BindRenderbuffer, glBindRenderbufferEXT);
        VIGS_GL_GET_PROC(RenderbufferStorage, glRenderbufferStorageEXT);
        VIGS_GL_GET_PROC(FramebufferRenderbuffer, glFramebufferRenderbufferEXT);
        VIGS_GL_GET_PROC(FramebufferTexture2D, glFramebufferTexture2DEXT);
    } else {
        VIGS_GL_GET_PROC(GenFramebuffers, glGenFramebuffers);
        VIGS_GL_GET_PROC(GenRenderbuffers, glGenRenderbuffers);
        VIGS_GL_GET_PROC(DeleteFramebuffers, glDeleteFramebuffers);
        VIGS_GL_GET_PROC(DeleteRenderbuffers, glDeleteRenderbuffers);
        VIGS_GL_GET_PROC(BindFramebuffer, glBindFramebuffer);
        VIGS_GL_GET_PROC(BindRenderbuffer, glBindRenderbuffer);
        VIGS_GL_GET_PROC(RenderbufferStorage, glRenderbufferStorage);
        VIGS_GL_GET_PROC(FramebufferRenderbuffer, glFramebufferRenderbuffer);
        VIGS_GL_GET_PROC(FramebufferTexture2D, glFramebufferTexture2D);
        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;
    ReleaseDC(tmp_win, tmp_dc);
    tmp_dc = NULL;
    DestroyWindow(tmp_win);
    tmp_win = NULL;

    gl_backend_wgl->win = CreateWindow(VIGS_WGL_WIN_CLASS, "VIGSWin",
                                       WS_DISABLED | WS_POPUP,
                                       0, 0, 1, 1, NULL, NULL, 0, 0);

    if (!gl_backend_wgl->win) {
        VIGS_LOG_CRITICAL("Unable to create window");
        goto fail;
    }

    gl_backend_wgl->dc = GetDC(gl_backend_wgl->win);

    if (!gl_backend_wgl->dc) {
        VIGS_LOG_CRITICAL("Unable to get window DC");
        goto fail;
    }

    config_id = vigs_gl_backend_wgl_choose_config(gl_backend_wgl);

    if (!config_id) {
        goto fail;
    }

    if (!vigs_gl_backend_wgl_create_surface(gl_backend_wgl, config_id,
                                            &gl_backend_wgl->sfc,
                                            &gl_backend_wgl->sfc_dc)) {
        goto fail;
    }

    if (!vigs_gl_backend_wgl_create_surface(gl_backend_wgl, config_id,
                                            &gl_backend_wgl->read_pixels_sfc,
                                            &gl_backend_wgl->read_pixels_sfc_dc)) {
        goto fail;
    }

    if (!vigs_gl_backend_wgl_create_context(gl_backend_wgl,
                                            NULL,
                                            &gl_backend_wgl->ctx)) {
        goto fail;
    }

    if (!vigs_gl_backend_wgl_create_context(gl_backend_wgl,
                                            gl_backend_wgl->ctx,
                                            &gl_backend_wgl->read_pixels_ctx)) {
        goto fail;
    }

    gl_backend_wgl->base.base.destroy = &vigs_gl_backend_wgl_destroy;
    gl_backend_wgl->base.has_current = &vigs_gl_backend_wgl_has_current;
    gl_backend_wgl->base.make_current = &vigs_gl_backend_wgl_make_current;
    gl_backend_wgl->base.read_pixels_make_current = &vigs_gl_backend_wgl_read_pixels_make_current;
    gl_backend_wgl->base.ws_info.context = gl_backend_wgl->ctx;

    if (!vigs_gl_backend_init(&gl_backend_wgl->base)) {
        goto fail;
    }

    VIGS_LOG_DEBUG("created");

    return &gl_backend_wgl->base.base;

fail:
    if (gl_backend_wgl->ctx) {
        gl_backend_wgl->wglDeleteContext(gl_backend_wgl->ctx);
    }
    if (gl_backend_wgl->read_pixels_ctx) {
        gl_backend_wgl->wglDeleteContext(gl_backend_wgl->read_pixels_ctx);
    }
    if (gl_backend_wgl->sfc_dc) {
        gl_backend_wgl->wglReleasePbufferDCARB(gl_backend_wgl->sfc, gl_backend_wgl->sfc_dc);
    }
    if (gl_backend_wgl->sfc) {
        gl_backend_wgl->wglDestroyPbufferARB(gl_backend_wgl->sfc);
    }
    if (gl_backend_wgl->read_pixels_sfc_dc) {
        gl_backend_wgl->wglReleasePbufferDCARB(gl_backend_wgl->read_pixels_sfc, gl_backend_wgl->read_pixels_sfc_dc);
    }
    if (gl_backend_wgl->read_pixels_sfc) {
        gl_backend_wgl->wglDestroyPbufferARB(gl_backend_wgl->read_pixels_sfc);
    }
    if (gl_backend_wgl->dc) {
        ReleaseDC(gl_backend_wgl->win, gl_backend_wgl->dc);
    }
    if (gl_backend_wgl->win) {
        DestroyWindow(gl_backend_wgl->win);
    }
    if (gl_backend_wgl->wglMakeCurrent && tmp_ctx) {
        gl_backend_wgl->wglMakeCurrent(NULL, NULL);
    }
    if (gl_backend_wgl->wglDeleteContext && tmp_ctx) {
        gl_backend_wgl->wglDeleteContext(tmp_ctx);
    }
    if (tmp_dc) {
        ReleaseDC(tmp_win, tmp_dc);
    }
    if (tmp_win) {
        DestroyWindow(tmp_win);
    }
    if (gl_backend_wgl->handle) {
        FreeLibrary(gl_backend_wgl->handle);
    }

    vigs_backend_cleanup(&gl_backend_wgl->base.base);

    g_free(gl_backend_wgl);

    UnregisterClassA((LPCTSTR)VIGS_WGL_WIN_CLASS, NULL);

    return NULL;
}
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;
}