summaryrefslogtreecommitdiffstats
path: root/src/opengl/utils.c
blob: d96a3e74a5777538aa6f058d203c036674c51f46 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
 * This file is part of libplacebo.
 *
 * libplacebo is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * libplacebo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
 */

#include "common.h"
#include "gpu.h"
#include "utils.h"

const char *gl_err_str(GLenum err)
{
    switch (err) {
#define CASE(name) case name: return #name
    CASE(GL_NO_ERROR);
    CASE(GL_INVALID_ENUM);
    CASE(GL_INVALID_VALUE);
    CASE(GL_INVALID_OPERATION);
    CASE(GL_INVALID_FRAMEBUFFER_OPERATION);
    CASE(GL_OUT_OF_MEMORY);
    CASE(GL_STACK_UNDERFLOW);
    CASE(GL_STACK_OVERFLOW);
#undef CASE

    default: return "unknown error";
    }
}

void gl_poll_callbacks(pl_gpu gpu)
{
    const gl_funcs *gl = gl_funcs_get(gpu);
    struct pl_gl *p = PL_PRIV(gpu);
    while (p->callbacks.num) {
        struct gl_cb cb = p->callbacks.elem[0];
        GLenum res = gl->ClientWaitSync(cb.sync, 0, 0);
        switch (res) {
        case GL_ALREADY_SIGNALED:
        case GL_CONDITION_SATISFIED:
            PL_ARRAY_REMOVE_AT(p->callbacks, 0);
            cb.callback(cb.priv);
            continue;

        case GL_WAIT_FAILED:
            PL_ARRAY_REMOVE_AT(p->callbacks, 0);
            gl->DeleteSync(cb.sync);
            p->failed = true;
            gl_check_err(gpu, "gl_poll_callbacks"); // NOTE: will recurse!
            return;

        case GL_TIMEOUT_EXPIRED:
            return;

        default:
            pl_unreachable();
        }
    }
}

bool gl_check_err(pl_gpu gpu, const char *fun)
{
    const gl_funcs *gl = gl_funcs_get(gpu);
    struct pl_gl *p = PL_PRIV(gpu);
    bool ret = true;

    while (true) {
        GLenum error = gl->GetError();
        if (error == GL_NO_ERROR)
            break;
        PL_ERR(gpu, "%s: OpenGL error: %s", fun, gl_err_str(error));
        ret = false;
        p->failed = true;
    }

    gl_poll_callbacks(gpu);
    return ret;
}

bool gl_is_software(pl_opengl pl_gl)
{
    struct gl_ctx *glctx = PL_PRIV(pl_gl);
    const gl_funcs *gl = &glctx->func;
    const char *renderer = (char *) gl->GetString(GL_RENDERER);
    return !renderer ||
           strcmp(renderer, "Software Rasterizer") == 0 ||
           strstr(renderer, "llvmpipe") ||
           strstr(renderer, "softpipe") ||
           strcmp(renderer, "Mesa X11") == 0 ||
           strcmp(renderer, "Apple Software Renderer") == 0;
}

bool gl_is_gles(pl_opengl pl_gl)
{
    struct gl_ctx *glctx = PL_PRIV(pl_gl);
    const gl_funcs *gl = &glctx->func;
    const char *version = (char *) gl->GetString(GL_VERSION);
    return pl_str_startswith0(pl_str0(version), "OpenGL ES");
}

bool gl_test_ext(pl_gpu gpu, const char *ext, int gl_ver, int gles_ver)
{
    struct pl_gl *p = PL_PRIV(gpu);
    if (gl_ver && p->gl_ver >= gl_ver)
        return true;
    if (gles_ver && p->gles_ver >= gles_ver)
        return true;

    return ext ? pl_opengl_has_ext(p->gl, ext) : false;
}

const char *egl_err_str(EGLenum err)
{
    switch (err) {
#define CASE(name) case name: return #name
    CASE(EGL_SUCCESS);
    CASE(EGL_NOT_INITIALIZED);
    CASE(EGL_BAD_ACCESS);
    CASE(EGL_BAD_ALLOC);
    CASE(EGL_BAD_ATTRIBUTE);
    CASE(EGL_BAD_CONFIG);
    CASE(EGL_BAD_CONTEXT);
    CASE(EGL_BAD_CURRENT_SURFACE);
    CASE(EGL_BAD_DISPLAY);
    CASE(EGL_BAD_MATCH);
    CASE(EGL_BAD_NATIVE_PIXMAP);
    CASE(EGL_BAD_NATIVE_WINDOW);
    CASE(EGL_BAD_PARAMETER);
    CASE(EGL_BAD_SURFACE);
#undef CASE

    default: return "unknown error";
    }
}

bool egl_check_err(pl_gpu gpu, const char *fun)
{
    struct pl_gl *p = PL_PRIV(gpu);
    bool ret = true;

    while (true) {
        GLenum error = eglGetError();
        if (error == EGL_SUCCESS)
            return ret;
        PL_ERR(gpu, "%s: EGL error: %s", fun, egl_err_str(error));
        ret = false;
        p->failed = true;
    }
}