1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include "interface/khronos/common/khrn_int_common.h"
29
30#include "interface/khronos/glxx/glxx_client.h"
31#include "interface/khronos/vg/vg_client.h"
32#include "interface/khronos/common/khrn_client_rpc.h"
33
34#include "interface/khronos/egl/egl_client_context.h"
35#include "interface/khronos/egl/egl_client_surface.h"
36
37#ifdef RPC_DIRECT
38#include "interface/khronos/egl/egl_int_impl.h"
39#endif
40
41#include <string.h>
42#include <stdlib.h>
43
44EGLBoolean egl_context_check_attribs(const EGLint *attrib_list, EGLint max_version, EGLint *version)
45{
46 if (!attrib_list)
47 return EGL_TRUE;
48
49 while (1) {
50 switch (*attrib_list++) {
51 case EGL_CONTEXT_CLIENT_VERSION:
52 {
53 EGLint value = *attrib_list++;
54
55 if (value < 1 || value > max_version)
56 return EGL_FALSE;
57 else
58 *version = value;
59
60 break;
61 }
62 case EGL_NONE:
63 return EGL_TRUE;
64 default:
65 return EGL_FALSE;
66 }
67 }
68}
69
70EGL_CONTEXT_T *egl_context_create(EGL_CONTEXT_T *share_context, EGLContext name, EGLDisplay display, EGLConfig configname, EGL_CONTEXT_TYPE_T type)
71{
72 EGL_CONTEXT_T *context = (EGL_CONTEXT_T *)khrn_platform_malloc(sizeof(EGL_CONTEXT_T), "EGL_CONTEXT_T");
73 if (!context)
74 return 0;
75
76 context->name = name;
77 context->display = display;
78 context->configname = configname;
79
80 context->type = type;
81
82 context->renderbuffer = EGL_NONE;
83
84 context->is_current = false;
85 context->is_destroyed = false;
86
87 switch (type) {
88#ifndef NO_OPENVG
89 case OPENVG:
90 {
91 VG_CLIENT_SHARED_STATE_T *shared_state;
92 if (share_context) {
93 shared_state = ((VG_CLIENT_STATE_T *)share_context->state)->shared_state;
94 vg_client_shared_state_acquire(shared_state);
95 } else {
96 shared_state = vg_client_shared_state_alloc();
97 if (!shared_state) {
98 khrn_platform_free(context);
99 return 0;
100 }
101 }
102
103 context->state = vg_client_state_alloc(shared_state);
104 vg_client_shared_state_release(shared_state);
105 if (!context->state) {
106 khrn_platform_free(context);
107 return 0;
108 }
109
110 {
111 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
112 /* uint64_t pid = khronos_platform_get_process_id(); */ /* unused */
113 context->servercontext = RPC_UINT_RES(RPC_CALL2_RES(eglIntCreateVG_impl,
114 thread,
115 EGLINTCREATEVG_ID,
116 share_context ? share_context->servercontext : 0,
117 share_context ? share_context->type : OPENVG/*ignored*/));
118 }
119 if (!context->servercontext) {
120 vg_client_state_free((VG_CLIENT_STATE_T *)context->state);
121 khrn_platform_free(context);
122 return 0;
123 }
124
125 break;
126 }
127#endif /* NO_OPENVG */
128 case OPENGL_ES_11:
129 {
130 GLXX_CLIENT_STATE_T *state = (GLXX_CLIENT_STATE_T *)khrn_platform_malloc(sizeof(GLXX_CLIENT_STATE_T), "GLXX_CLIENT_STATE_T");
131 if (!state) {
132 khrn_platform_free(context);
133 return 0;
134 }
135
136 context->state = state;
137 if (gl11_client_state_init(state)) {
138 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
139 context->servercontext = RPC_UINT_RES(RPC_CALL2_RES(eglIntCreateGLES11_impl,
140 thread,
141 EGLINTCREATEGLES11_ID,
142 share_context ? share_context->servercontext : 0,
143 share_context ? share_context->type : OPENGL_ES_11/*ignored*/));
144 if (!context->servercontext) {
145 glxx_client_state_free(state);
146 khrn_platform_free(context);
147 return 0;
148 }
149 }
150 break;
151 }
152 case OPENGL_ES_20:
153 {
154 GLXX_CLIENT_STATE_T *state = (GLXX_CLIENT_STATE_T *)khrn_platform_malloc(sizeof(GLXX_CLIENT_STATE_T), "GLXX_CLIENT_STATE_T");
155 if (!state) {
156 khrn_platform_free(context);
157 return 0;
158 }
159
160 context->state = state;
161
162 if (gl20_client_state_init(state)) {
163 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
164 context->servercontext = RPC_UINT_RES(RPC_CALL2_RES(eglIntCreateGLES20_impl,
165 thread,
166 EGLINTCREATEGLES20_ID,
167 share_context ? share_context->servercontext : 0,
168 share_context ? share_context->type : OPENGL_ES_20/*ignored*/));
169 if (!context->servercontext) {
170 glxx_client_state_free(state);
171 khrn_platform_free(context);
172 return 0;
173 }
174 }
175 break;
176 }
177 default:
178 UNREACHABLE();
179 break;
180 }
181
182 return context;
183}
184
185void egl_context_term(EGL_CONTEXT_T *context)
186{
187 CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
188 /* If we're current then there should still be a reference to us */
189 /* (if this wasn't the case we should call egl_context_release_surfaces here) */
190 vcos_assert(!context->is_current);
191 vcos_assert(context->is_destroyed);
192
193 switch (context->type) {
194#ifndef NO_OPENVG
195 case OPENVG:
196 RPC_CALL1(eglIntDestroyVG_impl,
197 thread,
198 EGLINTDESTROYVG_ID,
199 RPC_UINT(context->servercontext));
200 RPC_FLUSH(thread);
201 vg_client_state_free((VG_CLIENT_STATE_T *)context->state);
202 break;
203#endif
204 case OPENGL_ES_11:
205 case OPENGL_ES_20:
206 RPC_CALL1(eglIntDestroyGL_impl,
207 thread,
208 EGLINTDESTROYGL_ID,
209 RPC_UINT(context->servercontext));
210 RPC_FLUSH(thread);
211 glxx_client_state_free((GLXX_CLIENT_STATE_T *)context->state);
212 break;
213 default:
214 UNREACHABLE();
215 }
216
217 context->state = 0;
218}
219
220EGLBoolean egl_context_get_attrib(EGL_CONTEXT_T *context, EGLint attrib, EGLint *value)
221{
222 switch (attrib) {
223 case EGL_CONFIG_ID:
224 *value = (int)(intptr_t)context->configname;
225 return EGL_TRUE;
226 case EGL_CONTEXT_CLIENT_TYPE:
227 switch (context->type) {
228 case OPENGL_ES_11:
229 case OPENGL_ES_20:
230 *value = EGL_OPENGL_ES_API;
231 break;
232 case OPENVG:
233 *value = EGL_OPENVG_API;
234 break;
235 default:
236 UNREACHABLE();
237 break;
238 }
239 return EGL_TRUE;
240 case EGL_CONTEXT_CLIENT_VERSION:
241 switch (context->type) {
242 case OPENGL_ES_11:
243 case OPENVG:
244 *value = 1;
245 break;
246 case OPENGL_ES_20:
247 *value = 2;
248 break;
249 default:
250 UNREACHABLE();
251 break;
252 }
253 return EGL_TRUE;
254 case EGL_RENDER_BUFFER:
255 {
256 /* TODO: GLES supposedly doesn't support single-buffered rendering. Should we take this into account? */
257 *value = context->renderbuffer;
258 return EGL_TRUE;
259 }
260 default:
261 return EGL_FALSE;
262 }
263}
264
265void egl_context_set_callbacks(EGL_CONTEXT_T *context,
266 void (*gl_render_callback)(void),
267 void (*gl_flush_callback)(bool),
268 void (*vg_render_callback)(void),
269 void (*vg_flush_callback)(bool))
270{
271 switch (context->type) {
272 case OPENGL_ES_11:
273 {
274 GLXX_CLIENT_STATE_T *state = (GLXX_CLIENT_STATE_T *)context->state;
275 state->render_callback = gl_render_callback;
276 state->flush_callback = gl_flush_callback;
277 break;
278 }
279 case OPENGL_ES_20:
280 {
281 GLXX_CLIENT_STATE_T *state = (GLXX_CLIENT_STATE_T *)context->state;
282 state->render_callback = gl_render_callback;
283 state->flush_callback = gl_flush_callback;
284 break;
285 }
286 case OPENVG:
287 {
288 VG_CLIENT_STATE_T *state = (VG_CLIENT_STATE_T *)context->state;
289 state->render_callback = vg_render_callback;
290 state->flush_callback = vg_flush_callback;
291 break;
292 }
293 default:
294 UNREACHABLE();
295 }
296}
297
298
299/*
300 void egl_context_maybe_free(EGL_CONTEXT_T *context)
301
302 Frees a map together with its server-side resources if:
303 - it has been destroyed
304 - it is no longer current
305
306 Implementation notes:
307
308 -
309
310 Preconditions:
311
312 context is a valid pointer
313
314 Postconditions:
315
316 Either:
317 - context->is_destroyed is false (we don't change this), or
318 - context->is_current is true, or
319 - context has been deleted.
320
321 Invariants preserved:
322
323 -
324
325 Invariants used:
326
327 -
328 */
329void egl_context_maybe_free(EGL_CONTEXT_T *context)
330{
331 vcos_assert(context);
332
333 if (!context->is_destroyed)
334 return;
335
336 if (context->is_current)
337 return;
338
339 egl_context_term(context);
340 khrn_platform_free(context);
341}
342