0d5e5e60f14731db48a3eb0c66ab7239195611e6
[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
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <assert.h>
24
25 #include <EGL/eglext.h>
26
27 #if !defined(CON_GL1) && !defined(CON_GLES2)
28 #error "Valid GL contexts for EGL are: GL1, 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 exitEglError(const char *what)
50 {
51         EGLint e = eglGetError();
52         fprintf(stderr, "EGL error %d (%s): %s\n", e, eglErrorToString(e), what);
53         exit(1);
54 }
55
56 static const EGLint context_attribs[] = {
57 #ifdef CON_GLES2
58         EGL_CONTEXT_CLIENT_VERSION, 2,
59 #endif
60         EGL_NONE
61 };
62 static const EGLint config_attribs[] = {
63         EGL_RED_SIZE,             4,
64         EGL_GREEN_SIZE,           4,
65         EGL_BLUE_SIZE,            4,
66 #ifdef CON_GLES2
67         EGL_RENDERABLE_TYPE,      EGL_OPENGL_ES2_BIT,
68 #else
69         EGL_RENDERABLE_TYPE,      EGL_OPENGL_BIT,
70 #endif
71         EGL_NONE,
72 };
73
74 VisualID EGLBackend::initialize(Display *xDisplay)
75 {
76         if (display == EGL_NO_DISPLAY) { // this implies that the context is also unitialized
77                 // get connection and bind API
78                 EGLint eglMajor, eglMinor;
79                 display = eglGetDisplay(xDisplay);
80                 if (display == EGL_NO_DISPLAY)
81                         exitEglError("Failed to get EGL display");
82                 if (eglInitialize(display, &eglMajor, &eglMinor) == EGL_FALSE)
83                         exitEglError("Failed to initialize EGL");
84                 printf("Using EGL version %d.%d\n", eglMajor, eglMinor);
85                 if (eglMajor == 1 && eglMinor < 3) {
86                         fprintf(stderr, "Need at least EGL 1.3 to function properly\n");
87                         exit(1);
88                 }
89 #ifdef CON_GLES2
90                 if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE)
91 #else
92                 if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE)
93 #endif
94                         exitEglError("Failed to bind API");
95                 // get an appropriate config
96                 EGLConfig configs[1];
97                 EGLint count;
98                 if (eglChooseConfig(display, config_attribs, configs, 1, &count) == EGL_FALSE){
99                         exitEglError("Failed to choose config");
100                 }
101                 if (count == 0) {
102                         fprintf(stderr, "Found no matching EGL configuration\n");
103                         exit(1);
104                 }
105                 config = configs[0];
106         }
107         // return visual ID
108         EGLint val;
109         eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &val);
110         return (VisualID)val;
111 }
112
113 void EGLBackend::createContext(Window window)
114 {
115         assert(display != EGL_NO_DISPLAY && context == EGL_NO_CONTEXT);
116         surface = eglCreateWindowSurface(display, config, window, NULL);
117         // create an EGL context and use it with the surface
118         context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attribs);
119         if (context == EGL_NO_CONTEXT)
120                 exitEglError("Failed to create context");
121         if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
122                 exitEglError("Failed to make context current");
123 }
124
125 EGLBackend::~EGLBackend()
126 {
127         if (display != EGL_NO_DISPLAY) {
128                 if (context != EGL_NO_CONTEXT) {
129                         eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
130                         eglDestroyContext(display, context);
131                         eglDestroySurface(display, surface);
132                 }
133                 eglTerminate(display);
134                 eglReleaseThread();
135         }
136 }
137
138 void EGLBackend::swapBuffers() const
139 {
140         assert(context != EGL_NO_CONTEXT); // this implies the display is also initialized
141         if (eglSwapBuffers(display, surface) == EGL_FALSE)
142                 exitEglError("Failed to swap buffers");
143 }
144
145 void EGLBackend::setSwapInterval(int i) const
146 {
147         assert(context != EGL_NO_CONTEXT);
148         // check if swap interval value is supported
149         EGLint val;
150         eglGetConfigAttrib(display, config, EGL_MIN_SWAP_INTERVAL, &val);
151         if (i < val) {
152                 fprintf(stderr, "Cannot set swap interval to %d, minimum supported value is %d\n", i, val);
153                 exit(1);
154         }
155         eglGetConfigAttrib(display, config, EGL_MAX_SWAP_INTERVAL, &val);
156         if (i > val) {
157                 fprintf(stderr, "Cannot set swap interval to %d, maximum supported value is %d\n", i, val);
158                 exit(1);
159         }
160         // use it
161         if (eglSwapInterval(display, i) == EGL_FALSE)
162                 exitEglError("Failed to set swap interval");
163 }