1 | /* |
2 | Copyright (c) 2012, Broadcom Europe Ltd |
3 | All rights reserved. |
4 | |
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, 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 | |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | ON 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 |
25 | SOFTWARE, 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 | |
44 | EGLBoolean 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 | |
70 | EGL_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 | |
185 | void 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 | |
220 | EGLBoolean 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 | |
265 | void 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 | */ |
329 | void 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 | |