Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 1 | /* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. |
| 2 | * Use of this source code is governed by a BSD-style license that can be |
| 3 | * found in the LICENSE file. |
| 4 | */ |
| 5 | |
Gurchetan Singh | fee57f0 | 2017-02-22 13:42:37 -0800 | [diff] [blame] | 6 | #include "bs_drm.h" |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 7 | |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 8 | const char *get_gl_error() |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 9 | { |
| 10 | switch (glGetError()) { |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 11 | case GL_NO_ERROR: |
| 12 | return "No error has been recorded."; |
| 13 | case GL_INVALID_ENUM: |
| 14 | return "An unacceptable value is specified for an enumerated argument. The " |
| 15 | "offending command is ignored and has no other side effect than to " |
| 16 | "set the error flag."; |
| 17 | case GL_INVALID_VALUE: |
| 18 | return "A numeric argument is out of range. The offending command is " |
| 19 | "ignored and has no other side effect than to set the error flag."; |
| 20 | case GL_INVALID_OPERATION: |
| 21 | return "The specified operation is not allowed in the current state. The " |
| 22 | "offending command is ignored and has no other side effect than to " |
| 23 | "set the error flag."; |
| 24 | case GL_INVALID_FRAMEBUFFER_OPERATION: |
| 25 | return "The command is trying to render to or read from the framebuffer " |
| 26 | "while the currently bound framebuffer is not framebuffer complete " |
| 27 | "(i.e. the return value from glCheckFramebufferStatus is not " |
| 28 | "GL_FRAMEBUFFER_COMPLETE). The offending command is ignored and has " |
| 29 | "no other side effect than to set the error flag."; |
| 30 | case GL_OUT_OF_MEMORY: |
| 31 | return "There is not enough memory left to execute the command. The state " |
| 32 | "of the GL is undefined, except for the state of the error flags, " |
| 33 | "after this error is recorded."; |
| 34 | default: |
| 35 | return "Unknown error"; |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 36 | } |
| 37 | } |
| 38 | |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 39 | const char *get_egl_error() |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 40 | { |
| 41 | switch (eglGetError()) { |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 42 | case EGL_SUCCESS: |
| 43 | return "The last function succeeded without error."; |
| 44 | case EGL_NOT_INITIALIZED: |
| 45 | return "EGL is not initialized, or could not be initialized, for the " |
| 46 | "specified EGL display connection."; |
| 47 | case EGL_BAD_ACCESS: |
| 48 | return "EGL cannot access a requested resource (for example a context is " |
| 49 | "bound in another thread)."; |
| 50 | case EGL_BAD_ALLOC: |
| 51 | return "EGL failed to allocate resources for the requested operation."; |
| 52 | case EGL_BAD_ATTRIBUTE: |
| 53 | return "An unrecognized attribute or attribute value was passed in the " |
| 54 | "attribute list."; |
| 55 | case EGL_BAD_CONTEXT: |
| 56 | return "An EGLContext argument does not name a valid EGL rendering " |
| 57 | "context."; |
| 58 | case EGL_BAD_CONFIG: |
| 59 | return "An EGLConfig argument does not name a valid EGL frame buffer " |
| 60 | "configuration."; |
| 61 | case EGL_BAD_CURRENT_SURFACE: |
| 62 | return "The current surface of the calling thread is a window, pixel " |
| 63 | "buffer or pixmap that is no longer valid."; |
| 64 | case EGL_BAD_DISPLAY: |
| 65 | return "An EGLDisplay argument does not name a valid EGL display " |
| 66 | "connection."; |
| 67 | case EGL_BAD_SURFACE: |
| 68 | return "An EGLSurface argument does not name a valid surface (window, " |
| 69 | "pixel buffer or pixmap) configured for GL rendering."; |
| 70 | case EGL_BAD_MATCH: |
| 71 | return "Arguments are inconsistent (for example, a valid context requires " |
| 72 | "buffers not supplied by a valid surface)."; |
| 73 | case EGL_BAD_PARAMETER: |
| 74 | return "One or more argument values are invalid."; |
| 75 | case EGL_BAD_NATIVE_PIXMAP: |
| 76 | return "A NativePixmapType argument does not refer to a valid native " |
| 77 | "pixmap."; |
| 78 | case EGL_BAD_NATIVE_WINDOW: |
| 79 | return "A NativeWindowType argument does not refer to a valid native " |
| 80 | "window."; |
| 81 | case EGL_CONTEXT_LOST: |
| 82 | return "A power management event has occurred. The application must " |
| 83 | "destroy all contexts and reinitialise OpenGL ES state and objects " |
| 84 | "to continue rendering."; |
| 85 | default: |
| 86 | return "Unknown error"; |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 87 | } |
| 88 | } |
| 89 | |
| 90 | struct context { |
| 91 | unsigned width; |
| 92 | unsigned height; |
| 93 | EGLDisplay egl_display; |
| 94 | EGLContext egl_ctx; |
| 95 | |
| 96 | unsigned gl_fb; |
| 97 | unsigned gl_rb; |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 98 | }; |
| 99 | |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 100 | float f(int i) |
| 101 | { |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 102 | int a = i % 40; |
| 103 | int b = (i / 40) % 6; |
| 104 | switch (b) { |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 105 | case 0: |
| 106 | case 1: |
| 107 | return 0.0f; |
| 108 | case 3: |
| 109 | case 4: |
| 110 | return 1.0f; |
| 111 | case 2: |
| 112 | return (a / 40.0f); |
| 113 | case 5: |
| 114 | return 1.0f - (a / 40.0f); |
| 115 | default: |
| 116 | return 0.0f; |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 117 | } |
| 118 | } |
| 119 | |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 120 | void draw(struct context *ctx) |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 121 | { |
| 122 | int i; |
| 123 | const GLchar *vertexShaderStr = |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 124 | "attribute vec4 vPosition;\n" |
| 125 | "attribute vec4 vColor;\n" |
| 126 | "varying vec4 vFillColor;\n" |
| 127 | "void main() {\n" |
| 128 | " gl_Position = vPosition;\n" |
| 129 | " vFillColor = vColor;\n" |
| 130 | "}\n"; |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 131 | const GLchar *fragmentShaderStr = |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 132 | "precision mediump float;\n" |
| 133 | "varying vec4 vFillColor;\n" |
| 134 | "void main() {\n" |
| 135 | " gl_FragColor = vFillColor;\n" |
| 136 | "}\n"; |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 137 | GLint vertexShader, fragmentShader, program, status; |
| 138 | |
| 139 | vertexShader = glCreateShader(GL_VERTEX_SHADER); |
| 140 | if (!vertexShader) { |
| 141 | fprintf(stderr, "Failed to create vertex shader. Error=0x%x\n", glGetError()); |
| 142 | return; |
| 143 | } |
| 144 | glShaderSource(vertexShader, 1, &vertexShaderStr, NULL); |
| 145 | glCompileShader(vertexShader); |
| 146 | glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status); |
| 147 | if (!status) { |
| 148 | fprintf(stderr, "Failed to compile vertex shader. Error=0x%x\n", glGetError()); |
| 149 | return; |
| 150 | } |
| 151 | |
| 152 | fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); |
| 153 | if (!fragmentShader) { |
| 154 | fprintf(stderr, "Failed to create fragment shader. Error=0x%x\n", glGetError()); |
| 155 | return; |
| 156 | } |
| 157 | glShaderSource(fragmentShader, 1, &fragmentShaderStr, NULL); |
| 158 | glCompileShader(fragmentShader); |
| 159 | glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status); |
| 160 | if (!status) { |
| 161 | fprintf(stderr, "Failed to compile fragment shader. Error=0x%x\n", glGetError()); |
| 162 | return; |
| 163 | } |
| 164 | |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 165 | program = glCreateProgram(); |
| 166 | if (!program) { |
| 167 | fprintf(stderr, "Failed to create program.\n"); |
| 168 | return; |
| 169 | } |
| 170 | glAttachShader(program, vertexShader); |
| 171 | glAttachShader(program, fragmentShader); |
| 172 | glBindAttribLocation(program, 0, "vPosition"); |
| 173 | glBindAttribLocation(program, 1, "vColor"); |
| 174 | glLinkProgram(program); |
| 175 | glGetShaderiv(program, GL_LINK_STATUS, &status); |
| 176 | if (!status) { |
| 177 | fprintf(stderr, "Failed to link program.\n"); |
| 178 | return; |
| 179 | } |
| 180 | |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 181 | glViewport(0, 0, (GLint)ctx->width, (GLint)ctx->height); |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 182 | |
| 183 | for (i = 0; i <= 500; i++) { |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 184 | GLfloat verts[] = { 0.0f, -0.5f, 0.0f, -0.5f, 0.5f, 0.0f, 0.5f, 0.5f, 0.0f }; |
| 185 | GLfloat colors[] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, |
| 186 | 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }; |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 187 | |
| 188 | glClearColor(f(i), f(i + 80), f(i + 160), 0.0f); |
| 189 | glClear(GL_COLOR_BUFFER_BIT); |
| 190 | |
| 191 | glUseProgram(program); |
| 192 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, verts); |
| 193 | glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, colors); |
| 194 | glEnableVertexAttribArray(0); |
| 195 | glEnableVertexAttribArray(1); |
| 196 | glDrawArrays(GL_TRIANGLES, 0, 3); |
| 197 | |
| 198 | usleep(1e6 / 120); /* 120 Hz */ |
| 199 | glFinish(); |
| 200 | |
| 201 | unsigned char pixels[4]; |
| 202 | glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 203 | printf("color = %hhu %hhu %hhu %hhu\n", pixels[0], pixels[1], pixels[2], pixels[3]); |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 204 | } |
| 205 | |
| 206 | glDeleteProgram(program); |
| 207 | } |
| 208 | |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 209 | int main(int argc, char **argv) |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 210 | { |
| 211 | int ret = 0; |
| 212 | struct context ctx; |
| 213 | EGLint egl_major, egl_minor; |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 214 | const char *extensions; |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 215 | EGLint num_configs; |
| 216 | EGLConfig egl_config; |
| 217 | |
| 218 | ctx.width = 800; |
| 219 | ctx.height = 600; |
| 220 | |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 221 | const EGLint config_attribs[] = { EGL_RED_SIZE, |
| 222 | 1, |
| 223 | EGL_GREEN_SIZE, |
| 224 | 1, |
| 225 | EGL_BLUE_SIZE, |
| 226 | 1, |
| 227 | EGL_DEPTH_SIZE, |
| 228 | 1, |
| 229 | EGL_RENDERABLE_TYPE, |
| 230 | EGL_OPENGL_ES2_BIT, |
Gurchetan Singh | fcac800 | 2017-04-26 10:29:28 -0700 | [diff] [blame] | 231 | EGL_SURFACE_TYPE, |
| 232 | EGL_DONT_CARE, |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 233 | EGL_NONE }; |
| 234 | const EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 235 | |
| 236 | ctx.egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); |
| 237 | if (ctx.egl_display == EGL_NO_DISPLAY) { |
| 238 | fprintf(stderr, "failed to get egl display\n"); |
| 239 | ret = 1; |
| 240 | goto fail; |
| 241 | } |
| 242 | |
| 243 | if (!eglInitialize(ctx.egl_display, &egl_major, &egl_minor)) { |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 244 | fprintf(stderr, "failed to initialize egl: %s\n", get_egl_error()); |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 245 | ret = 1; |
| 246 | goto terminate_display; |
| 247 | } |
| 248 | |
Pratik Vishwakarma | 2402056 | 2016-12-12 14:18:04 +0530 | [diff] [blame] | 249 | printf("EGL %d.%d\n", egl_major, egl_minor); |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 250 | printf("EGL %s\n", eglQueryString(ctx.egl_display, EGL_VERSION)); |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 251 | |
| 252 | extensions = eglQueryString(ctx.egl_display, EGL_EXTENSIONS); |
Pratik Vishwakarma | 2402056 | 2016-12-12 14:18:04 +0530 | [diff] [blame] | 253 | printf("EGL Extensions: %s\n", extensions); |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 254 | |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 255 | if (!eglChooseConfig(ctx.egl_display, config_attribs, NULL, 0, &num_configs)) { |
| 256 | fprintf(stderr, "eglChooseConfig() failed with error: %x\n", eglGetError()); |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 257 | goto terminate_display; |
| 258 | } |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 259 | if (!eglChooseConfig(ctx.egl_display, config_attribs, &egl_config, 1, &num_configs)) { |
| 260 | fprintf(stderr, "eglChooseConfig() failed with error: %x\n", eglGetError()); |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 261 | goto terminate_display; |
| 262 | } |
| 263 | |
| 264 | if (!eglBindAPI(EGL_OPENGL_ES_API)) { |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 265 | fprintf(stderr, "failed to bind OpenGL ES: %s\n", get_egl_error()); |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 266 | ret = 1; |
| 267 | goto terminate_display; |
| 268 | } |
| 269 | |
Gurchetan Singh | 9a1cf16 | 2017-03-07 14:19:06 -0800 | [diff] [blame] | 270 | if (bs_egl_has_extension("EGL_KHR_no_config_context", extensions)) { |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 271 | ctx.egl_ctx = |
| 272 | eglCreateContext(ctx.egl_display, NULL /* No Config */, |
| 273 | EGL_NO_CONTEXT /* No shared context */, context_attribs); |
Gurchetan Singh | fee57f0 | 2017-02-22 13:42:37 -0800 | [diff] [blame] | 274 | } else { |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 275 | ctx.egl_ctx = |
| 276 | eglCreateContext(ctx.egl_display, egl_config, |
| 277 | EGL_NO_CONTEXT /* No shared context */, context_attribs); |
Gurchetan Singh | fee57f0 | 2017-02-22 13:42:37 -0800 | [diff] [blame] | 278 | } |
| 279 | |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 280 | if (ctx.egl_ctx == EGL_NO_CONTEXT) { |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 281 | fprintf(stderr, "failed to create OpenGL ES Context: %s\n", get_egl_error()); |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 282 | ret = 1; |
| 283 | goto terminate_display; |
| 284 | } |
| 285 | |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 286 | if (!eglMakeCurrent(ctx.egl_display, EGL_NO_SURFACE /* No default draw surface */, |
| 287 | EGL_NO_SURFACE /* No default draw read */, ctx.egl_ctx)) { |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 288 | fprintf(stderr, "failed to make the OpenGL ES Context current: %s\n", |
| 289 | get_egl_error()); |
| 290 | ret = 1; |
| 291 | goto destroy_context; |
| 292 | } |
| 293 | |
Pratik Vishwakarma | 2402056 | 2016-12-12 14:18:04 +0530 | [diff] [blame] | 294 | printf("GL extensions: %s\n", glGetString(GL_EXTENSIONS)); |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 295 | |
| 296 | glGenFramebuffers(1, &ctx.gl_fb); |
| 297 | glBindFramebuffer(GL_FRAMEBUFFER, ctx.gl_fb); |
| 298 | glGenRenderbuffers(1, &ctx.gl_rb); |
| 299 | glBindRenderbuffer(GL_RENDERBUFFER, ctx.gl_rb); |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 300 | glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, ctx.width, ctx.height); |
| 301 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, ctx.gl_rb); |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 302 | |
Gurchetan Singh | 9019228 | 2017-02-22 15:05:06 -0800 | [diff] [blame] | 303 | if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { |
| 304 | fprintf(stderr, "failed to create framebuffer: %s\n", get_gl_error()); |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 305 | ret = 1; |
| 306 | goto delete_gl_buffers; |
| 307 | } |
| 308 | |
| 309 | draw(&ctx); |
| 310 | |
| 311 | delete_gl_buffers: |
| 312 | glBindRenderbuffer(GL_RENDERBUFFER, 0); |
| 313 | glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| 314 | glDeleteFramebuffers(1, &ctx.gl_fb); |
| 315 | glDeleteRenderbuffers(1, &ctx.gl_rb); |
| 316 | destroy_context: |
Gurchetan Singh | 5cd9c8b | 2017-03-09 10:42:01 -0800 | [diff] [blame] | 317 | eglMakeCurrent(ctx.egl_display, NULL, NULL, NULL); |
Zach Reizner | e60ae5d | 2014-12-03 15:55:53 -0800 | [diff] [blame] | 318 | eglDestroyContext(ctx.egl_display, ctx.egl_ctx); |
| 319 | terminate_display: |
| 320 | eglTerminate(ctx.egl_display); |
| 321 | fail: |
| 322 | return ret; |
| 323 | } |