From 8dd990b1ed5cb3a4b78dfdf48b1f39d3f8bb0f0f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Apr 2013 23:01:18 +0200 Subject: [PATCH 1/1] support for GLES2 --- .gitignore | 1 + Makefile | 21 ++++--- eglbackend.cpp | 16 +++++- gltest.cpp | 82 ++++++++++------------------ glutil.h | 27 +++++++++ glutil_gl1.cpp | 40 ++++++++++++++ glutil_gl2.cpp | 145 +++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 267 insertions(+), 65 deletions(-) create mode 100644 glutil.h create mode 100644 glutil_gl1.cpp create mode 100644 glutil_gl2.cpp diff --git a/.gitignore b/.gitignore index e6c19fe..a1b274b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ glxtest egltest eglinfo +glestest diff --git a/Makefile b/Makefile index c07c0fc..52a6495 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,23 @@ -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) diff --git a/eglbackend.cpp b/eglbackend.cpp index ac7ab38..a9e2019 100644 --- a/eglbackend.cpp +++ b/eglbackend.cpp @@ -49,7 +49,12 @@ static void exitEglError(const char *what) 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, @@ -69,7 +74,12 @@ VisualID EGLBackend::initialize(Display *xDisplay) 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; @@ -88,7 +98,7 @@ void EGLBackend::createContext(Window window) 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) diff --git a/gltest.cpp b/gltest.cpp index d8768a7..440e8f5 100644 --- a/gltest.cpp +++ b/gltest.cpp @@ -24,13 +24,14 @@ #include #include #include -#include #include 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() @@ -63,24 +64,29 @@ static double getTime() 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() @@ -99,17 +105,9 @@ protected: 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) @@ -158,31 +156,18 @@ protected: 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(); @@ -199,18 +184,6 @@ protected: 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) @@ -220,7 +193,6 @@ int main(int argc, char ** argv) desc.add_options() ("help,h", "produce help message") ("swap-interval,i", po::value(), "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()->default_value(0), "Number of milliseconds to sleap in each frame (in the drawing phase)") ; @@ -234,7 +206,9 @@ int main(int argc, char ** argv) } // actual program - TearTestWindow w(vm.count("overdraw"), vm.count("copy"), vm["sleep"].as()); + TearTestWindow w; + w.setOverdraw(vm.count("overdraw")); + w.setSleepTime(vm["sleep"].as()); w.open(800, 600); if (vm.count("swap-interval")) w.setSwapInterval(vm["swap-interval"].as()); diff --git a/glutil.h b/glutil.h new file mode 100644 index 0000000..704d2cb --- /dev/null +++ b/glutil.h @@ -0,0 +1,27 @@ +/* gltest - small OpenGL tearing test program + * Copyright (C) 2012-2013 Ralf Jung + * + * 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 +#else +#include +#endif + +void initialise2dProjection(); +void drawQuad(GLfloat red, GLfloat green, GLfloat blue, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); diff --git a/glutil_gl1.cpp b/glutil_gl1.cpp new file mode 100644 index 0000000..8e31114 --- /dev/null +++ b/glutil_gl1.cpp @@ -0,0 +1,40 @@ +/* gltest - small OpenGL tearing test program + * Copyright (C) 2012-2013 Ralf Jung + * + * 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 diff --git a/glutil_gl2.cpp b/glutil_gl2.cpp new file mode 100644 index 0000000..c14b3a5 --- /dev/null +++ b/glutil_gl2.cpp @@ -0,0 +1,145 @@ +/* gltest - small OpenGL tearing test program + * Copyright (C) 2012-2013 Ralf Jung + * + * 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 +#include +#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); +} -- 2.30.2