uiacceltk/hitchcock/coretoolkit/rendervg10/src/HuiFxVg10OffscreenRenderbuffer.cpp
changeset 0 15bf7259bb7c
child 17 3ac8bf5c5014
--- /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);
+        }
+    }