Make the shaders work on NVidia
[gltest.git] / eglbackend.cpp
1 /* gltest - small OpenGL tearing test program
2  * Copyright (C) 2012-2013 Ralf Jung <post@ralfj.de>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program 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 General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include "eglbackend.h"
20 #include "glutil.h"
21
22 #include <stdio.h>
23 #include <assert.h>
24
25 #include <EGL/eglext.h>
26
27 #if !defined(CON_GL1) && !defined(CON_GL3) && !defined(CON_GLES2)
28 #error "Valid GL contexts for EGL are: GL1, GL3, GLES2"
29 #endif
30
31 static const char *eglErrorToString(EGLint e)
32 {
33 #define CASE(name) case name: return #name
34         switch (e) {
35                 CASE(EGL_SUCCESS);
36                 CASE(EGL_NOT_INITIALIZED);
37                 CASE(EGL_BAD_ACCESS);
38                 CASE(EGL_BAD_ALLOC);
39                 CASE(EGL_BAD_ATTRIBUTE);
40                 CASE(EGL_BAD_CONTEXT);
41                 CASE(EGL_BAD_CONFIG);
42                 CASE(EGL_BAD_CURRENT_SURFACE);
43                 CASE(EGL_BAD_DISPLAY);
44                 default: return "<unknown>";
45         }
46 #undef CASE
47 }
48
49 static void dieEgl(const char *what)
50 {
51         EGLint e = eglGetError();
52         die("EGL error %d (%s): %s\n", e, eglErrorToString(e), what);
53 }
54
55 static const EGLint configAttribs[] = {
56         EGL_RED_SIZE,             4,
57         EGL_GREEN_SIZE,           4,
58         EGL_BLUE_SIZE,            4,
59 #ifdef CON_GLES2
60         EGL_RENDERABLE_TYPE,      EGL_OPENGL_ES2_BIT,
61 #else
62         EGL_RENDERABLE_TYPE,      EGL_OPENGL_BIT,
63 #endif
64         EGL_NONE,
65 };
66 static const EGLint contextAttribs[] = {
67 #ifdef CON_GLES2
68         EGL_CONTEXT_CLIENT_VERSION, 2,
69 #elif CON_GL3
70         EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
71         EGL_CONTEXT_MINOR_VERSION_KHR, 0,
72         EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR,
73 #endif
74         EGL_NONE
75 };
76
77 VisualID EGLBackend::initialize(Display *xDisplay)
78 {
79         if (display == EGL_NO_DISPLAY) { // this implies that the context is also unitialized
80                 // get connection and bind API
81                 EGLint eglMajor, eglMinor;
82                 display = eglGetDisplay(xDisplay);
83                 if (display == EGL_NO_DISPLAY)
84                         dieEgl("Failed to get EGL display");
85                 if (eglInitialize(display, &eglMajor, &eglMinor) == EGL_FALSE)
86                         dieEgl("Failed to initialize EGL");
87                 printf("Using EGL version: %d.%d\n", eglMajor, eglMinor);
88                 if (eglMajor == 1 && eglMinor < 4) {
89                         // Choosing the GL context version requires EGL 1.3, creating an OpenGL 3 context requires EGL 1.4
90                         die("Need at least EGL 1.4 to function properly\n");
91                 }
92 #ifdef CON_GLES2
93                 if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE)
94 #else
95                 if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE)
96 #endif
97                         dieEgl("Failed to bind API");
98                 // check for the extension we need
99 #ifdef CON_GL3
100                 if (!haveEGLExtension("EGL_KHR_create_context")) {
101                         die("Required EGL extension EGL_KHR_create_context is not supported\n");
102                 }
103 #endif
104                 // get an appropriate config
105                 EGLConfig configs[1];
106                 EGLint count;
107                 if (eglChooseConfig(display, configAttribs, configs, 1, &count) == EGL_FALSE){
108                         dieEgl("Failed to choose framebuffer configuration");
109                 }
110                 if (count == 0) {
111                         die("Found no matching framebuffer configuration\n");
112                 }
113                 config = configs[0];
114         }
115         // return visual ID
116         EGLint val;
117         eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &val);
118         return (VisualID)val;
119 }
120
121 bool EGLBackend::haveEGLExtension(const std::string &name)
122 {
123         assert(display != EGL_NO_DISPLAY);
124         std::string extensions = eglQueryString(display, EGL_EXTENSIONS);
125         return (std::string(" "+extensions+" ").find(" "+name+" ") != std::string::npos);
126 }
127
128 void EGLBackend::createContext(Window window)
129 {
130         assert(display != EGL_NO_DISPLAY && context == EGL_NO_CONTEXT);
131         surface = eglCreateWindowSurface(display, config, window, NULL);
132         // create an EGL context and use it with the surface
133         context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
134         if (context == EGL_NO_CONTEXT)
135                 dieEgl("Failed to create context");
136         if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
137                 dieEgl("Failed to make context current");
138         printf("Using GL version: %s\n", glGetString(GL_VERSION));
139         // initialise GL utilities
140         resolveFunctionPointers(eglGetProcAddress);
141 }
142
143 EGLBackend::~EGLBackend()
144 {
145         if (display != EGL_NO_DISPLAY) {
146                 if (context != EGL_NO_CONTEXT) {
147                         eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
148                         eglDestroyContext(display, context);
149                         eglDestroySurface(display, surface);
150                 }
151                 eglTerminate(display);
152                 eglReleaseThread();
153         }
154 }
155
156 void EGLBackend::swapBuffers() const
157 {
158         assert(context != EGL_NO_CONTEXT); // this implies the display is also initialized
159         if (eglSwapBuffers(display, surface) == EGL_FALSE)
160                 dieEgl("Failed to swap buffers");
161 }
162
163 void EGLBackend::setSwapInterval(int i) const
164 {
165         assert(context != EGL_NO_CONTEXT);
166         // check if swap interval value is supported
167         if (i < 0) {
168                 die("Cannot set swap interval to %d, must not be negative\n", i);
169         }
170         EGLint val;
171         eglGetConfigAttrib(display, config, EGL_MAX_SWAP_INTERVAL, &val);
172         if (i > val) {
173                 die("Cannot set swap interval to %d, maximum supported value is %d\n", i, val);
174         }
175         // use it
176         if (eglSwapInterval(display, i) == EGL_FALSE)
177                 dieEgl("Failed to set swap interval");
178 }