132001f49Smrg/* 232001f49Smrg * Copyright © 2011 Kristian Høgsberg 332001f49Smrg * Copyright © 2011 Benjamin Franzke 432001f49Smrg * 532001f49Smrg * Permission to use, copy, modify, distribute, and sell this software and its 632001f49Smrg * documentation for any purpose is hereby granted without fee, provided that 732001f49Smrg * the above copyright notice appear in all copies and that both that copyright 832001f49Smrg * notice and this permission notice appear in supporting documentation, and 932001f49Smrg * that the name of the copyright holders not be used in advertising or 1032001f49Smrg * publicity pertaining to distribution of the software without specific, 1132001f49Smrg * written prior permission. The copyright holders make no representations 1232001f49Smrg * about the suitability of this software for any purpose. It is provided "as 1332001f49Smrg * is" without express or implied warranty. 1432001f49Smrg * 1532001f49Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1632001f49Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1732001f49Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1832001f49Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1932001f49Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 2032001f49Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 2132001f49Smrg * OF THIS SOFTWARE. 2232001f49Smrg */ 2332001f49Smrg 2432001f49Smrg#include <stdio.h> 2532001f49Smrg#include <stdlib.h> 2632001f49Smrg 2732001f49Smrg#define EGL_EGLEXT_PROTOTYPES 2832001f49Smrg#define GL_GLEXT_PROTOTYPES 2932001f49Smrg 3032001f49Smrg#include <gbm.h> 3132001f49Smrg#include "gl_wrap.h" 3232001f49Smrg#include <GL/glext.h> 3332001f49Smrg#include <EGL/egl.h> 3432001f49Smrg#include <EGL/eglext.h> 3532001f49Smrg#include <drm.h> 3632001f49Smrg#include <xf86drmMode.h> 3732001f49Smrg#include <fcntl.h> 3832001f49Smrg#include <unistd.h> 3932001f49Smrg#include <string.h> 4032001f49Smrg 4132001f49Smrgstruct kms { 4232001f49Smrg drmModeConnector *connector; 4332001f49Smrg drmModeEncoder *encoder; 4432001f49Smrg drmModeModeInfo mode; 4532001f49Smrg uint32_t fb_id; 4632001f49Smrg}; 4732001f49Smrg 4832001f49Smrgstatic EGLBoolean 4932001f49Smrgsetup_kms(int fd, struct kms *kms) 5032001f49Smrg{ 5132001f49Smrg drmModeRes *resources; 5232001f49Smrg drmModeConnector *connector; 5332001f49Smrg drmModeEncoder *encoder; 5432001f49Smrg int i; 5532001f49Smrg 5632001f49Smrg resources = drmModeGetResources(fd); 5732001f49Smrg if (!resources) { 5832001f49Smrg fprintf(stderr, "drmModeGetResources failed\n"); 5932001f49Smrg return EGL_FALSE; 6032001f49Smrg } 6132001f49Smrg 6232001f49Smrg for (i = 0; i < resources->count_connectors; i++) { 6332001f49Smrg connector = drmModeGetConnector(fd, resources->connectors[i]); 6432001f49Smrg if (connector == NULL) 6532001f49Smrg continue; 6632001f49Smrg 6732001f49Smrg if (connector->connection == DRM_MODE_CONNECTED && 6832001f49Smrg connector->count_modes > 0) 6932001f49Smrg break; 7032001f49Smrg 7132001f49Smrg drmModeFreeConnector(connector); 7232001f49Smrg } 7332001f49Smrg 7432001f49Smrg if (i == resources->count_connectors) { 7532001f49Smrg fprintf(stderr, "No currently active connector found.\n"); 7632001f49Smrg return EGL_FALSE; 7732001f49Smrg } 7832001f49Smrg 7932001f49Smrg for (i = 0; i < resources->count_encoders; i++) { 8032001f49Smrg encoder = drmModeGetEncoder(fd, resources->encoders[i]); 8132001f49Smrg 8232001f49Smrg if (encoder == NULL) 8332001f49Smrg continue; 8432001f49Smrg 8532001f49Smrg if (encoder->encoder_id == connector->encoder_id) 8632001f49Smrg break; 8732001f49Smrg 8832001f49Smrg drmModeFreeEncoder(encoder); 8932001f49Smrg } 9032001f49Smrg 9132001f49Smrg kms->connector = connector; 9232001f49Smrg kms->encoder = encoder; 9332001f49Smrg kms->mode = connector->modes[0]; 9432001f49Smrg 9532001f49Smrg return EGL_TRUE; 9632001f49Smrg} 9732001f49Smrg 9832001f49Smrgstatic void 9932001f49Smrgrender_stuff(int width, int height) 10032001f49Smrg{ 10132001f49Smrg GLfloat view_rotx = 0.0, view_roty = 0.0, view_rotz = 0.0; 10232001f49Smrg static const GLfloat verts[3][2] = { 10332001f49Smrg { -1, -1 }, 10432001f49Smrg { 1, -1 }, 10532001f49Smrg { 0, 1 } 10632001f49Smrg }; 10732001f49Smrg static const GLfloat colors[3][3] = { 10832001f49Smrg { 1, 0, 0 }, 10932001f49Smrg { 0, 1, 0 }, 11032001f49Smrg { 0, 0, 1 } 11132001f49Smrg }; 11232001f49Smrg GLfloat ar = (GLfloat) width / (GLfloat) height; 11332001f49Smrg 11432001f49Smrg glViewport(0, 0, (GLint) width, (GLint) height); 11532001f49Smrg 11632001f49Smrg glMatrixMode(GL_PROJECTION); 11732001f49Smrg glLoadIdentity(); 11832001f49Smrg glFrustum(-ar, ar, -1, 1, 5.0, 60.0); 11932001f49Smrg 12032001f49Smrg glMatrixMode(GL_MODELVIEW); 12132001f49Smrg glLoadIdentity(); 12232001f49Smrg glTranslatef(0.0, 0.0, -10.0); 12332001f49Smrg 12432001f49Smrg glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 12532001f49Smrg glClearColor(0.4, 0.4, 0.4, 0.0); 12632001f49Smrg 12732001f49Smrg glPushMatrix(); 12832001f49Smrg glRotatef(view_rotx, 1, 0, 0); 12932001f49Smrg glRotatef(view_roty, 0, 1, 0); 13032001f49Smrg glRotatef(view_rotz, 0, 0, 1); 13132001f49Smrg 13232001f49Smrg glVertexPointer(2, GL_FLOAT, 0, verts); 13332001f49Smrg glColorPointer(3, GL_FLOAT, 0, colors); 13432001f49Smrg glEnableClientState(GL_VERTEX_ARRAY); 13532001f49Smrg glEnableClientState(GL_COLOR_ARRAY); 13632001f49Smrg 13732001f49Smrg glDrawArrays(GL_TRIANGLES, 0, 3); 13832001f49Smrg 13932001f49Smrg glDisableClientState(GL_VERTEX_ARRAY); 14032001f49Smrg glDisableClientState(GL_COLOR_ARRAY); 14132001f49Smrg 14232001f49Smrg glPopMatrix(); 14332001f49Smrg 14432001f49Smrg glFinish(); 14532001f49Smrg} 14632001f49Smrg 14732001f49Smrgstatic const char device_name[] = "/dev/dri/card0"; 14832001f49Smrg 14932001f49Smrgstatic const EGLint attribs[] = { 15032001f49Smrg EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 15132001f49Smrg EGL_RED_SIZE, 1, 15232001f49Smrg EGL_GREEN_SIZE, 1, 15332001f49Smrg EGL_BLUE_SIZE, 1, 15432001f49Smrg EGL_ALPHA_SIZE, 0, 15532001f49Smrg EGL_DEPTH_SIZE, 1, 15632001f49Smrg EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, 15732001f49Smrg EGL_NONE 15832001f49Smrg}; 15932001f49Smrg 16032001f49Smrgint main(int argc, char *argv[]) 16132001f49Smrg{ 16232001f49Smrg EGLDisplay dpy; 16332001f49Smrg EGLContext ctx; 16432001f49Smrg EGLSurface surface; 16532001f49Smrg EGLConfig config; 16632001f49Smrg EGLint major, minor, n; 16732001f49Smrg const char *ver; 16832001f49Smrg uint32_t handle, stride; 16932001f49Smrg struct kms kms; 17032001f49Smrg int ret, fd; 17132001f49Smrg struct gbm_device *gbm; 17232001f49Smrg struct gbm_bo *bo; 17332001f49Smrg drmModeCrtcPtr saved_crtc; 17432001f49Smrg struct gbm_surface *gs; 17532001f49Smrg 17632001f49Smrg fd = open(device_name, O_RDWR); 17732001f49Smrg if (fd < 0) { 17832001f49Smrg /* Probably permissions error */ 17932001f49Smrg fprintf(stderr, "couldn't open %s, skipping\n", device_name); 18032001f49Smrg return -1; 18132001f49Smrg } 18232001f49Smrg 18332001f49Smrg gbm = gbm_create_device(fd); 18432001f49Smrg if (gbm == NULL) { 18532001f49Smrg fprintf(stderr, "couldn't create gbm device\n"); 18632001f49Smrg ret = -1; 18732001f49Smrg goto close_fd; 18832001f49Smrg } 18932001f49Smrg 19032001f49Smrg dpy = eglGetDisplay(gbm); 19132001f49Smrg if (dpy == EGL_NO_DISPLAY) { 19232001f49Smrg fprintf(stderr, "eglGetDisplay() failed\n"); 19332001f49Smrg ret = -1; 19432001f49Smrg goto destroy_gbm_device; 19532001f49Smrg } 19632001f49Smrg 19732001f49Smrg if (!eglInitialize(dpy, &major, &minor)) { 19832001f49Smrg printf("eglInitialize() failed\n"); 19932001f49Smrg ret = -1; 20032001f49Smrg goto egl_terminate; 20132001f49Smrg } 20232001f49Smrg 20332001f49Smrg ver = eglQueryString(dpy, EGL_VERSION); 20432001f49Smrg printf("EGL_VERSION = %s\n", ver); 20532001f49Smrg 20632001f49Smrg if (!setup_kms(fd, &kms)) { 20732001f49Smrg ret = -1; 20832001f49Smrg goto egl_terminate; 20932001f49Smrg } 21032001f49Smrg 21132001f49Smrg eglBindAPI(EGL_OPENGL_API); 21232001f49Smrg 21332001f49Smrg if (!eglChooseConfig(dpy, attribs, &config, 1, &n) || n != 1) { 21432001f49Smrg fprintf(stderr, "failed to choose argb config\n"); 21532001f49Smrg goto egl_terminate; 21632001f49Smrg } 21732001f49Smrg 21832001f49Smrg ctx = eglCreateContext(dpy, config, EGL_NO_CONTEXT, NULL); 21932001f49Smrg if (ctx == NULL) { 22032001f49Smrg fprintf(stderr, "failed to create context\n"); 22132001f49Smrg ret = -1; 22232001f49Smrg goto egl_terminate; 22332001f49Smrg } 22432001f49Smrg 22532001f49Smrg gs = gbm_surface_create(gbm, kms.mode.hdisplay, kms.mode.vdisplay, 22632001f49Smrg GBM_BO_FORMAT_XRGB8888, 22732001f49Smrg GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); 22832001f49Smrg surface = eglCreateWindowSurface(dpy, config, gs, NULL); 22932001f49Smrg 23032001f49Smrg if (!eglMakeCurrent(dpy, surface, surface, ctx)) { 23132001f49Smrg fprintf(stderr, "failed to make context current\n"); 23232001f49Smrg ret = -1; 23332001f49Smrg goto destroy_context; 23432001f49Smrg } 23532001f49Smrg 23632001f49Smrg render_stuff(kms.mode.hdisplay, kms.mode.vdisplay); 23732001f49Smrg 23832001f49Smrg eglSwapBuffers(dpy, surface); 23932001f49Smrg 24032001f49Smrg bo = gbm_surface_lock_front_buffer(gs); 24132001f49Smrg handle = gbm_bo_get_handle(bo).u32; 24232001f49Smrg stride = gbm_bo_get_stride(bo); 24332001f49Smrg 24432001f49Smrg printf("handle=%d, stride=%d\n", handle, stride); 24532001f49Smrg 24632001f49Smrg ret = drmModeAddFB(fd, 24732001f49Smrg kms.mode.hdisplay, kms.mode.vdisplay, 24832001f49Smrg 24, 32, stride, handle, &kms.fb_id); 24932001f49Smrg if (ret) { 25032001f49Smrg fprintf(stderr, "failed to create fb\n"); 25132001f49Smrg goto rm_fb; 25232001f49Smrg } 25332001f49Smrg 25432001f49Smrg saved_crtc = drmModeGetCrtc(fd, kms.encoder->crtc_id); 25532001f49Smrg if (saved_crtc == NULL) 25632001f49Smrg goto rm_fb; 25732001f49Smrg 25832001f49Smrg ret = drmModeSetCrtc(fd, kms.encoder->crtc_id, kms.fb_id, 0, 0, 25932001f49Smrg &kms.connector->connector_id, 1, &kms.mode); 26032001f49Smrg if (ret) { 26132001f49Smrg fprintf(stderr, "failed to set mode: %m\n"); 26232001f49Smrg goto free_saved_crtc; 26332001f49Smrg } 26432001f49Smrg 26532001f49Smrg getchar(); 26632001f49Smrg 26732001f49Smrg ret = drmModeSetCrtc(fd, saved_crtc->crtc_id, saved_crtc->buffer_id, 26832001f49Smrg saved_crtc->x, saved_crtc->y, 26932001f49Smrg &kms.connector->connector_id, 1, &saved_crtc->mode); 27032001f49Smrg if (ret) { 27132001f49Smrg fprintf(stderr, "failed to restore crtc: %m\n"); 27232001f49Smrg } 27332001f49Smrg 27432001f49Smrgfree_saved_crtc: 27532001f49Smrg drmModeFreeCrtc(saved_crtc); 27632001f49Smrgrm_fb: 27732001f49Smrg drmModeRmFB(fd, kms.fb_id); 27832001f49Smrg eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 27932001f49Smrgdestroy_context: 28032001f49Smrg eglDestroyContext(dpy, ctx); 28132001f49Smrgegl_terminate: 28232001f49Smrg eglTerminate(dpy); 28332001f49Smrgdestroy_gbm_device: 28432001f49Smrg gbm_device_destroy(gbm); 28532001f49Smrgclose_fd: 28632001f49Smrg close(fd); 28732001f49Smrg 28832001f49Smrg return ret; 28932001f49Smrg} 290