|
1 // Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // Implementation of guest egl context |
|
15 |
|
16 #include <e32debug.h> |
|
17 #include "eglapi.h" |
|
18 |
|
19 |
|
20 |
|
21 // factory function |
|
22 CEglContext* CEglContext::Create(TEglThreadState& aThreadState, EGLDisplay aDisplay, EGLConfig aConfig, CEglContext* aShareContext, const EGLint* aAttribList) |
|
23 { |
|
24 // ToDo validate aConfig |
|
25 // ToDo validate aShareContext |
|
26 |
|
27 // which Khronos Graphics API is the Context for: Open GL ES, Open VG, ... |
|
28 EGLenum api = aThreadState.EglBoundApi(); |
|
29 // (in case supported APIs ever change) ensure the current API is valid |
|
30 if (api == EGL_NONE) |
|
31 { |
|
32 aThreadState.SetEglError(EGL_BAD_MATCH); |
|
33 return EGL_NO_CONTEXT; |
|
34 } |
|
35 |
|
36 EGLint glesClientVersion = 1; |
|
37 // validate AttribList parameter |
|
38 if ( aAttribList && (*aAttribList != EGL_NONE) ) |
|
39 { |
|
40 TBool attribsOkay = EFalse; |
|
41 // As of EGL 1.4 only Open GL ES api supports any attributes for eglCreateContext |
|
42 if (api == EGL_OPENGL_ES_API) |
|
43 { |
|
44 // only supported attribute for Open GL ES is EGL_CONTEXT_CLIENT_VERSION |
|
45 if ( (aAttribList[0] == EGL_CONTEXT_CLIENT_VERSION) && (aAttribList[2] == EGL_NONE) ) |
|
46 { |
|
47 glesClientVersion = aAttribList[1]; |
|
48 // modify this code when GL ES 2 support is added |
|
49 if (glesClientVersion == 1) |
|
50 { |
|
51 attribsOkay = ETrue; |
|
52 } |
|
53 } |
|
54 } |
|
55 if (!attribsOkay) |
|
56 { |
|
57 aThreadState.SetEglError(EGL_BAD_PARAMETER); |
|
58 return EGL_NO_CONTEXT; |
|
59 } |
|
60 } |
|
61 |
|
62 // ToDo validate that aConfig supports this API (inc GL ES v2 versus v1) |
|
63 EGLContext shareContextFamily = EGL_NO_CONTEXT; |
|
64 if (aShareContext) |
|
65 { |
|
66 shareContextFamily = aShareContext->ShareContextFamily(); |
|
67 } |
|
68 RHeap* threadHeap = CVghwUtils::SwitchToVghwHeap(); |
|
69 CEglContext* self = new CEglContext(aDisplay, aConfig, shareContextFamily, api, glesClientVersion); |
|
70 if (self == EGL_NO_CONTEXT) |
|
71 { |
|
72 aThreadState.SetEglError(EGL_BAD_ALLOC); |
|
73 } |
|
74 else |
|
75 { |
|
76 // call Host EGL, & set iHostContext |
|
77 RemoteFunctionCallData rfcdata; EglRFC eglApiData( rfcdata ); |
|
78 eglApiData.Init(EglRFC::EeglCreateContext); |
|
79 eglApiData.AppendEGLDisplay(aDisplay); |
|
80 eglApiData.AppendEGLConfig(aConfig); |
|
81 eglApiData.AppendEGLContext(aShareContext ? aShareContext->HostContext() : EGL_NO_CONTEXT); |
|
82 eglApiData.AppendEGLintVector(aAttribList, TAttribUtils::AttribListLength(aAttribList)); |
|
83 self->iHostContext = aThreadState.ExecEglContextCmd(eglApiData); |
|
84 if (self->iHostContext == EGL_NO_CONTEXT) |
|
85 { // Host EGL error |
|
86 delete self; |
|
87 self = EGL_NO_CONTEXT; |
|
88 } |
|
89 } |
|
90 CVghwUtils::SwitchFromVghwHeap(threadHeap); |
|
91 return self; |
|
92 } |
|
93 |
|
94 |
|
95 CEglContext::CEglContext(EGLDisplay aDisplay, EGLConfig aConfig, EGLContext aShareContextFamily, EGLenum aRenderingApi, |
|
96 EGLint aGlesClientVersion) : |
|
97 iFirstUse(ETrue), iHostContext(EGL_NO_CONTEXT), iDisplay(aDisplay), iShareContextFamily(aShareContextFamily), |
|
98 iConfigId(aConfig), iRenderingApi(aRenderingApi), iDrawSurface(EGL_NO_SURFACE), iReadSurface(EGL_NO_SURFACE), |
|
99 iGlesClientVersion(aGlesClientVersion), iIsDestroyed(EFalse) |
|
100 { |
|
101 iCtxMutex.CreateLocal(EOwnerProcess); |
|
102 } |
|
103 |
|
104 |
|
105 void CEglContext::Delete(TEglThreadState& aThreadState) |
|
106 { |
|
107 EGLPANIC_ASSERT_DEBUG(iCtxMutex.IsHeld(), EEglPanicTemp); |
|
108 |
|
109 // tell Host EGL to destroy the Context now |
|
110 RemoteFunctionCallData rfcdata; EglRFC eglApiData( rfcdata ); |
|
111 eglApiData.Init(EglRFC::EeglDestroyContext); |
|
112 eglApiData.AppendEGLDisplay(iDisplay); |
|
113 eglApiData.AppendEGLContext(iHostContext); |
|
114 EGLBoolean hostResult = aThreadState.ExecEglBooleanCmd(eglApiData); |
|
115 EGLPANIC_ASSERT_DEBUG(hostResult, EEglPanicTemp); |
|
116 |
|
117 // free |
|
118 iCtxMutex.Close(); |
|
119 RHeap* threadHeap = CVghwUtils::SwitchToVghwHeap(); |
|
120 delete this; |
|
121 CVghwUtils::SwitchFromVghwHeap(threadHeap); |
|
122 } |
|
123 |
|
124 |
|
125 CEglContext::~CEglContext() |
|
126 { |
|
127 if (iCtxMutex.Handle()) |
|
128 { |
|
129 iCtxMutex.Close(); |
|
130 } |
|
131 } |
|
132 |
|
133 |
|
134 EGLBoolean CEglContext::MakeCurrent(TEglThreadState& aThreadState, EGLSurface aDraw, EGLSurface aRead) |
|
135 { |
|
136 // ToDo support different number spaces for Host & Client EGL Surfaces |
|
137 EGLBoolean hostResult = EGL_FALSE; |
|
138 EGLint error = EGL_SUCCESS; |
|
139 iCtxMutex.Wait(); |
|
140 if (iIsDestroyed) |
|
141 { |
|
142 error = EGL_BAD_CONTEXT; |
|
143 } |
|
144 else |
|
145 { |
|
146 // ToDo validate aDraw & aRead are compatible with API |
|
147 RemoteFunctionCallData rfcdata; EglRFC eglApiData( rfcdata ); |
|
148 eglApiData.Init( EglRFC::EeglMakeCurrent ); |
|
149 eglApiData.AppendEGLDisplay(iDisplay); |
|
150 eglApiData.AppendEGLSurface(aDraw); |
|
151 eglApiData.AppendEGLSurface(aRead); |
|
152 eglApiData.AppendEGLContext(iHostContext); |
|
153 hostResult = aThreadState.ExecEglBooleanCmd(eglApiData); |
|
154 if (hostResult) |
|
155 { |
|
156 iDrawSurface = aDraw; |
|
157 iReadSurface = aRead; |
|
158 } |
|
159 } |
|
160 iCtxMutex.Signal(); |
|
161 if (error != EGL_SUCCESS) |
|
162 { // error in parameter checks |
|
163 aThreadState.SetEglError(error); |
|
164 } |
|
165 return hostResult; |
|
166 } |
|
167 |
|
168 |
|
169 TBool CEglContext::Destroy(TEglThreadState& aThreadState) |
|
170 { |
|
171 iCtxMutex.Wait(); |
|
172 iIsDestroyed = ETrue; |
|
173 if ( (iDrawSurface == EGL_NO_SURFACE) && (iReadSurface == EGL_NO_SURFACE) ) |
|
174 { // Context not in use |
|
175 Delete(aThreadState); |
|
176 return ETrue; |
|
177 } |
|
178 iCtxMutex.Signal(); |
|
179 return EFalse; |
|
180 } |
|
181 |
|
182 |
|
183 TBool CEglContext::MakeNotCurrent(TEglThreadState& aThreadState) |
|
184 { |
|
185 iCtxMutex.Wait(); |
|
186 iDrawSurface = EGL_NO_SURFACE; |
|
187 iReadSurface = EGL_NO_SURFACE; |
|
188 |
|
189 if (iIsDestroyed) |
|
190 { // Destroyed & no longer in use |
|
191 Delete(aThreadState); |
|
192 return ETrue; |
|
193 } |
|
194 iCtxMutex.Signal(); |
|
195 return EFalse; |
|
196 } |
|
197 |
|
198 |
|
199 EGLContext CEglContext::ShareContextFamily() |
|
200 { |
|
201 EGLContext result = EGL_NO_CONTEXT; |
|
202 // ToDo review - maybe just check Mutex is held |
|
203 iCtxMutex.Wait(); |
|
204 if (!iIsDestroyed) |
|
205 { |
|
206 if (iShareContextFamily) |
|
207 { |
|
208 result = iShareContextFamily; |
|
209 } |
|
210 else |
|
211 { |
|
212 result = iHostContext; |
|
213 } |
|
214 } |
|
215 iCtxMutex.Signal(); |
|
216 return result; |
|
217 } |
|
218 |
|
219 // Valid attributes are: EGL_CONFIG_ID, EGL_CONTEXT_CLIENT_TYPE, EGL_CONTEXT_CLIENT_VERSION, or EGL_RENDER_BUFFER |
|
220 EGLBoolean CEglContext::QueryAttribute(TEglThreadState& aThreadState, EGLint aAttribute, EGLint* aValue) |
|
221 { |
|
222 EGLint error = EGL_SUCCESS; |
|
223 iCtxMutex.Wait(); |
|
224 if (iIsDestroyed) |
|
225 { |
|
226 error = EGL_BAD_CONTEXT; |
|
227 } |
|
228 else |
|
229 { |
|
230 switch (aAttribute) |
|
231 { |
|
232 case EGL_CONFIG_ID: |
|
233 *aValue = iConfigId; |
|
234 break; |
|
235 |
|
236 case EGL_CONTEXT_CLIENT_TYPE: |
|
237 *aValue = iRenderingApi; |
|
238 break; |
|
239 |
|
240 case EGL_CONTEXT_CLIENT_VERSION: |
|
241 *aValue = iGlesClientVersion; |
|
242 break; |
|
243 |
|
244 case EGL_RENDER_BUFFER: |
|
245 if (iDrawSurface == NULL) |
|
246 { // context is not bound to any surface |
|
247 *aValue = EGL_NONE; |
|
248 } |
|
249 else |
|
250 // ToDo check the currently bound surface type to answer this |
|
251 { |
|
252 RemoteFunctionCallData rfcdata; EglRFC eglApiData( rfcdata ); |
|
253 eglApiData.Init(EglRFC::EeglQueryContext); |
|
254 eglApiData.AppendEGLDisplay(iDisplay); |
|
255 eglApiData.AppendEGLContext(iHostContext); |
|
256 eglApiData.AppendEGLint(aAttribute); |
|
257 eglApiData.AppendEGLintVector(aValue, 1, RemoteFunctionCallData::EOut); |
|
258 EGLBoolean hostResult = aThreadState.ExecEglBooleanCmd(eglApiData); |
|
259 return hostResult; |
|
260 } |
|
261 break; |
|
262 |
|
263 default: |
|
264 error = EGL_BAD_ATTRIBUTE; |
|
265 break; |
|
266 } |
|
267 // Debug compare with Host EGL result |
|
268 #ifdef _DEBUG |
|
269 EGLint hostValue = 0; |
|
270 RemoteFunctionCallData rfcdata; EglRFC eglApiData( rfcdata ); |
|
271 eglApiData.Init(EglRFC::EeglQueryContext); |
|
272 eglApiData.AppendEGLDisplay(iDisplay); |
|
273 eglApiData.AppendEGLContext(iHostContext); |
|
274 eglApiData.AppendEGLint(aAttribute); |
|
275 eglApiData.AppendEGLintVector(&hostValue, 1, RemoteFunctionCallData::EOut); |
|
276 EGLBoolean hostResult = aThreadState.ExecEglBooleanCmd(eglApiData); |
|
277 if (error == EGL_SUCCESS) |
|
278 { // Host EGl result should match ours |
|
279 EGLPANIC_ASSERT(hostResult, EEglPanicTemp); |
|
280 EGLPANIC_ASSERT(hostValue == *aValue, EEglPanicTemp); |
|
281 } |
|
282 else |
|
283 { |
|
284 EGLPANIC_ASSERT(!hostResult, EEglPanicTemp); |
|
285 } |
|
286 #endif |
|
287 } |
|
288 aThreadState.SetEglError(error); |
|
289 iCtxMutex.Signal(); |
|
290 return (error == EGL_SUCCESS); |
|
291 } |
|
292 |
|
293 // end of file eglcontext.cpp |