1 /*
2  * This file is part of libplacebo.
3  *
4  * libplacebo is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * libplacebo is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "common.h"
19 #include "gpu.h"
20 #include "utils.h"
21 
gl_err_str(GLenum err)22 const char *gl_err_str(GLenum err)
23 {
24     switch (err) {
25 #define CASE(name) case name: return #name
26     CASE(GL_NO_ERROR);
27     CASE(GL_INVALID_ENUM);
28     CASE(GL_INVALID_VALUE);
29     CASE(GL_INVALID_OPERATION);
30     CASE(GL_INVALID_FRAMEBUFFER_OPERATION);
31     CASE(GL_OUT_OF_MEMORY);
32     CASE(GL_STACK_UNDERFLOW);
33     CASE(GL_STACK_OVERFLOW);
34 #undef CASE
35 
36     default: return "unknown error";
37     }
38 }
39 
gl_poll_callbacks(pl_gpu gpu)40 void gl_poll_callbacks(pl_gpu gpu)
41 {
42     struct pl_gl *gl = PL_PRIV(gpu);
43     while (gl->callbacks.num) {
44         struct gl_cb cb = gl->callbacks.elem[0];
45         GLenum res = glClientWaitSync(cb.sync, 0, 0);
46         switch (res) {
47         case GL_ALREADY_SIGNALED:
48         case GL_CONDITION_SATISFIED:
49             PL_ARRAY_REMOVE_AT(gl->callbacks, 0);
50             cb.callback(cb.priv);
51             continue;
52 
53         case GL_WAIT_FAILED:
54             PL_ARRAY_REMOVE_AT(gl->callbacks, 0);
55             glDeleteSync(cb.sync);
56             gl->failed = true;
57             gl_check_err(gpu, "gl_poll_callbacks"); // NOTE: will recurse!
58             return;
59 
60         case GL_TIMEOUT_EXPIRED:
61             return;
62 
63         default:
64             pl_unreachable();
65         }
66     }
67 }
68 
gl_check_err(pl_gpu gpu,const char * fun)69 bool gl_check_err(pl_gpu gpu, const char *fun)
70 {
71     struct pl_gl *gl = PL_PRIV(gpu);
72     bool ret = true;
73 
74     while (true) {
75         GLenum error = glGetError();
76         if (error == GL_NO_ERROR)
77             break;
78         PL_ERR(gpu, "%s: OpenGL error: %s", fun, gl_err_str(error));
79         ret = false;
80         gl->failed = true;
81     }
82 
83     gl_poll_callbacks(gpu);
84     return ret;
85 }
86 
gl_is_software(void)87 bool gl_is_software(void)
88 {
89     const char *renderer = glGetString(GL_RENDERER);
90     const char *vendor = glGetString(GL_VENDOR);
91     return !(renderer && vendor) ||
92            strcmp(renderer, "Software Rasterizer") == 0 ||
93            strstr(renderer, "llvmpipe") ||
94            strstr(renderer, "softpipe") ||
95            strcmp(vendor, "Microsoft Corporation") == 0 ||
96            strcmp(renderer, "Mesa X11") == 0 ||
97            strcmp(renderer, "Apple Software Renderer") == 0;
98 }
99 
gl_test_ext(pl_gpu gpu,const char * ext,int gl_ver,int gles_ver)100 bool gl_test_ext(pl_gpu gpu, const char *ext, int gl_ver, int gles_ver)
101 {
102     struct pl_gl *p = PL_PRIV(gpu);
103     if (gl_ver && p->gl_ver >= gl_ver)
104         return true;
105     if (gles_ver && p->gles_ver >= gles_ver)
106         return true;
107 
108     return ext ? epoxy_has_gl_extension(ext) : false;
109 }
110 
111 #ifdef EPOXY_HAS_EGL
112 
egl_err_str(EGLenum err)113 const char *egl_err_str(EGLenum err)
114 {
115     switch (err) {
116 #define CASE(name) case name: return #name
117     CASE(EGL_SUCCESS);
118     CASE(EGL_NOT_INITIALIZED);
119     CASE(EGL_BAD_ACCESS);
120     CASE(EGL_BAD_ALLOC);
121     CASE(EGL_BAD_ATTRIBUTE);
122     CASE(EGL_BAD_CONFIG);
123     CASE(EGL_BAD_CONTEXT);
124     CASE(EGL_BAD_CURRENT_SURFACE);
125     CASE(EGL_BAD_DISPLAY);
126     CASE(EGL_BAD_MATCH);
127     CASE(EGL_BAD_NATIVE_PIXMAP);
128     CASE(EGL_BAD_NATIVE_WINDOW);
129     CASE(EGL_BAD_PARAMETER);
130     CASE(EGL_BAD_SURFACE);
131 #undef CASE
132 
133     default: return "unknown error";
134     }
135 }
136 
egl_check_err(pl_gpu gpu,const char * fun)137 bool egl_check_err(pl_gpu gpu, const char *fun)
138 {
139     struct pl_gl *gl = PL_PRIV(gpu);
140     bool ret = true;
141 
142     while (true) {
143         GLenum error = eglGetError();
144         if (error == EGL_SUCCESS)
145             return ret;
146         PL_ERR(gpu, "%s: EGL error: %s", fun, egl_err_str(error));
147         ret = false;
148         gl->failed = true;
149     }
150 }
151 
152 #endif // EPOXY_HAS_EGL
153