diff -r 000000000000 -r 15bf7259bb7c uiacceltk/hitchcock/coretoolkit/rendervg10/src/HuiFxVg10OffscreenRenderbuffer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uiacceltk/hitchcock/coretoolkit/rendervg10/src/HuiFxVg10OffscreenRenderbuffer.cpp Tue Feb 02 07:56:43 2010 +0200 @@ -0,0 +1,374 @@ +/* +* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + + +#include "HuiFxVg10OffscreenRenderbuffer.h" +#include "HuiVg10RenderPlugin.h" +#include "uiacceltk/HuiEnv.h" +#include "uiacceltk/HuiDisplay.h" + +CHuiFxVg10OffscreenRenderbuffer* CHuiFxVg10OffscreenRenderbuffer::NewL(CHuiVg10RenderPlugin& aPlugin, const TSize& aSize) + { + CHuiFxVg10OffscreenRenderbuffer* e = new (ELeave) CHuiFxVg10OffscreenRenderbuffer(); + CleanupStack::PushL(e); + e->ConstructL(aPlugin, aSize); + CleanupStack::Pop(e); + return e; + } + +void CHuiFxVg10OffscreenRenderbuffer::ConstructL(CHuiVg10RenderPlugin& aPlugin, const TSize& aSize) + { + CHuiFxRenderbuffer::ConstructL(aSize, EBufferTypeOffscreen); + iPlugin = &aPlugin; + + PushEGLContext(); + +#ifndef __WINS__ // Should possibly query the supported mode instead? + VGImageFormat imageInternalFormat = VG_sARGB_8888_PRE; +#else + VGImageFormat imageInternalFormat = VG_sARGB_8888; +#endif + + iImage = vgCreateImage(imageInternalFormat, aSize.iWidth, aSize.iHeight, + VG_IMAGE_QUALITY_NONANTIALIASED); + + HUIFX_VG_INVARIANT(); + + const TInt BITS_PER_CHANNEL = 8; + + // Choose an EGL config + const EGLint attrs[] = + { + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT, + EGL_RED_SIZE, BITS_PER_CHANNEL, + EGL_GREEN_SIZE, BITS_PER_CHANNEL, + EGL_BLUE_SIZE, BITS_PER_CHANNEL, + EGL_ALPHA_SIZE, BITS_PER_CHANNEL, + EGL_NONE + }; + TInt configCount = iPlugin->EglChooseConfig(attrs); + ASSERT(configCount > 0); + EGLConfig config = iPlugin->EglConfig(0); + + // Create a context + iContext = eglCreateContext(iPlugin->EglDisplay(), config, + iPlugin->EglSharedContext(), NULL); + EGLint err = eglGetError(); + ASSERT(iContext); + + // Create a pbuffer surface + iSurface = eglCreatePbufferFromClientBuffer(iPlugin->EglDisplay(), EGL_OPENVG_IMAGE, + iImage, config, NULL); + ASSERT(iSurface); + + // Initialize the context + iGc = iPlugin->CreateGcL(); + this->InitGc(aSize); + + PopEGLContext(); + } + +CHuiFxVg10OffscreenRenderbuffer::~CHuiFxVg10OffscreenRenderbuffer() + { + delete iGc; + + if(iPlugin) + { + eglDestroySurface(iPlugin->EglDisplay(), iSurface); + eglDestroyContext(iPlugin->EglDisplay(), iContext); + } + + if (iRotatedImage != VG_INVALID_HANDLE) + { + vgDestroyImage(iRotatedImage); + HUIFX_VG_INVARIANT(); + } + vgDestroyImage(iImage); + HUIFX_VG_INVARIANT(); + } + +void CHuiFxVg10OffscreenRenderbuffer::InitGc(const TSize& aSize) + { + BindAsRenderTarget(); + iGc->InitState(); + VGfloat color[] = + { + .0f, .0f, .0f, .0f + }; + vgSetfv(VG_CLEAR_COLOR, sizeof(color) / sizeof(VGfloat), color); + vgClear(0, 0, aSize.iWidth, aSize.iHeight); + UnbindAsRenderTarget(); + + // Let renderer know that we have been fiddlling with OpenVg state directly + // "iGc->InitState" confuses scissoring setting, so lets notify it. + CHuiVg10RenderPlugin& renderer = CHuiStatic::Vg10Renderer(); + renderer.AddRestoreStateFlags(EHuiVg10GcStateFlagDirtyScissor); + renderer.AddRestoreStateFlags(EHuiVg10GcStateFlagDirtyBlendMode); + } + +void CHuiFxVg10OffscreenRenderbuffer::PrepareForReuse(const TSize& aReusedSize) + { + if (iBackgroundEnabled) + { + ReadBackground(); + } + else + { + const TInt COLOR_COMPONENTS = 4; + VGfloat savedColor[COLOR_COMPONENTS]; + vgGetfv(VG_CLEAR_COLOR, COLOR_COMPONENTS, savedColor); + + VGfloat color[COLOR_COMPONENTS] = + { + .0f, .0f, .0f, .0f + }; + vgSetfv(VG_CLEAR_COLOR, COLOR_COMPONENTS, color); + vgClearImage(Image(), 0, 0, aReusedSize.iWidth, aReusedSize.iHeight); + vgSetfv(VG_CLEAR_COLOR, COLOR_COMPONENTS, savedColor); + } + + HUIFX_VG_INVARIANT(); + } + +CHuiGc& CHuiFxVg10OffscreenRenderbuffer::BindAsRenderTarget() + { + // Save current context and surfaces + iSavedContext = eglGetCurrentContext(); + iSavedDrawSurface = eglGetCurrentSurface(EGL_DRAW); + iSavedReadSurface = eglGetCurrentSurface(EGL_READ); + ASSERT(iSavedContext != iContext); + ASSERT(iSavedDrawSurface != iSurface); + ASSERT(iSavedReadSurface != iSurface); + + // Bind our own surface + eglMakeCurrent(iPlugin->EglDisplay(), iSurface, iSurface, iContext); + ASSERT(eglGetError() == EGL_SUCCESS); + + return *iGc; + } + +void CHuiFxVg10OffscreenRenderbuffer::BindAsTexture(THuiFxRenderbufferUsage aUsage) + { + // Nothing to do + } + +void CHuiFxVg10OffscreenRenderbuffer::UnbindAsTexture() + { + // Nothing to do + } + +void CHuiFxVg10OffscreenRenderbuffer::UnbindAsRenderTarget() + { + // Restore original surface & context + eglMakeCurrent(iPlugin->EglDisplay(), iSavedDrawSurface, iSavedReadSurface, + iSavedContext); + ASSERT(eglGetError() == EGL_SUCCESS); + } + +VGImage CHuiFxVg10OffscreenRenderbuffer::Image() const + { + return iImage; + } + +void CHuiFxVg10OffscreenRenderbuffer::ReadBackground() + { + if (iBackgroundEnabled) + { + CHuiDisplay& display = CHuiStatic::Env().PrimaryDisplay(); + TBool rotatedDisplay = display.Orientation() == CHuiGc::EOrientationCCW90 || display.Orientation() == CHuiGc::EOrientationCW90; + TRect renderBufferLocation = TRect(iPosition, iSize); + +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxVg10OffscreenRenderbuffer::PrepareForReuse - renderBufferLocation original: %i,%i, %i,%i "), + renderBufferLocation.iTl.iX, + renderBufferLocation.iTl.iY, + renderBufferLocation.iBr.iX, + renderBufferLocation.iBr.iY); +#endif + + TRect displayArea = display.VisibleArea(); + + TInt displayHeight = displayArea.Height(); + TInt displayWidth = displayArea.Width(); + + TSize rotatedSize = iSize; + TPoint rotatedPos = iPosition; + + // Read pixels from surface + if (rotatedDisplay) + { + if (iRotatedImage == VG_INVALID_HANDLE) + { + PushEGLContext(); + + #ifndef __WINS__ // Should possibly query the supported mode instead? + VGImageFormat imageInternalFormat = VG_sARGB_8888_PRE; + #else + VGImageFormat imageInternalFormat = VG_sARGB_8888; + #endif + + TSize rotatedImageSize = TSize(iSize.iHeight, iSize.iWidth); + iRotatedImage = vgCreateImage(imageInternalFormat, rotatedImageSize.iWidth, rotatedImageSize.iHeight, + VG_IMAGE_QUALITY_NONANTIALIASED); + + PopEGLContext(); + } + + + // If we have rotation on CHuiGc level, we must manually take that into account when + // accessing pixels directly + if(display.Orientation() == CHuiGc::EOrientationCCW90) + { + // Rotate the buffer location relative to real surface coordinates + rotatedSize = TSize(iSize.iHeight, iSize.iWidth); + rotatedPos = TPoint(displayHeight - iPosition.iY - iSize.iHeight, iPosition.iX); + renderBufferLocation = TRect(rotatedPos, rotatedSize); + } + else if(display.Orientation() == CHuiGc::EOrientationCW90) + { + // Rotate the buffer location relative to real surface coordinates + rotatedSize = TSize(iSize.iHeight, iSize.iWidth); + rotatedPos = TPoint(iPosition.iY, displayWidth - iPosition.iX - iSize.iWidth); + renderBufferLocation = TRect(rotatedPos, rotatedSize); + } + else + { + // nothing + } + + // If screen is rotated but surface is not in native orientation, this gets difficult + // because vgGetPixels is not affected by transformations. + + // Swap h and w so that those are the "real" values from surface point of view. + displayHeight = displayWidth; + + #ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxVg10OffscreenRenderbuffer::PrepareForReuse - renderBufferLocation: %i,%i, %i,%i "), + renderBufferLocation.iTl.iX, + renderBufferLocation.iTl.iY, + renderBufferLocation.iBr.iX, + renderBufferLocation.iBr.iY); + + TRect vgRect(TPoint(renderBufferLocation.iTl.iX, displayHeight - renderBufferLocation.iTl.iY - rotatedSize.iHeight), rotatedSize); + + RDebug::Print(_L("CHuiFxVg10OffscreenRenderbuffer::PrepareForReuse - vgRect: %i,%i, %i,%i "), + vgRect.iTl.iX, + vgRect.iTl.iY, + vgRect.iBr.iX, + vgRect.iBr.iY); + #endif + + // So...first get pixels from surface into rotated image + vgGetPixels(iRotatedImage, 0, 0, renderBufferLocation.iTl.iX, displayHeight - renderBufferLocation.iTl.iY - rotatedSize.iHeight, rotatedSize.iWidth, rotatedSize.iHeight); + + // Draw rotated image into real buffer image, first bind it as render target... + BindAsRenderTarget(); + + // ...store some states... + const TInt VG_MATRIX_SIZE = 9; + VGfloat oldMatrix[VG_MATRIX_SIZE]; + vgGetMatrix(oldMatrix); + + // ...set some vg states... + vgLoadIdentity(); + vgSeti(VG_BLEND_MODE, VG_BLEND_SRC); + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL); + vgSeti(VG_SCISSORING, VG_FALSE); + + TInt w = iSize.iWidth; + TInt h = iSize.iHeight; + + // ...select right rotation... + if (display.Orientation() == CHuiGc::EOrientationCW90) + { + // Rotate around origo and move back to displayarea + vgRotate(-90); + vgTranslate(-h, 0); + } + else if (display.Orientation() == CHuiGc::EOrientationCCW90) + { + // Rotate around origo and move back to displayarea + vgRotate(90); + vgTranslate(0, -w); + } + else if (display.Orientation() == CHuiGc::EOrientation180) + { + // Rotate around origo and move back to displayarea + vgRotate(180); + vgTranslate(-w, -h); + } + else + { + } + + // ...Draw... + if (iRotatedImage != VG_INVALID_HANDLE) + { + vgDrawImage(iRotatedImage); + } + + // ..and restore default VG states + vgSeti(VG_SCISSORING, VG_TRUE); + vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER); + vgLoadMatrix(oldMatrix); + + // ...finally unbind image and we should have the content correctly. + UnbindAsRenderTarget(); + } + else + { + // Much easier if no rotation ! + vgGetPixels(iImage, 0, 0, renderBufferLocation.iTl.iX, displayHeight - renderBufferLocation.iTl.iY - rotatedSize.iHeight, rotatedSize.iWidth, rotatedSize.iHeight); + } + } + } + +void CHuiFxVg10OffscreenRenderbuffer::PushEGLContext() + { + iPreviousEGLState.iContext= eglGetCurrentContext(); + TEGLState& state = iPlugin->GetUploadState(); + if (state.iContext == KErrNotFound) + { + TEGLState& state = iPlugin->GetUploadState(); + // the first context used for uploading will be used for all texture uploads + state.iContext = iPreviousEGLState.iContext; + state.iDrawSurface = eglGetCurrentSurface(EGL_DRAW); + state.iReadSurface = eglGetCurrentSurface(EGL_READ); + state.iDisplay = eglGetCurrentDisplay(); + } + else + { + // change context only if necessary + if (iPreviousEGLState.iContext != state.iContext) + { + iPreviousEGLState.iDrawSurface = eglGetCurrentSurface(EGL_DRAW); + iPreviousEGLState.iReadSurface = eglGetCurrentSurface(EGL_READ); + iPreviousEGLState.iDisplay = eglGetCurrentDisplay(); + eglMakeCurrent(state.iDisplay, state.iDrawSurface, state.iReadSurface, state.iContext); + } + } + } + +void CHuiFxVg10OffscreenRenderbuffer::PopEGLContext() + { + if (iPreviousEGLState.iContext != iPlugin->GetUploadState().iContext) + { + eglMakeCurrent(iPreviousEGLState.iDisplay, iPreviousEGLState.iDrawSurface, iPreviousEGLState.iReadSurface,iPreviousEGLState.iContext); + } + }