glxtest
egltest
eglinfo
+glestest
-FLAGS := -Wall
+FLAGS := -Wall -g -O1
COMMON_SRC = gltest.cpp glwindow.cpp
-COMMON_HDR = glwindow.h
+COMMON_HDR = glwindow.h glutil.h
-all: glxtest egltest eglinfo
+BINARIES := glxtest egltest glestest eglinfo
-glxtest: $(COMMON_SRC) $(COMMON_HDR) glxbackend.cpp glxbackend.h
- g++ $(FLAGS) -DUSE_GLX $(COMMON_SRC) glxbackend.cpp -lGL -lX11 -lboost_program_options -o glxtest
+all: $(BINARIES)
-egltest: $(COMMON_SRC) $(COMMON_HDR) eglbackend.cpp eglbackend.h
- g++ $(FLAGS) -DUSE_EGL $(COMMON_SRC) eglbackend.cpp -lEGL -lGL -lX11 -lboost_program_options -o egltest
+glxtest: $(COMMON_SRC) $(COMMON_HDR) glutil_gl1.cpp glxbackend.cpp glxbackend.h
+ g++ $(FLAGS) -DUSE_GLX $(COMMON_SRC) glutil_gl1.cpp glxbackend.cpp -lGL -lX11 -lboost_program_options -o glxtest
+
+egltest: $(COMMON_SRC) $(COMMON_HDR) glutil_gl1.cpp eglbackend.cpp eglbackend.h
+ g++ $(FLAGS) -DUSE_EGL $(COMMON_SRC) glutil_gl1.cpp eglbackend.cpp -lEGL -lGL -lX11 -lboost_program_options -o egltest
+
+glestest: $(COMMON_SRC) $(COMMON_HDR) glutil_gl2.cpp eglbackend.cpp eglbackend.h
+ g++ $(FLAGS) -DUSE_EGL -DUSE_GLES $(COMMON_SRC) glutil_gl2.cpp eglbackend.cpp -lEGL -lGLESv2 -lX11 -lboost_program_options -o glestest
eglinfo: eglinfo.c
gcc $(FLAGS) eglinfo.c -lEGL -lGL -lX11 -o eglinfo
clean:
- rm -f glxtest egltest eglinfo
+ rm -f $(BINARIES)
exit(1);
}
-// attributes for a visual in RGBA format with at least 4 bits per color
+static const EGLint context_attribs[] = {
+#ifdef USE_GLES
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+#endif
+ EGL_NONE
+};
static const EGLint config_attribs[] = {
EGL_RED_SIZE, 4,
EGL_GREEN_SIZE, 4,
if (eglInitialize(display, &eglMajor, &eglMinor) == EGL_FALSE)
exitEglError("Failed to initialize EGL");
printf("Using EGL version %d.%d\n", eglMajor, eglMinor);
- eglBindAPI(EGL_OPENGL_API);
+#ifdef USE_GLES
+ if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE)
+#else
+ if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE)
+#endif
+ exitEglError("Failed to bind API");
// get an appropriate config
EGLConfig configs[1];
EGLint count;
assert(display != EGL_NO_DISPLAY && context == EGL_NO_CONTEXT);
surface = eglCreateWindowSurface(display, config, window, NULL);
// create an EGL context and use it with the surface
- context = eglCreateContext(display, config, EGL_NO_CONTEXT, NULL);
+ context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attribs);
if (context == EGL_NO_CONTEXT)
exitEglError("Failed to create context");
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
#include <limits.h>
#include <unistd.h>
#include <assert.h>
-#include <GL/gl.h>
#include <boost/program_options.hpp>
namespace po = boost::program_options;
-// include proper GL connector
+// my GL utility functions and the GL window class
+#include "glutil.h"
#include "glwindow.h"
+// include proper GL backend
#if defined(USE_GLX)
#include "glxbackend.h"
static GLBackend *createGLBackend()
return tp.tv_sec + 1e-9 * tp.tv_nsec;
}
-static void rectQuad(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
-{
- glVertex2f(x1, y1);
- glVertex2f(x2, y1);
- glVertex2f(x2, y2);
- glVertex2f(x1, y2);
-}
-
// the window
class TearTestWindow : public GLWindow {
public:
- TearTestWindow(bool overdraw, bool copy, int sleep_time) : GLWindow(XOpenDisplay(0), createGLBackend()),
- overdraw(overdraw), copy(copy), sleep_time(sleep_time), boxPos(0), boxDirection(1)
+ TearTestWindow() : GLWindow(XOpenDisplay(0), createGLBackend()),
+ overdraw(false), sleep_time(0), boxPos(0), boxDirection(1)
{}
- void setSwapInterval(int i) {
- getBackend()->setSwapInterval(i);
- }
+ void setOverdraw(bool overdraw) { this->overdraw = overdraw; }
+ void setSleepTime(int sleep_time) { this->sleep_time = sleep_time; }
+
+ void setSwapInterval(int i) { getBackend()->setSwapInterval(i); }
+
+private:
+ bool overdraw;
+ int sleep_time;
+ // animation control
+ double lastFrame;
+ GLfloat boxPos, boxDirection;
+ // FPS, profiler
+ double lastDisplay, lastProfile;
+ int framect;
+ ProfilerState curState;
+ double stateTime[NumProfilerStates];
protected:
virtual void initGL()
virtual void resizeGL(unsigned int width, unsigned int height)
{
- // prevent divide-by-zero
- if (height == 0)
- height = 1;
glViewport(0, 0, width, height);
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho (0, 1, 1, 0, 0, 1);
- glMatrixMode(GL_MODELVIEW);
+ initialise2dProjection();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- glClear(GL_COLOR_BUFFER_BIT);
- glFlush();
}
void profilerTick(ProfilerState nextState)
profilerTick(StateClear);
if (overdraw) {
// clear manually
- glBegin(GL_QUADS);
- glColor3f(0.0f, 0.0f, 0.0f);
- rectQuad(0, 0, 1, 1);
- glEnd();
+ drawQuad(/*color*/0.0f, 0.0f, 0.0f, /*coordinates*/0, 0, 1, 1);
}
else {
glClear(GL_COLOR_BUFFER_BIT);
}
//////////////////////////////////////////////
profilerTick(StateDraw);
- glBegin(GL_QUADS);
- glColor3f(0.8f, 1.0f, 0.75f);
- rectQuad(boxPos, 0, boxPos+boxWidth, 1);
- glEnd();
+ drawQuad(/*color*/0.8f, 1.0f, 0.75f, /*coordinates*/boxPos, 0, boxPos+boxWidth, 1);
usleep(sleep_time*1000);
//////////////////////////////////////////////
profilerTick(StatePresent);
- if (copy) {
- glDrawBuffer(GL_FRONT);
- glCopyPixels(0, 0, getWidth(), getHeight(), GL_COLOR);
- glDrawBuffer(GL_BACK);
- }
- else {
- getBackend()->swapBuffers();
- }
+ getBackend()->swapBuffers();
//////////////////////////////////////////////
profilerTick(StatePostRender);
glFinish();
default: break;
}
}
-
-private:
- bool overdraw, copy;
- int sleep_time;
- // animation control
- double lastFrame;
- GLfloat boxPos, boxDirection;
- // FPS, profiler
- double lastDisplay, lastProfile;
- int framect;
- ProfilerState curState;
- double stateTime[NumProfilerStates];
};
int main(int argc, char ** argv)
desc.add_options()
("help,h", "produce help message")
("swap-interval,i", po::value<int>(), "set swap interval")
- ("copy,c", "copy to front buffer (instead of performing a buffer swap)")
("overdraw,o", "overdraw previous image (instead of calling glClear)")
("sleep,s", po::value<int>()->default_value(0), "Number of milliseconds to sleap in each frame (in the drawing phase)")
;
}
// actual program
- TearTestWindow w(vm.count("overdraw"), vm.count("copy"), vm["sleep"].as<int>());
+ TearTestWindow w;
+ w.setOverdraw(vm.count("overdraw"));
+ w.setSleepTime(vm["sleep"].as<int>());
w.open(800, 600);
if (vm.count("swap-interval"))
w.setSwapInterval(vm["swap-interval"].as<int>());
--- /dev/null
+/* gltest - small OpenGL tearing test program
+ * Copyright (C) 2012-2013 Ralf Jung <post@ralfj.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifdef USE_GLES
+#include <GLES2/gl2.h>
+#else
+#include <GL/gl.h>
+#endif
+
+void initialise2dProjection();
+void drawQuad(GLfloat red, GLfloat green, GLfloat blue, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);
--- /dev/null
+/* gltest - small OpenGL tearing test program
+ * Copyright (C) 2012-2013 Ralf Jung <post@ralfj.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "glutil.h"
+
+// initialisation
+void initialise2dProjection()
+{
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho (0, 1, 1, 0, 0, 1);
+ glMatrixMode(GL_MODELVIEW);
+}
+
+// draw a quad
+void drawQuad(GLfloat red, GLfloat green, GLfloat blue, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
+{
+ glBegin(GL_QUADS);
+ glColor3f(red, green, blue);
+ glVertex2f(x1, y1);
+ glVertex2f(x2, y1);
+ glVertex2f(x2, y2);
+ glVertex2f(x1, y2);
+ glEnd();
+}
\ No newline at end of file
--- /dev/null
+/* gltest - small OpenGL tearing test program
+ * Copyright (C) 2012-2013 Ralf Jung <post@ralfj.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "glutil.h"
+
+// shaders
+static const char *vertex_shader_source =
+"#version 100 \n\
+attribute vec2 position; \n\
+attribute vec3 color; \n\
+varying vec3 frag_color; \n\
+void main() \n\
+{ \n\
+ frag_color = color; \n\
+ gl_Position = vec4(position * vec2(2) - vec2(1), 0.0, 1.0); \n\
+}";
+static const char *fragment_shader_source =
+"#version 100 \n\
+varying vec3 frag_color; \n\
+void main(void) \n\
+{ \n\
+ gl_FragColor = vec4(frag_color, 1.0); \n\
+}";
+
+
+// OpenGL IDs (yeah, this is a bad hack... do we care?)
+static GLuint program;
+static struct {
+ GLint position;
+ GLint color;
+} attributes;
+
+// some local hlper functions
+static void show_info_log(GLuint object)
+{
+ GLint log_length;
+ glGetShaderiv(object, GL_INFO_LOG_LENGTH, &log_length);
+ char *log = new char[log_length];
+ glGetShaderInfoLog(object, log_length, NULL, log);
+ fprintf(stderr, "%s", log);
+ delete[] log;
+}
+
+static GLuint compile_shader(GLenum shader_type, const char *source)
+{
+ GLuint shader = glCreateShader(shader_type);
+ glShaderSource(shader, 1, &source, NULL);
+ glCompileShader(shader);
+ GLint shader_ok;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok);
+ if (!shader_ok) {
+ fprintf(stderr, "Failed to compile shader\n");
+ show_info_log(shader);
+ exit(1);
+ }
+ return shader;
+}
+
+static GLuint createArrayBuffer(GLsizeiptr size, GLfloat *data)
+{
+ GLuint buffer;
+ glGenBuffers(1, &buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
+ return buffer;
+}
+
+// initialisation
+void initialise2dProjection()
+{
+ GLuint vertex_shader = compile_shader(GL_VERTEX_SHADER, vertex_shader_source);
+ GLuint fragment_shader = compile_shader(GL_FRAGMENT_SHADER, fragment_shader_source);
+ program = glCreateProgram();
+ glAttachShader(program, vertex_shader);
+ glAttachShader(program, fragment_shader);
+ glLinkProgram(program);
+ attributes.position = glGetAttribLocation(program, "position");
+ attributes.color = glGetAttribLocation(program, "color");
+}
+
+// draw a quad
+void drawQuad(GLfloat red, GLfloat green, GLfloat blue, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
+{
+ glUseProgram(program);
+
+ // send vertex data to card with given attribute
+ GLfloat vertex_buffer_data[] = {
+ x1, y1,
+ x2, y1,
+ x2, y2,
+ x1, y2,
+ };
+ GLuint vertex_buffer = createArrayBuffer(sizeof(vertex_buffer_data), vertex_buffer_data);
+ glVertexAttribPointer(
+ attributes.position, /* attribute */
+ 2, /* size */
+ GL_FLOAT, /* type */
+ GL_FALSE, /* normalized? */
+ 0, /* stride */
+ (void*)0 /* array buffer offset */
+ );
+ glEnableVertexAttribArray(attributes.position);
+
+ // same with color data
+ GLfloat color_buffer_data[] = {
+ red, green, blue,
+ red, green, blue,
+ red, green, blue,
+ red, green, blue,
+ };
+ GLuint color_buffer = createArrayBuffer(sizeof(color_buffer_data), color_buffer_data);
+ glVertexAttribPointer(
+ attributes.color, /* attribute */
+ 3, /* size */
+ GL_FLOAT, /* type */
+ GL_FALSE, /* normalized? */
+ 0, /* stride */
+ (void*)0 /* array buffer offset */
+ );
+ glEnableVertexAttribArray(attributes.color);
+
+ // draw
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ // cleanup
+ glDeleteBuffers(1, &vertex_buffer);
+ glDeleteBuffers(1, &color_buffer);
+}