|
1 /* |
|
2 * Copyright (c) 2006-2008 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: OpenVG 1.0 render surface implementation. |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 #include "HuiVg10RenderSurface.h" |
|
21 #include "HuiVg10RenderPlugin.h" |
|
22 #include "uiacceltk/HuiSegmentedTexture.h" |
|
23 #include "uiacceltk/HuiDisplay.h" |
|
24 #include "uiacceltk/HuiStatic.h" |
|
25 #include "uiacceltk/HuiUtil.h" |
|
26 #include <coecntrl.h> |
|
27 #include <w32std.h> |
|
28 #include <gdi.h> |
|
29 #include "uiacceltk/HuiProbe.h" |
|
30 #include "uiacceltk/HuiEnv.h" |
|
31 |
|
32 #include <M3G/m3g_core.h> |
|
33 |
|
34 |
|
35 CHuiVg10RenderSurface* CHuiVg10RenderSurface::NewL(CHuiDisplay& aDisplay) |
|
36 { |
|
37 CHuiVg10RenderSurface* self = CHuiVg10RenderSurface::NewLC(aDisplay); |
|
38 CleanupStack::Pop(self); |
|
39 return self; |
|
40 } |
|
41 |
|
42 |
|
43 CHuiVg10RenderSurface* CHuiVg10RenderSurface::NewLC(CHuiDisplay& aDisplay) |
|
44 { |
|
45 CHuiVg10RenderSurface* self = new (ELeave) CHuiVg10RenderSurface(aDisplay); |
|
46 CleanupStack::PushL(self); |
|
47 self->ConstructL(); |
|
48 return self; |
|
49 } |
|
50 |
|
51 |
|
52 CHuiVg10RenderSurface::CHuiVg10RenderSurface(CHuiDisplay& aDisplay) |
|
53 : iDisplay(&aDisplay) |
|
54 { |
|
55 HUI_PROBE_ASSOCIATE_WITH_CURRENT_SESSION |
|
56 HUI_PROBE_REPORT_CONSTRUCTED |
|
57 } |
|
58 |
|
59 |
|
60 void CHuiVg10RenderSurface::ConstructL() |
|
61 { |
|
62 HUI_DEBUG(_L("CHuiVg10RenderSurface::ConstructL() - Constructing OpenVG 1.0 Rendering surface.")); |
|
63 |
|
64 // Size of the surface. |
|
65 iSize = iDisplay->Size(); |
|
66 |
|
67 // Create egl context and rendering surface |
|
68 iEglContext = iEglSurface = NULL; |
|
69 iBoundTexture = NULL; |
|
70 RestoreL(); |
|
71 |
|
72 HUI_DEBUG(_L("CHuiVg10RenderSurface::ConstructL() - Construction succeeded.")); |
|
73 } |
|
74 |
|
75 |
|
76 CHuiVg10RenderSurface::~CHuiVg10RenderSurface() |
|
77 { |
|
78 Release(); |
|
79 iDisplay = NULL; |
|
80 HUI_PROBE_REPORT_DESTRUCTED |
|
81 } |
|
82 |
|
83 |
|
84 CHuiDisplay& CHuiVg10RenderSurface::Display() const |
|
85 { |
|
86 return *iDisplay; |
|
87 } |
|
88 |
|
89 |
|
90 TUint CHuiVg10RenderSurface::Flags() const |
|
91 { |
|
92 TBool useDirtyAreas = CHuiStatic::Renderer().Allows(EHuiRenderPluginAllowSwapBufferPreserve); |
|
93 if (useDirtyAreas) |
|
94 { |
|
95 return MHuiRenderSurface::EFlagUseDirtyRects; |
|
96 } |
|
97 else |
|
98 { |
|
99 return MHuiRenderSurface::EFlagNone; |
|
100 } |
|
101 } |
|
102 |
|
103 |
|
104 TBool CHuiVg10RenderSurface::GetScreenOrigin(TPoint& aOrigin) const |
|
105 { |
|
106 if(iDisplay && iDisplay->NativeControl()) |
|
107 { |
|
108 aOrigin = iDisplay->NativeControl()->PositionRelativeToScreen(); |
|
109 return ETrue; |
|
110 } |
|
111 return EFalse; |
|
112 } |
|
113 |
|
114 static void CreateConstEglAttribs(int& i, EGLint* attribList) |
|
115 { |
|
116 const TInt BITS_PER_CHANNEL = 8; |
|
117 |
|
118 attribList[i++] = EGL_RED_SIZE; |
|
119 attribList[i++] = BITS_PER_CHANNEL; |
|
120 |
|
121 attribList[i++] = EGL_GREEN_SIZE; |
|
122 attribList[i++] = BITS_PER_CHANNEL; |
|
123 |
|
124 attribList[i++] = EGL_BLUE_SIZE; |
|
125 attribList[i++] = BITS_PER_CHANNEL; |
|
126 |
|
127 attribList[i++] = EGL_ALPHA_SIZE; |
|
128 attribList[i++] = BITS_PER_CHANNEL; |
|
129 |
|
130 attribList[i++] = EGL_SURFACE_TYPE; |
|
131 |
|
132 TBool useDirtyAreas = CHuiStatic::Renderer().Allows(EHuiRenderPluginAllowSwapBufferPreserve); |
|
133 if (useDirtyAreas) |
|
134 { |
|
135 attribList[i++] = EGL_WINDOW_BIT | EGL_PBUFFER_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT; |
|
136 } |
|
137 else |
|
138 { |
|
139 attribList[i++] = EGL_WINDOW_BIT | EGL_PBUFFER_BIT; |
|
140 } |
|
141 |
|
142 attribList[i++] = EGL_RENDERABLE_TYPE; |
|
143 attribList[i++] = EGL_OPENVG_BIT; |
|
144 } |
|
145 |
|
146 EGLConfig CHuiVg10RenderSurface::DetermineConfig() |
|
147 { |
|
148 EGLint attribList[20]; // reserve enough space for configurations |
|
149 int i = 0; |
|
150 |
|
151 // Get default properties for the wanted EGLSurface. |
|
152 CreateConstEglAttribs(i, attribList); |
|
153 |
|
154 // Terminate attribute list |
|
155 attribList[i++] = EGL_NONE; |
|
156 |
|
157 CHuiVg10RenderPlugin& render = CHuiStatic::Vg10Renderer(); |
|
158 |
|
159 // Choose an EGLConfig that best matches to the properties in attribList. |
|
160 TInt numOfConfigs = render.EglChooseConfig(attribList); |
|
161 |
|
162 if(!numOfConfigs) |
|
163 { |
|
164 TInt eglerr = eglGetError(); |
|
165 HUI_DEBUG2(_L("CHuiVg10RenderSurface::DetermineConfig() - eglChooseConfig failed, no required EGL configuration found. Cause: %S (error %i). Panicking."), &CHuiVg10RenderSurface::EglErrorMessage(eglerr), eglerr); |
|
166 HUI_PANIC(THuiPanic::ERenderSurfaceUnknownDisplayMode); |
|
167 } |
|
168 |
|
169 HUI_DEBUG1(_L("CHuiVg10RenderSurface::DetermineConfig() - Got %i configs."), numOfConfigs); |
|
170 |
|
171 // Print the attributes of the selected config to log file. |
|
172 render.EglPrintConfig(0); |
|
173 |
|
174 // Choose the best EGLConfig. EGLConfigs returned by eglChooseConfig |
|
175 // are sorted so that the best matching EGLConfig is first in the list. |
|
176 return render.EglConfig(0); |
|
177 } |
|
178 |
|
179 |
|
180 EGLSurface CHuiVg10RenderSurface::CreateSurface(EGLConfig aConfig) |
|
181 { |
|
182 EGLint* attriblistPtr = NULL; |
|
183 #ifndef __WINS__ // \todo instead of "#ifndef" should make a check if alpha mode is supported |
|
184 // Create a rendering surface. |
|
185 EGLint attriblist[] = |
|
186 { |
|
187 EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_PRE, |
|
188 EGL_NONE |
|
189 }; |
|
190 attriblistPtr = &attriblist[0]; |
|
191 #endif |
|
192 |
|
193 if(iDisplay->NativeWindow()) |
|
194 { |
|
195 HUI_DEBUG(_L("CHuiVg10RenderSurface::CreateSurface() - Attempting to create a real window surface.")); |
|
196 EGLSurface surf = eglCreateWindowSurface(iEglDisplay, aConfig, |
|
197 iDisplay->NativeWindow(), attriblistPtr); |
|
198 |
|
199 TBool useDirtyAreas = CHuiStatic::Renderer().Allows(EHuiRenderPluginAllowSwapBufferPreserve); |
|
200 if (useDirtyAreas) |
|
201 { |
|
202 eglSurfaceAttrib(iEglDisplay, surf, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED ); |
|
203 } |
|
204 return surf; |
|
205 } |
|
206 else |
|
207 { |
|
208 // Pbuffer attributes. |
|
209 EGLint pbufferAttribList[] = |
|
210 { |
|
211 EGL_WIDTH, iSize.iWidth, |
|
212 EGL_HEIGHT, iSize.iHeight, |
|
213 EGL_NONE |
|
214 }; |
|
215 |
|
216 HUI_DEBUG(_L("CHuiVg10RenderSurface::CreateSurface() - Attempting to create a pbuffer surface.")); |
|
217 return eglCreatePbufferSurface(iEglDisplay, aConfig, pbufferAttribList); |
|
218 } |
|
219 } |
|
220 |
|
221 |
|
222 TSize CHuiVg10RenderSurface::Size() const |
|
223 { |
|
224 return iSize; |
|
225 } |
|
226 |
|
227 |
|
228 void CHuiVg10RenderSurface::SetSizeL(const TSize& aSize) |
|
229 { |
|
230 iSize = aSize; |
|
231 |
|
232 if(!iDisplay->NativeWindow()) |
|
233 { |
|
234 // Recreate pbuffer surfaces. |
|
235 eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); |
|
236 |
|
237 // Recreate the rendering surface. |
|
238 eglDestroySurface(iEglDisplay, iEglSurface); |
|
239 |
|
240 iEglSurface = CreateSurface(DetermineConfig()); |
|
241 |
|
242 if(iEglSurface == EGL_NO_SURFACE) |
|
243 { |
|
244 TInt eglerr = eglGetError(); |
|
245 switch (eglerr) |
|
246 { |
|
247 case EGL_BAD_ALLOC: |
|
248 HUI_DEBUG2(_L("CHuiVg10RenderSurface::SetSizeL() - ERROR! Failed to (re)create surface having size (%ix%i). Out of memory."), |
|
249 aSize.iWidth, aSize.iHeight); |
|
250 User::Leave(KErrNoMemory); |
|
251 default: |
|
252 HUI_DEBUG4(_L("CHuiVg10RenderSurface::SetSizeL() - ERROR! Failed to (re)create surface having size (%ix%i).Cause: %S (EGL error code: %i). Leaving."), |
|
253 aSize.iWidth, aSize.iHeight, |
|
254 &CHuiVg10RenderSurface::EglErrorMessage(eglerr), eglerr); |
|
255 case EGL_SUCCESS: // indicates that no error was recorded, but still the CreateSurface call failed (=> unable to continue!) |
|
256 User::Leave(KErrNotSupported); |
|
257 } |
|
258 } |
|
259 } |
|
260 } |
|
261 |
|
262 |
|
263 void CHuiVg10RenderSurface::MakeCurrent() |
|
264 { |
|
265 // No need to change the current render surface if this render surface is current already. |
|
266 if(CHuiStatic::CurrentRenderSurface() != ((MHuiRenderSurface*)this)) |
|
267 { |
|
268 CHuiEnv* env = CHuiEnv::Static(); |
|
269 if (env && env->iSwapObserver) |
|
270 { |
|
271 env->iSwapObserver->ReleaseWindowServer(); |
|
272 } |
|
273 |
|
274 eglMakeCurrent(iEglDisplay, iEglSurface, iEglSurface, iEglContext); |
|
275 |
|
276 if (env && env->iSwapObserver) |
|
277 { |
|
278 env->iSwapObserver->ReleaseWindowServer(EFalse); |
|
279 } |
|
280 |
|
281 TInt eglerr = eglGetError(); |
|
282 if(eglerr != EGL_SUCCESS) |
|
283 { |
|
284 HUI_DEBUG3(_L("CHuiVg10RenderSurface::MakeCurrent() - Error in switching on the render surface, EGLDisplay: %i, EGLSurface: %i, EGLContext: %i."), |
|
285 iEglDisplay, iEglSurface, iEglContext); |
|
286 HUI_DEBUG2(_L("CHuiVg10RenderSurface::MakeCurrent() - Could not switch this rendering surface on. Cause: %S (EGL error code: %i). Panicking."), |
|
287 &CHuiVg10RenderSurface::EglErrorMessage(eglerr), eglerr); |
|
288 HUI_PANIC(THuiPanic::ERenderSurfaceActivationFailed) |
|
289 } |
|
290 CHuiStatic::SetCurrentRenderSurface(this); |
|
291 } |
|
292 } |
|
293 |
|
294 void CHuiVg10RenderSurface::SwapBuffers() |
|
295 { |
|
296 eglSwapBuffers(iEglDisplay, iEglSurface); |
|
297 } |
|
298 |
|
299 |
|
300 void CHuiVg10RenderSurface::BindTexture(TInt /*aTextureUnit*/, |
|
301 const MHuiSegmentedTexture& aTexture, |
|
302 TInt /*aSegment*/) |
|
303 { |
|
304 iBoundTexture = &aTexture; |
|
305 } |
|
306 |
|
307 |
|
308 const MHuiSegmentedTexture* CHuiVg10RenderSurface::BoundTexture() const |
|
309 { |
|
310 return iBoundTexture; |
|
311 } |
|
312 |
|
313 void CHuiVg10RenderSurface::HandleVisibilityEvent(TBool /* aIsVisible */ ) |
|
314 { |
|
315 // Dummy method, does not handle the events in any way... |
|
316 } |
|
317 |
|
318 void CHuiVg10RenderSurface::Release() |
|
319 { |
|
320 HUI_DEBUG( _L("CHuiVg10RenderSurface::Release() - Releasing EGL surface and context..") ); |
|
321 if (iEglSurface != NULL) |
|
322 { |
|
323 eglDestroySurface(iEglDisplay, iEglSurface); |
|
324 TInt eglerr = eglGetError(); |
|
325 if(eglerr != EGL_SUCCESS) |
|
326 { |
|
327 HUI_DEBUG2(_L("CHuiVg10RenderSurface::Release() - WARNING! Could not destroy EGL surface. Cause: %S (EGL error code: %i)."), |
|
328 &CHuiVg10RenderSurface::EglErrorMessage(eglerr), eglerr); |
|
329 } |
|
330 iEglSurface = NULL; |
|
331 } |
|
332 if (iEglContext != NULL) |
|
333 { |
|
334 // Unshare this context if it was |
|
335 // set as shared.. |
|
336 CHuiVg10RenderPlugin& renderer = CHuiStatic::Vg10Renderer(); |
|
337 if(renderer.EglSharedContext() == iEglContext) |
|
338 { |
|
339 HUI_DEBUG(_L("CHuiVg10RenderSurface::Release() - Unsharing this render context.")); |
|
340 renderer.EglSetSharedContext(EGL_NO_CONTEXT); |
|
341 } |
|
342 |
|
343 eglDestroyContext(iEglDisplay, iEglContext); |
|
344 TInt eglerr = eglGetError(); |
|
345 if(eglerr != EGL_SUCCESS) |
|
346 { |
|
347 HUI_DEBUG2(_L("CHuiVg10RenderSurface::Release() - WARNING! Could not destroy EGL context. Cause: %S (EGL error code: %i)."), |
|
348 &CHuiVg10RenderSurface::EglErrorMessage(eglerr), eglerr); |
|
349 } |
|
350 iEglContext = NULL; |
|
351 } |
|
352 } |
|
353 |
|
354 void CHuiVg10RenderSurface::RestoreL() |
|
355 { |
|
356 HUI_DEBUG( _L("CHuiVg10RenderSurface::RestoreL() - Recreating render surface.") ); |
|
357 |
|
358 if((iEglSurface != NULL) && (iEglContext != NULL)) |
|
359 { |
|
360 HUI_DEBUG( _L("CHuiVg10RenderSurface::RestoreL() - Render surface and context already in place, no need to restore.") ); |
|
361 } |
|
362 |
|
363 CHuiVg10RenderPlugin& render = CHuiStatic::Vg10Renderer(); |
|
364 iEglDisplay = render.EglDisplay(); |
|
365 |
|
366 // Create an EGL rendering surface. |
|
367 EGLConfig config = DetermineConfig(); |
|
368 iEglSurface = CreateSurface(config); |
|
369 |
|
370 if(iEglSurface == EGL_NO_SURFACE) |
|
371 { |
|
372 TInt eglerr = eglGetError(); |
|
373 switch (eglerr) |
|
374 { |
|
375 case EGL_BAD_ALLOC: |
|
376 HUI_DEBUG2(_L("CHuiVg10RenderSurface::RestoreL() - ERROR! Failed to create rendering surface having size (%ix%i). Out of memory."), |
|
377 iSize.iWidth, iSize.iHeight); |
|
378 User::Leave(KErrNoMemory); |
|
379 default: |
|
380 HUI_DEBUG4(_L("CHuiVg10RenderSurface::RestoreL() - ERROR! Failed to create rendering surface having size (%ix%i). Cause: %S (EGL error code: %i)."), |
|
381 iSize.iWidth, iSize.iHeight, |
|
382 &CHuiVg10RenderSurface::EglErrorMessage(eglerr), eglerr); |
|
383 User::Leave(KErrNotSupported); |
|
384 } |
|
385 } |
|
386 |
|
387 // There is only a single texture manager in the environment, so textures |
|
388 // need to shared between all contexts. |
|
389 iEglContext = eglCreateContext(iEglDisplay, config, |
|
390 render.EglSharedContext(), NULL); |
|
391 if(iEglContext == EGL_NO_CONTEXT) |
|
392 { |
|
393 TInt eglerr = eglGetError(); |
|
394 switch (eglerr) |
|
395 { |
|
396 case EGL_BAD_ALLOC: |
|
397 HUI_DEBUG(_L("CHuiVg10RenderSurface::RestoreL() - ERROR! Failed to create rendering context. Out of memory.")); |
|
398 User::Leave(KErrNoMemory); |
|
399 default: |
|
400 HUI_DEBUG2(_L("CHuiVg10RenderSurface::RestoreL() - ERROR! Failed to create rendering context. Cause: %S (EGL error code: %i)."), |
|
401 &CHuiVg10RenderSurface::EglErrorMessage(eglerr), eglerr); |
|
402 User::Leave(KErrNotSupported); |
|
403 } |
|
404 } |
|
405 |
|
406 // Share the created context for texture management. |
|
407 if(render.EglSharedContext() == EGL_NO_CONTEXT) |
|
408 { |
|
409 // Now that there is a context, make sure the renderer knows of it. |
|
410 render.EglSetSharedContext(iEglContext); |
|
411 } |
|
412 } |
|
413 |
|
414 const TDesC& CHuiVg10RenderSurface::EglErrorMessage(TInt aErrorCode) |
|
415 { |
|
416 // EGL Error messages. |
|
417 _LIT(KEglErrorSUCCESS, "The last function succeeded without error."); |
|
418 _LIT(KEglErrorNOT_INITIALIZED, "EGL is not initialized, or could not be initialized, for the specified EGL display connection."); |
|
419 _LIT(KEglErrorBAD_ACCESS, "EGL cannot access a requested resource (for example a context is bound in another thread)."); |
|
420 _LIT(KEglErrorBAD_ALLOC, "EGL failed to allocate resources for the requested operation."); |
|
421 _LIT(KEglErrorBAD_ATTRIBUTE, "An unrecognized attribute or attribute value was passed in the attribute list."); |
|
422 _LIT(KEglErrorBAD_CONTEXT, "An EGLContext argument does not name a valid EGL rendering context."); |
|
423 _LIT(KEglErrorBAD_CONFIG, "An EGLConfig argument does not name a valid EGL frame buffer configuration."); |
|
424 _LIT(KEglErrorBAD_CURRENT_SURFACE, "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid."); |
|
425 _LIT(KEglErrorBAD_DISPLAY, "An EGLDisplay argument does not name a valid EGL display connection."); |
|
426 _LIT(KEglErrorBAD_SURFACE, "An EGLSurface argument does not name a valid surface (window, pixel buffer or pixmap) configured for GL rendering."); |
|
427 _LIT(KEglErrorBAD_MATCH, "Arguments are inconsistent (for example, a valid context requires buffers not supplied by a valid surface)."); |
|
428 _LIT(KEglErrorBAD_PARAMETER, "One or more argument values are invalid."); |
|
429 _LIT(KEglErrorBAD_NATIVE_PIXMAP, "A NativePixmapType argument does not refer to a valid native pixmap."); |
|
430 _LIT(KEglErrorBAD_NATIVE_WINDOW, "A NativeWindowType argument does not refer to a valid native window."); |
|
431 _LIT(KEglErrorUNKNOWN, "Unknown EGL Error."); |
|
432 |
|
433 // Define literals for the errors |
|
434 switch(aErrorCode) |
|
435 { |
|
436 case EGL_SUCCESS: return KEglErrorSUCCESS; |
|
437 case EGL_NOT_INITIALIZED: return KEglErrorNOT_INITIALIZED; |
|
438 case EGL_BAD_ACCESS: return KEglErrorBAD_ACCESS; |
|
439 case EGL_BAD_ALLOC: return KEglErrorBAD_ALLOC; |
|
440 case EGL_BAD_ATTRIBUTE: return KEglErrorBAD_ATTRIBUTE; |
|
441 case EGL_BAD_CONTEXT: return KEglErrorBAD_CONTEXT; |
|
442 case EGL_BAD_CONFIG: return KEglErrorBAD_CONFIG; |
|
443 case EGL_BAD_CURRENT_SURFACE: return KEglErrorBAD_CURRENT_SURFACE; |
|
444 case EGL_BAD_DISPLAY: return KEglErrorBAD_DISPLAY; |
|
445 case EGL_BAD_SURFACE: return KEglErrorBAD_SURFACE; |
|
446 case EGL_BAD_MATCH: return KEglErrorBAD_MATCH; |
|
447 case EGL_BAD_PARAMETER: return KEglErrorBAD_PARAMETER; |
|
448 case EGL_BAD_NATIVE_PIXMAP: return KEglErrorBAD_NATIVE_PIXMAP; |
|
449 case EGL_BAD_NATIVE_WINDOW: return KEglErrorBAD_NATIVE_WINDOW; |
|
450 default: return KEglErrorUNKNOWN; |
|
451 } |
|
452 } |
|
453 |
|
454 void CHuiVg10RenderSurface::HandleDisplayUsageChangeL() |
|
455 { |
|
456 // Nothing to do |
|
457 } |
|
458 |
|
459 void CHuiVg10RenderSurface::SetDirtyRect(const TRect& /*aRect*/) |
|
460 { |
|
461 // Nothing to do |
|
462 } |
|
463 |
|
464 MHuiTargetBitmap* CHuiVg10RenderSurface::BackBuffer() |
|
465 { |
|
466 // Nothing to do |
|
467 return NULL; |
|
468 } |
|
469 |
|
470 CFbsBitGc* CHuiVg10RenderSurface::Gc() |
|
471 { |
|
472 // Nothing to do |
|
473 return NULL; |
|
474 } |
|
475 |
|
476 void CHuiVg10RenderSurface::RenderSurfaceExtension(const TUid& /*aExtensionUid*/, TAny** aExtensionParams) |
|
477 { |
|
478 *aExtensionParams = NULL; |
|
479 } |
|
480 |
|
481 HUI_SESSION_OBJECT_IMPL(CHuiVg10RenderSurface, ETypeRenderSurface) |