aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSubhajit Paul2018-04-10 10:54:09 -0500
committerAnand Balagopalakrishnan2018-04-10 10:54:09 -0500
commite10d670007282a1720bc9c71a5eddb182275b9a3 (patch)
tree64aedca10f1ebf2a1d3a07a4f6f8cce7d78c73c9
parent02f22a883871663a573dad1bb736e0a9dc2df9cd (diff)
downloadgfx-apps-master.tar.gz
gfx-apps-master.tar.xz
gfx-apps-master.zip
egl-multi-thread: Add example application for multi-threaded EGLHEADmaster
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>
-rw-r--r--egl-multi-thread/Makefile46
-rw-r--r--egl-multi-thread/README18
-rw-r--r--egl-multi-thread/drm_gbm.c315
-rw-r--r--egl-multi-thread/drm_gbm.h31
-rw-r--r--egl-multi-thread/esTransform.c235
-rw-r--r--egl-multi-thread/esUtil.h303
-rw-r--r--egl-multi-thread/gl_kmscube.c368
-rw-r--r--egl-multi-thread/gl_kmscube.h9
-rw-r--r--egl-multi-thread/main.c192
-rw-r--r--egl-multi-thread/render_thread.c98
-rw-r--r--egl-multi-thread/render_thread.h29
-rw-r--r--egl-multi-thread/wayland-window.c90
-rw-r--r--egl-multi-thread/wayland_window.h22
13 files changed, 1756 insertions, 0 deletions
diff --git a/egl-multi-thread/Makefile b/egl-multi-thread/Makefile
new file mode 100644
index 0000000..5d76a15
--- /dev/null
+++ b/egl-multi-thread/Makefile
@@ -0,0 +1,46 @@
1# Makefile
2
3# Set the cross compiler and target file system path
4CROSS_COMPILE=arm-linux-gnueabihf-
5
6## No need to change below this
7
8COMMON_INCLUDES = -I$(FSDIR)/usr/include
9COMMON_LFLAGS = -L$(FSDIR)/usr/lib -Wl,--rpath-link,$(FSDIR)/usr/lib
10
11PLAT_CPP = $(CROSS_COMPILE)gcc
12
13PLAT_CFLAGS = $(COMMON_INCLUDES) -g
14PLAT_LINK = $(COMMON_LFLAGS) -lEGL -lGLESv2 -ludev -lpthread -lm -lrt
15
16SRCNAME = esTransform.c \
17 gl_kmscube.c \
18 main.c \
19 render_thread.c \
20
21BASE_OUTNAME = egl_multi_layer
22
23ifeq ($(BUILD_WAYLAND), yes)
24SRCNAME += wayland-window.c \
25
26PLAT_CFLAGS += -DUSE_WAYLAND
27PLAT_LINK += -lwayland-client -lpvr_wlegl
28OUTNAME = $(BASE_OUTNAME)_wayland
29else
30SRCNAME += drm_gbm.c \
31
32PLAT_CFLAGS += -I$(FSDIR)/usr/include/libdrm -I$(FSDIR)/usr/include/gbm
33PLAT_LINK += -lgbm -ldrm
34OUTNAME = $(BASE_OUTNAME)_drm
35endif
36
37OBJECTS = $(SRCNAME:.c=.o)
38
39$(OUTNAME): $(SRCNAME)
40 $(PLAT_CPP) -o $@ $^ $(PLAT_CFLAGS) $(LINK) $(PLAT_LINK)
41
42install:
43 cp $(OUTNAME) $(FSDIR)/home/root
44
45clean:
46 rm $(OUTNAME)
diff --git a/egl-multi-thread/README b/egl-multi-thread/README
new file mode 100644
index 0000000..df1901c
--- /dev/null
+++ b/egl-multi-thread/README
@@ -0,0 +1,18 @@
1**************
2Build Instructions
3**************
4
5# Mount target file system on host
6# Set FSDIR to the target file system in Makefile
7
8# Include 4.9 cross compiler in the PATH
9export PATH=<4.9_CROSS_COMPILER>/bin:$PATH
10export FSDIR=<TARGETFS_PATH>
11
12#if the application is to be a wayland-client, then export the following as well
13#export BUILD_WAYLAND=yes
14
15make
16sudo -E make install
17
18# 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
index 0000000..fc238da
--- /dev/null
+++ b/egl-multi-thread/drm_gbm.c
@@ -0,0 +1,315 @@
1#include <stdio.h>
2
3#include <stdint.h>
4#include <stdlib.h>
5#include <fcntl.h>
6
7#include <libdrm/drm.h>
8#include <libdrm/drm_mode.h>
9#include <xf86drm.h>
10#include <xf86drmMode.h>
11
12#include <gbm/gbm.h>
13
14#include "drm_gbm.h"
15
16struct drm_data {
17 int fd;
18 int conn_id;
19 int crtc_id;
20 int width;
21 int height;
22
23 int count_planes;
24 struct plane_data *pdata;
25 int primary_planes;
26 int nonprimary_planes;
27
28 struct gbm_device *gbm_dev;
29};
30
31struct drm_fb {
32 struct gbm_bo *bo;
33 uint32_t fb_id;
34 int dmabuf_fd;
35 int fd;
36};
37
38static void
39drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
40{
41 struct drm_fb *fb = data;
42 struct gbm_device *gbm = gbm_bo_get_device(bo);
43
44 if (fb->fb_id)
45 drmModeRmFB(fb->fd, fb->fb_id);
46
47 free(fb);
48}
49
50static struct drm_fb * drm_fb_get_from_bo(int fd, struct gbm_bo *bo)
51{
52 struct drm_fb *fb = gbm_bo_get_user_data(bo);
53 uint32_t width, height, stride, handle;
54 int ret;
55
56 if (fb)
57 return fb;
58
59 fb = calloc(1, sizeof *fb);
60 fb->bo = bo;
61 fb->fd = fd;
62
63 width = gbm_bo_get_width(bo);
64 height = gbm_bo_get_height(bo);
65 stride = gbm_bo_get_stride(bo);
66 handle = gbm_bo_get_handle(bo).u32;
67
68 ret = drmModeAddFB(fd, width, height, 32, 32, stride, handle, &fb->fb_id);
69 if (ret) {
70 free(fb);
71 return NULL;
72 }
73
74 fb->dmabuf_fd = gbm_bo_get_fd(bo);
75
76 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
77
78 return fb;
79}
80
81static void page_flip_handler(int fd, unsigned int frame,
82 unsigned int sec, unsigned int usec,
83 void *data)
84{
85 int *flips = data;
86 *flips= *flips - 1;
87}
88
89
90struct drm_data *init_drm_gbm (int conn_id) {
91 int ret;
92 int count;
93 struct drm_set_client_cap req;
94
95 struct drm_data *drm = calloc(sizeof(struct drm_data), 1);
96 if(!drm) {
97 printf("drm data alloc failed\n");
98 return NULL;
99 }
100
101 int fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
102 drm->fd = fd;
103 if(fd < 0) {
104 printf("drm open failed\n");
105 return NULL;
106 }
107
108 ret = drmSetMaster(fd);
109 if(ret < 0) {
110 printf("drm set master failed\n");
111 return NULL;
112 }
113
114 req.capability = DRM_CLIENT_CAP_ATOMIC;
115 req.value = 1;
116 ret = ioctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &req);
117 if(ret < 0) {
118 printf("drm set atomic cap failed\n");
119 return NULL;
120 }
121
122 int conn_found = 0;
123 drm->conn_id = conn_id;
124 drmModeResPtr res = drmModeGetResources(fd);
125 for(count = 0; count < res->count_connectors; count++) {
126 if(res->connectors[count]== drm->conn_id) {
127 drmModeConnectorPtr connector = drmModeGetConnector(fd, drm->conn_id);
128 drmModeEncoderPtr encoder = drmModeGetEncoder(fd, connector->encoder_id);
129 drm->crtc_id = encoder->crtc_id;
130 drmModeCrtcPtr crtc = drmModeGetCrtc(fd, encoder->crtc_id);
131 drm->width = crtc->width;
132 drm->height = crtc->height;
133 conn_found = 1;
134 break;
135 }
136 }
137 if(!conn_found) {
138 printf("drm connector %d not found\n", drm->conn_id);
139 return NULL;
140 }
141
142 drm->gbm_dev = gbm_create_device(fd);
143
144 drmModePlaneResPtr planes = drmModeGetPlaneResources(fd);
145 drm->count_planes = planes->count_planes;
146 drm->pdata = calloc(sizeof(struct plane_data), planes->count_planes);
147 for(count = 0; count < planes->count_planes; count++) {
148 drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(fd, planes->planes[count], DRM_MODE_OBJECT_PLANE);
149 int propc;
150 for(propc = 0; propc < props->count_props; propc++) {
151 drmModePropertyPtr prop = drmModeGetProperty(fd, props->props[propc]);
152 if(strcmp(prop->name, "type") == 0) {
153 unsigned long long prop_value = props->prop_values[propc];
154 if(prop_value) {
155 drm->pdata[count].primary = 1;
156 drm->primary_planes++;
157 } else {
158 drm->pdata[count].primary = 0;
159 drm->nonprimary_planes++;
160 }
161 }
162 if(strcmp(prop->name, "zorder") == 0) {
163 if(drm->pdata[count].primary) {
164 drm->pdata[count].zorder = drm->primary_planes -1 ;
165 } else {
166 drm->pdata[count].zorder = 4 - drm->nonprimary_planes;
167 }
168 drmModeObjectSetProperty(fd, planes->planes[count],
169 DRM_MODE_OBJECT_PLANE,
170 props->props[propc], drm->pdata[count].zorder);
171 }
172 if(strcmp(prop->name, "FB_ID") == 0)
173 drm->pdata[count].fb_id_property = props->props[propc];
174 }
175 drm->pdata[count].plane = planes->planes[count];
176 drm->pdata[count].occupied = 0;
177 drm->pdata[count].gbm_dev = drm->gbm_dev;
178
179 }
180
181 return drm;
182
183}
184
185struct plane_data *get_new_surface(struct drm_data *drm, int posx, int posy, int width, int height)
186{
187 int count;
188
189 if(posx < 0 || posx + width > drm->width || posy < 0 || posy + height > drm->height) {
190 printf("surface dimensions exceed crtc dimensions\n");
191 return NULL;
192 }
193
194 for(count = 0; count < drm->count_planes; count++) {
195 if(drm->pdata[count].primary)
196 continue;
197 if(drm->pdata[count].occupied)
198 continue;
199 break;
200 }
201
202 if(count == drm->count_planes) {
203 printf("no more planes\n");
204 return NULL;
205 }
206
207 drm->pdata[count].gbm_surf = gbm_surface_create(drm->gbm_dev,
208 width, height,
209 GBM_FORMAT_XRGB8888,
210 GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
211 drm->pdata[count].posx = posx;
212 drm->pdata[count].posy = posy;
213 drm->pdata[count].width = width;
214 drm->pdata[count].height = height;
215 drm->pdata[count].occupied = 1;
216
217 return &drm->pdata[count];
218}
219
220int update_all_surfaces(struct drm_data *drm)
221{
222 int count;
223 int ret;
224 static int firsttime = 1;
225 static int flip_pending = 0;
226
227 if(firsttime) {
228 firsttime = 0;
229 for(count = 0; count < drm->count_planes; count++) {
230 struct plane_data *pdata = &drm->pdata[count];
231 if(drm->pdata[count].occupied == 0)
232 continue;
233 struct gbm_surface *surf = drm->pdata[count].gbm_surf;
234 struct gbm_bo *bo = gbm_surface_lock_front_buffer(surf);
235 struct drm_fb *fb = drm_fb_get_from_bo(drm->fd, bo);
236
237 ret = drmModeSetPlane(drm->fd,
238 drm->pdata[count].plane,
239 drm->crtc_id,
240 fb->fb_id,
241 0,
242 drm->pdata[count].posx,
243 drm->pdata[count].posy,
244 drm->pdata[count].width,
245 drm->pdata[count].height,
246 0,
247 0,
248 drm->pdata[count].width << 16,
249 drm->pdata[count].height << 16);
250 }
251
252 }
253
254 drmModeAtomicReqPtr m_req = drmModeAtomicAlloc();
255
256 for(count = 0; count < drm->count_planes; count++) {
257 struct plane_data *pdata = &drm->pdata[count];
258 if(drm->pdata[count].occupied == 0)
259 continue;
260 struct gbm_surface *surf = drm->pdata[count].gbm_surf;
261 struct gbm_bo *bo = gbm_surface_lock_front_buffer(surf);
262 struct drm_fb *fb = drm_fb_get_from_bo(drm->fd, bo);
263
264 drmModeAtomicAddProperty(m_req,
265 drm->pdata[count].plane,
266 drm->pdata[count].fb_id_property,
267 fb->fb_id);
268
269 drm->pdata[count].current_bo = bo;
270 }
271
272
273 flip_pending++;
274 ret = drmModeAtomicCommit(drm->fd, m_req, DRM_MODE_ATOMIC_TEST_ONLY, 0);
275 ret = drmModeAtomicCommit(drm->fd, m_req, DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK, &flip_pending);
276
277 drmModeAtomicFree(m_req);
278
279 while (flip_pending) {
280 fd_set fds;
281 FD_ZERO(&fds);
282 FD_SET(drm->fd, &fds);
283
284 ret = select(drm->fd + 1, &fds, NULL, NULL, NULL);
285
286 if(ret <= 0) {
287 printf("failing %d\n", ret);
288 return 0;
289 }
290
291 if (FD_ISSET(drm->fd, &fds)) {
292 drmEventContext ev = {
293 .version = DRM_EVENT_CONTEXT_VERSION,
294 .vblank_handler = 0,
295 .page_flip_handler = page_flip_handler,
296 };
297
298 drmHandleEvent(drm->fd, &ev);
299 }
300 }
301
302 for(count = 0; count < drm->count_planes; count++) {
303 struct plane_data *pdata = &drm->pdata[count];
304 if(drm->pdata[count].occupied == 0)
305 continue;
306 struct gbm_surface *surf = drm->pdata[count].gbm_surf;
307 struct gbm_bo *bo = drm->pdata[count].current_bo;
308 gbm_surface_release_buffer(surf, bo);
309 drm->pdata[count].current_bo = NULL;
310
311 }
312
313 return 0;
314
315}
diff --git a/egl-multi-thread/drm_gbm.h b/egl-multi-thread/drm_gbm.h
new file mode 100644
index 0000000..4ab9f03
--- /dev/null
+++ b/egl-multi-thread/drm_gbm.h
@@ -0,0 +1,31 @@
1#ifndef __DRM_GBM_H__
2#define __DRM_GBM_H__
3
4#include <gbm/gbm.h>
5
6struct plane_data {
7 int plane;
8 int fb_id_property;
9 int zorder;
10 int primary;
11
12 struct gbm_device *gbm_dev;
13 struct gbm_surface *gbm_surf;
14
15 struct gbm_bo *current_bo;
16
17 int width;
18 int height;
19 int posx;
20 int posy;
21
22 int occupied;
23};
24
25struct drm_data;
26
27struct drm_data *init_drm_gbm (int conn_id);
28struct plane_data *get_new_surface(struct drm_data *drm, int posx, int posy, int width, int height);
29int update_all_surfaces(struct drm_data *drm);
30
31#endif /*__DRM_GBM_H__*/
diff --git a/egl-multi-thread/esTransform.c b/egl-multi-thread/esTransform.c
new file mode 100644
index 0000000..5fff0c9
--- /dev/null
+++ b/egl-multi-thread/esTransform.c
@@ -0,0 +1,235 @@
1//
2// Book: OpenGL(R) ES 2.0 Programming Guide
3// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
4// ISBN-10: 0321502795
5// ISBN-13: 9780321502797
6// Publisher: Addison-Wesley Professional
7// URLs: http://safari.informit.com/9780321563835
8// http://www.opengles-book.com
9//
10
11/*
12 * (c) 2009 Aaftab Munshi, Dan Ginsburg, Dave Shreiner
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a
15 * copy of this software and associated documentation files (the "Software"),
16 * to deal in the Software without restriction, including without limitation
17 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 * and/or sell copies of the Software, and to permit persons to whom the
19 * Software is furnished to do so, subject to the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included
22 * in all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 * DEALINGS IN THE SOFTWARE.
31 */
32
33// ESUtil.c
34//
35// A utility library for OpenGL ES. This library provides a
36// basic common framework for the example applications in the
37// OpenGL ES 2.0 Programming Guide.
38//
39
40///
41// Includes
42//
43#include "esUtil.h"
44#include <math.h>
45#include <string.h>
46
47#define PI 3.1415926535897932384626433832795f
48
49void ESUTIL_API
50esScale(ESMatrix *result, GLfloat sx, GLfloat sy, GLfloat sz)
51{
52 result->m[0][0] *= sx;
53 result->m[0][1] *= sx;
54 result->m[0][2] *= sx;
55 result->m[0][3] *= sx;
56
57 result->m[1][0] *= sy;
58 result->m[1][1] *= sy;
59 result->m[1][2] *= sy;
60 result->m[1][3] *= sy;
61
62 result->m[2][0] *= sz;
63 result->m[2][1] *= sz;
64 result->m[2][2] *= sz;
65 result->m[2][3] *= sz;
66}
67
68void ESUTIL_API
69esTranslate(ESMatrix *result, GLfloat tx, GLfloat ty, GLfloat tz)
70{
71 result->m[3][0] += (result->m[0][0] * tx + result->m[1][0] * ty + result->m[2][0] * tz);
72 result->m[3][1] += (result->m[0][1] * tx + result->m[1][1] * ty + result->m[2][1] * tz);
73 result->m[3][2] += (result->m[0][2] * tx + result->m[1][2] * ty + result->m[2][2] * tz);
74 result->m[3][3] += (result->m[0][3] * tx + result->m[1][3] * ty + result->m[2][3] * tz);
75}
76
77void ESUTIL_API
78esRotate(ESMatrix *result, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
79{
80 GLfloat sinAngle, cosAngle;
81 GLfloat mag = sqrtf(x * x + y * y + z * z);
82
83 sinAngle = sinf ( angle * PI / 180.0f );
84 cosAngle = cosf ( angle * PI / 180.0f );
85 if ( mag > 0.0f )
86 {
87 GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs;
88 GLfloat oneMinusCos;
89 ESMatrix rotMat;
90
91 x /= mag;
92 y /= mag;
93 z /= mag;
94
95 xx = x * x;
96 yy = y * y;
97 zz = z * z;
98 xy = x * y;
99 yz = y * z;
100 zx = z * x;
101 xs = x * sinAngle;
102 ys = y * sinAngle;
103 zs = z * sinAngle;
104 oneMinusCos = 1.0f - cosAngle;
105
106 rotMat.m[0][0] = (oneMinusCos * xx) + cosAngle;
107 rotMat.m[0][1] = (oneMinusCos * xy) - zs;
108 rotMat.m[0][2] = (oneMinusCos * zx) + ys;
109 rotMat.m[0][3] = 0.0F;
110
111 rotMat.m[1][0] = (oneMinusCos * xy) + zs;
112 rotMat.m[1][1] = (oneMinusCos * yy) + cosAngle;
113 rotMat.m[1][2] = (oneMinusCos * yz) - xs;
114 rotMat.m[1][3] = 0.0F;
115
116 rotMat.m[2][0] = (oneMinusCos * zx) - ys;
117 rotMat.m[2][1] = (oneMinusCos * yz) + xs;
118 rotMat.m[2][2] = (oneMinusCos * zz) + cosAngle;
119 rotMat.m[2][3] = 0.0F;
120
121 rotMat.m[3][0] = 0.0F;
122 rotMat.m[3][1] = 0.0F;
123 rotMat.m[3][2] = 0.0F;
124 rotMat.m[3][3] = 1.0F;
125
126 esMatrixMultiply( result, &rotMat, result );
127 }
128}
129
130void ESUTIL_API
131esFrustum(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ)
132{
133 float deltaX = right - left;
134 float deltaY = top - bottom;
135 float deltaZ = farZ - nearZ;
136 ESMatrix frust;
137
138 if ( (nearZ <= 0.0f) || (farZ <= 0.0f) ||
139 (deltaX <= 0.0f) || (deltaY <= 0.0f) || (deltaZ <= 0.0f) )
140 return;
141
142 frust.m[0][0] = 2.0f * nearZ / deltaX;
143 frust.m[0][1] = frust.m[0][2] = frust.m[0][3] = 0.0f;
144
145 frust.m[1][1] = 2.0f * nearZ / deltaY;
146 frust.m[1][0] = frust.m[1][2] = frust.m[1][3] = 0.0f;
147
148 frust.m[2][0] = (right + left) / deltaX;
149 frust.m[2][1] = (top + bottom) / deltaY;
150 frust.m[2][2] = -(nearZ + farZ) / deltaZ;
151 frust.m[2][3] = -1.0f;
152
153 frust.m[3][2] = -2.0f * nearZ * farZ / deltaZ;
154 frust.m[3][0] = frust.m[3][1] = frust.m[3][3] = 0.0f;
155
156 esMatrixMultiply(result, &frust, result);
157}
158
159
160void ESUTIL_API
161esPerspective(ESMatrix *result, float fovy, float aspect, float nearZ, float farZ)
162{
163 GLfloat frustumW, frustumH;
164
165 frustumH = tanf( fovy / 360.0f * PI ) * nearZ;
166 frustumW = frustumH * aspect;
167
168 esFrustum( result, -frustumW, frustumW, -frustumH, frustumH, nearZ, farZ );
169}
170
171void ESUTIL_API
172esOrtho(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ)
173{
174 float deltaX = right - left;
175 float deltaY = top - bottom;
176 float deltaZ = farZ - nearZ;
177 ESMatrix ortho;
178
179 if ( (deltaX == 0.0f) || (deltaY == 0.0f) || (deltaZ == 0.0f) )
180 return;
181
182 esMatrixLoadIdentity(&ortho);
183 ortho.m[0][0] = 2.0f / deltaX;
184 ortho.m[3][0] = -(right + left) / deltaX;
185 ortho.m[1][1] = 2.0f / deltaY;
186 ortho.m[3][1] = -(top + bottom) / deltaY;
187 ortho.m[2][2] = -2.0f / deltaZ;
188 ortho.m[3][2] = -(nearZ + farZ) / deltaZ;
189
190 esMatrixMultiply(result, &ortho, result);
191}
192
193
194void ESUTIL_API
195esMatrixMultiply(ESMatrix *result, ESMatrix *srcA, ESMatrix *srcB)
196{
197 ESMatrix tmp;
198 int i;
199
200 for (i=0; i<4; i++)
201 {
202 tmp.m[i][0] = (srcA->m[i][0] * srcB->m[0][0]) +
203 (srcA->m[i][1] * srcB->m[1][0]) +
204 (srcA->m[i][2] * srcB->m[2][0]) +
205 (srcA->m[i][3] * srcB->m[3][0]) ;
206
207 tmp.m[i][1] = (srcA->m[i][0] * srcB->m[0][1]) +
208 (srcA->m[i][1] * srcB->m[1][1]) +
209 (srcA->m[i][2] * srcB->m[2][1]) +
210 (srcA->m[i][3] * srcB->m[3][1]) ;
211
212 tmp.m[i][2] = (srcA->m[i][0] * srcB->m[0][2]) +
213 (srcA->m[i][1] * srcB->m[1][2]) +
214 (srcA->m[i][2] * srcB->m[2][2]) +
215 (srcA->m[i][3] * srcB->m[3][2]) ;
216
217 tmp.m[i][3] = (srcA->m[i][0] * srcB->m[0][3]) +
218 (srcA->m[i][1] * srcB->m[1][3]) +
219 (srcA->m[i][2] * srcB->m[2][3]) +
220 (srcA->m[i][3] * srcB->m[3][3]) ;
221 }
222 memcpy(result, &tmp, sizeof(ESMatrix));
223}
224
225
226void ESUTIL_API
227esMatrixLoadIdentity(ESMatrix *result)
228{
229 memset(result, 0x0, sizeof(ESMatrix));
230 result->m[0][0] = 1.0f;
231 result->m[1][1] = 1.0f;
232 result->m[2][2] = 1.0f;
233 result->m[3][3] = 1.0f;
234}
235
diff --git a/egl-multi-thread/esUtil.h b/egl-multi-thread/esUtil.h
new file mode 100644
index 0000000..c2d7c1d
--- /dev/null
+++ b/egl-multi-thread/esUtil.h
@@ -0,0 +1,303 @@
1//
2// Book: OpenGL(R) ES 2.0 Programming Guide
3// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
4// ISBN-10: 0321502795
5// ISBN-13: 9780321502797
6// Publisher: Addison-Wesley Professional
7// URLs: http://safari.informit.com/9780321563835
8// http://www.opengles-book.com
9//
10
11/*
12 * (c) 2009 Aaftab Munshi, Dan Ginsburg, Dave Shreiner
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a
15 * copy of this software and associated documentation files (the "Software"),
16 * to deal in the Software without restriction, including without limitation
17 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 * and/or sell copies of the Software, and to permit persons to whom the
19 * Software is furnished to do so, subject to the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included
22 * in all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 * DEALINGS IN THE SOFTWARE.
31 */
32
33//
34/// \file ESUtil.h
35/// \brief A utility library for OpenGL ES. This library provides a
36/// basic common framework for the example applications in the
37/// OpenGL ES 2.0 Programming Guide.
38//
39#ifndef ESUTIL_H
40#define ESUTIL_H
41
42///
43// Includes
44//
45#include <GLES2/gl2.h>
46#include <EGL/egl.h>
47
48#ifdef __cplusplus
49
50extern "C" {
51#endif
52
53
54///
55// Macros
56//
57#define ESUTIL_API
58#define ESCALLBACK
59
60
61/// esCreateWindow flag - RGB color buffer
62#define ES_WINDOW_RGB 0
63/// esCreateWindow flag - ALPHA color buffer
64#define ES_WINDOW_ALPHA 1
65/// esCreateWindow flag - depth buffer
66#define ES_WINDOW_DEPTH 2
67/// esCreateWindow flag - stencil buffer
68#define ES_WINDOW_STENCIL 4
69/// esCreateWindow flat - multi-sample buffer
70#define ES_WINDOW_MULTISAMPLE 8
71
72
73///
74// Types
75//
76
77#ifndef FALSE
78#define FALSE 0
79#endif
80#ifndef TRUE
81#define TRUE 1
82#endif
83
84typedef struct
85{
86 GLfloat m[4][4];
87} ESMatrix;
88
89typedef struct _escontext
90{
91 /// Put your user data here...
92 void* userData;
93
94 /// Window width
95 GLint width;
96
97 /// Window height
98 GLint height;
99
100 /// Window handle
101 EGLNativeWindowType hWnd;
102
103 /// EGL display
104 EGLDisplay eglDisplay;
105
106 /// EGL context
107 EGLContext eglContext;
108
109 /// EGL surface
110 EGLSurface eglSurface;
111
112 /// Callbacks
113 void (ESCALLBACK *drawFunc) ( struct _escontext * );
114 void (ESCALLBACK *keyFunc) ( struct _escontext *, unsigned char, int, int );
115 void (ESCALLBACK *updateFunc) ( struct _escontext *, float deltaTime );
116} ESContext;
117
118
119///
120// Public Functions
121//
122
123//
124///
125/// \brief Initialize ES framework context. This must be called before calling any other functions.
126/// \param esContext Application context
127//
128void ESUTIL_API esInitContext ( ESContext *esContext );
129
130//
131/// \brief Create a window with the specified parameters
132/// \param esContext Application context
133/// \param title Name for title bar of window
134/// \param width Width in pixels of window to create
135/// \param height Height in pixels of window to create
136/// \param flags Bitfield for the window creation flags
137/// ES_WINDOW_RGB - specifies that the color buffer should have R,G,B channels
138/// ES_WINDOW_ALPHA - specifies that the color buffer should have alpha
139/// ES_WINDOW_DEPTH - specifies that a depth buffer should be created
140/// ES_WINDOW_STENCIL - specifies that a stencil buffer should be created
141/// ES_WINDOW_MULTISAMPLE - specifies that a multi-sample buffer should be created
142/// \return GL_TRUE if window creation is succesful, GL_FALSE otherwise
143GLboolean ESUTIL_API esCreateWindow ( ESContext *esContext, const char *title, GLint width, GLint height, GLuint flags );
144
145//
146/// \brief Start the main loop for the OpenGL ES application
147/// \param esContext Application context
148//
149void ESUTIL_API esMainLoop ( ESContext *esContext );
150
151//
152/// \brief Register a draw callback function to be used to render each frame
153/// \param esContext Application context
154/// \param drawFunc Draw callback function that will be used to render the scene
155//
156void ESUTIL_API esRegisterDrawFunc ( ESContext *esContext, void (ESCALLBACK *drawFunc) ( ESContext* ) );
157
158//
159/// \brief Register an update callback function to be used to update on each time step
160/// \param esContext Application context
161/// \param updateFunc Update callback function that will be used to render the scene
162//
163void ESUTIL_API esRegisterUpdateFunc ( ESContext *esContext, void (ESCALLBACK *updateFunc) ( ESContext*, float ) );
164
165//
166/// \brief Register an keyboard input processing callback function
167/// \param esContext Application context
168/// \param keyFunc Key callback function for application processing of keyboard input
169//
170void ESUTIL_API esRegisterKeyFunc ( ESContext *esContext,
171 void (ESCALLBACK *drawFunc) ( ESContext*, unsigned char, int, int ) );
172//
173/// \brief Log a message to the debug output for the platform
174/// \param formatStr Format string for error log.
175//
176void ESUTIL_API esLogMessage ( const char *formatStr, ... );
177
178//
179///
180/// \brief Load a shader, check for compile errors, print error messages to output log
181/// \param type Type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER)
182/// \param shaderSrc Shader source string
183/// \return A new shader object on success, 0 on failure
184//
185GLuint ESUTIL_API esLoadShader ( GLenum type, const char *shaderSrc );
186
187//
188///
189/// \brief Load a vertex and fragment shader, create a program object, link program.
190/// Errors output to log.
191/// \param vertShaderSrc Vertex shader source code
192/// \param fragShaderSrc Fragment shader source code
193/// \return A new program object linked with the vertex/fragment shader pair, 0 on failure
194//
195GLuint ESUTIL_API esLoadProgram ( const char *vertShaderSrc, const char *fragShaderSrc );
196
197
198//
199/// \brief Generates geometry for a sphere. Allocates memory for the vertex data and stores
200/// the results in the arrays. Generate index list for a TRIANGLE_STRIP
201/// \param numSlices The number of slices in the sphere
202/// \param vertices If not NULL, will contain array of float3 positions
203/// \param normals If not NULL, will contain array of float3 normals
204/// \param texCoords If not NULL, will contain array of float2 texCoords
205/// \param indices If not NULL, will contain the array of indices for the triangle strip
206/// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array
207/// if it is not NULL ) as a GL_TRIANGLE_STRIP
208//
209int ESUTIL_API esGenSphere ( int numSlices, float radius, GLfloat **vertices, GLfloat **normals,
210 GLfloat **texCoords, GLuint **indices );
211
212//
213/// \brief Generates geometry for a cube. Allocates memory for the vertex data and stores
214/// the results in the arrays. Generate index list for a TRIANGLES
215/// \param scale The size of the cube, use 1.0 for a unit cube.
216/// \param vertices If not NULL, will contain array of float3 positions
217/// \param normals If not NULL, will contain array of float3 normals
218/// \param texCoords If not NULL, will contain array of float2 texCoords
219/// \param indices If not NULL, will contain the array of indices for the triangle strip
220/// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array
221/// if it is not NULL ) as a GL_TRIANGLES
222//
223int ESUTIL_API esGenCube ( float scale, GLfloat **vertices, GLfloat **normals,
224 GLfloat **texCoords, GLuint **indices );
225
226//
227/// \brief Loads a 24-bit TGA image from a file
228/// \param fileName Name of the file on disk
229/// \param width Width of loaded image in pixels
230/// \param height Height of loaded image in pixels
231/// \return Pointer to loaded image. NULL on failure.
232//
233char* ESUTIL_API esLoadTGA ( char *fileName, int *width, int *height );
234
235
236//
237/// \brief multiply matrix specified by result with a scaling matrix and return new matrix in result
238/// \param result Specifies the input matrix. Scaled matrix is returned in result.
239/// \param sx, sy, sz Scale factors along the x, y and z axes respectively
240//
241void ESUTIL_API esScale(ESMatrix *result, GLfloat sx, GLfloat sy, GLfloat sz);
242
243//
244/// \brief multiply matrix specified by result with a translation matrix and return new matrix in result
245/// \param result Specifies the input matrix. Translated matrix is returned in result.
246/// \param tx, ty, tz Scale factors along the x, y and z axes respectively
247//
248void ESUTIL_API esTranslate(ESMatrix *result, GLfloat tx, GLfloat ty, GLfloat tz);
249
250//
251/// \brief multiply matrix specified by result with a rotation matrix and return new matrix in result
252/// \param result Specifies the input matrix. Rotated matrix is returned in result.
253/// \param angle Specifies the angle of rotation, in degrees.
254/// \param x, y, z Specify the x, y and z coordinates of a vector, respectively
255//
256void ESUTIL_API esRotate(ESMatrix *result, GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
257
258//
259// \brief multiply matrix specified by result with a perspective matrix and return new matrix in result
260/// \param result Specifies the input matrix. new matrix is returned in result.
261/// \param left, right Coordinates for the left and right vertical clipping planes
262/// \param bottom, top Coordinates for the bottom and top horizontal clipping planes
263/// \param nearZ, farZ Distances to the near and far depth clipping planes. Both distances must be positive.
264//
265void ESUTIL_API esFrustum(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ);
266
267//
268/// \brief multiply matrix specified by result with a perspective matrix and return new matrix in result
269/// \param result Specifies the input matrix. new matrix is returned in result.
270/// \param fovy Field of view y angle in degrees
271/// \param aspect Aspect ratio of screen
272/// \param nearZ Near plane distance
273/// \param farZ Far plane distance
274//
275void ESUTIL_API esPerspective(ESMatrix *result, float fovy, float aspect, float nearZ, float farZ);
276
277//
278/// \brief multiply matrix specified by result with a perspective matrix and return new matrix in result
279/// \param result Specifies the input matrix. new matrix is returned in result.
280/// \param left, right Coordinates for the left and right vertical clipping planes
281/// \param bottom, top Coordinates for the bottom and top horizontal clipping planes
282/// \param nearZ, farZ Distances to the near and far depth clipping planes. These values are negative if plane is behind the viewer
283//
284void ESUTIL_API esOrtho(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ);
285
286//
287/// \brief perform the following operation - result matrix = srcA matrix * srcB matrix
288/// \param result Returns multiplied matrix
289/// \param srcA, srcB Input matrices to be multiplied
290//
291void ESUTIL_API esMatrixMultiply(ESMatrix *result, ESMatrix *srcA, ESMatrix *srcB);
292
293//
294//// \brief return an indentity matrix
295//// \param result returns identity matrix
296//
297void ESUTIL_API esMatrixLoadIdentity(ESMatrix *result);
298
299#ifdef __cplusplus
300}
301#endif
302
303#endif // ESUTIL_H
diff --git a/egl-multi-thread/gl_kmscube.c b/egl-multi-thread/gl_kmscube.c
new file mode 100644
index 0000000..82bf8e1
--- /dev/null
+++ b/egl-multi-thread/gl_kmscube.c
@@ -0,0 +1,368 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <GLES2/gl2.h>
4
5#include "render_thread.h"
6#include "gl_kmscube.h"
7#include "esUtil.h"
8
9static const GLfloat vVertices[] = {
10 // front
11 -1.0f, -1.0f, +1.0f, // point blue
12 +1.0f, -1.0f, +1.0f, // point magenta
13 -1.0f, +1.0f, +1.0f, // point cyan
14 +1.0f, +1.0f, +1.0f, // point white
15 // back
16 +1.0f, -1.0f, -1.0f, // point red
17 -1.0f, -1.0f, -1.0f, // point black
18 +1.0f, +1.0f, -1.0f, // point yellow
19 -1.0f, +1.0f, -1.0f, // point green
20 // right
21 +1.0f, -1.0f, +1.0f, // point magenta
22 +1.0f, -1.0f, -1.0f, // point red
23 +1.0f, +1.0f, +1.0f, // point white
24 +1.0f, +1.0f, -1.0f, // point yellow
25 // left
26 -1.0f, -1.0f, -1.0f, // point black
27 -1.0f, -1.0f, +1.0f, // point blue
28 -1.0f, +1.0f, -1.0f, // point green
29 -1.0f, +1.0f, +1.0f, // point cyan
30 // top
31 -1.0f, +1.0f, +1.0f, // point cyan
32 +1.0f, +1.0f, +1.0f, // point white
33 -1.0f, +1.0f, -1.0f, // point green
34 +1.0f, +1.0f, -1.0f, // point yellow
35 // bottom
36 -1.0f, -1.0f, -1.0f, // point black
37 +1.0f, -1.0f, -1.0f, // point red
38 -1.0f, -1.0f, +1.0f, // point blue
39 +1.0f, -1.0f, +1.0f // point magenta
40};
41
42static const GLfloat vColors[] = {
43 // front
44 0.0f, 0.0f, 1.0f, // blue
45 1.0f, 0.0f, 1.0f, // magenta
46 0.0f, 1.0f, 1.0f, // cyan
47 1.0f, 1.0f, 1.0f, // white
48 // back
49 1.0f, 0.0f, 0.0f, // red
50 0.0f, 0.0f, 0.0f, // black
51 1.0f, 1.0f, 0.0f, // yellow
52 0.0f, 1.0f, 0.0f, // green
53 // right
54 1.0f, 0.0f, 1.0f, // magenta
55 1.0f, 0.0f, 0.0f, // red
56 1.0f, 1.0f, 1.0f, // white
57 1.0f, 1.0f, 0.0f, // yellow
58 // left
59 0.0f, 0.0f, 0.0f, // black
60 0.0f, 0.0f, 1.0f, // blue
61 0.0f, 1.0f, 0.0f, // green
62 0.0f, 1.0f, 1.0f, // cyan
63 // top
64 0.0f, 1.0f, 1.0f, // cyan
65 1.0f, 1.0f, 1.0f, // white
66 0.0f, 1.0f, 0.0f, // green
67 1.0f, 1.0f, 0.0f, // yellow
68 // bottom
69 0.0f, 0.0f, 0.0f, // black
70 1.0f, 0.0f, 0.0f, // red
71 0.0f, 0.0f, 1.0f, // blue
72 1.0f, 0.0f, 1.0f // magenta
73};
74
75static const GLfloat vNormals[] = {
76 // front
77 +0.0f, +0.0f, +1.0f, // forward
78 +0.0f, +0.0f, +1.0f, // forward
79 +0.0f, +0.0f, +1.0f, // forward
80 +0.0f, +0.0f, +1.0f, // forward
81 // back
82 +0.0f, +0.0f, -1.0f, // backbard
83 +0.0f, +0.0f, -1.0f, // backbard
84 +0.0f, +0.0f, -1.0f, // backbard
85 +0.0f, +0.0f, -1.0f, // backbard
86 // right
87 +1.0f, +0.0f, +0.0f, // right
88 +1.0f, +0.0f, +0.0f, // right
89 +1.0f, +0.0f, +0.0f, // right
90 +1.0f, +0.0f, +0.0f, // right
91 // left
92 -1.0f, +0.0f, +0.0f, // left
93 -1.0f, +0.0f, +0.0f, // left
94 -1.0f, +0.0f, +0.0f, // left
95 -1.0f, +0.0f, +0.0f, // left
96 // top
97 +0.0f, +1.0f, +0.0f, // up
98 +0.0f, +1.0f, +0.0f, // up
99 +0.0f, +1.0f, +0.0f, // up
100 +0.0f, +1.0f, +0.0f, // up
101 // bottom
102 +0.0f, -1.0f, +0.0f, // down
103 +0.0f, -1.0f, +0.0f, // down
104 +0.0f, -1.0f, +0.0f, // down
105 +0.0f, -1.0f, +0.0f // down
106};
107
108static const char *vertex_shader_source =
109 "uniform mat4 modelviewMatrix; \n"
110 "uniform mat4 modelviewprojectionMatrix;\n"
111 "uniform mat3 normalMatrix; \n"
112 " \n"
113 "attribute vec4 in_position; \n"
114 "attribute vec3 in_normal; \n"
115 "attribute vec4 in_color; \n"
116 "\n"
117 "vec4 lightSource = vec4(2.0, 2.0, 20.0, 0.0);\n"
118 " \n"
119 "varying vec4 vVaryingColor; \n"
120 " \n"
121 "void main() \n"
122 "{ \n"
123 " gl_Position = modelviewprojectionMatrix * in_position;\n"
124 " vec3 vEyeNormal = normalMatrix * in_normal;\n"
125 " vec4 vPosition4 = modelviewMatrix * in_position;\n"
126 " vec3 vPosition3 = vPosition4.xyz / vPosition4.w;\n"
127 " vec3 vLightDir = normalize(lightSource.xyz - vPosition3);\n"
128 " float diff = max(0.0, dot(vEyeNormal, vLightDir));\n"
129 " vVaryingColor = vec4(diff * in_color.rgb, 1.0);\n"
130 "} \n";
131
132static const char *fragment_shader_source =
133 "precision mediump float; \n"
134 " \n"
135 "varying vec4 vVaryingColor; \n"
136 " \n"
137 "void main() \n"
138 "{ \n"
139 " gl_FragColor = vVaryingColor; \n"
140 "} \n";
141
142struct gl_kmscube_data {
143 GLuint program;
144 GLint modelviewmatrix;
145 GLint modelviewprojectionmatrix;
146 GLint normalmatrix;
147 GLuint vbo;
148 GLuint positionsoffset;
149 GLuint colorsoffset;
150 GLuint normalsoffset;
151 GLuint vertex_shader;
152 GLuint fragment_shader;
153 GLuint bgcolor;
154 GLuint alpha;
155 GLuint width;
156 GLuint height;
157};
158
159
160/*
161 * kmscube setup
162 * NOTE: Must be called after eglMakeCurrent returns successfully.
163 *
164 * NOTE: Caller can safely call eglMakeCurrent(disp,
165 * EGL_NO_SURFACE,
166 * EGL_NO_SURFACE,
167 * EGL_NO_CONTEXT);
168 * after this function returns a valid pointer.
169 *
170 * NOTE: If this function fails, it returns NULL, but DOES NOT free the
171 * resources allocated prior to the failure.
172 */
173void *setup_kmscube (struct render_thread_param *prm)
174{
175
176 int ret;
177
178 struct gl_kmscube_data *priv = calloc(sizeof(struct gl_kmscube_data), 1);
179 if(!priv) {
180 printf("kmscube: could not allocate priv data\n");
181 return NULL;
182 }
183
184 priv->vertex_shader = glCreateShader(GL_VERTEX_SHADER);
185
186 glShaderSource(priv->vertex_shader, 1, &vertex_shader_source, NULL);
187 glCompileShader(priv->vertex_shader);
188
189 glGetShaderiv(priv->vertex_shader, GL_COMPILE_STATUS, &ret);
190 if (!ret) {
191 char *log;
192
193 printf("kmscube : vertex shader compilation failed!:\n");
194 glGetShaderiv(priv->vertex_shader, GL_INFO_LOG_LENGTH, &ret);
195 if (ret > 1) {
196 log = malloc(ret);
197 glGetShaderInfoLog(priv->vertex_shader, ret, NULL, log);
198 printf("kmscube : %s", log);
199 }
200
201 return NULL;
202 }
203
204 priv->fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
205
206 glShaderSource(priv->fragment_shader, 1, &fragment_shader_source, NULL);
207 glCompileShader(priv->fragment_shader);
208
209 glGetShaderiv(priv->fragment_shader, GL_COMPILE_STATUS, &ret);
210 if (!ret) {
211 char *log;
212
213 printf("kmscube : fragment shader compilation failed!:\n");
214 glGetShaderiv(priv->fragment_shader, GL_INFO_LOG_LENGTH, &ret);
215
216 if (ret > 1) {
217 log = malloc(ret);
218 glGetShaderInfoLog(priv->fragment_shader, ret, NULL, log);
219 printf("kmscube : %s", log);
220 }
221
222 return NULL;
223 }
224
225 priv->program = glCreateProgram();
226
227 glAttachShader(priv->program, priv->vertex_shader);
228 glAttachShader(priv->program, priv->fragment_shader);
229
230 glBindAttribLocation(priv->program, 0, "in_position");
231 glBindAttribLocation(priv->program, 1, "in_normal");
232 glBindAttribLocation(priv->program, 2, "in_color");
233
234 glLinkProgram(priv->program);
235
236 glGetProgramiv(priv->program, GL_LINK_STATUS, &ret);
237 if (!ret) {
238 char *log;
239
240 printf("kmscube : program linking failed!:\n");
241 glGetProgramiv(priv->program, GL_INFO_LOG_LENGTH, &ret);
242
243 if (ret > 1) {
244 log = malloc(ret);
245 glGetProgramInfoLog(priv->program, ret, NULL, log);
246 printf("kmscube : %s", log);
247 }
248
249 return NULL;
250 }
251
252 glUseProgram(priv->program);
253
254 priv->modelviewmatrix = glGetUniformLocation(priv->program, "modelviewMatrix");
255 priv->modelviewprojectionmatrix = glGetUniformLocation(priv->program, "modelviewprojectionMatrix");
256 priv->normalmatrix = glGetUniformLocation(priv->program, "normalMatrix");
257
258
259 priv->positionsoffset = 0;
260 priv->colorsoffset = sizeof(vVertices);
261 priv->normalsoffset = sizeof(vVertices) + sizeof(vColors);
262 glGenBuffers(1, &priv->vbo);
263 glBindBuffer(GL_ARRAY_BUFFER, priv->vbo);
264 glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices) + sizeof(vColors) + sizeof(vNormals), 0, GL_STATIC_DRAW);
265 glBufferSubData(GL_ARRAY_BUFFER, priv->positionsoffset, sizeof(vVertices), &vVertices[0]);
266 glBufferSubData(GL_ARRAY_BUFFER, priv->colorsoffset, sizeof(vColors), &vColors[0]);
267 glBufferSubData(GL_ARRAY_BUFFER, priv->normalsoffset, sizeof(vNormals), &vNormals[0]);
268 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)priv->positionsoffset);
269 glEnableVertexAttribArray(0);
270 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)priv->normalsoffset);
271 glEnableVertexAttribArray(1);
272 glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)priv->colorsoffset);
273 glEnableVertexAttribArray(2);
274
275 priv->bgcolor = rand();
276 priv->alpha = (priv->bgcolor & 0xff000000) >> 24;
277 priv->width = prm->frame_width;
278 priv->height = prm->frame_height;
279
280 return (void *)priv;
281}
282
283/*
284 * kmscube render
285 * NOTE: Must be called after eglMakeCurrent returns successfully.
286 * NOTE: Caller thread must be current
287 *
288 * NOTE: Caller can safely call eglMakeCurrent(disp,
289 * EGL_NO_SURFACE,
290 * EGL_NO_SURFACE,
291 * EGL_NO_CONTEXT);
292 * after this function returns a valid pointer.
293 */
294int render_kmscube (void *priv)
295{
296 static int j = 0;
297 int r, g, b;
298 struct gl_kmscube_data *prm = priv;
299 /* connect the context to the surface */
300
301 r = (((prm->bgcolor & 0x00ff0000) >> 16) + j) % 512;
302 g = (((prm->bgcolor & 0x0000ff00) >> 8) + j) % 512;
303 b = ((prm->bgcolor & 0x000000ff) + j) % 512;
304
305 if(r >= 256)
306 r = 511 - r;
307 if(g >= 256)
308 g = 511 - g;
309 if(b >= 256)
310 b = 511 - b;
311
312 glViewport(0, 0, prm->width, prm->height);
313 glEnable(GL_CULL_FACE);
314
315 /*
316 * Different color every frame
317 */
318 glClearColor(r/256.0, g/256.0, b/256.0, prm->alpha/256.0);
319 glClear(GL_COLOR_BUFFER_BIT);
320
321 ESMatrix modelview;
322
323 /* clear the color buffer */
324
325 esMatrixLoadIdentity(&modelview);
326 esTranslate(&modelview, 0.0f, 0.0f, -8.0f);
327 esRotate(&modelview, 45.0f + (0.25f * j), 1.0f, 0.0f, 0.0f);
328 esRotate(&modelview, 45.0f - (0.5f * j), 0.0f, 1.0f, 0.0f);
329 esRotate(&modelview, 10.0f + (0.15f * j), 0.0f, 0.0f, 1.0f);
330
331 GLfloat aspect = (GLfloat)(prm->height) / (GLfloat)(prm->width);
332
333 ESMatrix projection;
334 esMatrixLoadIdentity(&projection);
335 esFrustum(&projection, -2.8f, +2.8f, -2.8f * aspect, +2.8f * aspect, 6.0f, 10.0f);
336
337 ESMatrix modelviewprojection;
338 esMatrixLoadIdentity(&modelviewprojection);
339 esMatrixMultiply(&modelviewprojection, &modelview, &projection);
340
341 float normal[9];
342 normal[0] = modelview.m[0][0];
343 normal[1] = modelview.m[0][1];
344 normal[2] = modelview.m[0][2];
345 normal[3] = modelview.m[1][0];
346 normal[4] = modelview.m[1][1];
347 normal[5] = modelview.m[1][2];
348 normal[6] = modelview.m[2][0];
349 normal[7] = modelview.m[2][1];
350 normal[8] = modelview.m[2][2];
351
352 glUniformMatrix4fv(prm->modelviewmatrix, 1, GL_FALSE, &modelview.m[0][0]);
353 glUniformMatrix4fv(prm->modelviewprojectionmatrix, 1, GL_FALSE, &modelviewprojection.m[0][0]);
354 glUniformMatrix3fv(prm->normalmatrix, 1, GL_FALSE, normal);
355
356 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
357 glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
358 glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
359 glDrawArrays(GL_TRIANGLE_STRIP, 12, 4);
360 glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);
361 glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);
362
363 glDisable(GL_CULL_FACE);
364
365 j++;
366
367 return 0;
368}
diff --git a/egl-multi-thread/gl_kmscube.h b/egl-multi-thread/gl_kmscube.h
new file mode 100644
index 0000000..5d3bd59
--- /dev/null
+++ b/egl-multi-thread/gl_kmscube.h
@@ -0,0 +1,9 @@
1#ifndef __GL_KMSCUBE_H__
2#define __GL_KMSCUBE_H__
3
4#include "render_thread.h"
5
6void *setup_kmscube (struct render_thread_param *prm);
7int render_kmscube (void *prm);
8
9#endif /*__GL_KMSCUBE_H__*/
diff --git a/egl-multi-thread/main.c b/egl-multi-thread/main.c
new file mode 100644
index 0000000..2265559
--- /dev/null
+++ b/egl-multi-thread/main.c
@@ -0,0 +1,192 @@
1#include <stdio.h>
2#include <time.h>
3#include <pthread.h>
4
5#include "esUtil.h"
6#include "render_thread.h"
7#include "gl_kmscube.h"
8
9#ifndef USE_WAYLAND
10#include "drm_gbm.h"
11#else
12#include "wayland_window.h"
13#endif
14
15#ifndef USE_WAYLAND
16int CONNECTOR_ID = (24);
17#endif
18
19#define FRAME_W (960)
20#define FRAME_H (540)
21
22#define MAX_NUM_THREADS (8)
23
24int num_threads = 3;
25
26#ifndef USE_WAYLAND
27static uint32_t gettime_msec()
28{
29 struct timespec t;
30 clock_gettime(CLOCK_REALTIME, &t);
31 return (uint32_t)(t.tv_sec * 1000) + (uint32_t)(t.tv_nsec / 1000000);
32}
33
34static uint32_t gettime_usec()
35{
36 struct timespec t;
37 clock_gettime(CLOCK_REALTIME, &t);
38 return (uint32_t)(t.tv_sec * 1000000) + (uint32_t)(t.tv_nsec / 1000);
39}
40
41unsigned long long gettime_nsec()
42{
43 struct timespec t;
44 clock_gettime(CLOCK_REALTIME, &t);
45 return ((unsigned long long)t.tv_sec) * 1000000000 + t.tv_nsec;
46}
47
48unsigned long long __gettime()
49{
50 struct timespec t;
51 clock_gettime(CLOCK_REALTIME, &t);
52 return ((unsigned long long)t.tv_sec) * 1000000000 + t.tv_nsec;
53}
54#endif
55
56#ifndef USE_WAYLAND
57void print_usage(char *app)
58{
59 printf("./%s --connector <CONNECTOR ID>\n", app);
60 printf("You can get the CONNECTOR_ID by running modetest on the \n \
61 target. For example our board shows the following:\n \
62 Connectors: \n \
63 id encoder status name size (mm) modes encoders \n \
64 26 25 connected HDMI-A-1 160x90 40 25 \n \
65 modes: \n \
66 name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot) \n \
67 1920x1080 60 1920 2008 2052 2200 1080 1084 1089 1125 flags: phsync, pvsync; type: preferred, driver \n \
68 1920x1080 60 1920 2008 2052 2200 1080 1084 1089 1125 flags: phsync, pvsync; type: driver \n \
69 \n \
70 On the above board, the CONNECTOR_ID will be set to 26.\n \
71 \n");
72}
73#else
74void print_usage(char *app)
75{
76 printf("./%s\n", app);
77}
78#endif
79
80int main(int argc, char **argv)
81{
82 int ret;
83 int count;
84
85#ifndef USE_WAYLAND
86 struct drm_data *dev;
87#else
88 struct wayland_data *dev;
89#endif
90
91 pthread_t threadid[MAX_NUM_THREADS];
92 struct render_thread_param threadparams[MAX_NUM_THREADS];
93
94#ifndef USE_WAYLAND
95 float fps;
96 int frame_num = 0;
97 unsigned long long starttime = 0;
98#endif
99
100 for(count = 0; count < argc; count++) {
101#ifndef USE_WAYLAND
102 if(strcmp(argv[count], "--connector") == 0)
103 if(count + 1 < argc)
104 CONNECTOR_ID = atoi(argv[count+1]);
105#endif
106
107 if (strcmp(argv[count], "--help") == 0)
108 print_usage(argv[0]);
109 }
110
111 srand(time(0));
112
113#ifndef USE_WAYLAND
114 dev = init_drm_gbm(CONNECTOR_ID);
115#else
116 dev = init_wayland_display();
117#endif
118 if(!dev) {
119 print_usage(argv[0]);
120 return -1;
121 }
122
123
124 for(count = 0; count < num_threads; count++) {
125#ifndef USE_WAYLAND
126 struct plane_data *pdata = get_new_surface(dev, count * FRAME_W, count * FRAME_H, FRAME_W, FRAME_H);
127#else
128 struct wayland_window_data *pdata = get_new_surface(dev, count * FRAME_W, count * FRAME_H, FRAME_W, FRAME_H);
129#endif
130 if(!pdata) {
131 break;
132 }
133#ifndef USE_WAYLAND
134 threadparams[count].dev = pdata->gbm_dev;
135 threadparams[count].surf = pdata->gbm_surf;
136#else
137 threadparams[count].dev = dev->display;
138 threadparams[count].surf = pdata->surf;
139#endif
140 threadparams[count].frame_width = FRAME_W;
141 threadparams[count].frame_height = FRAME_H;
142 threadparams[count].render_priv_setup = setup_kmscube;
143 threadparams[count].render_priv_render = render_kmscube;
144 }
145
146 printf("requested %d instances, rendering %d instances\n", num_threads, count);
147 num_threads = count;
148
149
150 /*
151 * Create the different GBM surfaces and start the draw threads
152 */
153
154 for(count = 0; count < num_threads; count++) {
155
156 int ret = setup_render_thread(&threadparams[count]);
157 if(ret != 0) {
158 printf("render_thread setup failed\n");
159 return -1;
160 }
161 }
162
163 for(count = 0; count < num_threads; count++) {
164 start_render_thread(&threadparams[count]);
165 }
166
167
168#ifndef USE_WAYLAND
169 starttime = __gettime();
170#endif
171
172 while(1) {
173
174 update_all_surfaces(dev);
175
176#ifndef USE_WAYLAND
177 unsigned long long __time;
178 frame_num++;
179 if(frame_num == 60) {
180 __time = __gettime();
181 fps = (60.0 * 1000000000) / (__time - starttime);
182 frame_num = 0;
183 starttime = __time;
184 printf("FPS = %f\n", fps);
185
186 }
187#endif
188
189 }
190
191}
192
diff --git a/egl-multi-thread/render_thread.c b/egl-multi-thread/render_thread.c
new file mode 100644
index 0000000..fd580a8
--- /dev/null
+++ b/egl-multi-thread/render_thread.c
@@ -0,0 +1,98 @@
1#include <stdio.h>
2#include <pthread.h>
3
4#include <EGL/egl.h>
5
6#include "render_thread.h"
7
8int setup_render_thread (struct render_thread_param *prm)
9{
10 EGLConfig config;
11 EGLint major, minor, n;
12 int ret;
13
14 EGLint context_attribs[] = {
15 EGL_CONTEXT_CLIENT_VERSION, 2,
16 EGL_NONE
17 };
18
19 EGLint config_attribs[] = {
20 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
21 EGL_RED_SIZE, 1,
22 EGL_GREEN_SIZE, 1,
23 EGL_BLUE_SIZE, 1,
24 EGL_ALPHA_SIZE, 0,
25 EGL_DEPTH_SIZE, 8,
26 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
27 EGL_NONE
28 };
29
30 prm->display = eglGetDisplay((EGLNativeDisplayType)prm->dev);
31
32 if (!eglInitialize(prm->display, &major, &minor)) {
33 printf("failed to initialize\n");
34 return -1;
35 }
36
37 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
38 printf("failed to bind api EGL_OPENGL_ES_API\n");
39 return -1;
40 }
41
42 if (!eglChooseConfig(prm->display, config_attribs, &config, 1, &n) || n != 1) {
43 printf("failed to choose config: %d\n", n);
44 return -1;
45 }
46
47 prm->context = eglCreateContext(prm->display, config,
48 EGL_NO_CONTEXT, context_attribs);
49 if (prm->context == NULL) {
50 printf("failed to create context\n");
51 return -1;
52 }
53
54 prm->surface = eglCreateWindowSurface(prm->display, config, prm->surf, NULL);
55 if (prm->surface == EGL_NO_SURFACE) {
56 printf("failed to create egl surface\n");
57 return -1;
58 }
59
60 eglMakeCurrent(prm->display, prm->surface, prm->surface, prm->context);
61
62 prm->render_priv_data = prm->render_priv_setup(prm);
63 if(!prm->render_priv_data) {
64 printf("failed to setup renderpriv\n");
65 return -1;
66 }
67
68 eglMakeCurrent(prm->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
69
70 return 0;
71}
72
73static void *render_thread (void *arg)
74{
75 struct render_thread_param *prm = arg;
76
77 eglMakeCurrent(prm->display, prm->surface, prm->surface, prm->context);
78
79 while(1) {
80 int ret = prm->render_priv_render(prm->render_priv_data);
81
82 if(ret != 0)
83 printf("renderpriv render returned %d\n", ret);
84
85 eglSwapBuffers(prm->display, prm->surface);
86
87 }
88}
89
90pthread_t start_render_thread (struct render_thread_param *prm)
91{
92 pthread_t threadid;
93
94 int ret = pthread_create(&threadid, NULL, render_thread, prm);
95
96 return ret == 0 ? threadid : -1;
97}
98
diff --git a/egl-multi-thread/render_thread.h b/egl-multi-thread/render_thread.h
new file mode 100644
index 0000000..4b8561f
--- /dev/null
+++ b/egl-multi-thread/render_thread.h
@@ -0,0 +1,29 @@
1#ifndef __RENDER_THREAD__
2#define __RENDER_THREAD__
3
4#include <EGL/egl.h>
5#include <gbm/gbm.h>
6#include <pthread.h>
7
8struct render_thread_param {
9 struct gbm_device *dev;
10 struct gbm_surface *surf;
11 EGLDisplay display;
12 EGLContext context;
13 EGLSurface surface;
14
15
16 unsigned int frame_width;
17 unsigned int frame_height;
18
19 void *render_priv_data;
20 void *(*render_priv_setup) (struct render_thread_param *prm);
21 int (*render_priv_render) (void *priv);
22
23};
24
25int setup_render_thread (struct render_thread_param *prm);
26
27pthread_t start_render_thread (struct render_thread_param *prm);
28
29#endif /*__RENDER_THREAD__*/
diff --git a/egl-multi-thread/wayland-window.c b/egl-multi-thread/wayland-window.c
new file mode 100644
index 0000000..c578259
--- /dev/null
+++ b/egl-multi-thread/wayland-window.c
@@ -0,0 +1,90 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <stdint.h>
4
5#include <wayland-client.h>
6#include <wayland-egl.h>
7
8#include "wayland_window.h"
9
10static void
11registry_handle_global(void *data, struct wl_registry *registry,
12 uint32_t name, const char *interface, uint32_t version)
13{
14 struct wayland_data *d = data;
15
16 if (strcmp(interface, "wl_compositor") == 0) {
17 d->compositor =
18 wl_registry_bind(registry, name,
19 &wl_compositor_interface, 1);
20 } else if (strcmp(interface, "wl_shell") == 0) {
21 d->shell = wl_registry_bind(registry, name,
22 &wl_shell_interface, 1);
23 }
24}
25
26static void
27registry_handle_global_remove(void *data, struct wl_registry *registry,
28 uint32_t name)
29{
30}
31
32static const struct wl_registry_listener registry_listener = {
33 registry_handle_global,
34 registry_handle_global_remove
35};
36
37
38struct wayland_window_data *get_new_surface(struct wayland_data *wayland, int posx, int posy, int width, int height)
39{
40 struct wayland_window_data *window = calloc(sizeof(struct wayland_window_data), 1);
41 if(!window) {
42 printf("wayland window data alloc failed\n");
43 return NULL;
44 }
45
46 struct wl_surface *surface = wl_compositor_create_surface(wayland->compositor);
47 struct wl_shell_surface *shell_surface = wl_shell_get_shell_surface(wayland->shell, surface);
48
49 wl_shell_surface_set_toplevel(shell_surface);
50
51 struct wl_egl_window *egl_window = wl_egl_window_create(surface,
52 width, height);
53
54 window->surf = egl_window;
55
56 return window;
57}
58
59
60struct wayland_data *init_wayland_display () {
61 struct wayland_data *wayland = calloc(sizeof(struct wayland_data), 1);
62 if(!wayland) {
63 printf("wayland data alloc failed\n");
64 return NULL;
65 }
66
67 wayland->display = wl_display_connect(NULL);
68 if(!wayland->display) {
69 free(wayland);
70 printf("wl_display_connect failed\n");
71 return NULL;
72 }
73
74 wayland->registry = wl_display_get_registry(wayland->display);
75 wl_registry_add_listener(wayland->registry,
76 &registry_listener, wayland);
77 wl_display_dispatch(wayland->display);
78
79 while(1) {
80 if(wayland->compositor && wayland->shell)
81 break;
82 wl_display_roundtrip(wayland->display);
83 }
84
85 return wayland;
86
87}
88
89int update_all_surfaces(struct wayland_data *wayland) {
90}
diff --git a/egl-multi-thread/wayland_window.h b/egl-multi-thread/wayland_window.h
new file mode 100644
index 0000000..b59862a
--- /dev/null
+++ b/egl-multi-thread/wayland_window.h
@@ -0,0 +1,22 @@
1#ifndef __WAYLAND_WINDOW_H__
2#define __WAYLAND_WINDOW_H__
3
4#include <wayland-client.h>
5#include <wayland-egl.h>
6
7struct wayland_data {
8 struct wl_display *display;
9 struct wl_registry *registry;
10 struct wl_compositor *compositor;
11 struct wl_shell *shell;
12};
13
14struct wayland_window_data {
15 struct wl_egl_window *surf;
16};
17
18struct wayland_data *init_wayland_display (void);
19struct wayland_window_data *get_new_surface(struct wayland_data *wayland, int posx, int posy, int width, int height);
20int update_all_surfaces(struct wayland_data *drm);
21
22#endif /*__WAYLAND_WINDOW_H__*/