]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - graphics/gfx-apps.git/commitdiff
egl-multi-thread: Add example application for multi-threaded EGL master
authorSubhajit Paul <subhajit_paul@ti.com>
Tue, 10 Apr 2018 15:54:09 +0000 (21:24 +0530)
committerAnand Balagopalakrishnan <anandb@ti.com>
Tue, 10 Apr 2018 15:54:09 +0000 (21:24 +0530)
Multi-threaded EGL is always a very tricky operation. This application shows
how to use GBM EGL or Wayland EGL for correct multi-threaded operation on TI
DRA7xx SoC.

Signed-off-by: Subhajit Paul <subhajit_paul@ti.com>
Signed-off-by: Anand Balagopalakrishnan <anandb@ti.com>
13 files changed:
egl-multi-thread/Makefile [new file with mode: 0644]
egl-multi-thread/README [new file with mode: 0644]
egl-multi-thread/drm_gbm.c [new file with mode: 0644]
egl-multi-thread/drm_gbm.h [new file with mode: 0644]
egl-multi-thread/esTransform.c [new file with mode: 0644]
egl-multi-thread/esUtil.h [new file with mode: 0644]
egl-multi-thread/gl_kmscube.c [new file with mode: 0644]
egl-multi-thread/gl_kmscube.h [new file with mode: 0644]
egl-multi-thread/main.c [new file with mode: 0644]
egl-multi-thread/render_thread.c [new file with mode: 0644]
egl-multi-thread/render_thread.h [new file with mode: 0644]
egl-multi-thread/wayland-window.c [new file with mode: 0644]
egl-multi-thread/wayland_window.h [new file with mode: 0644]

