tizen 2.4 release
[sdk/emulator-yagl.git] / EGL / yagl_egl_state.c
1 /*
2  * YaGL
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact :
7  * Stanislav Vorobiov <s.vorobiov@samsung.com>
8  * Jinhyung Jo <jinhyung.jo@samsung.com>
9  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27  * THE SOFTWARE.
28  *
29  * Contributors:
30  * - S-Core Co., Ltd
31  *
32  */
33
34 #include "yagl_egl_state.h"
35 #include "yagl_context.h"
36 #include "yagl_surface.h"
37 #include "yagl_log.h"
38 #include "yagl_malloc.h"
39 #include "yagl_client_interface.h"
40 #include "yagl_client_context.h"
41 #include <pthread.h>
42 #include <dlfcn.h>
43
44 struct yagl_egl_state
45 {
46     EGLint error;
47
48     EGLenum api;
49
50     struct yagl_context *ctx;
51     struct yagl_surface *draw_sfc;
52     struct yagl_surface *read_sfc;
53
54     struct yagl_client_interface *gles1_iface;
55     struct yagl_client_interface *gles2_iface;
56 };
57
58 static pthread_key_t g_state_key;
59 static pthread_once_t g_state_key_init = PTHREAD_ONCE_INIT;
60
61 void *yagl_get_gles1_sym(const char *name)
62 {
63     void *handle;
64     void *sym = dlsym(NULL, name);
65
66     if (sym) {
67         return sym;
68     }
69
70     handle = dlopen("libGLESv1_CM.so.1", RTLD_NOW|RTLD_GLOBAL);
71     if (!handle) {
72         handle = dlopen("libGLESv1_CM.so", RTLD_NOW|RTLD_GLOBAL);
73     }
74
75     if (handle) {
76         return dlsym(handle, name);
77     }
78
79     return NULL;
80 }
81
82 void *yagl_get_gles2_sym(const char *name)
83 {
84     void *handle;
85     void *sym = NULL;
86
87     handle = dlopen("libGLESv2.so.1", RTLD_NOW|RTLD_GLOBAL);
88     if (!handle) {
89         handle = dlopen("libGLESv2.so", RTLD_NOW|RTLD_GLOBAL);
90     }
91
92     if (handle) {
93         sym = dlsym(handle, name);
94     }
95
96     if (!sym) {
97         sym = dlsym(NULL, name);
98     }
99
100     return sym;
101 }
102
103 static void yagl_egl_state_free(void* ptr)
104 {
105     struct yagl_egl_state *state = ptr;
106
107     YAGL_LOG_FUNC_ENTER(yagl_egl_state_free, "%p", ptr);
108
109     if (!ptr) {
110         return;
111     }
112
113     yagl_surface_release(state->read_sfc);
114     yagl_surface_release(state->draw_sfc);
115     yagl_context_release(state->ctx);
116
117     yagl_free(state);
118
119     YAGL_LOG_FUNC_EXIT(NULL);
120 }
121
122 static void yagl_egl_state_key_init()
123 {
124     pthread_key_create(&g_state_key, yagl_egl_state_free);
125 }
126
127 static void yagl_egl_state_atfork()
128 {
129     struct yagl_egl_state *state;
130
131     /*
132      * See yagl_state.c:yagl_state_atfork.
133      */
134
135     pthread_once(&g_state_key_init, yagl_egl_state_key_init);
136
137     state = (struct yagl_egl_state*)pthread_getspecific(g_state_key);
138
139     if (state) {
140         yagl_free(state);
141     }
142
143     pthread_setspecific(g_state_key, NULL);
144 }
145
146 static void yagl_egl_state_init()
147 {
148     struct yagl_egl_state *state;
149
150     pthread_once(&g_state_key_init, yagl_egl_state_key_init);
151
152     if (pthread_getspecific(g_state_key)) {
153         return;
154     }
155
156     YAGL_LOG_FUNC_ENTER(yagl_egl_state_init, NULL);
157
158     state = yagl_malloc0(sizeof(struct yagl_egl_state));
159
160     state->error = EGL_SUCCESS;
161     state->api = EGL_OPENGL_ES_API;
162
163     pthread_setspecific(g_state_key, state);
164
165     pthread_atfork(NULL, NULL, &yagl_egl_state_atfork);
166
167     YAGL_LOG_FUNC_EXIT("%p", state);
168 }
169
170 static struct yagl_egl_state *yagl_egl_get_state()
171 {
172     yagl_egl_state_init();
173
174     return (struct yagl_egl_state*)pthread_getspecific(g_state_key);
175 }
176
177 EGLint yagl_get_error()
178 {
179     struct yagl_egl_state *state = yagl_egl_get_state();
180
181     EGLint error = state->error;
182
183     state->error = EGL_SUCCESS;
184
185     return error;
186 }
187
188 void yagl_set_error(EGLint error)
189 {
190     struct yagl_egl_state *state = yagl_egl_get_state();
191
192     if (state->error == EGL_SUCCESS) {
193         state->error = error;
194     }
195 }
196
197 EGLenum yagl_get_api()
198 {
199     struct yagl_egl_state *state = yagl_egl_get_state();
200
201     return state->api;
202 }
203
204 void yagl_set_api(EGLenum api)
205 {
206     struct yagl_egl_state *state = yagl_egl_get_state();
207
208     state->api = api;
209 }
210
211 struct yagl_context *yagl_get_context()
212 {
213     struct yagl_egl_state *state = yagl_egl_get_state();
214
215     return state->ctx;
216 }
217
218 struct yagl_surface *yagl_get_draw_surface()
219 {
220     struct yagl_egl_state *state = yagl_egl_get_state();
221
222     return state->draw_sfc;
223 }
224
225 struct yagl_surface *yagl_get_read_surface()
226 {
227     struct yagl_egl_state *state = yagl_egl_get_state();
228
229     return state->read_sfc;
230 }
231
232 int yagl_set_context(struct yagl_context *ctx,
233                      struct yagl_surface *draw_sfc,
234                      struct yagl_surface *read_sfc)
235 {
236     struct yagl_egl_state *state = yagl_egl_get_state();
237     int ctx_marked = 0, draw_sfc_marked = 0;
238
239     if (ctx && (state->ctx != ctx)) {
240         if (!yagl_context_mark_current(ctx, 1)) {
241             goto fail;
242         }
243         ctx_marked = 1;
244     }
245
246     if (draw_sfc && (state->draw_sfc != draw_sfc)) {
247         if (!yagl_surface_mark_current(draw_sfc, 1)) {
248             goto fail;
249         }
250         draw_sfc_marked = 1;
251     }
252
253     if (read_sfc &&
254         (state->read_sfc != read_sfc) &&
255         (read_sfc != draw_sfc) &&
256         !yagl_surface_mark_current(read_sfc, 1)) {
257         goto fail;
258     }
259
260     if (state->ctx && (state->ctx != ctx)) {
261         yagl_context_mark_current(state->ctx, 0);
262     }
263
264     if (state->draw_sfc && (state->draw_sfc != draw_sfc)) {
265         yagl_surface_mark_current(state->draw_sfc, 0);
266     }
267
268     if (state->read_sfc &&
269         (state->read_sfc != read_sfc) &&
270         (state->read_sfc != state->draw_sfc)) {
271         yagl_surface_mark_current(state->read_sfc, 0);
272     }
273
274     yagl_context_acquire(ctx);
275     yagl_surface_acquire(draw_sfc);
276     yagl_surface_acquire(read_sfc);
277
278     yagl_surface_release(state->read_sfc);
279     yagl_surface_release(state->draw_sfc);
280     yagl_context_release(state->ctx);
281
282     state->ctx = ctx;
283     state->read_sfc = read_sfc;
284     state->draw_sfc = draw_sfc;
285
286     return 1;
287
288 fail:
289     if (ctx_marked) {
290         yagl_context_mark_current(ctx, 0);
291     }
292     if (draw_sfc_marked) {
293         yagl_surface_mark_current(draw_sfc, 0);
294     }
295
296     return 0;
297 }
298
299 void yagl_reset_state()
300 {
301     struct yagl_egl_state *state = yagl_egl_get_state();
302
303     yagl_set_context(NULL, NULL, NULL);
304
305     state->error = EGL_SUCCESS;
306     state->api = EGL_OPENGL_ES_API;
307 }
308
309 struct yagl_client_context *yagl_get_client_context(void)
310 {
311     struct yagl_egl_state *state = yagl_egl_get_state();
312
313     return state->ctx ? state->ctx->client_ctx : NULL;
314 }
315
316 struct yagl_client_interface *yagl_get_client_interface(yagl_client_api client_api)
317 {
318     struct yagl_egl_state *state = yagl_egl_get_state();
319
320     switch (client_api) {
321     case yagl_client_api_gles1:
322         if (!state->gles1_iface) {
323             state->gles1_iface = yagl_get_gles1_sym("yagl_gles1_interface");
324         }
325         return state->gles1_iface;
326     case yagl_client_api_gles2:
327     case yagl_client_api_gles3:
328         if (!state->gles2_iface) {
329             state->gles2_iface = yagl_get_gles1_sym("yagl_gles2_interface");
330         }
331         return state->gles2_iface;
332     default:
333         return NULL;
334     }
335 }
336
337 struct yagl_client_interface *yagl_get_any_client_interface()
338 {
339     struct yagl_client_interface *iface;
340
341     iface = yagl_get_client_interface(yagl_client_api_gles2);
342     if (!iface) {
343         iface = yagl_get_client_interface(yagl_client_api_gles1);
344     }
345
346     return iface;
347 }