|
1 /* |
|
2 * Copyright (c) 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: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 #include "HuiFxVg10OffscreenRenderbuffer.h" |
|
21 #include "HuiVg10RenderPlugin.h" |
|
22 #include "uiacceltk/HuiEnv.h" |
|
23 #include "uiacceltk/HuiDisplay.h" |
|
24 |
|
25 CHuiFxVg10OffscreenRenderbuffer* CHuiFxVg10OffscreenRenderbuffer::NewL(CHuiVg10RenderPlugin& aPlugin, const TSize& aSize) |
|
26 { |
|
27 CHuiFxVg10OffscreenRenderbuffer* e = new (ELeave) CHuiFxVg10OffscreenRenderbuffer(); |
|
28 CleanupStack::PushL(e); |
|
29 e->ConstructL(aPlugin, aSize); |
|
30 CleanupStack::Pop(e); |
|
31 return e; |
|
32 } |
|
33 |
|
34 void CHuiFxVg10OffscreenRenderbuffer::ConstructL(CHuiVg10RenderPlugin& aPlugin, const TSize& aSize) |
|
35 { |
|
36 CHuiFxRenderbuffer::ConstructL(aSize, EBufferTypeOffscreen); |
|
37 iPlugin = &aPlugin; |
|
38 |
|
39 PushEGLContext(); |
|
40 |
|
41 #ifndef __WINS__ // Should possibly query the supported mode instead? |
|
42 VGImageFormat imageInternalFormat = VG_sARGB_8888_PRE; |
|
43 #else |
|
44 VGImageFormat imageInternalFormat = VG_sARGB_8888; |
|
45 #endif |
|
46 |
|
47 iImage = vgCreateImage(imageInternalFormat, aSize.iWidth, aSize.iHeight, |
|
48 VG_IMAGE_QUALITY_NONANTIALIASED); |
|
49 |
|
50 HUIFX_VG_INVARIANT(); |
|
51 |
|
52 const TInt BITS_PER_CHANNEL = 8; |
|
53 |
|
54 // Choose an EGL config |
|
55 const EGLint attrs[] = |
|
56 { |
|
57 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, |
|
58 EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT, |
|
59 EGL_RED_SIZE, BITS_PER_CHANNEL, |
|
60 EGL_GREEN_SIZE, BITS_PER_CHANNEL, |
|
61 EGL_BLUE_SIZE, BITS_PER_CHANNEL, |
|
62 EGL_ALPHA_SIZE, BITS_PER_CHANNEL, |
|
63 EGL_NONE |
|
64 }; |
|
65 TInt configCount = iPlugin->EglChooseConfig(attrs); |
|
66 ASSERT(configCount > 0); |
|
67 EGLConfig config = iPlugin->EglConfig(0); |
|
68 |
|
69 // Create a context |
|
70 iContext = eglCreateContext(iPlugin->EglDisplay(), config, |
|
71 iPlugin->EglSharedContext(), NULL); |
|
72 EGLint err = eglGetError(); |
|
73 ASSERT(iContext); |
|
74 |
|
75 // Create a pbuffer surface |
|
76 iSurface = eglCreatePbufferFromClientBuffer(iPlugin->EglDisplay(), EGL_OPENVG_IMAGE, |
|
77 iImage, config, NULL); |
|
78 ASSERT(iSurface); |
|
79 |
|
80 // Initialize the context |
|
81 iGc = iPlugin->CreateGcL(); |
|
82 this->InitGc(aSize); |
|
83 |
|
84 PopEGLContext(); |
|
85 } |
|
86 |
|
87 CHuiFxVg10OffscreenRenderbuffer::~CHuiFxVg10OffscreenRenderbuffer() |
|
88 { |
|
89 delete iGc; |
|
90 |
|
91 if(iPlugin) |
|
92 { |
|
93 eglDestroySurface(iPlugin->EglDisplay(), iSurface); |
|
94 eglDestroyContext(iPlugin->EglDisplay(), iContext); |
|
95 } |
|
96 |
|
97 if (iRotatedImage != VG_INVALID_HANDLE) |
|
98 { |
|
99 vgDestroyImage(iRotatedImage); |
|
100 HUIFX_VG_INVARIANT(); |
|
101 } |
|
102 vgDestroyImage(iImage); |
|
103 HUIFX_VG_INVARIANT(); |
|
104 } |
|
105 |
|
106 void CHuiFxVg10OffscreenRenderbuffer::InitGc(const TSize& aSize) |
|
107 { |
|
108 BindAsRenderTarget(); |
|
109 iGc->InitState(); |
|
110 VGfloat color[] = |
|
111 { |
|
112 .0f, .0f, .0f, .0f |
|
113 }; |
|
114 vgSetfv(VG_CLEAR_COLOR, sizeof(color) / sizeof(VGfloat), color); |
|
115 vgClear(0, 0, aSize.iWidth, aSize.iHeight); |
|
116 UnbindAsRenderTarget(); |
|
117 |
|
118 // Let renderer know that we have been fiddlling with OpenVg state directly |
|
119 // "iGc->InitState" confuses scissoring setting, so lets notify it. |
|
120 CHuiVg10RenderPlugin& renderer = CHuiStatic::Vg10Renderer(); |
|
121 renderer.AddRestoreStateFlags(EHuiVg10GcStateFlagDirtyScissor); |
|
122 renderer.AddRestoreStateFlags(EHuiVg10GcStateFlagDirtyBlendMode); |
|
123 } |
|
124 |
|
125 void CHuiFxVg10OffscreenRenderbuffer::PrepareForReuse(const TSize& aReusedSize) |
|
126 { |
|
127 if (iBackgroundEnabled) |
|
128 { |
|
129 ReadBackground(); |
|
130 } |
|
131 else |
|
132 { |
|
133 const TInt COLOR_COMPONENTS = 4; |
|
134 VGfloat savedColor[COLOR_COMPONENTS]; |
|
135 vgGetfv(VG_CLEAR_COLOR, COLOR_COMPONENTS, savedColor); |
|
136 |
|
137 VGfloat color[COLOR_COMPONENTS] = |
|
138 { |
|
139 .0f, .0f, .0f, .0f |
|
140 }; |
|
141 vgSetfv(VG_CLEAR_COLOR, COLOR_COMPONENTS, color); |
|
142 vgClearImage(Image(), 0, 0, aReusedSize.iWidth, aReusedSize.iHeight); |
|
143 vgSetfv(VG_CLEAR_COLOR, COLOR_COMPONENTS, savedColor); |
|
144 } |
|
145 |
|
146 HUIFX_VG_INVARIANT(); |
|
147 } |
|
148 |
|
149 CHuiGc& CHuiFxVg10OffscreenRenderbuffer::BindAsRenderTarget() |
|
150 { |
|
151 // Save current context and surfaces |
|
152 iSavedContext = eglGetCurrentContext(); |
|
153 iSavedDrawSurface = eglGetCurrentSurface(EGL_DRAW); |
|
154 iSavedReadSurface = eglGetCurrentSurface(EGL_READ); |
|
155 ASSERT(iSavedContext != iContext); |
|
156 ASSERT(iSavedDrawSurface != iSurface); |
|
157 ASSERT(iSavedReadSurface != iSurface); |
|
158 |
|
159 // Bind our own surface |
|
160 eglMakeCurrent(iPlugin->EglDisplay(), iSurface, iSurface, iContext); |
|
161 ASSERT(eglGetError() == EGL_SUCCESS); |
|
162 |
|
163 return *iGc; |
|
164 } |
|
165 |
|
166 void CHuiFxVg10OffscreenRenderbuffer::BindAsTexture(THuiFxRenderbufferUsage aUsage) |
|
167 { |
|
168 // Nothing to do |
|
169 } |
|
170 |
|
171 void CHuiFxVg10OffscreenRenderbuffer::UnbindAsTexture() |
|
172 { |
|
173 // Nothing to do |
|
174 } |
|
175 |
|
176 void CHuiFxVg10OffscreenRenderbuffer::UnbindAsRenderTarget() |
|
177 { |
|
178 // Restore original surface & context |
|
179 eglMakeCurrent(iPlugin->EglDisplay(), iSavedDrawSurface, iSavedReadSurface, |
|
180 iSavedContext); |
|
181 ASSERT(eglGetError() == EGL_SUCCESS); |
|
182 } |
|
183 |
|
184 VGImage CHuiFxVg10OffscreenRenderbuffer::Image() const |
|
185 { |
|
186 return iImage; |
|
187 } |
|
188 |
|
189 void CHuiFxVg10OffscreenRenderbuffer::ReadBackground() |
|
190 { |
|
191 if (iBackgroundEnabled) |
|
192 { |
|
193 CHuiDisplay& display = CHuiStatic::Env().PrimaryDisplay(); |
|
194 TBool rotatedDisplay = display.Orientation() == CHuiGc::EOrientationCCW90 || display.Orientation() == CHuiGc::EOrientationCW90; |
|
195 TRect renderBufferLocation = TRect(iPosition, iSize); |
|
196 |
|
197 #ifdef HUIFX_TRACE |
|
198 RDebug::Print(_L("CHuiFxVg10OffscreenRenderbuffer::PrepareForReuse - renderBufferLocation original: %i,%i, %i,%i "), |
|
199 renderBufferLocation.iTl.iX, |
|
200 renderBufferLocation.iTl.iY, |
|
201 renderBufferLocation.iBr.iX, |
|
202 renderBufferLocation.iBr.iY); |
|
203 #endif |
|
204 |
|
205 TRect displayArea = display.VisibleArea(); |
|
206 |
|
207 TInt displayHeight = displayArea.Height(); |
|
208 TInt displayWidth = displayArea.Width(); |
|
209 |
|
210 TSize rotatedSize = iSize; |
|
211 TPoint rotatedPos = iPosition; |
|
212 |
|
213 // Read pixels from surface |
|
214 if (rotatedDisplay) |
|
215 { |
|
216 if (iRotatedImage == VG_INVALID_HANDLE) |
|
217 { |
|
218 PushEGLContext(); |
|
219 |
|
220 #ifndef __WINS__ // Should possibly query the supported mode instead? |
|
221 VGImageFormat imageInternalFormat = VG_sARGB_8888_PRE; |
|
222 #else |
|
223 VGImageFormat imageInternalFormat = VG_sARGB_8888; |
|
224 #endif |
|
225 |
|
226 TSize rotatedImageSize = TSize(iSize.iHeight, iSize.iWidth); |
|
227 iRotatedImage = vgCreateImage(imageInternalFormat, rotatedImageSize.iWidth, rotatedImageSize.iHeight, |
|
228 VG_IMAGE_QUALITY_NONANTIALIASED); |
|
229 |
|
230 PopEGLContext(); |
|
231 } |
|
232 |
|
233 |
|
234 // If we have rotation on CHuiGc level, we must manually take that into account when |
|
235 // accessing pixels directly |
|
236 if(display.Orientation() == CHuiGc::EOrientationCCW90) |
|
237 { |
|
238 // Rotate the buffer location relative to real surface coordinates |
|
239 rotatedSize = TSize(iSize.iHeight, iSize.iWidth); |
|
240 rotatedPos = TPoint(displayHeight - iPosition.iY - iSize.iHeight, iPosition.iX); |
|
241 renderBufferLocation = TRect(rotatedPos, rotatedSize); |
|
242 } |
|
243 else if(display.Orientation() == CHuiGc::EOrientationCW90) |
|
244 { |
|
245 // Rotate the buffer location relative to real surface coordinates |
|
246 rotatedSize = TSize(iSize.iHeight, iSize.iWidth); |
|
247 rotatedPos = TPoint(iPosition.iY, displayWidth - iPosition.iX - iSize.iWidth); |
|
248 renderBufferLocation = TRect(rotatedPos, rotatedSize); |
|
249 } |
|
250 else |
|
251 { |
|
252 // nothing |
|
253 } |
|
254 |
|
255 // If screen is rotated but surface is not in native orientation, this gets difficult |
|
256 // because vgGetPixels is not affected by transformations. |
|
257 |
|
258 // Swap h and w so that those are the "real" values from surface point of view. |
|
259 displayHeight = displayWidth; |
|
260 |
|
261 #ifdef HUIFX_TRACE |
|
262 RDebug::Print(_L("CHuiFxVg10OffscreenRenderbuffer::PrepareForReuse - renderBufferLocation: %i,%i, %i,%i "), |
|
263 renderBufferLocation.iTl.iX, |
|
264 renderBufferLocation.iTl.iY, |
|
265 renderBufferLocation.iBr.iX, |
|
266 renderBufferLocation.iBr.iY); |
|
267 |
|
268 TRect vgRect(TPoint(renderBufferLocation.iTl.iX, displayHeight - renderBufferLocation.iTl.iY - rotatedSize.iHeight), rotatedSize); |
|
269 |
|
270 RDebug::Print(_L("CHuiFxVg10OffscreenRenderbuffer::PrepareForReuse - vgRect: %i,%i, %i,%i "), |
|
271 vgRect.iTl.iX, |
|
272 vgRect.iTl.iY, |
|
273 vgRect.iBr.iX, |
|
274 vgRect.iBr.iY); |
|
275 #endif |
|
276 |
|
277 // So...first get pixels from surface into rotated image |
|
278 vgGetPixels(iRotatedImage, 0, 0, renderBufferLocation.iTl.iX, displayHeight - renderBufferLocation.iTl.iY - rotatedSize.iHeight, rotatedSize.iWidth, rotatedSize.iHeight); |
|
279 |
|
280 // Draw rotated image into real buffer image, first bind it as render target... |
|
281 BindAsRenderTarget(); |
|
282 |
|
283 // ...store some states... |
|
284 const TInt VG_MATRIX_SIZE = 9; |
|
285 VGfloat oldMatrix[VG_MATRIX_SIZE]; |
|
286 vgGetMatrix(oldMatrix); |
|
287 |
|
288 // ...set some vg states... |
|
289 vgLoadIdentity(); |
|
290 vgSeti(VG_BLEND_MODE, VG_BLEND_SRC); |
|
291 vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL); |
|
292 vgSeti(VG_SCISSORING, VG_FALSE); |
|
293 |
|
294 TInt w = iSize.iWidth; |
|
295 TInt h = iSize.iHeight; |
|
296 |
|
297 // ...select right rotation... |
|
298 if (display.Orientation() == CHuiGc::EOrientationCW90) |
|
299 { |
|
300 // Rotate around origo and move back to displayarea |
|
301 vgRotate(-90); |
|
302 vgTranslate(-h, 0); |
|
303 } |
|
304 else if (display.Orientation() == CHuiGc::EOrientationCCW90) |
|
305 { |
|
306 // Rotate around origo and move back to displayarea |
|
307 vgRotate(90); |
|
308 vgTranslate(0, -w); |
|
309 } |
|
310 else if (display.Orientation() == CHuiGc::EOrientation180) |
|
311 { |
|
312 // Rotate around origo and move back to displayarea |
|
313 vgRotate(180); |
|
314 vgTranslate(-w, -h); |
|
315 } |
|
316 else |
|
317 { |
|
318 } |
|
319 |
|
320 // ...Draw... |
|
321 if (iRotatedImage != VG_INVALID_HANDLE) |
|
322 { |
|
323 vgDrawImage(iRotatedImage); |
|
324 } |
|
325 |
|
326 // ..and restore default VG states |
|
327 vgSeti(VG_SCISSORING, VG_TRUE); |
|
328 vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER); |
|
329 vgLoadMatrix(oldMatrix); |
|
330 |
|
331 // ...finally unbind image and we should have the content correctly. |
|
332 UnbindAsRenderTarget(); |
|
333 } |
|
334 else |
|
335 { |
|
336 // Much easier if no rotation ! |
|
337 vgGetPixels(iImage, 0, 0, renderBufferLocation.iTl.iX, displayHeight - renderBufferLocation.iTl.iY - rotatedSize.iHeight, rotatedSize.iWidth, rotatedSize.iHeight); |
|
338 } |
|
339 } |
|
340 } |
|
341 |
|
342 void CHuiFxVg10OffscreenRenderbuffer::PushEGLContext() |
|
343 { |
|
344 iPreviousEGLState.iContext= eglGetCurrentContext(); |
|
345 TEGLState& state = iPlugin->GetUploadState(); |
|
346 if (state.iContext == KErrNotFound) |
|
347 { |
|
348 TEGLState& state = iPlugin->GetUploadState(); |
|
349 // the first context used for uploading will be used for all texture uploads |
|
350 state.iContext = iPreviousEGLState.iContext; |
|
351 state.iDrawSurface = eglGetCurrentSurface(EGL_DRAW); |
|
352 state.iReadSurface = eglGetCurrentSurface(EGL_READ); |
|
353 state.iDisplay = eglGetCurrentDisplay(); |
|
354 } |
|
355 else |
|
356 { |
|
357 // change context only if necessary |
|
358 if (iPreviousEGLState.iContext != state.iContext) |
|
359 { |
|
360 iPreviousEGLState.iDrawSurface = eglGetCurrentSurface(EGL_DRAW); |
|
361 iPreviousEGLState.iReadSurface = eglGetCurrentSurface(EGL_READ); |
|
362 iPreviousEGLState.iDisplay = eglGetCurrentDisplay(); |
|
363 eglMakeCurrent(state.iDisplay, state.iDrawSurface, state.iReadSurface, state.iContext); |
|
364 } |
|
365 } |
|
366 } |
|
367 |
|
368 void CHuiFxVg10OffscreenRenderbuffer::PopEGLContext() |
|
369 { |
|
370 if (iPreviousEGLState.iContext != iPlugin->GetUploadState().iContext) |
|
371 { |
|
372 eglMakeCurrent(iPreviousEGLState.iDisplay, iPreviousEGLState.iDrawSurface, iPreviousEGLState.iReadSurface,iPreviousEGLState.iContext); |
|
373 } |
|
374 } |