diff -r 000000000000 -r 15bf7259bb7c uiacceltk/hitchcock/coretoolkit/rendervg10/src/huivg10canvasrenderbuffer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uiacceltk/hitchcock/coretoolkit/rendervg10/src/huivg10canvasrenderbuffer.cpp Tue Feb 02 07:56:43 2010 +0200 @@ -0,0 +1,452 @@ +/* +* Copyright (c) 2006-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: Class canvas renderering target +* +*/ + + + +#include "huivg10canvasrenderbuffer.h" +#include "HuiVg10RenderPlugin.h" +#include "uiacceltk/HuiUtil.h" +#include "uiacceltk/HuiEnv.h" +#include "HuiVg10RenderPlugin.h" +#include "uiacceltk/HuiDisplay.h" + +//#define HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL + + +CHuiVg10CanvasRenderBuffer::CHuiVg10CanvasRenderBuffer() + { + } + +CHuiVg10CanvasRenderBuffer::~CHuiVg10CanvasRenderBuffer() + { + UnInitialize(); + } + +void CHuiVg10CanvasRenderBuffer::UnInitialize() + { + CHuiVg10RenderPlugin& renderer = CHuiStatic::Vg10Renderer(); + + UnBind(); + + if (iGc) + { + delete iGc; + iGc = 0; + } + + if (iRotatedImage) + { + vgDestroyImage(iRotatedImage); + iRotatedImage = VG_INVALID_HANDLE; + } + + if (iImage) + { + vgDestroyImage(iImage); + iImage = VG_INVALID_HANDLE; + } + + if (iSurface) + { + eglDestroySurface(renderer.EglDisplay(), iSurface); + iSurface = 0; + } + + if (iContext) + { + eglDestroyContext(renderer.EglDisplay(), iContext); + iContext = 0; + } + + iInitialized = EFalse; + } + +void CHuiVg10CanvasRenderBuffer::InitializeL(const TSize& aSize) + { + if (iSize == aSize && iImage && iContext && iSurface) + { + // Already initalized + return; + } + + CHuiVg10RenderPlugin& renderer = CHuiStatic::Vg10Renderer(); + + // Just in case... + UnInitialize(); + + PushEGLContext(); + +#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL + TTime startTime; + startTime.UniversalTime(); +#endif + + iSize = aSize; + +#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, iSize.iWidth, iSize.iHeight, + VG_IMAGE_QUALITY_NONANTIALIASED); + + if (iImage == VG_INVALID_HANDLE) + { + PopEGLContext(); + + VGErrorCode err = vgGetError(); + RDebug::Print(_L("CHuiVg10CanvasRenderBuffer::InitializeL() - vgCreateImage failed: VgError -- %04x"), err); + User::Leave(KErrGeneral); + } + + const TInt BITS_PER_CHANNEL = 8; + + // Choose an EGL config + const EGLint attrs[] = + { + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT | EGL_VG_ALPHA_FORMAT_PRE_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 = renderer.EglChooseConfig(attrs); + ASSERT(configCount > 0); + + if (configCount <= 0) + { + PopEGLContext(); + + RDebug::Print(_L("CHuiVg10CanvasRenderBuffer::InitializeL() - no EGL config found !")); + User::Leave(KErrGeneral); + } + + EGLConfig config = renderer.EglConfig(0); + + // Create a context + iContext = eglCreateContext(renderer.EglDisplay(), config, + renderer.EglSharedContext(), NULL); + + if(!iContext) + { + PopEGLContext(); + + EGLint err = eglGetError(); + RDebug::Print(_L("CHuiVg10CanvasRenderBuffer::InitializeL() - EGLContext creation failed: EglError -- %04x"), err); + User::Leave(KErrGeneral); + } + + // Create a pbuffer surface + iSurface = eglCreatePbufferFromClientBuffer(renderer.EglDisplay(), EGL_OPENVG_IMAGE, + iImage, config, NULL); + if(!iSurface) + { + PopEGLContext(); + + EGLint err = eglGetError(); + RDebug::Print(_L("CHuiVg10CanvasRenderBuffer::InitializeL() - EGLSurface creation failed: EglError -- %04x"), err); + User::Leave(KErrGeneral); + } + + // Initialize the context (TODO: We perhaps do not really need to do this by creating Cg + iGc = renderer.CreateGcL(); + Bind(); + iGc->InitState(); + + VGfloat color[] = + { + 0.f, 0.f, 0.f, 0.f + }; + vgSetfv(VG_CLEAR_COLOR, sizeof(color) / sizeof(VGfloat), color); + vgClear(0, 0, iSize.iWidth, iSize.iHeight); + UnBind(); + + // Let renderer know that we have been fiddlling with OpenVg state directly + // "iGc->InitState" confuses scissoring setting, so lets notify it. + renderer.AddRestoreStateFlags(EHuiVg10GcStateFlagDirtyScissor); + renderer.AddRestoreStateFlags(EHuiVg10GcStateFlagDirtyBlendMode); + + #ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL + TTime endTime; + endTime.UniversalTime(); + TInt timeInMs = endTime.MicroSecondsFrom( startTime ).Int64()/1000; + RDebug::Print(_L("> CHuiVg10CanvasRenderBuffer::InitializeL took %i ms"), timeInMs); +#endif + + iInitialized = ETrue; + + PopEGLContext(); + } + +void CHuiVg10CanvasRenderBuffer::Bind() + { + // Make sure it is safe to call even if "UnBind" has not been called or this function + // has already been called. + if (!iSurface || !iContext || iSavedContext || iSavedDrawSurface || iSavedReadSurface) + { + return; + } + + // Save current context and surfaces + iSavedContext = eglGetCurrentContext(); + iSavedDrawSurface = eglGetCurrentSurface(EGL_DRAW); + iSavedReadSurface = eglGetCurrentSurface(EGL_READ); + + // Bind our own surface + CHuiVg10RenderPlugin& renderer = CHuiStatic::Vg10Renderer(); + eglMakeCurrent(renderer.EglDisplay(), iSurface, iSurface, iContext); + } + +void CHuiVg10CanvasRenderBuffer::UnBind() + { + // Make sure it is safe to call even if "Bind" has not been called or this + // function has already been called. + if (!iSavedDrawSurface || !iSavedReadSurface || !iSavedContext) + { + return; + } + + // Restore original surface & context + CHuiVg10RenderPlugin& renderer = CHuiStatic::Vg10Renderer(); + + // Todo: Should check whether the saved surface was UI surface + // and call CHuiVg10RenderSurface::MakeCurrent() for that instead + CHuiEnv* env = CHuiEnv::Static(); + if (env && env->iSwapObserver) + { + env->iSwapObserver->ReleaseWindowServer(); + } + + eglMakeCurrent(renderer.EglDisplay(), iSavedDrawSurface, iSavedReadSurface, + iSavedContext); + + if (env && env->iSwapObserver) + { + env->iSwapObserver->ReleaseWindowServer(EFalse); + } + + iSavedDrawSurface = 0; + iSavedReadSurface = 0; + iSavedContext = 0; + } + +VGImage CHuiVg10CanvasRenderBuffer::Image() const + { + return iImage; + } + + +void CHuiVg10CanvasRenderBuffer::PushEGLContext() + { + CHuiVg10RenderPlugin& renderer = CHuiStatic::Vg10Renderer(); + iPreviousEGLState.iContext= eglGetCurrentContext(); + TEGLState& state = renderer.GetUploadState(); + if (state.iContext == KErrNotFound) + { + TEGLState& state = renderer.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 CHuiVg10CanvasRenderBuffer::PopEGLContext() + { + CHuiVg10RenderPlugin& renderer = CHuiStatic::Vg10Renderer(); + if (iPreviousEGLState.iContext != renderer.GetUploadState().iContext) + { + eglMakeCurrent(iPreviousEGLState.iDisplay, iPreviousEGLState.iDrawSurface, iPreviousEGLState.iReadSurface,iPreviousEGLState.iContext); + } + } + +void CHuiVg10CanvasRenderBuffer::Copy(const CHuiCanvasRenderBuffer& aSourceBuffer) + { + if (iSize != aSourceBuffer.Size()) + { + return; + } + + CHuiVg10CanvasRenderBuffer* sourcebuffer = (CHuiVg10CanvasRenderBuffer*) &aSourceBuffer; + vgCopyImage(iImage, 0, 0, + sourcebuffer->Image(), 0, 0, + iSize.iWidth, iSize.iHeight, VG_FALSE); + } + +void CHuiVg10CanvasRenderBuffer::Copy(TPoint aPoint) + { + ReadBackground(aPoint); + } + +void CHuiVg10CanvasRenderBuffer::ReadBackground(TPoint aPosition) + { + CHuiDisplay& display = CHuiStatic::Env().PrimaryDisplay(); + TBool rotatedDisplay = display.Orientation() == CHuiGc::EOrientationCCW90 || display.Orientation() == CHuiGc::EOrientationCW90; + TRect renderBufferLocation = TRect(aPosition, iSize); + + TRect displayArea = display.VisibleArea(); + + TInt displayHeight = displayArea.Height(); + TInt displayWidth = displayArea.Width(); + + TSize rotatedSize = iSize; + TPoint rotatedPos = aPosition; + + // 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 - aPosition.iY - iSize.iHeight, aPosition.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(aPosition.iY, displayWidth - aPosition.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... + Bind(); + + // ...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. + UnBind(); + } + else + { + // Much easier if no rotation ! + vgGetPixels(iImage, 0, 0, renderBufferLocation.iTl.iX, displayHeight - renderBufferLocation.iTl.iY - rotatedSize.iHeight, rotatedSize.iWidth, rotatedSize.iHeight); + } + } +