#include #include #include #include #include #include #include #include #include typedef struct _Data Data; struct _Data { Display *dpy; Window w; EGLSurface egl_surf; EGLContext egl_ctx; EGLDisplay egl_dpy; GLuint win_width, win_height; GLint attr_pos; GLint attr_tex_coord; GLint attr_test; }; static void draw_rectangle (Data *data, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) { GLuint vbo; struct vertex { float x, y; float s, t; float r, g, b, a; } verts[4] = { {x1, y2, 1.0f, 1.0f, 1.0f, .0f, 0.f, 1.0f}, {x1, y1, 1.0f, 1.0f, 1.0f, .0f, 0.f, 1.0f}, {x2, y1, 1.0f, 1.0f, 1.0f, .0f, 0.f, 1.0f}, {x2, y2, 1.0f, 1.0f, 1.0f, .0f, 0.f, 1.0f} }; glGenBuffers (1, &vbo); glBindBuffer (GL_ARRAY_BUFFER, vbo); glBufferData (GL_ARRAY_BUFFER, sizeof (verts), verts, GL_STATIC_DRAW); glVertexAttribPointer (data->attr_pos, 2, GL_FLOAT, GL_FALSE, sizeof (struct vertex), 0); glEnableVertexAttribArray (data->attr_pos); #define CONST_TEX_COORD #ifndef CONST_TEX_COORD glVertexAttribPointer (data->attr_tex_coord, 2, GL_FLOAT, GL_FALSE, sizeof (struct vertex), (GLvoid *)offsetof (struct vertex, s)); glEnableVertexAttribArray (data->attr_tex_coord); #else glVertexAttrib2f (data->attr_tex_coord, 1, 1); #endif #define CONST_TEST_COLOR #ifndef CONST_TEST_COLOR glVertexAttribPointer (data->attr_test, 4, GL_FLOAT, GL_FALSE, sizeof (struct vertex), (GLvoid *)offsetof (struct vertex, r)); glEnableVertexAttribArray (data->attr_test); #else glVertexAttrib4f (data->attr_test, 1, 0, 0, 1); #endif glBindBuffer (GL_ARRAY_BUFFER, 0); glDrawArrays (GL_TRIANGLE_FAN, 0, 4); glDisableVertexAttribArray (data->attr_pos); #ifndef CONST_TEX_COORD glDisableVertexAttribArray (data->attr_tex_coord); #endif #ifndef CONST_TEST_COLOR glDisableVertexAttribArray (data->attr_test); #endif glDeleteBuffers (1, &vbo); } static void redraw (Data *data) { int i; glViewport (0, 0, data->win_width, data->win_height); glClear (GL_COLOR_BUFFER_BIT); draw_rectangle (data, -1, -1, 1, 1); if (!eglSwapBuffers (data->egl_dpy, data->egl_surf)) { printf ("eglSwapBuffers failed!\n"); exit (1); } } static void create_shaders (Data *data) { static const char *vertShaderText = "attribute vec4 pos;\n" #if 0 "attribute vec4 tex_coord;\n" "attribute vec4 test;\n" #else "attribute vec4 test;\n" "attribute vec4 tex_coord;\n" #endif "varying vec4 v_tex_coord;\n" "varying vec4 v_test;\n" "\n" "void main () {\n" " gl_Position = pos;\n" " v_tex_coord = tex_coord;\n" " v_test = test;\n" "}\n"; static const char *fragShaderText = "varying vec4 v_tex_coord;\n" "varying vec4 v_test;\n" "\n" "void main () {\n" " gl_FragColor = vec4 (v_test.x, v_test.y, v_tex_coord.s, v_test.z);\n" "}\n"; GLuint fragShader, vertShader, program; GLint stat; GLint u_tex; fragShader = glCreateShader (GL_FRAGMENT_SHADER); glShaderSource (fragShader, 1, (const char **) &fragShaderText, NULL); glCompileShader (fragShader); glGetShaderiv (fragShader, GL_COMPILE_STATUS, &stat); if (!stat) { char log[1000]; GLsizei len; glGetShaderInfoLog (fragShader, 1000, &len, log); printf("Error: fragment shader did not compile: %s\n", log); exit(1); } vertShader = glCreateShader (GL_VERTEX_SHADER); glShaderSource (vertShader, 1, (const char **) &vertShaderText, NULL); glCompileShader (vertShader); glGetShaderiv (vertShader, GL_COMPILE_STATUS, &stat); if (!stat) { char log[1000]; GLsizei len; glGetShaderInfoLog (vertShader, 1000, &len, log); printf("Error: vertex shader did not compile: %s\n", log); exit(1); } program = glCreateProgram (); glAttachShader (program, fragShader); glAttachShader (program, vertShader); glLinkProgram (program); glGetProgramiv (program, GL_LINK_STATUS, &stat); if (!stat) { char log[1000]; GLsizei len; glGetProgramInfoLog (program, 1000, &len, log); printf ("Error: linking:\n%s\n", log); exit (1); } glUseProgram (program); #if 0 glBindAttribLocation (program, 0, "pos"); data->attr_pos = 0; glBindAttribLocation (program, 1, "tex_coord"); data->attr_tex_coord = 1; glBindAttribLocation (program, 2, "test"); data->attr_test = 2; #else data->attr_pos = glGetAttribLocation (program, "pos"); data->attr_tex_coord = glGetAttribLocation (program, "tex_coord"); data->attr_test = glGetAttribLocation (program, "test"); #endif printf ("Attrib pos at %d\n", data->attr_pos); printf ("Attrib tex_coord at %d\n", data->attr_tex_coord); printf ("Attrib test at %d\n", data->attr_test); } static Window make_window (Data *data) { static const EGLint attribs[] = { EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1, EGL_BLUE_SIZE, 1, EGL_DEPTH_SIZE, 1, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; static const EGLint ctx_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; int scrnum; XSetWindowAttributes attr; unsigned long mask; Window root; Window win; XVisualInfo *visInfo, visTemplate; int num_visuals; EGLContext ctx; EGLConfig config; EGLint num_configs; EGLint vid; scrnum = DefaultScreen (data->dpy); root = RootWindow (data->dpy, scrnum); if (!eglChooseConfig (data->egl_dpy, attribs, &config, 1, &num_configs)) { printf("Error: couldn't get an EGL visual config\n"); exit(1); } assert (config); assert (num_configs > 0); if (!eglGetConfigAttrib (data->egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) { printf("Error: eglGetConfigAttrib() failed\n"); exit(1); } /* The X window visual must match the EGL config */ visTemplate.visualid = vid; visInfo = XGetVisualInfo (data->dpy, VisualIDMask, &visTemplate, &num_visuals); if (!visInfo) { printf("Error: couldn't get X visual\n"); exit(1); } /* window attributes */ attr.background_pixel = 0; attr.border_pixel = 0; attr.colormap = XCreateColormap (data->dpy, root, visInfo->visual, AllocNone); attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; win = XCreateWindow (data->dpy, root, 0, 0, data->win_width, data->win_height, 0, visInfo->depth, InputOutput, visInfo->visual, mask, &attr); /* set hints and properties */ { XSizeHints sizehints; sizehints.x = 0; sizehints.y = 0; sizehints.width = data->win_width; sizehints.height = data->win_height; sizehints.flags = USSize | USPosition; XSetNormalHints (data->dpy, win, &sizehints); XSetStandardProperties (data->dpy, win, "test-const-attrib-gles2", "test-const-attrib-gles2", None, (char **)NULL, 0, &sizehints); } #if 0 eglBindAPI(EGL_OPENGL_API); #else eglBindAPI(EGL_OPENGL_ES_API); #endif ctx = eglCreateContext (data->egl_dpy, config, EGL_NO_CONTEXT, ctx_attribs); if (!ctx) { printf("Error: eglCreateContext failed\n"); exit(1); } /* test eglQueryContext() */ { EGLint val; eglQueryContext (data->egl_dpy, ctx, EGL_CONTEXT_CLIENT_VERSION, &val); assert (val == 2); } data->egl_surf = eglCreateWindowSurface (data->egl_dpy, config, win, NULL); if (!data->egl_surf) { printf("Error: eglCreateWindowSurface failed\n"); exit(1); } /* sanity checks */ { EGLint val; eglQuerySurface (data->egl_dpy, data->egl_surf, EGL_WIDTH, &val); assert (val == data->win_width); eglQuerySurface (data->egl_dpy, data->egl_surf, EGL_HEIGHT, &val); assert (val == data->win_height); assert (eglGetConfigAttrib (data->egl_dpy, config, EGL_SURFACE_TYPE, &val)); assert (val & EGL_WINDOW_BIT); } XFree (visInfo); data->egl_ctx = ctx; if (!eglMakeCurrent (data->egl_dpy, data->egl_surf, data->egl_surf, data->egl_ctx)) { printf("Error: eglMakeCurrent failed\n"); exit(1); } /* init GL state */ glClearColor (1.0, 0.0, 1.0, 1.0); glClearStencil (0); return win; } static void event_loop (Data *data) { while (1) { while (XPending (data->dpy)) { XEvent event; XNextEvent (data->dpy, &event); if (event.type == KeyPress) { KeySym sym = XKeycodeToKeysym (data->dpy, event.xkey.keycode, 0); if (sym == XK_Escape || sym == XK_q || sym == XK_Q) break; } } redraw (data); } } int main (int argc, char *argv[]) { Data data; EGLint egl_major, egl_minor; int x, y; data.dpy = XOpenDisplay (NULL); if (!data.dpy) { printf ("Error: XOpenDisplay failed\n"); return 1; } data.egl_dpy = eglGetDisplay (data.dpy); if (!data.egl_dpy) { printf("Error: eglGetDisplay() failed\n"); return -1; } if (!eglInitialize (data.egl_dpy, &egl_major, &egl_minor)) { printf("Error: eglInitialize() failed\n"); return -1; } data.win_width = 800; data.win_height = 600; data.w = make_window (&data); XMapWindow (data.dpy, data.w); create_shaders (&data); event_loop (&data); eglMakeCurrent (data.dpy, None, None, NULL); eglDestroyContext (data.dpy, data.egl_ctx); XDestroyWindow (data.dpy, data.w); XCloseDisplay (data.dpy); return 0; }