diff --git a/egl-multi-thread/Makefile b/egl-multi-thread/Makefile
new file mode 100644 (file)
index 0000000..5d76a15
--- /dev/null
@@ -0,0 +1,46 @@
+# Makefile
+
+# Set the cross compiler and target file system path
+CROSS_COMPILE=arm-linux-gnueabihf-
+
+## No need to change below this
+
+COMMON_INCLUDES = -I$(FSDIR)/usr/include
+COMMON_LFLAGS = -L$(FSDIR)/usr/lib -Wl,--rpath-link,$(FSDIR)/usr/lib
+
+PLAT_CPP = $(CROSS_COMPILE)gcc
+
+PLAT_CFLAGS   = $(COMMON_INCLUDES) -g
+PLAT_LINK =  $(COMMON_LFLAGS) -lEGL -lGLESv2 -ludev -lpthread -lm -lrt
+
+SRCNAME = esTransform.c \
+       gl_kmscube.c \
+       main.c \
+       render_thread.c \
+
+BASE_OUTNAME = egl_multi_layer
+
+ifeq ($(BUILD_WAYLAND), yes)
+SRCNAME += wayland-window.c \
+
+PLAT_CFLAGS += -DUSE_WAYLAND
+PLAT_LINK += -lwayland-client -lpvr_wlegl
+OUTNAME = $(BASE_OUTNAME)_wayland
+else
+SRCNAME += drm_gbm.c \
+
+PLAT_CFLAGS += -I$(FSDIR)/usr/include/libdrm -I$(FSDIR)/usr/include/gbm
+PLAT_LINK += -lgbm -ldrm
+OUTNAME = $(BASE_OUTNAME)_drm
+endif
+
+OBJECTS = $(SRCNAME:.c=.o)
+
+$(OUTNAME): $(SRCNAME)
+       $(PLAT_CPP) -o $@ $^ $(PLAT_CFLAGS) $(LINK) $(PLAT_LINK)
+
+install:
+       cp $(OUTNAME) $(FSDIR)/home/root
+
+clean:
+       rm $(OUTNAME)
diff --git a/egl-multi-thread/README b/egl-multi-thread/README
new file mode 100644 (file)
index 0000000..df1901c
--- /dev/null
@@ -0,0 +1,18 @@
+**************
+Build Instructions
+**************
+
+# Mount target file system on host
+# Set FSDIR to the target file system in Makefile
+
+# Include 4.9 cross compiler in the PATH
+export PATH=<4.9_CROSS_COMPILER>/bin:$PATH
+export FSDIR=<TARGETFS_PATH>
+
+#if the application is to be a wayland-client, then export the following as well
+#export BUILD_WAYLAND=yes
+
+make
+sudo -E make install
+
+# egl_multi_layer_{wayland/drm} will be installed to /home/root on target fs
diff --git a/egl-multi-thread/drm_gbm.c b/egl-multi-thread/drm_gbm.c
new file mode 100644 (file)
index 0000000..fc238da
--- /dev/null
@@ -0,0 +1,315 @@
+#include <stdio.h>
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include <libdrm/drm.h>
+#include <libdrm/drm_mode.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <gbm/gbm.h>
+
+#include "drm_gbm.h"
+
+struct drm_data {
+       int fd;
+       int conn_id;
+       int crtc_id;
+       int width;
+       int height;
+
+       int count_planes;
+       struct plane_data *pdata;
+       int primary_planes;
+       int nonprimary_planes;
+
+       struct gbm_device *gbm_dev;
+};
+
+struct drm_fb {
+       struct gbm_bo *bo;
+       uint32_t fb_id;
+       int dmabuf_fd;
+       int fd;
+};
+
+static void
+drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
+{
+       struct drm_fb *fb = data;
+       struct gbm_device *gbm = gbm_bo_get_device(bo);
+
+       if (fb->fb_id)
+               drmModeRmFB(fb->fd, fb->fb_id);
+
+       free(fb);
+}
+
+static struct drm_fb * drm_fb_get_from_bo(int fd, struct gbm_bo *bo)
+{
+       struct drm_fb *fb = gbm_bo_get_user_data(bo);
+       uint32_t width, height, stride, handle;
+       int ret;
+
+       if (fb)
+               return fb;
+
+       fb = calloc(1, sizeof *fb);
+       fb->bo = bo;
+       fb->fd = fd;
+
+       width = gbm_bo_get_width(bo);
+       height = gbm_bo_get_height(bo);
+       stride = gbm_bo_get_stride(bo);
+       handle = gbm_bo_get_handle(bo).u32;
+
+       ret = drmModeAddFB(fd, width, height, 32, 32, stride, handle, &fb->fb_id);
+       if (ret) {
+               free(fb);
+               return NULL;
+       }
+
+       fb->dmabuf_fd = gbm_bo_get_fd(bo);
+
+       gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
+
+       return fb;
+}
+
+static void page_flip_handler(int fd, unsigned int frame,
+                             unsigned int sec, unsigned int usec,
+                             void *data)
+{
+       int *flips = data;
+       *flips= *flips - 1;
+}
+
+
+struct drm_data *init_drm_gbm (int conn_id) {
+       int ret;
+       int count;
+       struct drm_set_client_cap req;
+
+       struct drm_data *drm = calloc(sizeof(struct drm_data), 1);
+       if(!drm) {
+               printf("drm data alloc failed\n");
+               return NULL;
+       }
+
+       int fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
+       drm->fd = fd;
+       if(fd < 0) {
+               printf("drm open failed\n");
+               return NULL;
+       }
+
+       ret = drmSetMaster(fd); 
+       if(ret < 0) {
+               printf("drm set master failed\n");
+               return NULL;
+       }
+
+       req.capability = DRM_CLIENT_CAP_ATOMIC;
+       req.value = 1;
+       ret = ioctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &req);
+       if(ret < 0) {
+               printf("drm set atomic cap failed\n");
+               return NULL;
+       }
+
+       int conn_found = 0;
+       drm->conn_id = conn_id;
+       drmModeResPtr res = drmModeGetResources(fd);
+       for(count = 0; count < res->count_connectors; count++) {
+               if(res->connectors[count]== drm->conn_id) {
+                       drmModeConnectorPtr connector = drmModeGetConnector(fd, drm->conn_id);
+                       drmModeEncoderPtr encoder = drmModeGetEncoder(fd, connector->encoder_id);
+                       drm->crtc_id = encoder->crtc_id;
+                       drmModeCrtcPtr crtc = drmModeGetCrtc(fd, encoder->crtc_id);
+                       drm->width = crtc->width;
+                       drm->height = crtc->height;
+                       conn_found = 1;
+                       break;
+               }
+       }
+       if(!conn_found) {
+               printf("drm connector %d not found\n", drm->conn_id);
+               return NULL;
+       }
+
+       drm->gbm_dev = gbm_create_device(fd);
+
+       drmModePlaneResPtr planes = drmModeGetPlaneResources(fd);
+       drm->count_planes = planes->count_planes;
+       drm->pdata = calloc(sizeof(struct plane_data), planes->count_planes);
+       for(count = 0; count < planes->count_planes; count++) {
+               drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(fd, planes->planes[count], DRM_MODE_OBJECT_PLANE);
+               int propc;
+               for(propc = 0; propc < props->count_props; propc++) {
+                       drmModePropertyPtr prop = drmModeGetProperty(fd, props->props[propc]);
+                       if(strcmp(prop->name, "type") == 0) {
+                               unsigned long long prop_value = props->prop_values[propc];
+                               if(prop_value) {
+                                       drm->pdata[count].primary = 1;
+                                       drm->primary_planes++;
+                               } else {
+                                       drm->pdata[count].primary = 0;
+                                       drm->nonprimary_planes++;
+                               }
+                       }
+                       if(strcmp(prop->name, "zorder") == 0) {
+                               if(drm->pdata[count].primary) {
+                                       drm->pdata[count].zorder = drm->primary_planes -1 ;
+                               } else {
+                                       drm->pdata[count].zorder = 4 - drm->nonprimary_planes;
+                               }
+                               drmModeObjectSetProperty(fd, planes->planes[count],
+                                               DRM_MODE_OBJECT_PLANE,
+                                               props->props[propc], drm->pdata[count].zorder);
+                       }
+                       if(strcmp(prop->name, "FB_ID") == 0)
+                               drm->pdata[count].fb_id_property = props->props[propc];
+               }
+               drm->pdata[count].plane = planes->planes[count];
+               drm->pdata[count].occupied = 0;
+               drm->pdata[count].gbm_dev = drm->gbm_dev;
+               
+       }
+
+       return drm;
+
+}
+
+struct plane_data *get_new_surface(struct drm_data *drm, int posx, int posy, int width, int height)
+{
+       int count;
+
+       if(posx < 0 || posx + width > drm->width || posy < 0 || posy + height > drm->height) {
+               printf("surface dimensions exceed crtc dimensions\n");
+               return NULL;
+       }
+
+       for(count = 0; count < drm->count_planes; count++) {
+               if(drm->pdata[count].primary)
+                       continue;
+               if(drm->pdata[count].occupied)
+                       continue;
+               break;
+       }
+
+       if(count == drm->count_planes) {
+               printf("no more planes\n");
+               return NULL;
+       }
+
+       drm->pdata[count].gbm_surf = gbm_surface_create(drm->gbm_dev,
+                       width, height,
+                       GBM_FORMAT_XRGB8888,
+                       GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+       drm->pdata[count].posx = posx;
+       drm->pdata[count].posy = posy;
+       drm->pdata[count].width = width;
+       drm->pdata[count].height = height;
+       drm->pdata[count].occupied = 1;
+
+       return &drm->pdata[count];
+}
+
+int update_all_surfaces(struct drm_data *drm)
+{
+       int count;
+       int ret;
+       static int firsttime = 1;
+       static int flip_pending = 0;
+
+       if(firsttime) {
+               firsttime = 0;
+               for(count = 0; count < drm->count_planes; count++) {    
+                       struct plane_data *pdata = &drm->pdata[count];
+                       if(drm->pdata[count].occupied == 0)
+                               continue;
+                       struct gbm_surface *surf = drm->pdata[count].gbm_surf;
+                       struct gbm_bo *bo = gbm_surface_lock_front_buffer(surf);
+                       struct drm_fb *fb = drm_fb_get_from_bo(drm->fd, bo);
+
+                       ret = drmModeSetPlane(drm->fd,
+                                       drm->pdata[count].plane,
+                                       drm->crtc_id,
+                                       fb->fb_id,
+                                       0,
+                                       drm->pdata[count].posx,
+                                       drm->pdata[count].posy,
+                                       drm->pdata[count].width,
+                                       drm->pdata[count].height,
+                                       0,
+                                       0,
+                                       drm->pdata[count].width << 16,
+                                       drm->pdata[count].height << 16);
+               }
+
+       }
+
+       drmModeAtomicReqPtr m_req = drmModeAtomicAlloc();
+
+       for(count = 0; count < drm->count_planes; count++) {    
+               struct plane_data *pdata = &drm->pdata[count];
+               if(drm->pdata[count].occupied == 0)
+                       continue;
+               struct gbm_surface *surf = drm->pdata[count].gbm_surf;
+               struct gbm_bo *bo = gbm_surface_lock_front_buffer(surf);
+               struct drm_fb *fb = drm_fb_get_from_bo(drm->fd, bo);
+
+               drmModeAtomicAddProperty(m_req,
+                               drm->pdata[count].plane,
+                               drm->pdata[count].fb_id_property,
+                               fb->fb_id);
+
+               drm->pdata[count].current_bo = bo;
+       }
+
+
+       flip_pending++;
+       ret = drmModeAtomicCommit(drm->fd, m_req, DRM_MODE_ATOMIC_TEST_ONLY, 0);
+       ret = drmModeAtomicCommit(drm->fd, m_req, DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK, &flip_pending);
+
+       drmModeAtomicFree(m_req);
+
+       while (flip_pending) {
+               fd_set fds;
+               FD_ZERO(&fds);
+               FD_SET(drm->fd, &fds);
+
+               ret = select(drm->fd + 1, &fds, NULL, NULL, NULL);
+
+               if(ret <= 0) {
+                       printf("failing %d\n", ret);
+                       return 0;
+               }
+
+               if (FD_ISSET(drm->fd, &fds)) {
+                       drmEventContext ev = {
+                               .version = DRM_EVENT_CONTEXT_VERSION,
+                               .vblank_handler = 0,
+                               .page_flip_handler = page_flip_handler,
+                       };
+
+                       drmHandleEvent(drm->fd, &ev);
+               }
+       }
+
+       for(count = 0; count < drm->count_planes; count++) {    
+               struct plane_data *pdata = &drm->pdata[count];
+               if(drm->pdata[count].occupied == 0)
+                       continue;
+               struct gbm_surface *surf = drm->pdata[count].gbm_surf;
+               struct gbm_bo *bo = drm->pdata[count].current_bo;       
+               gbm_surface_release_buffer(surf, bo);
+               drm->pdata[count].current_bo = NULL;
+               
+       }
+
+       return 0;
+
+}
diff --git a/egl-multi-thread/drm_gbm.h b/egl-multi-thread/drm_gbm.h
new file mode 100644 (file)
index 0000000..4ab9f03
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __DRM_GBM_H__
+#define __DRM_GBM_H__
+
+#include <gbm/gbm.h>
+
+struct plane_data {
+       int plane;
+       int fb_id_property;
+       int zorder;
+       int primary;
+
+       struct gbm_device *gbm_dev;
+       struct gbm_surface *gbm_surf;
+
+       struct gbm_bo *current_bo;
+
+       int width;
+       int height;
+       int posx;
+       int posy;
+
+       int occupied;
+};
+
+struct drm_data;
+
+struct drm_data *init_drm_gbm (int conn_id);
+struct plane_data *get_new_surface(struct drm_data *drm, int posx, int posy, int width, int height);
+int update_all_surfaces(struct drm_data *drm);
+
+#endif /*__DRM_GBM_H__*/
diff --git a/egl-multi-thread/esTransform.c b/egl-multi-thread/esTransform.c
new file mode 100644 (file)
index 0000000..5fff0c9
--- /dev/null
@@ -0,0 +1,235 @@
+//
+// Book:      OpenGL(R) ES 2.0 Programming Guide
+// Authors:   Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10:   0321502795
+// ISBN-13:   9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs:      http://safari.informit.com/9780321563835
+//            http://www.opengles-book.com
+//
+
+/*
+ * (c) 2009 Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+// ESUtil.c
+//
+//    A utility library for OpenGL ES.  This library provides a
+//    basic common framework for the example applications in the
+//    OpenGL ES 2.0 Programming Guide.
+//
+
+///
+//  Includes
+//
+#include "esUtil.h"
+#include <math.h>
+#include <string.h>
+
+#define PI 3.1415926535897932384626433832795f
+
+void ESUTIL_API
+esScale(ESMatrix *result, GLfloat sx, GLfloat sy, GLfloat sz)
+{
+    result->m[0][0] *= sx;
+    result->m[0][1] *= sx;
+    result->m[0][2] *= sx;
+    result->m[0][3] *= sx;
+
+    result->m[1][0] *= sy;
+    result->m[1][1] *= sy;
+    result->m[1][2] *= sy;
+    result->m[1][3] *= sy;
+
+    result->m[2][0] *= sz;
+    result->m[2][1] *= sz;
+    result->m[2][2] *= sz;
+    result->m[2][3] *= sz;
+}
+
+void ESUTIL_API
+esTranslate(ESMatrix *result, GLfloat tx, GLfloat ty, GLfloat tz)
+{
+    result->m[3][0] += (result->m[0][0] * tx + result->m[1][0] * ty + result->m[2][0] * tz);
+    result->m[3][1] += (result->m[0][1] * tx + result->m[1][1] * ty + result->m[2][1] * tz);
+    result->m[3][2] += (result->m[0][2] * tx + result->m[1][2] * ty + result->m[2][2] * tz);
+    result->m[3][3] += (result->m[0][3] * tx + result->m[1][3] * ty + result->m[2][3] * tz);
+}
+
+void ESUTIL_API
+esRotate(ESMatrix *result, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
+{
+   GLfloat sinAngle, cosAngle;
+   GLfloat mag = sqrtf(x * x + y * y + z * z);
+      
+   sinAngle = sinf ( angle * PI / 180.0f );
+   cosAngle = cosf ( angle * PI / 180.0f );
+   if ( mag > 0.0f )
+   {
+      GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs;
+      GLfloat oneMinusCos;
+      ESMatrix rotMat;
+   
+      x /= mag;
+      y /= mag;
+      z /= mag;
+
+      xx = x * x;
+      yy = y * y;
+      zz = z * z;
+      xy = x * y;
+      yz = y * z;
+      zx = z * x;
+      xs = x * sinAngle;
+      ys = y * sinAngle;
+      zs = z * sinAngle;
+      oneMinusCos = 1.0f - cosAngle;
+
+      rotMat.m[0][0] = (oneMinusCos * xx) + cosAngle;
+      rotMat.m[0][1] = (oneMinusCos * xy) - zs;
+      rotMat.m[0][2] = (oneMinusCos * zx) + ys;
+      rotMat.m[0][3] = 0.0F; 
+
+      rotMat.m[1][0] = (oneMinusCos * xy) + zs;
+      rotMat.m[1][1] = (oneMinusCos * yy) + cosAngle;
+      rotMat.m[1][2] = (oneMinusCos * yz) - xs;
+      rotMat.m[1][3] = 0.0F;
+
+      rotMat.m[2][0] = (oneMinusCos * zx) - ys;
+      rotMat.m[2][1] = (oneMinusCos * yz) + xs;
+      rotMat.m[2][2] = (oneMinusCos * zz) + cosAngle;
+      rotMat.m[2][3] = 0.0F; 
+
+      rotMat.m[3][0] = 0.0F;
+      rotMat.m[3][1] = 0.0F;
+      rotMat.m[3][2] = 0.0F;
+      rotMat.m[3][3] = 1.0F;
+
+      esMatrixMultiply( result, &rotMat, result );
+   }
+}
+
+void ESUTIL_API
+esFrustum(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ)
+{
+    float       deltaX = right - left;
+    float       deltaY = top - bottom;
+    float       deltaZ = farZ - nearZ;
+    ESMatrix    frust;
+
+    if ( (nearZ <= 0.0f) || (farZ <= 0.0f) ||
+         (deltaX <= 0.0f) || (deltaY <= 0.0f) || (deltaZ <= 0.0f) )
+         return;
+
+    frust.m[0][0] = 2.0f * nearZ / deltaX;
+    frust.m[0][1] = frust.m[0][2] = frust.m[0][3] = 0.0f;
+
+    frust.m[1][1] = 2.0f * nearZ / deltaY;
+    frust.m[1][0] = frust.m[1][2] = frust.m[1][3] = 0.0f;
+
+    frust.m[2][0] = (right + left) / deltaX;
+    frust.m[2][1] = (top + bottom) / deltaY;
+    frust.m[2][2] = -(nearZ + farZ) / deltaZ;
+    frust.m[2][3] = -1.0f;
+
+    frust.m[3][2] = -2.0f * nearZ * farZ / deltaZ;
+    frust.m[3][0] = frust.m[3][1] = frust.m[3][3] = 0.0f;
+
+    esMatrixMultiply(result, &frust, result);
+}
+
+
+void ESUTIL_API 
+esPerspective(ESMatrix *result, float fovy, float aspect, float nearZ, float farZ)
+{
+   GLfloat frustumW, frustumH;
+   
+   frustumH = tanf( fovy / 360.0f * PI ) * nearZ;
+   frustumW = frustumH * aspect;
+
+   esFrustum( result, -frustumW, frustumW, -frustumH, frustumH, nearZ, farZ );
+}
+
+void ESUTIL_API
+esOrtho(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ)
+{
+    float       deltaX = right - left;
+    float       deltaY = top - bottom;
+    float       deltaZ = farZ - nearZ;
+    ESMatrix    ortho;
+
+    if ( (deltaX == 0.0f) || (deltaY == 0.0f) || (deltaZ == 0.0f) )
+        return;
+
+    esMatrixLoadIdentity(&ortho);
+    ortho.m[0][0] = 2.0f / deltaX;
+    ortho.m[3][0] = -(right + left) / deltaX;
+    ortho.m[1][1] = 2.0f / deltaY;
+    ortho.m[3][1] = -(top + bottom) / deltaY;
+    ortho.m[2][2] = -2.0f / deltaZ;
+    ortho.m[3][2] = -(nearZ + farZ) / deltaZ;
+
+    esMatrixMultiply(result, &ortho, result);
+}
+
+
+void ESUTIL_API
+esMatrixMultiply(ESMatrix *result, ESMatrix *srcA, ESMatrix *srcB)
+{
+    ESMatrix    tmp;
+    int         i;
+
+       for (i=0; i<4; i++)
+       {
+               tmp.m[i][0] =   (srcA->m[i][0] * srcB->m[0][0]) +
+                                               (srcA->m[i][1] * srcB->m[1][0]) +
+                                               (srcA->m[i][2] * srcB->m[2][0]) +
+                                               (srcA->m[i][3] * srcB->m[3][0]) ;
+
+               tmp.m[i][1] =   (srcA->m[i][0] * srcB->m[0][1]) + 
+                                               (srcA->m[i][1] * srcB->m[1][1]) +
+                                               (srcA->m[i][2] * srcB->m[2][1]) +
+                                               (srcA->m[i][3] * srcB->m[3][1]) ;
+
+               tmp.m[i][2] =   (srcA->m[i][0] * srcB->m[0][2]) + 
+                                               (srcA->m[i][1] * srcB->m[1][2]) +
+                                               (srcA->m[i][2] * srcB->m[2][2]) +
+                                               (srcA->m[i][3] * srcB->m[3][2]) ;
+
+               tmp.m[i][3] =   (srcA->m[i][0] * srcB->m[0][3]) + 
+                                               (srcA->m[i][1] * srcB->m[1][3]) +
+                                               (srcA->m[i][2] * srcB->m[2][3]) +
+                                               (srcA->m[i][3] * srcB->m[3][3]) ;
+       }
+    memcpy(result, &tmp, sizeof(ESMatrix));
+}
+
+
+void ESUTIL_API
+esMatrixLoadIdentity(ESMatrix *result)
+{
+    memset(result, 0x0, sizeof(ESMatrix));
+    result->m[0][0] = 1.0f;
+    result->m[1][1] = 1.0f;
+    result->m[2][2] = 1.0f;
+    result->m[3][3] = 1.0f;
+}
+
diff --git a/egl-multi-thread/esUtil.h b/egl-multi-thread/esUtil.h
new file mode 100644 (file)
index 0000000..c2d7c1d
--- /dev/null
@@ -0,0 +1,303 @@
+//
+// Book:      OpenGL(R) ES 2.0 Programming Guide
+// Authors:   Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10:   0321502795
+// ISBN-13:   9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs:      http://safari.informit.com/9780321563835
+//            http://www.opengles-book.com
+//
+
+/*
+ * (c) 2009 Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+//
+/// \file ESUtil.h
+/// \brief A utility library for OpenGL ES.  This library provides a
+///        basic common framework for the example applications in the
+///        OpenGL ES 2.0 Programming Guide.
+//
+#ifndef ESUTIL_H
+#define ESUTIL_H
+
+///
+//  Includes
+//
+#include <GLES2/gl2.h>
+#include <EGL/egl.h>
+
+#ifdef __cplusplus
+
+extern "C" {
+#endif
+
+   
+///
+//  Macros
+//
+#define ESUTIL_API
+#define ESCALLBACK
+
+
+/// esCreateWindow flag - RGB color buffer
+#define ES_WINDOW_RGB           0
+/// esCreateWindow flag - ALPHA color buffer
+#define ES_WINDOW_ALPHA         1 
+/// esCreateWindow flag - depth buffer
+#define ES_WINDOW_DEPTH         2 
+/// esCreateWindow flag - stencil buffer
+#define ES_WINDOW_STENCIL       4
+/// esCreateWindow flat - multi-sample buffer
+#define ES_WINDOW_MULTISAMPLE   8
+
+
+///
+// Types
+//
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+typedef struct
+{
+    GLfloat   m[4][4];
+} ESMatrix;
+
+typedef struct _escontext
+{
+   /// Put your user data here...
+   void*       userData;
+
+   /// Window width
+   GLint       width;
+
+   /// Window height
+   GLint       height;
+
+   /// Window handle
+   EGLNativeWindowType  hWnd;
+
+   /// EGL display
+   EGLDisplay  eglDisplay;
+      
+   /// EGL context
+   EGLContext  eglContext;
+
+   /// EGL surface
+   EGLSurface  eglSurface;
+
+   /// Callbacks
+   void (ESCALLBACK *drawFunc) ( struct _escontext * );
+   void (ESCALLBACK *keyFunc) ( struct _escontext *, unsigned char, int, int );
+   void (ESCALLBACK *updateFunc) ( struct _escontext *, float deltaTime );
+} ESContext;
+
+
+///
+//  Public Functions
+//
+
+//
+///
+/// \brief Initialize ES framework context.  This must be called before calling any other functions.
+/// \param esContext Application context
+//
+void ESUTIL_API esInitContext ( ESContext *esContext );
+
+//
+/// \brief Create a window with the specified parameters
+/// \param esContext Application context
+/// \param title Name for title bar of window
+/// \param width Width in pixels of window to create
+/// \param height Height in pixels of window to create
+/// \param flags Bitfield for the window creation flags 
+///         ES_WINDOW_RGB     - specifies that the color buffer should have R,G,B channels
+///         ES_WINDOW_ALPHA   - specifies that the color buffer should have alpha
+///         ES_WINDOW_DEPTH   - specifies that a depth buffer should be created
+///         ES_WINDOW_STENCIL - specifies that a stencil buffer should be created
+///         ES_WINDOW_MULTISAMPLE - specifies that a multi-sample buffer should be created
+/// \return GL_TRUE if window creation is succesful, GL_FALSE otherwise
+GLboolean ESUTIL_API esCreateWindow ( ESContext *esContext, const char *title, GLint width, GLint height, GLuint flags );
+
+//
+/// \brief Start the main loop for the OpenGL ES application
+/// \param esContext Application context
+//
+void ESUTIL_API esMainLoop ( ESContext *esContext );
+
+//
+/// \brief Register a draw callback function to be used to render each frame
+/// \param esContext Application context
+/// \param drawFunc Draw callback function that will be used to render the scene
+//
+void ESUTIL_API esRegisterDrawFunc ( ESContext *esContext, void (ESCALLBACK *drawFunc) ( ESContext* ) );
+
+//
+/// \brief Register an update callback function to be used to update on each time step
+/// \param esContext Application context
+/// \param updateFunc Update callback function that will be used to render the scene
+//
+void ESUTIL_API esRegisterUpdateFunc ( ESContext *esContext, void (ESCALLBACK *updateFunc) ( ESContext*, float ) );
+
+//
+/// \brief Register an keyboard input processing callback function
+/// \param esContext Application context
+/// \param keyFunc Key callback function for application processing of keyboard input
+//
+void ESUTIL_API esRegisterKeyFunc ( ESContext *esContext, 
+                                    void (ESCALLBACK *drawFunc) ( ESContext*, unsigned char, int, int ) );
+//
+/// \brief Log a message to the debug output for the platform
+/// \param formatStr Format string for error log.  
+//
+void ESUTIL_API esLogMessage ( const char *formatStr, ... );
+
+//
+///
+/// \brief Load a shader, check for compile errors, print error messages to output log
+/// \param type Type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER)
+/// \param shaderSrc Shader source string
+/// \return A new shader object on success, 0 on failure
+//
+GLuint ESUTIL_API esLoadShader ( GLenum type, const char *shaderSrc );
+
+//
+///
+/// \brief Load a vertex and fragment shader, create a program object, link program.
+///        Errors output to log.
+/// \param vertShaderSrc Vertex shader source code
+/// \param fragShaderSrc Fragment shader source code
+/// \return A new program object linked with the vertex/fragment shader pair, 0 on failure
+//
+GLuint ESUTIL_API esLoadProgram ( const char *vertShaderSrc, const char *fragShaderSrc );
+
+
+//
+/// \brief Generates geometry for a sphere.  Allocates memory for the vertex data and stores 
+///        the results in the arrays.  Generate index list for a TRIANGLE_STRIP
+/// \param numSlices The number of slices in the sphere
+/// \param vertices If not NULL, will contain array of float3 positions
+/// \param normals If not NULL, will contain array of float3 normals
+/// \param texCoords If not NULL, will contain array of float2 texCoords
+/// \param indices If not NULL, will contain the array of indices for the triangle strip
+/// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array
+///         if it is not NULL ) as a GL_TRIANGLE_STRIP
+//
+int ESUTIL_API esGenSphere ( int numSlices, float radius, GLfloat **vertices, GLfloat **normals, 
+                             GLfloat **texCoords, GLuint **indices );
+
+//
+/// \brief Generates geometry for a cube.  Allocates memory for the vertex data and stores 
+///        the results in the arrays.  Generate index list for a TRIANGLES
+/// \param scale The size of the cube, use 1.0 for a unit cube.
+/// \param vertices If not NULL, will contain array of float3 positions
+/// \param normals If not NULL, will contain array of float3 normals
+/// \param texCoords If not NULL, will contain array of float2 texCoords
+/// \param indices If not NULL, will contain the array of indices for the triangle strip
+/// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array
+///         if it is not NULL ) as a GL_TRIANGLES
+//
+int ESUTIL_API esGenCube ( float scale, GLfloat **vertices, GLfloat **normals, 
+                           GLfloat **texCoords, GLuint **indices );
+
+//
+/// \brief Loads a 24-bit TGA image from a file
+/// \param fileName Name of the file on disk
+/// \param width Width of loaded image in pixels
+/// \param height Height of loaded image in pixels
+///  \return Pointer to loaded image.  NULL on failure. 
+//
+char* ESUTIL_API esLoadTGA ( char *fileName, int *width, int *height );
+
+
+//
+/// \brief multiply matrix specified by result with a scaling matrix and return new matrix in result
+/// \param result Specifies the input matrix.  Scaled matrix is returned in result.
+/// \param sx, sy, sz Scale factors along the x, y and z axes respectively
+//
+void ESUTIL_API esScale(ESMatrix *result, GLfloat sx, GLfloat sy, GLfloat sz);
+
+//
+/// \brief multiply matrix specified by result with a translation matrix and return new matrix in result
+/// \param result Specifies the input matrix.  Translated matrix is returned in result.
+/// \param tx, ty, tz Scale factors along the x, y and z axes respectively
+//
+void ESUTIL_API esTranslate(ESMatrix *result, GLfloat tx, GLfloat ty, GLfloat tz);
+
+//
+/// \brief multiply matrix specified by result with a rotation matrix and return new matrix in result
+/// \param result Specifies the input matrix.  Rotated matrix is returned in result.
+/// \param angle Specifies the angle of rotation, in degrees.
+/// \param x, y, z Specify the x, y and z coordinates of a vector, respectively
+//
+void ESUTIL_API esRotate(ESMatrix *result, GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+
+//
+// \brief multiply matrix specified by result with a perspective matrix and return new matrix in result
+/// \param result Specifies the input matrix.  new matrix is returned in result.
+/// \param left, right Coordinates for the left and right vertical clipping planes
+/// \param bottom, top Coordinates for the bottom and top horizontal clipping planes
+/// \param nearZ, farZ Distances to the near and far depth clipping planes.  Both distances must be positive.
+//
+void ESUTIL_API esFrustum(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ);
+
+//
+/// \brief multiply matrix specified by result with a perspective matrix and return new matrix in result
+/// \param result Specifies the input matrix.  new matrix is returned in result.
+/// \param fovy Field of view y angle in degrees
+/// \param aspect Aspect ratio of screen
+/// \param nearZ Near plane distance
+/// \param farZ Far plane distance
+//
+void ESUTIL_API esPerspective(ESMatrix *result, float fovy, float aspect, float nearZ, float farZ);
+
+//
+/// \brief multiply matrix specified by result with a perspective matrix and return new matrix in result
+/// \param result Specifies the input matrix.  new matrix is returned in result.
+/// \param left, right Coordinates for the left and right vertical clipping planes
+/// \param bottom, top Coordinates for the bottom and top horizontal clipping planes
+/// \param nearZ, farZ Distances to the near and far depth clipping planes.  These values are negative if plane is behind the viewer
+//
+void ESUTIL_API esOrtho(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ);
+
+//
+/// \brief perform the following operation - result matrix = srcA matrix * srcB matrix
+/// \param result Returns multiplied matrix
+/// \param srcA, srcB Input matrices to be multiplied
+//
+void ESUTIL_API esMatrixMultiply(ESMatrix *result, ESMatrix *srcA, ESMatrix *srcB);
+
+//
+//// \brief return an indentity matrix 
+//// \param result returns identity matrix
+//
+void ESUTIL_API esMatrixLoadIdentity(ESMatrix *result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // ESUTIL_H
diff --git a/egl-multi-thread/gl_kmscube.c b/egl-multi-thread/gl_kmscube.c
new file mode 100644 (file)
index 0000000..82bf8e1
--- /dev/null
@@ -0,0 +1,368 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <GLES2/gl2.h>
+
+#include "render_thread.h"
+#include "gl_kmscube.h"
+#include "esUtil.h"
+
+static const GLfloat vVertices[] = {
+                       // front
+       -1.0f, -1.0f, +1.0f, // point blue
+       +1.0f, -1.0f, +1.0f, // point magenta
+       -1.0f, +1.0f, +1.0f, // point cyan
+       +1.0f, +1.0f, +1.0f, // point white
+       // back
+       +1.0f, -1.0f, -1.0f, // point red
+       -1.0f, -1.0f, -1.0f, // point black
+       +1.0f, +1.0f, -1.0f, // point yellow
+       -1.0f, +1.0f, -1.0f, // point green
+       // right
+       +1.0f, -1.0f, +1.0f, // point magenta
+       +1.0f, -1.0f, -1.0f, // point red
+       +1.0f, +1.0f, +1.0f, // point white
+       +1.0f, +1.0f, -1.0f, // point yellow
+       // left
+       -1.0f, -1.0f, -1.0f, // point black
+       -1.0f, -1.0f, +1.0f, // point blue
+       -1.0f, +1.0f, -1.0f, // point green
+       -1.0f, +1.0f, +1.0f, // point cyan
+       // top
+       -1.0f, +1.0f, +1.0f, // point cyan
+       +1.0f, +1.0f, +1.0f, // point white
+       -1.0f, +1.0f, -1.0f, // point green
+       +1.0f, +1.0f, -1.0f, // point yellow
+       // bottom
+       -1.0f, -1.0f, -1.0f, // point black
+       +1.0f, -1.0f, -1.0f, // point red
+       -1.0f, -1.0f, +1.0f, // point blue
+       +1.0f, -1.0f, +1.0f  // point magenta
+};
+
+static const GLfloat vColors[] = {
+       // front
+       0.0f,  0.0f,  1.0f, // blue
+       1.0f,  0.0f,  1.0f, // magenta
+       0.0f,  1.0f,  1.0f, // cyan
+       1.0f,  1.0f,  1.0f, // white
+       // back
+       1.0f,  0.0f,  0.0f, // red
+       0.0f,  0.0f,  0.0f, // black
+       1.0f,  1.0f,  0.0f, // yellow
+       0.0f,  1.0f,  0.0f, // green
+       // right
+       1.0f,  0.0f,  1.0f, // magenta
+       1.0f,  0.0f,  0.0f, // red
+       1.0f,  1.0f,  1.0f, // white
+       1.0f,  1.0f,  0.0f, // yellow
+       // left
+       0.0f,  0.0f,  0.0f, // black
+       0.0f,  0.0f,  1.0f, // blue
+       0.0f,  1.0f,  0.0f, // green
+       0.0f,  1.0f,  1.0f, // cyan
+       // top
+       0.0f,  1.0f,  1.0f, // cyan
+       1.0f,  1.0f,  1.0f, // white
+       0.0f,  1.0f,  0.0f, // green
+       1.0f,  1.0f,  0.0f, // yellow
+       // bottom
+       0.0f,  0.0f,  0.0f, // black
+       1.0f,  0.0f,  0.0f, // red
+       0.0f,  0.0f,  1.0f, // blue
+       1.0f,  0.0f,  1.0f  // magenta
+};
+
+static const GLfloat vNormals[] = {
+       // front
+       +0.0f, +0.0f, +1.0f, // forward
+       +0.0f, +0.0f, +1.0f, // forward
+       +0.0f, +0.0f, +1.0f, // forward
+       +0.0f, +0.0f, +1.0f, // forward
+       // back
+       +0.0f, +0.0f, -1.0f, // backbard
+       +0.0f, +0.0f, -1.0f, // backbard
+       +0.0f, +0.0f, -1.0f, // backbard
+       +0.0f, +0.0f, -1.0f, // backbard
+       // right
+       +1.0f, +0.0f, +0.0f, // right
+       +1.0f, +0.0f, +0.0f, // right
+       +1.0f, +0.0f, +0.0f, // right
+       +1.0f, +0.0f, +0.0f, // right
+       // left
+       -1.0f, +0.0f, +0.0f, // left
+       -1.0f, +0.0f, +0.0f, // left
+       -1.0f, +0.0f, +0.0f, // left
+       -1.0f, +0.0f, +0.0f, // left
+       // top
+       +0.0f, +1.0f, +0.0f, // up
+       +0.0f, +1.0f, +0.0f, // up
+       +0.0f, +1.0f, +0.0f, // up
+       +0.0f, +1.0f, +0.0f, // up
+       // bottom
+       +0.0f, -1.0f, +0.0f, // down
+       +0.0f, -1.0f, +0.0f, // down
+       +0.0f, -1.0f, +0.0f, // down
+       +0.0f, -1.0f, +0.0f  // down
+};
+
+static const char *vertex_shader_source =
+       "uniform mat4 modelviewMatrix;      \n"
+       "uniform mat4 modelviewprojectionMatrix;\n"
+       "uniform mat3 normalMatrix;         \n"
+       "                                   \n"
+       "attribute vec4 in_position;        \n"
+       "attribute vec3 in_normal;          \n"
+       "attribute vec4 in_color;           \n"
+       "\n"
+       "vec4 lightSource = vec4(2.0, 2.0, 20.0, 0.0);\n"
+       "                                   \n"
+       "varying vec4 vVaryingColor;        \n"
+       "                                   \n"
+       "void main()                        \n"
+       "{                                  \n"
+       "    gl_Position = modelviewprojectionMatrix * in_position;\n"
+       "    vec3 vEyeNormal = normalMatrix * in_normal;\n"
+       "    vec4 vPosition4 = modelviewMatrix * in_position;\n"
+       "    vec3 vPosition3 = vPosition4.xyz / vPosition4.w;\n"
+       "    vec3 vLightDir = normalize(lightSource.xyz - vPosition3);\n"
+       "    float diff = max(0.0, dot(vEyeNormal, vLightDir));\n"
+       "    vVaryingColor = vec4(diff * in_color.rgb, 1.0);\n"
+       "}                                  \n";
+
+static const char *fragment_shader_source =
+       "precision mediump float;           \n"
+       "                                   \n"
+       "varying vec4 vVaryingColor;        \n"
+       "                                   \n"
+       "void main()                        \n"
+       "{                                  \n"
+       "    gl_FragColor = vVaryingColor;  \n"
+       "}                                  \n";
+
+struct gl_kmscube_data {
+       GLuint program;
+       GLint modelviewmatrix;
+       GLint modelviewprojectionmatrix;
+       GLint normalmatrix;
+       GLuint vbo;
+       GLuint positionsoffset;
+       GLuint colorsoffset;
+       GLuint normalsoffset;
+       GLuint vertex_shader;
+       GLuint fragment_shader;
+       GLuint bgcolor;
+       GLuint alpha;
+       GLuint width;
+       GLuint height;
+};
+
+
+/*
+ * kmscube setup
+ * NOTE:  Must be called after eglMakeCurrent returns successfully.
+ *
+ * NOTE: Caller can safely call eglMakeCurrent(disp, 
+ *                     EGL_NO_SURFACE,
+ *                     EGL_NO_SURFACE,
+ *                     EGL_NO_CONTEXT);
+ * after this function returns a valid pointer.
+ *
+ * NOTE: If this function fails, it returns NULL, but DOES NOT free the
+ * resources allocated prior to the failure.
+ */
+void *setup_kmscube (struct render_thread_param *prm)
+{
+
+       int ret;
+
+       struct gl_kmscube_data *priv = calloc(sizeof(struct gl_kmscube_data), 1);
+       if(!priv) {
+               printf("kmscube: could not allocate priv data\n");
+               return NULL;
+       }
+
+       priv->vertex_shader = glCreateShader(GL_VERTEX_SHADER);
+
+       glShaderSource(priv->vertex_shader, 1, &vertex_shader_source, NULL);
+       glCompileShader(priv->vertex_shader);
+
+       glGetShaderiv(priv->vertex_shader, GL_COMPILE_STATUS, &ret);
+       if (!ret) {
+               char *log;
+
+               printf("kmscube : vertex shader compilation failed!:\n");
+               glGetShaderiv(priv->vertex_shader, GL_INFO_LOG_LENGTH, &ret);
+               if (ret > 1) {
+                       log = malloc(ret);
+                       glGetShaderInfoLog(priv->vertex_shader, ret, NULL, log);
+                       printf("kmscube : %s", log);
+               }
+
+               return NULL;
+       }
+
+       priv->fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
+
+       glShaderSource(priv->fragment_shader, 1, &fragment_shader_source, NULL);
+       glCompileShader(priv->fragment_shader);
+
+       glGetShaderiv(priv->fragment_shader, GL_COMPILE_STATUS, &ret);
+       if (!ret) {
+               char *log;
+
+               printf("kmscube : fragment shader compilation failed!:\n");
+               glGetShaderiv(priv->fragment_shader, GL_INFO_LOG_LENGTH, &ret);
+
+               if (ret > 1) {
+                       log = malloc(ret);
+                       glGetShaderInfoLog(priv->fragment_shader, ret, NULL, log);
+                       printf("kmscube : %s", log);
+               }
+
+               return NULL;
+       }
+
+       priv->program = glCreateProgram();
+
+       glAttachShader(priv->program, priv->vertex_shader);
+       glAttachShader(priv->program, priv->fragment_shader);
+
+       glBindAttribLocation(priv->program, 0, "in_position");
+       glBindAttribLocation(priv->program, 1, "in_normal");
+       glBindAttribLocation(priv->program, 2, "in_color");
+
+       glLinkProgram(priv->program);
+
+       glGetProgramiv(priv->program, GL_LINK_STATUS, &ret);
+       if (!ret) {
+               char *log;
+
+               printf("kmscube : program linking failed!:\n");
+               glGetProgramiv(priv->program, GL_INFO_LOG_LENGTH, &ret);
+
+               if (ret > 1) {
+                       log = malloc(ret);
+                       glGetProgramInfoLog(priv->program, ret, NULL, log);
+                       printf("kmscube : %s", log);
+               }
+
+               return NULL;
+       }
+
+       glUseProgram(priv->program);
+
+       priv->modelviewmatrix = glGetUniformLocation(priv->program, "modelviewMatrix");
+       priv->modelviewprojectionmatrix = glGetUniformLocation(priv->program, "modelviewprojectionMatrix");
+       priv->normalmatrix = glGetUniformLocation(priv->program, "normalMatrix");
+
+
+       priv->positionsoffset = 0;
+       priv->colorsoffset = sizeof(vVertices);
+       priv->normalsoffset = sizeof(vVertices) + sizeof(vColors);
+       glGenBuffers(1, &priv->vbo);
+       glBindBuffer(GL_ARRAY_BUFFER, priv->vbo);
+       glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices) + sizeof(vColors) + sizeof(vNormals), 0, GL_STATIC_DRAW);
+       glBufferSubData(GL_ARRAY_BUFFER, priv->positionsoffset, sizeof(vVertices), &vVertices[0]);
+       glBufferSubData(GL_ARRAY_BUFFER, priv->colorsoffset, sizeof(vColors), &vColors[0]);
+       glBufferSubData(GL_ARRAY_BUFFER, priv->normalsoffset, sizeof(vNormals), &vNormals[0]);
+       glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)priv->positionsoffset);
+       glEnableVertexAttribArray(0);
+       glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)priv->normalsoffset);
+       glEnableVertexAttribArray(1);
+       glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)priv->colorsoffset);
+       glEnableVertexAttribArray(2);
+
+       priv->bgcolor = rand();
+       priv->alpha = (priv->bgcolor & 0xff000000) >> 24;
+       priv->width = prm->frame_width;
+       priv->height = prm->frame_height;
+
+       return (void *)priv;
+}
+
+/*
+ * kmscube render
+ * NOTE:  Must be called after eglMakeCurrent returns successfully.
+ * NOTE: Caller thread must be current
+ *
+ * NOTE: Caller can safely call eglMakeCurrent(disp, 
+ *                     EGL_NO_SURFACE,
+ *                     EGL_NO_SURFACE,
+ *                     EGL_NO_CONTEXT);
+ * after this function returns a valid pointer.
+ */
+int render_kmscube (void *priv)
+{
+       static int j = 0;
+       int r, g, b;
+       struct gl_kmscube_data *prm = priv;
+       /* connect the context to the surface */
+
+       r = (((prm->bgcolor & 0x00ff0000) >> 16) + j) % 512;
+       g = (((prm->bgcolor & 0x0000ff00) >> 8) + j) % 512;
+       b = ((prm->bgcolor & 0x000000ff) + j) % 512;
+
+       if(r >= 256) 
+               r = 511 - r;
+       if(g >= 256) 
+               g = 511 - g;
+       if(b >= 256) 
+               b = 511 - b;
+
+       glViewport(0, 0, prm->width, prm->height);
+       glEnable(GL_CULL_FACE);
+
+       /*
+        * Different color every frame
+        */
+       glClearColor(r/256.0, g/256.0, b/256.0, prm->alpha/256.0);
+       glClear(GL_COLOR_BUFFER_BIT);
+
+       ESMatrix modelview;
+
+       /* clear the color buffer */
+
+       esMatrixLoadIdentity(&modelview);
+       esTranslate(&modelview, 0.0f, 0.0f, -8.0f);
+       esRotate(&modelview, 45.0f + (0.25f * j), 1.0f, 0.0f, 0.0f);
+       esRotate(&modelview, 45.0f - (0.5f * j), 0.0f, 1.0f, 0.0f);
+       esRotate(&modelview, 10.0f + (0.15f * j), 0.0f, 0.0f, 1.0f);
+
+       GLfloat aspect = (GLfloat)(prm->height) / (GLfloat)(prm->width);
+
+       ESMatrix projection;
+       esMatrixLoadIdentity(&projection);
+       esFrustum(&projection, -2.8f, +2.8f, -2.8f * aspect, +2.8f * aspect, 6.0f, 10.0f);
+
+       ESMatrix modelviewprojection;
+       esMatrixLoadIdentity(&modelviewprojection);
+       esMatrixMultiply(&modelviewprojection, &modelview, &projection);
+
+       float normal[9];
+       normal[0] = modelview.m[0][0];
+       normal[1] = modelview.m[0][1];
+       normal[2] = modelview.m[0][2];
+       normal[3] = modelview.m[1][0];
+       normal[4] = modelview.m[1][1];
+       normal[5] = modelview.m[1][2];
+       normal[6] = modelview.m[2][0];
+       normal[7] = modelview.m[2][1];
+       normal[8] = modelview.m[2][2];
+
+       glUniformMatrix4fv(prm->modelviewmatrix, 1, GL_FALSE, &modelview.m[0][0]);
+       glUniformMatrix4fv(prm->modelviewprojectionmatrix, 1, GL_FALSE, &modelviewprojection.m[0][0]);
+       glUniformMatrix3fv(prm->normalmatrix, 1, GL_FALSE, normal);
+
+       glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+       glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
+       glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
+       glDrawArrays(GL_TRIANGLE_STRIP, 12, 4);
+       glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);
+       glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);
+
+       glDisable(GL_CULL_FACE);
+
+       j++;
+
+       return 0;
+}
diff --git a/egl-multi-thread/gl_kmscube.h b/egl-multi-thread/gl_kmscube.h
new file mode 100644 (file)
index 0000000..5d3bd59
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __GL_KMSCUBE_H__
+#define __GL_KMSCUBE_H__
+
+#include "render_thread.h"
+
+void *setup_kmscube (struct render_thread_param *prm);
+int render_kmscube (void *prm);
+
+#endif /*__GL_KMSCUBE_H__*/
diff --git a/egl-multi-thread/main.c b/egl-multi-thread/main.c
new file mode 100644 (file)
index 0000000..2265559
--- /dev/null
@@ -0,0 +1,192 @@
+#include <stdio.h>
+#include <time.h>
+#include <pthread.h>
+
+#include "esUtil.h"
+#include "render_thread.h"
+#include "gl_kmscube.h"
+
+#ifndef USE_WAYLAND
+#include "drm_gbm.h"
+#else
+#include "wayland_window.h"
+#endif
+
+#ifndef USE_WAYLAND
+int CONNECTOR_ID = (24);
+#endif
+
+#define FRAME_W (960)
+#define FRAME_H (540)
+
+#define MAX_NUM_THREADS (8)
+
+int num_threads = 3;
+
+#ifndef USE_WAYLAND
+static uint32_t gettime_msec()
+{
+       struct timespec t;
+       clock_gettime(CLOCK_REALTIME, &t);
+       return (uint32_t)(t.tv_sec * 1000) + (uint32_t)(t.tv_nsec / 1000000);
+}
+
+static uint32_t gettime_usec()
+{
+       struct timespec t;
+       clock_gettime(CLOCK_REALTIME, &t);
+       return (uint32_t)(t.tv_sec * 1000000) + (uint32_t)(t.tv_nsec / 1000);
+}
+
+unsigned long long gettime_nsec()
+{
+       struct timespec t;
+       clock_gettime(CLOCK_REALTIME, &t);
+       return ((unsigned long long)t.tv_sec) * 1000000000 + t.tv_nsec;
+}
+
+unsigned long long __gettime()
+{
+       struct timespec t;
+       clock_gettime(CLOCK_REALTIME, &t);
+       return ((unsigned long long)t.tv_sec) * 1000000000 + t.tv_nsec;
+}
+#endif
+
+#ifndef USE_WAYLAND
+void print_usage(char *app)
+{
+       printf("./%s --connector <CONNECTOR ID>\n", app); 
+       printf("You can get the CONNECTOR_ID by running modetest on the \n \
+                       target. For example our board shows the following:\n \
+               Connectors: \n \
+               id      encoder status          name            size (mm) modes encoders \n \
+               26      25      connected       HDMI-A-1        160x90    40 25 \n \
+                 modes: \n \
+                         name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot) \n \
+                 1920x1080 60 1920 2008 2052 2200 1080 1084 1089 1125 flags: phsync, pvsync; type: preferred, driver \n \
+                 1920x1080 60 1920 2008 2052 2200 1080 1084 1089 1125 flags: phsync, pvsync; type: driver \n \
+                 \n \
+                 On the above board, the CONNECTOR_ID will be set to 26.\n \
+       \n");
+}
+#else
+void print_usage(char *app)
+{
+       printf("./%s\n", app);
+}
+#endif
+
+int main(int argc, char **argv)
+{
+       int ret;
+       int count;
+       
+#ifndef USE_WAYLAND
+       struct drm_data *dev;
+#else
+       struct wayland_data *dev;
+#endif
+
+       pthread_t threadid[MAX_NUM_THREADS];
+       struct render_thread_param threadparams[MAX_NUM_THREADS];
+
+#ifndef USE_WAYLAND
+       float fps;
+       int frame_num = 0;
+       unsigned long long starttime = 0;
+#endif
+
+       for(count = 0; count < argc; count++) {
+#ifndef USE_WAYLAND
+               if(strcmp(argv[count], "--connector") == 0)
+                       if(count + 1 < argc)
+                               CONNECTOR_ID = atoi(argv[count+1]);
+#endif
+
+               if (strcmp(argv[count], "--help") == 0)
+                       print_usage(argv[0]);
+       }
+       
+       srand(time(0));
+
+#ifndef USE_WAYLAND
+       dev = init_drm_gbm(CONNECTOR_ID);
+#else
+       dev = init_wayland_display();
+#endif
+       if(!dev) {
+               print_usage(argv[0]);
+               return -1;
+       }
+
+
+       for(count = 0; count < num_threads; count++) {
+#ifndef USE_WAYLAND
+               struct plane_data *pdata = get_new_surface(dev, count * FRAME_W, count * FRAME_H, FRAME_W, FRAME_H);
+#else
+               struct wayland_window_data *pdata = get_new_surface(dev, count * FRAME_W, count * FRAME_H, FRAME_W, FRAME_H);
+#endif
+               if(!pdata) {
+                       break;
+               }
+#ifndef USE_WAYLAND
+               threadparams[count].dev = pdata->gbm_dev;
+               threadparams[count].surf = pdata->gbm_surf;
+#else
+               threadparams[count].dev = dev->display;
+               threadparams[count].surf = pdata->surf;
+#endif
+               threadparams[count].frame_width = FRAME_W;
+               threadparams[count].frame_height = FRAME_H;
+               threadparams[count].render_priv_setup = setup_kmscube;
+               threadparams[count].render_priv_render = render_kmscube;
+       }
+
+       printf("requested %d instances, rendering %d instances\n", num_threads, count);
+       num_threads = count;
+       
+
+       /*
+        * Create the different GBM surfaces and start the draw threads
+        */
+
+       for(count = 0; count < num_threads; count++) {
+
+               int ret = setup_render_thread(&threadparams[count]);
+               if(ret != 0) {
+                       printf("render_thread setup failed\n");
+                       return -1;
+               }
+       }
+
+       for(count = 0; count < num_threads; count++) {
+               start_render_thread(&threadparams[count]);
+       }
+
+
+#ifndef USE_WAYLAND
+       starttime = __gettime();
+#endif
+
+       while(1) {
+
+               update_all_surfaces(dev);
+
+#ifndef USE_WAYLAND
+               unsigned long long __time;
+               frame_num++;
+               if(frame_num == 60) {
+                       __time = __gettime();
+                       fps = (60.0 * 1000000000) / (__time - starttime);
+                       frame_num = 0;
+                       starttime = __time;
+                       printf("FPS = %f\n", fps);
+               
+               }
+#endif
+
+       }
+
+}
+
diff --git a/egl-multi-thread/render_thread.c b/egl-multi-thread/render_thread.c
new file mode 100644 (file)
index 0000000..fd580a8
--- /dev/null
@@ -0,0 +1,98 @@
+#include <stdio.h>
+#include <pthread.h>
+
+#include <EGL/egl.h>
+
+#include "render_thread.h"
+
+int setup_render_thread (struct render_thread_param *prm)
+{
+       EGLConfig config;
+       EGLint major, minor, n;
+       int ret;
+
+       EGLint context_attribs[] = {
+               EGL_CONTEXT_CLIENT_VERSION, 2,
+               EGL_NONE
+       };
+
+       EGLint config_attribs[] = {
+               EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+               EGL_RED_SIZE, 1,
+               EGL_GREEN_SIZE, 1,
+               EGL_BLUE_SIZE, 1,
+               EGL_ALPHA_SIZE, 0,
+               EGL_DEPTH_SIZE, 8,
+               EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+               EGL_NONE
+       };
+
+       prm->display = eglGetDisplay((EGLNativeDisplayType)prm->dev);
+
+       if (!eglInitialize(prm->display, &major, &minor)) {
+               printf("failed to initialize\n");
+               return -1;
+       }
+
+       if (!eglBindAPI(EGL_OPENGL_ES_API)) {
+               printf("failed to bind api EGL_OPENGL_ES_API\n");
+               return -1;
+       }
+
+       if (!eglChooseConfig(prm->display, config_attribs, &config, 1, &n) || n != 1) {
+               printf("failed to choose config: %d\n", n);
+               return -1;
+       }
+
+       prm->context = eglCreateContext(prm->display, config,
+                               EGL_NO_CONTEXT, context_attribs);
+       if (prm->context == NULL) {
+               printf("failed to create context\n");
+               return -1;
+       }
+
+       prm->surface = eglCreateWindowSurface(prm->display, config, prm->surf, NULL);
+       if (prm->surface == EGL_NO_SURFACE) {
+               printf("failed to create egl surface\n");
+               return -1;
+       }
+
+       eglMakeCurrent(prm->display, prm->surface, prm->surface, prm->context);
+       
+       prm->render_priv_data = prm->render_priv_setup(prm);
+       if(!prm->render_priv_data) {
+               printf("failed to setup renderpriv\n");
+               return -1;
+       }
+
+       eglMakeCurrent(prm->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+       return 0;
+}
+
+static void *render_thread (void *arg)
+{
+       struct render_thread_param *prm = arg;
+
+       eglMakeCurrent(prm->display, prm->surface, prm->surface, prm->context);
+
+       while(1) {
+               int ret = prm->render_priv_render(prm->render_priv_data);
+
+               if(ret != 0)
+                       printf("renderpriv render returned %d\n", ret);
+
+               eglSwapBuffers(prm->display, prm->surface);
+
+       }
+}
+
+pthread_t start_render_thread (struct render_thread_param *prm)
+{
+       pthread_t threadid;
+
+       int ret = pthread_create(&threadid, NULL, render_thread, prm); 
+
+       return ret == 0 ? threadid : -1;
+}
+
diff --git a/egl-multi-thread/render_thread.h b/egl-multi-thread/render_thread.h
new file mode 100644 (file)
index 0000000..4b8561f
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __RENDER_THREAD__
+#define __RENDER_THREAD__
+
+#include <EGL/egl.h>
+#include <gbm/gbm.h>
+#include <pthread.h>
+
+struct render_thread_param {
+       struct gbm_device *dev;
+       struct gbm_surface *surf;
+       EGLDisplay display;             
+       EGLContext context;
+       EGLSurface surface;
+
+
+       unsigned int frame_width;
+       unsigned int frame_height;
+
+       void *render_priv_data;
+       void *(*render_priv_setup) (struct render_thread_param *prm);
+       int (*render_priv_render) (void *priv);
+
+};
+
+int setup_render_thread (struct render_thread_param *prm);
+
+pthread_t start_render_thread (struct render_thread_param *prm);
+
+#endif /*__RENDER_THREAD__*/
diff --git a/egl-multi-thread/wayland-window.c b/egl-multi-thread/wayland-window.c
new file mode 100644 (file)
index 0000000..c578259
--- /dev/null
@@ -0,0 +1,90 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <wayland-client.h>
+#include <wayland-egl.h>
+
+#include "wayland_window.h"
+
+static void
+registry_handle_global(void *data, struct wl_registry *registry,
+                      uint32_t name, const char *interface, uint32_t version)
+{
+       struct wayland_data *d = data;
+
+       if (strcmp(interface, "wl_compositor") == 0) {
+               d->compositor =
+                       wl_registry_bind(registry, name,
+                                        &wl_compositor_interface, 1);
+       } else if (strcmp(interface, "wl_shell") == 0) {
+               d->shell = wl_registry_bind(registry, name,
+                                           &wl_shell_interface, 1);
+       }
+}
+
+static void
+registry_handle_global_remove(void *data, struct wl_registry *registry,
+                             uint32_t name)
+{
+}
+
+static const struct wl_registry_listener registry_listener = {
+       registry_handle_global,
+       registry_handle_global_remove
+};
+
+
+struct wayland_window_data *get_new_surface(struct wayland_data *wayland, int posx, int posy, int width, int height)
+{
+       struct wayland_window_data *window = calloc(sizeof(struct wayland_window_data), 1);
+       if(!window) {
+               printf("wayland window data alloc failed\n");
+               return NULL;
+       }
+
+       struct wl_surface *surface = wl_compositor_create_surface(wayland->compositor);
+       struct wl_shell_surface *shell_surface = wl_shell_get_shell_surface(wayland->shell, surface);
+
+       wl_shell_surface_set_toplevel(shell_surface);
+
+       struct wl_egl_window *egl_window = wl_egl_window_create(surface,
+                               width, height);
+
+       window->surf = egl_window;
+
+       return window;
+}
+
+
+struct wayland_data *init_wayland_display () {
+       struct wayland_data *wayland = calloc(sizeof(struct wayland_data), 1);
+       if(!wayland) {
+               printf("wayland data alloc failed\n");
+               return NULL;
+       }
+
+       wayland->display = wl_display_connect(NULL);
+       if(!wayland->display) {
+               free(wayland);
+               printf("wl_display_connect failed\n");          
+               return NULL;
+       }
+
+       wayland->registry = wl_display_get_registry(wayland->display);
+       wl_registry_add_listener(wayland->registry,
+                                &registry_listener, wayland);
+       wl_display_dispatch(wayland->display);
+
+       while(1) {
+               if(wayland->compositor && wayland->shell)
+                       break;
+               wl_display_roundtrip(wayland->display);
+       }
+
+       return wayland;
+
+}
+
+int update_all_surfaces(struct wayland_data *wayland) {
+}
diff --git a/egl-multi-thread/wayland_window.h b/egl-multi-thread/wayland_window.h
new file mode 100644 (file)
index 0000000..b59862a
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __WAYLAND_WINDOW_H__
+#define __WAYLAND_WINDOW_H__
+
+#include <wayland-client.h>
+#include <wayland-egl.h>
+
+struct wayland_data {
+       struct wl_display *display;
+       struct wl_registry *registry;
+       struct wl_compositor *compositor;
+       struct wl_shell *shell;
+};
+
+struct wayland_window_data {
+       struct wl_egl_window *surf;
+};
+
+struct wayland_data *init_wayland_display (void);
+struct wayland_window_data *get_new_surface(struct wayland_data *wayland, int posx, int posy, int width, int height);
+int update_all_surfaces(struct wayland_data *drm);
+
+#endif /*__WAYLAND_WINDOW_H__*/