blob: ea7569695fd594914f51c4c49dc6468080ca17b0 [file] [log] [blame]
Haixia Shi4652b8c2014-11-19 17:55:38 -08001/*
2 * Copyright 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
Haixia Shie04ddfd2014-11-11 19:14:32 -08007#include <errno.h>
8#include <fcntl.h>
9#include <stdbool.h>
10#include <stdio.h>
11#include <string.h>
12#include <sys/types.h>
13#include <unistd.h>
14
15#define EGL_EGLEXT_PROTOTYPES
16#define GL_GLEXT_PROTOTYPES
17
18#include <gbm.h>
19#include <EGL/egl.h>
20#include <EGL/eglext.h>
21#include <drm_fourcc.h>
22#include <GLES2/gl2.h>
23#include <GLES2/gl2ext.h>
24#include <xf86drm.h>
25#include <xf86drmMode.h>
26
Lauri Peltonen95226da2014-12-18 16:39:54 -080027static const char * get_gl_error(void)
Haixia Shie04ddfd2014-11-11 19:14:32 -080028{
29 switch (glGetError()) {
30 case GL_NO_ERROR:
Haixia Shi4652b8c2014-11-19 17:55:38 -080031 return "GL_NO_ERROR";
Haixia Shie04ddfd2014-11-11 19:14:32 -080032 case GL_INVALID_ENUM:
Haixia Shi4652b8c2014-11-19 17:55:38 -080033 return "GL_INVALID_ENUM";
Haixia Shie04ddfd2014-11-11 19:14:32 -080034 case GL_INVALID_VALUE:
Haixia Shi4652b8c2014-11-19 17:55:38 -080035 return "GL_INVALID_VALUE";
Haixia Shie04ddfd2014-11-11 19:14:32 -080036 case GL_INVALID_OPERATION:
Haixia Shi4652b8c2014-11-19 17:55:38 -080037 return "GL_INVALID_OPERATION";
Haixia Shie04ddfd2014-11-11 19:14:32 -080038 case GL_INVALID_FRAMEBUFFER_OPERATION:
Haixia Shi4652b8c2014-11-19 17:55:38 -080039 return "GL_INVALID_FRAMEBUFFER_OPERATION";
Haixia Shie04ddfd2014-11-11 19:14:32 -080040 case GL_OUT_OF_MEMORY:
Haixia Shi4652b8c2014-11-19 17:55:38 -080041 return "GL_OUT_OF_MEMORY";
Haixia Shie04ddfd2014-11-11 19:14:32 -080042 default:
43 return "Unknown error";
44 }
45}
46
Lauri Peltonen95226da2014-12-18 16:39:54 -080047static const char * get_egl_error(void)
Haixia Shie04ddfd2014-11-11 19:14:32 -080048{
49 switch (eglGetError()) {
50 case EGL_SUCCESS:
Haixia Shi4652b8c2014-11-19 17:55:38 -080051 return "EGL_SUCCESS";
Haixia Shie04ddfd2014-11-11 19:14:32 -080052 case EGL_NOT_INITIALIZED:
Haixia Shi4652b8c2014-11-19 17:55:38 -080053 return "EGL_NOT_INITIALIZED";
Haixia Shie04ddfd2014-11-11 19:14:32 -080054 case EGL_BAD_ACCESS:
Haixia Shi4652b8c2014-11-19 17:55:38 -080055 return "EGL_BAD_ACCESS";
Haixia Shie04ddfd2014-11-11 19:14:32 -080056 case EGL_BAD_ALLOC:
Haixia Shi4652b8c2014-11-19 17:55:38 -080057 return "EGL_BAD_ALLOC";
Haixia Shie04ddfd2014-11-11 19:14:32 -080058 case EGL_BAD_ATTRIBUTE:
Haixia Shi4652b8c2014-11-19 17:55:38 -080059 return "EGL_BAD_ATTRIBUTE";
Haixia Shie04ddfd2014-11-11 19:14:32 -080060 case EGL_BAD_CONTEXT:
Haixia Shi4652b8c2014-11-19 17:55:38 -080061 return "EGL_BAD_CONTEXT";
Haixia Shie04ddfd2014-11-11 19:14:32 -080062 case EGL_BAD_CONFIG:
Haixia Shi4652b8c2014-11-19 17:55:38 -080063 return "EGL_BAD_CONFIG";
Haixia Shie04ddfd2014-11-11 19:14:32 -080064 case EGL_BAD_CURRENT_SURFACE:
Haixia Shi4652b8c2014-11-19 17:55:38 -080065 return "EGL_BAD_CURRENT_SURFACE";
Haixia Shie04ddfd2014-11-11 19:14:32 -080066 case EGL_BAD_DISPLAY:
Haixia Shi4652b8c2014-11-19 17:55:38 -080067 return "EGL_BAD_DISPLAY";
Haixia Shie04ddfd2014-11-11 19:14:32 -080068 case EGL_BAD_SURFACE:
Haixia Shi4652b8c2014-11-19 17:55:38 -080069 return "EGL_BAD_SURFACE";
Haixia Shie04ddfd2014-11-11 19:14:32 -080070 case EGL_BAD_MATCH:
Haixia Shi4652b8c2014-11-19 17:55:38 -080071 return "EGL_BAD_MATCH";
Haixia Shie04ddfd2014-11-11 19:14:32 -080072 case EGL_BAD_PARAMETER:
Haixia Shi4652b8c2014-11-19 17:55:38 -080073 return "EGL_BAD_PARAMETER";
Haixia Shie04ddfd2014-11-11 19:14:32 -080074 case EGL_BAD_NATIVE_PIXMAP:
Haixia Shi4652b8c2014-11-19 17:55:38 -080075 return "EGL_BAD_NATIVE_PIXMAP";
Haixia Shie04ddfd2014-11-11 19:14:32 -080076 case EGL_BAD_NATIVE_WINDOW:
Haixia Shi4652b8c2014-11-19 17:55:38 -080077 return "EGL_BAD_NATIVE_WINDOW";
Haixia Shie04ddfd2014-11-11 19:14:32 -080078 case EGL_CONTEXT_LOST:
Haixia Shi4652b8c2014-11-19 17:55:38 -080079 return "EGL_CONTEXT_LOST";
Haixia Shie04ddfd2014-11-11 19:14:32 -080080 default:
81 return "Unknown error";
82 }
83}
84
Lauri Peltonen763ca462014-12-17 12:22:21 -080085static bool has_extension(const char *extension, const char *extensions)
86{
87 const char *start, *where, *terminator;
88 start = extensions;
89 for (;;) {
90 where = (char *)strstr((const char *)start, extension);
91 if (!where)
92 break;
93 terminator = where + strlen(extension);
94 if (where == start || *(where - 1) == ' ')
95 if (*terminator == ' ' || *terminator == '\0')
96 return true;
97 start = terminator;
98 }
99 return false;
100}
101
Haixia Shi4652b8c2014-11-19 17:55:38 -0800102#define BUFFERS 2
103
Haixia Shie04ddfd2014-11-11 19:14:32 -0800104struct context {
Haixia Shibc4d0a02014-12-01 14:25:54 -0800105 int drm_card_fd;
Haixia Shibc4d0a02014-12-01 14:25:54 -0800106 struct gbm_device *drm_gbm;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800107
108 EGLDisplay egl_display;
109 EGLContext egl_ctx;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800110
111 drmModeConnector * connector;
112 drmModeEncoder * encoder;
113 drmModeModeInfo * mode;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800114
Haixia Shi4652b8c2014-11-19 17:55:38 -0800115 struct gbm_bo * gbm_buffer[BUFFERS];
116 EGLImageKHR egl_image[BUFFERS];
117 uint32_t drm_fb_id[BUFFERS];
118 unsigned gl_fb[BUFFERS];
119 unsigned gl_rb[BUFFERS];
Haixia Shie04ddfd2014-11-11 19:14:32 -0800120
121};
122
Lauri Peltonen95226da2014-12-18 16:39:54 -0800123static bool setup_drm(struct context * ctx)
Haixia Shie04ddfd2014-11-11 19:14:32 -0800124{
Haixia Shibc4d0a02014-12-01 14:25:54 -0800125 int fd = ctx->drm_card_fd;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800126 drmModeRes *resources = NULL;
127 drmModeConnector *connector = NULL;
128 drmModeEncoder *encoder = NULL;
129 int i, j;
130
131 resources = drmModeGetResources(fd);
132 if (!resources) {
133 fprintf(stderr, "drmModeGetResources failed\n");
134 return false;
135 }
136
137 for (i = 0; i < resources->count_connectors; i++) {
138 connector = drmModeGetConnector(fd, resources->connectors[i]);
139 if (connector == NULL)
140 continue;
141
142 if (connector->connection == DRM_MODE_CONNECTED &&
143 connector->count_modes > 0)
144 break;
145
146 drmModeFreeConnector(connector);
147 }
148
149 if (i == resources->count_connectors) {
150 fprintf(stderr, "no currently active connector found\n");
151 return false;
152 }
153
154 for (i = 0; i < resources->count_encoders; i++) {
155 encoder = drmModeGetEncoder(fd, resources->encoders[i]);
156
157 if (encoder == NULL)
158 continue;
159
160 for (j = 0; j < connector->count_encoders; j++) {
161 if (encoder->encoder_id == connector->encoders[j])
162 break;
163 }
164
165 if (j == connector->count_encoders) {
166 drmModeFreeEncoder(encoder);
167 continue;
168 }
169
170 break;
171 }
172
173 if (i == resources->count_encoders) {
174 fprintf(stderr, "no supported encoder found\n");
175 return false;
176 }
177
178 for (i = 0; i < resources->count_crtcs; i++) {
179 if (encoder->possible_crtcs & (1 << i)) {
180 encoder->crtc_id = resources->crtcs[i];
181 break;
182 }
183 }
184
185 if (i == resources->count_crtcs) {
186 fprintf(stderr, "no possible crtc found\n");
187 return false;
188 }
189
190 ctx->connector = connector;
191 ctx->encoder = encoder;
192 ctx->mode = &connector->modes[0];
193
194 return true;
195}
196
Lauri Peltonen95226da2014-12-18 16:39:54 -0800197static float f(int i)
198{
Haixia Shie04ddfd2014-11-11 19:14:32 -0800199 int a = i % 40;
200 int b = (i / 40) % 6;
201 switch (b) {
202 case 0:
203 case 1:
204 return 0.0f;
205 case 3:
206 case 4:
207 return 1.0f;
208 case 2:
209 return (a / 40.0f);
210 case 5:
211 return 1.0f - (a / 40.0f);
212 default:
213 return 0.0f;
214 }
215}
216
Haixia Shi4652b8c2014-11-19 17:55:38 -0800217static void page_flip_handler(int fd, unsigned int frame, unsigned int sec,
218 unsigned int usec, void *data)
219{
220 int *waiting_for_flip = data;
221 *waiting_for_flip = 0;
222}
223
Lauri Peltonen95226da2014-12-18 16:39:54 -0800224static void draw(struct context * ctx)
Haixia Shie04ddfd2014-11-11 19:14:32 -0800225{
226 int i;
227 const GLchar *vertexShaderStr =
228 "attribute vec4 vPosition;\n"
229 "attribute vec4 vColor;\n"
230 "varying vec4 vFillColor;\n"
231 "void main() {\n"
232 " gl_Position = vPosition;\n"
233 " vFillColor = vColor;\n"
234 "}\n";
235 const GLchar *fragmentShaderStr =
236 "precision mediump float;\n"
237 "varying vec4 vFillColor;\n"
238 "void main() {\n"
239 " gl_FragColor = vFillColor;\n"
240 "}\n";
241 GLint vertexShader, fragmentShader, program, status;
242
243 vertexShader = glCreateShader(GL_VERTEX_SHADER);
244 if (!vertexShader) {
245 fprintf(stderr, "Failed to create vertex shader. Error=0x%x\n", glGetError());
246 return;
247 }
248 glShaderSource(vertexShader, 1, &vertexShaderStr, NULL);
249 glCompileShader(vertexShader);
250 glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
251 if (!status) {
252 fprintf(stderr, "Failed to compile vertex shader. Error=0x%x\n", glGetError());
253 return;
254 }
255
256 fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
257 if (!fragmentShader) {
258 fprintf(stderr, "Failed to create fragment shader. Error=0x%x\n", glGetError());
259 return;
260 }
261 glShaderSource(fragmentShader, 1, &fragmentShaderStr, NULL);
262 glCompileShader(fragmentShader);
263 glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status);
264 if (!status) {
265 fprintf(stderr, "Failed to compile fragment shader. Error=0x%x\n", glGetError());
266 return;
267 }
268
269
270 program = glCreateProgram();
271 if (!program) {
272 fprintf(stderr, "Failed to create program.\n");
273 return;
274 }
275 glAttachShader(program, vertexShader);
276 glAttachShader(program, fragmentShader);
277 glBindAttribLocation(program, 0, "vPosition");
278 glBindAttribLocation(program, 1, "vColor");
279 glLinkProgram(program);
280 glGetShaderiv(program, GL_LINK_STATUS, &status);
281 if (!status) {
282 fprintf(stderr, "Failed to link program.\n");
283 return;
284 }
285
Haixia Shi4652b8c2014-11-19 17:55:38 -0800286 int fb_idx = 1;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800287 for (i = 0; i <= 500; i++) {
Haixia Shi4652b8c2014-11-19 17:55:38 -0800288 int waiting_for_flip = 1;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800289 GLfloat verts[] = {
290 0.0f, -0.5f, 0.0f,
291 -0.5f, 0.5f, 0.0f,
292 0.5f, 0.5f, 0.0f
293 };
294 GLfloat colors[] = {
295 1.0f, 0.0f, 0.0f, 1.0f,
296 0.0f, 1.0f, 0.0f, 1.0f,
297 0.0f, 0.0f, 1.0f, 1.0f
298 };
299
Haixia Shi4652b8c2014-11-19 17:55:38 -0800300 glBindFramebuffer(GL_FRAMEBUFFER, ctx->gl_fb[fb_idx]);
301 glViewport(0, 0,(GLint) ctx->mode->hdisplay,
302 (GLint) ctx->mode->vdisplay);
303
Haixia Shie04ddfd2014-11-11 19:14:32 -0800304 glClearColor(f(i), f(i + 80), f(i + 160), 0.0f);
305 glClear(GL_COLOR_BUFFER_BIT);
306
307 glUseProgram(program);
308 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, verts);
309 glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, colors);
310 glEnableVertexAttribArray(0);
311 glEnableVertexAttribArray(1);
312 glDrawArrays(GL_TRIANGLES, 0, 3);
313
314 usleep(1e6 / 120); /* 120 Hz */
315 glFinish();
Haixia Shibc4d0a02014-12-01 14:25:54 -0800316 drmModePageFlip(ctx->drm_card_fd, ctx->encoder->crtc_id,
Haixia Shi4652b8c2014-11-19 17:55:38 -0800317 ctx->drm_fb_id[fb_idx],
318 DRM_MODE_PAGE_FLIP_EVENT,
319 &waiting_for_flip);
320
321 while (waiting_for_flip) {
322 drmEventContext evctx = {
323 .version = DRM_EVENT_CONTEXT_VERSION,
324 .page_flip_handler = page_flip_handler,
325 };
326
327 fd_set fds;
328 FD_ZERO(&fds);
329 FD_SET(0, &fds);
Haixia Shibc4d0a02014-12-01 14:25:54 -0800330 FD_SET(ctx->drm_card_fd, &fds);
Haixia Shi4652b8c2014-11-19 17:55:38 -0800331
Haixia Shibc4d0a02014-12-01 14:25:54 -0800332 int ret = select(ctx->drm_card_fd + 1, &fds, NULL, NULL, NULL);
Haixia Shi4652b8c2014-11-19 17:55:38 -0800333 if (ret < 0) {
334 fprintf(stderr, "select err: %s\n", strerror(errno));
335 return;
336 } else if (ret == 0) {
337 fprintf(stderr, "select timeout\n");
338 return;
339 } else if (FD_ISSET(0, &fds)) {
340 fprintf(stderr, "user interrupted\n");
341 return;
342 }
Haixia Shibc4d0a02014-12-01 14:25:54 -0800343 drmHandleEvent(ctx->drm_card_fd, &evctx);
Haixia Shi4652b8c2014-11-19 17:55:38 -0800344 }
345 fb_idx = fb_idx ^ 1;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800346 }
347
348 glDeleteProgram(program);
349}
350
351int main(int argc, char ** argv)
352{
353 int ret = 0;
354 struct context ctx;
355 EGLint egl_major, egl_minor;
Lauri Peltonen763ca462014-12-17 12:22:21 -0800356 const char * egl_extensions;
357 const char * gl_extensions;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800358 uint32_t bo_handle;
359 uint32_t bo_stride;
360 int drm_prime_fd;
361 EGLint num_configs;
362 EGLConfig egl_config;
Haixia Shi4652b8c2014-11-19 17:55:38 -0800363 size_t i;
Lauri Peltonen71cdf952014-12-17 12:13:24 -0800364 char* drm_card_path = "/dev/dri/card0";
Lauri Peltonen763ca462014-12-17 12:22:21 -0800365 PFNEGLCREATEIMAGEKHRPROC pfeglCreateImageKHR;
366 PFNEGLDESTROYIMAGEKHRPROC pfeglDestroyImageKHR;
367 PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC pfglEGLImageTargetRenderbufferStorageOES;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800368
369 const EGLint config_attribs[] = {
370 EGL_RED_SIZE, 1,
371 EGL_GREEN_SIZE, 1,
372 EGL_BLUE_SIZE, 1,
373 EGL_DEPTH_SIZE, 1,
374 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
375 EGL_NONE
376 };
377 const EGLint context_attribs[] = {
378 EGL_CONTEXT_CLIENT_VERSION, 2,
379 EGL_NONE
380 };
381
Lauri Peltonen71cdf952014-12-17 12:13:24 -0800382 if (argc >= 2)
Haixia Shibc4d0a02014-12-01 14:25:54 -0800383 drm_card_path = argv[1];
Haixia Shie04ddfd2014-11-11 19:14:32 -0800384
Haixia Shibc4d0a02014-12-01 14:25:54 -0800385 ctx.drm_card_fd = open(drm_card_path, O_RDWR);
386 if (ctx.drm_card_fd < 0) {
387 fprintf(stderr, "failed to open %s\n", drm_card_path);
Haixia Shie04ddfd2014-11-11 19:14:32 -0800388 ret = 1;
389 goto fail;
390 }
391
Haixia Shibc4d0a02014-12-01 14:25:54 -0800392 ctx.drm_gbm = gbm_create_device(ctx.drm_card_fd);
393 if (!ctx.drm_gbm) {
394 fprintf(stderr, "failed to create gbm device on %s\n", drm_card_path);
Haixia Shie04ddfd2014-11-11 19:14:32 -0800395 ret = 1;
Haixia Shibc4d0a02014-12-01 14:25:54 -0800396 goto close_drm_card;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800397 }
398
Lauri Peltonen71cdf952014-12-17 12:13:24 -0800399 ctx.egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
Haixia Shie04ddfd2014-11-11 19:14:32 -0800400 if (ctx.egl_display == EGL_NO_DISPLAY) {
401 fprintf(stderr, "failed to get egl display\n");
402 ret = 1;
Lauri Peltonen71cdf952014-12-17 12:13:24 -0800403 goto destroy_drm_gbm;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800404 }
405
406 if (!eglInitialize(ctx.egl_display, &egl_major, &egl_minor)) {
407 fprintf(stderr, "failed to initialize egl: %s\n",
408 get_egl_error());
409 ret = 1;
410 goto terminate_display;
411 }
412
413 fprintf(stderr, "EGL %d.%d\n", egl_major, egl_minor);
414 fprintf(stderr, "EGL %s\n",
415 eglQueryString(ctx.egl_display, EGL_VERSION));
416
Lauri Peltonen763ca462014-12-17 12:22:21 -0800417 egl_extensions = eglQueryString(ctx.egl_display, EGL_EXTENSIONS);
418 fprintf(stderr, "EGL Extensions: %s\n", egl_extensions);
Haixia Shie04ddfd2014-11-11 19:14:32 -0800419
420 if (!setup_drm(&ctx)) {
421 fprintf(stderr, "failed to setup drm resources\n");
422 ret = 1;
423 goto terminate_display;
424 }
425
426 fprintf(stderr, "display size: %dx%d\n",
427 ctx.mode->hdisplay, ctx.mode->vdisplay);
428
429 if (!eglChooseConfig(ctx.egl_display, config_attribs, NULL, 0,
430 &num_configs)) {
431 fprintf(stderr, "eglChooseConfig() failed with error: %x\n", eglGetError());
432 goto free_drm;
433 }
434 if (!eglChooseConfig(ctx.egl_display, config_attribs, &egl_config, 1,
435 &num_configs)) {
436 fprintf(stderr, "eglChooseConfig() failed with error: %x\n", eglGetError());
437 goto free_drm;
438 }
439
440 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
441 fprintf(stderr, "failed to bind OpenGL ES: %s\n",
442 get_egl_error());
443 ret = 1;
444 goto free_drm;
445 }
446
447 ctx.egl_ctx = eglCreateContext(ctx.egl_display,
Lauri Peltonen44af28d2014-12-17 12:19:54 -0800448 egl_config,
Haixia Shie04ddfd2014-11-11 19:14:32 -0800449 EGL_NO_CONTEXT /* No shared context */,
450 context_attribs);
451 if (ctx.egl_ctx == EGL_NO_CONTEXT) {
452 fprintf(stderr, "failed to create OpenGL ES Context: %s\n",
453 get_egl_error());
454 ret = 1;
455 goto free_drm;
456 }
457
458 if (!eglMakeCurrent(ctx.egl_display,
459 EGL_NO_SURFACE /* No default draw surface */,
460 EGL_NO_SURFACE /* No default draw read */,
461 ctx.egl_ctx)) {
462 fprintf(stderr, "failed to make the OpenGL ES Context current: %s\n",
463 get_egl_error());
464 ret = 1;
465 goto destroy_context;
466 }
467
Lauri Peltonen763ca462014-12-17 12:22:21 -0800468 gl_extensions = (const char *)glGetString(GL_EXTENSIONS);
469 fprintf(stderr, "GL extensions: %s\n", gl_extensions);
470
471 if (!has_extension("EGL_EXT_image_dma_buf_import", egl_extensions)) {
472 fprintf(stderr, "EGL_EXT_image_dma_buf_import extension not supported\n");
473 ret = 1;
474 goto destroy_context;
475 }
476
477 if (!has_extension("GL_OES_EGL_image", gl_extensions)) {
478 fprintf(stderr, "GL_OES_EGL_image extension not supported\n");
479 ret = 1;
480 goto destroy_context;
481 }
482
483 pfeglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR");
484 pfeglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR");
485 pfglEGLImageTargetRenderbufferStorageOES = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)eglGetProcAddress("glEGLImageTargetRenderbufferStorageOES");
486 if (!pfeglCreateImageKHR || !pfeglDestroyImageKHR || !pfglEGLImageTargetRenderbufferStorageOES) {
487 fprintf(stderr, "eglGetProcAddress returned NULL for a required extension entry point\n");
488 ret = 1;
489 goto destroy_context;
490 }
Haixia Shie04ddfd2014-11-11 19:14:32 -0800491
Haixia Shi4652b8c2014-11-19 17:55:38 -0800492 glGenFramebuffers(BUFFERS, ctx.gl_fb);
493 glGenRenderbuffers(BUFFERS, ctx.gl_rb);
Haixia Shie04ddfd2014-11-11 19:14:32 -0800494
Haixia Shi4652b8c2014-11-19 17:55:38 -0800495 for (i = 0; i < BUFFERS; ++i) {
Haixia Shibc4d0a02014-12-01 14:25:54 -0800496 ctx.gbm_buffer[i] = gbm_bo_create(ctx.drm_gbm,
Haixia Shi4652b8c2014-11-19 17:55:38 -0800497 ctx.mode->hdisplay, ctx.mode->vdisplay, GBM_BO_FORMAT_XRGB8888,
498 GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
499
500 if (!ctx.gbm_buffer[i]) {
501 fprintf(stderr, "failed to create buffer object\n");
502 ret = 1;
503 goto free_buffers;
504 }
505
506 bo_handle = gbm_bo_get_handle(ctx.gbm_buffer[i]).u32;
507 bo_stride = gbm_bo_get_stride(ctx.gbm_buffer[i]);
508
Zach Reizner0feb1f12015-01-09 13:38:57 -0800509 drm_prime_fd = gbm_bo_get_fd(ctx.gbm_buffer[i]);
510
511 if (drm_prime_fd < 0) {
Haixia Shi4652b8c2014-11-19 17:55:38 -0800512 fprintf(stderr, "failed to turn handle into fd\n");
513 ret = 1;
514 goto free_buffers;
515 }
516
517 const EGLint khr_image_attrs[] = {
518 EGL_WIDTH, ctx.mode->hdisplay,
519 EGL_HEIGHT, ctx.mode->vdisplay,
520 EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_XRGB8888,
521 EGL_DMA_BUF_PLANE0_FD_EXT, drm_prime_fd,
522 EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
523 EGL_DMA_BUF_PLANE0_PITCH_EXT, bo_stride,
524 EGL_NONE
525 };
526
Lauri Peltonen763ca462014-12-17 12:22:21 -0800527 ctx.egl_image[i] = pfeglCreateImageKHR(ctx.egl_display, EGL_NO_CONTEXT,
Haixia Shi4652b8c2014-11-19 17:55:38 -0800528 EGL_LINUX_DMA_BUF_EXT, NULL, khr_image_attrs);
529 if (ctx.egl_image[i] == EGL_NO_IMAGE_KHR) {
530 fprintf(stderr, "failed to create egl image: %s\n",
531 get_egl_error());
532 ret = 1;
533 goto free_buffers;
534 }
535
536 glBindRenderbuffer(GL_RENDERBUFFER, ctx.gl_rb[i]);
537 glBindFramebuffer(GL_FRAMEBUFFER, ctx.gl_fb[i]);
Lauri Peltonen763ca462014-12-17 12:22:21 -0800538 pfglEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, ctx.egl_image[i]);
Haixia Shi4652b8c2014-11-19 17:55:38 -0800539 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
540 GL_RENDERBUFFER, ctx.gl_rb[i]);
541
542 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) !=
543 GL_FRAMEBUFFER_COMPLETE) {
544 fprintf(stderr, "failed to create framebuffer: %s\n", get_gl_error());
545 ret = 1;
546 goto free_buffers;
547 }
548
Haixia Shibc4d0a02014-12-01 14:25:54 -0800549 ret = drmModeAddFB(ctx.drm_card_fd, ctx.mode->hdisplay, ctx.mode->vdisplay,
Haixia Shi4652b8c2014-11-19 17:55:38 -0800550 24, 32, bo_stride, bo_handle, &ctx.drm_fb_id[i]);
551
552 if (ret) {
553 fprintf(stderr, "failed to add fb\n");
554 ret = 1;
555 goto free_buffers;
556 }
Haixia Shie04ddfd2014-11-11 19:14:32 -0800557 }
558
Haixia Shibc4d0a02014-12-01 14:25:54 -0800559 if (drmModeSetCrtc(ctx.drm_card_fd, ctx.encoder->crtc_id, ctx.drm_fb_id[0],
Haixia Shie04ddfd2014-11-11 19:14:32 -0800560 0, 0, &ctx.connector->connector_id, 1, ctx.mode)) {
561 fprintf(stderr, "failed to set CRTC\n");
562 ret = 1;
Haixia Shi4652b8c2014-11-19 17:55:38 -0800563 goto free_buffers;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800564 }
565
566 draw(&ctx);
567
Haixia Shi4652b8c2014-11-19 17:55:38 -0800568free_buffers:
Haixia Shie04ddfd2014-11-11 19:14:32 -0800569 glBindRenderbuffer(GL_RENDERBUFFER, 0);
570 glBindFramebuffer(GL_FRAMEBUFFER, 0);
Haixia Shi4652b8c2014-11-19 17:55:38 -0800571 for (i = 0; i < BUFFERS; ++i) {
572 if (ctx.drm_fb_id[i])
Haixia Shibc4d0a02014-12-01 14:25:54 -0800573 drmModeRmFB(ctx.drm_card_fd, ctx.drm_fb_id[i]);
Haixia Shi4652b8c2014-11-19 17:55:38 -0800574 if (ctx.egl_image[i])
Lauri Peltonen763ca462014-12-17 12:22:21 -0800575 pfeglDestroyImageKHR(ctx.egl_display, ctx.egl_image[i]);
Haixia Shi4652b8c2014-11-19 17:55:38 -0800576 if (ctx.gl_fb[i])
577 glDeleteFramebuffers(1, &ctx.gl_fb[i]);
578 if (ctx.gl_rb[i])
579 glDeleteRenderbuffers(1, &ctx.gl_rb[i]);
580 if (ctx.gbm_buffer[i])
581 gbm_bo_destroy(ctx.gbm_buffer[i]);
582 }
Haixia Shie04ddfd2014-11-11 19:14:32 -0800583destroy_context:
584 eglDestroyContext(ctx.egl_display, ctx.egl_ctx);
585free_drm:
586 drmModeFreeConnector(ctx.connector);
587 drmModeFreeEncoder(ctx.encoder);
588terminate_display:
589 eglTerminate(ctx.egl_display);
Haixia Shibc4d0a02014-12-01 14:25:54 -0800590destroy_drm_gbm:
591 gbm_device_destroy(ctx.drm_gbm);
592close_drm_card:
593 close(ctx.drm_card_fd);
Haixia Shie04ddfd2014-11-11 19:14:32 -0800594fail:
595 return ret;
596}