diff options
author | Subhajit Paul | 2018-04-10 10:54:09 -0500 |
---|---|---|
committer | Anand Balagopalakrishnan | 2018-04-10 10:54:09 -0500 |
commit | e10d670007282a1720bc9c71a5eddb182275b9a3 (patch) | |
tree | 64aedca10f1ebf2a1d3a07a4f6f8cce7d78c73c9 | |
parent | 02f22a883871663a573dad1bb736e0a9dc2df9cd (diff) | |
download | gfx-apps-master.tar.gz gfx-apps-master.tar.xz gfx-apps-master.zip |
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/Makefile | 46 | ||||
-rw-r--r-- | egl-multi-thread/README | 18 | ||||
-rw-r--r-- | egl-multi-thread/drm_gbm.c | 315 | ||||
-rw-r--r-- | egl-multi-thread/drm_gbm.h | 31 | ||||
-rw-r--r-- | egl-multi-thread/esTransform.c | 235 | ||||
-rw-r--r-- | egl-multi-thread/esUtil.h | 303 | ||||
-rw-r--r-- | egl-multi-thread/gl_kmscube.c | 368 | ||||
-rw-r--r-- | egl-multi-thread/gl_kmscube.h | 9 | ||||
-rw-r--r-- | egl-multi-thread/main.c | 192 | ||||
-rw-r--r-- | egl-multi-thread/render_thread.c | 98 | ||||
-rw-r--r-- | egl-multi-thread/render_thread.h | 29 | ||||
-rw-r--r-- | egl-multi-thread/wayland-window.c | 90 | ||||
-rw-r--r-- | egl-multi-thread/wayland_window.h | 22 |
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 | ||
4 | CROSS_COMPILE=arm-linux-gnueabihf- | ||
5 | |||
6 | ## No need to change below this | ||
7 | |||
8 | COMMON_INCLUDES = -I$(FSDIR)/usr/include | ||
9 | COMMON_LFLAGS = -L$(FSDIR)/usr/lib -Wl,--rpath-link,$(FSDIR)/usr/lib | ||
10 | |||
11 | PLAT_CPP = $(CROSS_COMPILE)gcc | ||
12 | |||
13 | PLAT_CFLAGS = $(COMMON_INCLUDES) -g | ||
14 | PLAT_LINK = $(COMMON_LFLAGS) -lEGL -lGLESv2 -ludev -lpthread -lm -lrt | ||
15 | |||
16 | SRCNAME = esTransform.c \ | ||
17 | gl_kmscube.c \ | ||
18 | main.c \ | ||
19 | render_thread.c \ | ||
20 | |||
21 | BASE_OUTNAME = egl_multi_layer | ||
22 | |||
23 | ifeq ($(BUILD_WAYLAND), yes) | ||
24 | SRCNAME += wayland-window.c \ | ||
25 | |||
26 | PLAT_CFLAGS += -DUSE_WAYLAND | ||
27 | PLAT_LINK += -lwayland-client -lpvr_wlegl | ||
28 | OUTNAME = $(BASE_OUTNAME)_wayland | ||
29 | else | ||
30 | SRCNAME += drm_gbm.c \ | ||
31 | |||
32 | PLAT_CFLAGS += -I$(FSDIR)/usr/include/libdrm -I$(FSDIR)/usr/include/gbm | ||
33 | PLAT_LINK += -lgbm -ldrm | ||
34 | OUTNAME = $(BASE_OUTNAME)_drm | ||
35 | endif | ||
36 | |||
37 | OBJECTS = $(SRCNAME:.c=.o) | ||
38 | |||
39 | $(OUTNAME): $(SRCNAME) | ||
40 | $(PLAT_CPP) -o $@ $^ $(PLAT_CFLAGS) $(LINK) $(PLAT_LINK) | ||
41 | |||
42 | install: | ||
43 | cp $(OUTNAME) $(FSDIR)/home/root | ||
44 | |||
45 | clean: | ||
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 | ************** | ||
2 | Build 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 | ||
9 | export PATH=<4.9_CROSS_COMPILER>/bin:$PATH | ||
10 | export 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 | |||
15 | make | ||
16 | sudo -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 | |||
16 | struct 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 | |||
31 | struct drm_fb { | ||
32 | struct gbm_bo *bo; | ||
33 | uint32_t fb_id; | ||
34 | int dmabuf_fd; | ||
35 | int fd; | ||
36 | }; | ||
37 | |||
38 | static void | ||
39 | drm_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 | |||
50 | static 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 | |||
81 | static 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 | |||
90 | struct 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 | |||
185 | struct 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 | |||
220 | int 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 | |||
6 | struct 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 | |||
25 | struct drm_data; | ||
26 | |||
27 | struct drm_data *init_drm_gbm (int conn_id); | ||
28 | struct plane_data *get_new_surface(struct drm_data *drm, int posx, int posy, int width, int height); | ||
29 | int 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 | |||
49 | void ESUTIL_API | ||
50 | esScale(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 | |||
68 | void ESUTIL_API | ||
69 | esTranslate(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 | |||
77 | void ESUTIL_API | ||
78 | esRotate(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 | |||
130 | void ESUTIL_API | ||
131 | esFrustum(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 | |||
160 | void ESUTIL_API | ||
161 | esPerspective(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 | |||
171 | void ESUTIL_API | ||
172 | esOrtho(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 | |||
194 | void ESUTIL_API | ||
195 | esMatrixMultiply(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 | |||
226 | void ESUTIL_API | ||
227 | esMatrixLoadIdentity(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 | |||
50 | extern "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 | |||
84 | typedef struct | ||
85 | { | ||
86 | GLfloat m[4][4]; | ||
87 | } ESMatrix; | ||
88 | |||
89 | typedef 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 | // | ||
128 | void 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 | ||
143 | GLboolean 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 | // | ||
149 | void 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 | // | ||
156 | void 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 | // | ||
163 | void 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 | // | ||
170 | void 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 | // | ||
176 | void 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 | // | ||
185 | GLuint 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 | // | ||
195 | GLuint 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 | // | ||
209 | int 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 | // | ||
223 | int 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 | // | ||
233 | char* 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 | // | ||
241 | void 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 | // | ||
248 | void 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 | // | ||
256 | void 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 | // | ||
265 | void 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 | // | ||
275 | void 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 | // | ||
284 | void 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 | // | ||
291 | void ESUTIL_API esMatrixMultiply(ESMatrix *result, ESMatrix *srcA, ESMatrix *srcB); | ||
292 | |||
293 | // | ||
294 | //// \brief return an indentity matrix | ||
295 | //// \param result returns identity matrix | ||
296 | // | ||
297 | void 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 | |||
9 | static 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 | |||
42 | static 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 | |||
75 | static 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 | |||
108 | static 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 | |||
132 | static 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 | |||
142 | struct 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 | */ | ||
173 | void *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 | */ | ||
294 | int 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 | |||
6 | void *setup_kmscube (struct render_thread_param *prm); | ||
7 | int 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 | ||
16 | int CONNECTOR_ID = (24); | ||
17 | #endif | ||
18 | |||
19 | #define FRAME_W (960) | ||
20 | #define FRAME_H (540) | ||
21 | |||
22 | #define MAX_NUM_THREADS (8) | ||
23 | |||
24 | int num_threads = 3; | ||
25 | |||
26 | #ifndef USE_WAYLAND | ||
27 | static 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 | |||
34 | static 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 | |||
41 | unsigned 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 | |||
48 | unsigned 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 | ||
57 | void 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 | ||
74 | void print_usage(char *app) | ||
75 | { | ||
76 | printf("./%s\n", app); | ||
77 | } | ||
78 | #endif | ||
79 | |||
80 | int 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 | |||
8 | int 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 | |||
73 | static 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 | |||
90 | pthread_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 | |||
8 | struct 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 | |||
25 | int setup_render_thread (struct render_thread_param *prm); | ||
26 | |||
27 | pthread_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 | |||
10 | static void | ||
11 | registry_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 | |||
26 | static void | ||
27 | registry_handle_global_remove(void *data, struct wl_registry *registry, | ||
28 | uint32_t name) | ||
29 | { | ||
30 | } | ||
31 | |||
32 | static const struct wl_registry_listener registry_listener = { | ||
33 | registry_handle_global, | ||
34 | registry_handle_global_remove | ||
35 | }; | ||
36 | |||
37 | |||
38 | struct 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 | |||
60 | struct 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 | ®istry_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 | |||
89 | int 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 | |||
7 | struct wayland_data { | ||
8 | struct wl_display *display; | ||
9 | struct wl_registry *registry; | ||
10 | struct wl_compositor *compositor; | ||
11 | struct wl_shell *shell; | ||
12 | }; | ||
13 | |||
14 | struct wayland_window_data { | ||
15 | struct wl_egl_window *surf; | ||
16 | }; | ||
17 | |||
18 | struct wayland_data *init_wayland_display (void); | ||
19 | struct wayland_window_data *get_new_surface(struct wayland_data *wayland, int posx, int posy, int width, int height); | ||
20 | int update_all_surfaces(struct wayland_data *drm); | ||
21 | |||
22 | #endif /*__WAYLAND_WINDOW_H__*/ | ||