--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graphicsresourceservices/graphicsresourceimplementation/src/sgdriver.cpp Tue Aug 31 16:31:06 2010 +0300
@@ -0,0 +1,569 @@
+// Copyright (c) 2007-2009 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:
+// Graphics Resource - driver implementation
+//
+
+#include "sgdriver.h"
+
+const TInt KSgMaxLocalChunkSize = 0x100000;
+const TInt KSgLocalChunkAlignment = 0x40;
+
+EXPORT_C TInt RSgDriver::Open()
+ {
+ if (iImpl)
+ {
+ return KErrInUse;
+ }
+ if (gPls.iError != KErrNone)
+ {
+ return gPls.iError;
+ }
+ gPls.iMutex.Wait();
+ if (gPls.iDriver)
+ {
+ ++gPls.iOpenCount;
+ iImpl = gPls.iDriver;
+ gPls.iMutex.Signal();
+ return KErrNone;
+ }
+ RChunk chunk;
+ TInt err = chunk.CreateLocal(KMinHeapGrowBy, KSgMaxLocalChunkSize, EOwnerProcess);
+ if (err != KErrNone)
+ {
+ gPls.iMutex.Signal();
+ return err;
+ }
+ RHeap* heap = UserHeap::ChunkHeap(chunk, 0, KMinHeapGrowBy, KSgMaxLocalChunkSize, KSgLocalChunkAlignment, ETrue);
+ __ASSERT_DEBUG(heap, Panic(ESgPanicResourceImplGeneral));
+ XSgDriver* driver = static_cast<XSgDriver*>(heap->Alloc(sizeof(XSgDriver)));
+ __ASSERT_DEBUG(driver, Panic(ESgPanicResourceImplGeneral));
+ new(driver) XSgDriver(heap);
+ err = driver->Construct();
+ if (err != KErrNone)
+ {
+ driver->Delete();
+ gPls.iMutex.Signal();
+ return err;
+ }
+ gPls.iOpenCount = 1;
+ iImpl = gPls.iDriver = driver;
+ gPls.iMutex.Signal();
+ return KErrNone;
+ }
+
+EXPORT_C void RSgDriver::Close()
+ {
+ if (iImpl)
+ {
+ __ASSERT_DEBUG(gPls.iError == KErrNone, Panic(ESgPanicResourceImplGeneral));
+ gPls.iMutex.Wait();
+ __ASSERT_DEBUG(gPls.iOpenCount > 0, Panic(ESgPanicResourceImplGeneral));
+ if (--gPls.iOpenCount == 0)
+ {
+ gPls.iDriver->Delete();
+ gPls.iDriver = NULL;
+ }
+ iImpl = NULL;
+ gPls.iMutex.Signal();
+ }
+ }
+
+EXPORT_C TInt RSgDriver::GetInterface(TUid aInterfaceUid, TAny*& aInterfacePtr) const
+ {
+ aInterfacePtr = NULL;
+ if (!iImpl)
+ {
+ return KErrBadHandle;
+ }
+ return static_cast<XSgDriver*>(iImpl)->GetInterface(aInterfaceUid, aInterfacePtr);
+ }
+
+EXPORT_C TVersion RSgDriver::Version()
+ {
+ return TVersion(1, 1, 1);
+ }
+
+_LIT(KSgResourceImplPanicCategory, "SGRES-IMPL");
+
+void Panic(TSgResourceImplPanicReason aReason)
+ {
+ User::Panic(KSgResourceImplPanicCategory, aReason);
+ }
+
+#ifdef SYMBIAN_GRAPHICS_USE_GPU
+const TUint32 KSgResourceAttributes = 0;
+#else
+const TUint32 KSgResourceAttributes = ESgResourceAttrCpuCached;
+#endif
+
+LOCAL_C TInt SgMinDataStride(TInt aWidthInPixels, TInt aPixelFormat)
+ {
+ switch (aPixelFormat)
+ {
+ case ESgPixelFormatA_8:
+ return aWidthInPixels;
+ case ESgPixelFormatRGB_565:
+ return aWidthInPixels << 1;
+ case ESgPixelFormatXRGB_8888:
+ case ESgPixelFormatARGB_8888:
+ case ESgPixelFormatARGB_8888_PRE:
+ return aWidthInPixels << 2;
+ default:
+#ifdef _DEBUG
+ Panic(ESgPanicResourceImplGeneral);
+#endif
+ return 0;
+ }
+ }
+
+LOCAL_C TInt SgAlignedDataStride(TInt aWidthInPixels, TInt aPixelFormat)
+ {
+#if defined(SYMBIAN_GRAPHICS_USE_MBX)
+ // MBX requires 2^n stride
+ for (TInt width = 8; width & KMaxTInt; width <<= 1)
+ {
+ if (width >= aWidthInPixels)
+ {
+ aWidthInPixels = width;
+ break;
+ }
+ }
+#elif defined(SYMBIAN_GRAPHICS_USE_SGX)
+ // SGX requires 32-pixel alignment
+ aWidthInPixels = (aWidthInPixels + 31) & ~31;
+#endif
+ return Align4(SgMinDataStride(aWidthInPixels, aPixelFormat));
+ }
+
+XSgDriverPls::XSgDriverPls()
+ {
+ iError = iMutex.CreateLocal();
+ iOpenCount = 0;
+ iDriver = NULL;
+ }
+
+XSgDriver::XSgDriver(RHeap* aHeap)
+ : iHeap(aHeap), iHasOpenVg(EFalse), iHasOpenGles(EFalse), iHasOpenGles2(EFalse)
+ {
+ }
+
+XSgDriver::~XSgDriver()
+ {
+ iMutex.Close();
+ iDevice.Close();
+ __ASSERT_DEBUG(iImagesByAddress.Count() == 0, Panic(ESgPanicUnclosedResources));
+ __ASSERT_DEBUG(iImagesById.Count() == 0, Panic(ESgPanicUnclosedResources));
+ }
+
+TInt XSgDriver::Construct()
+ {
+ TInt err = iMutex.CreateLocal();
+ if (err != KErrNone)
+ {
+ return err;
+ }
+ err = User::LoadLogicalDevice(KSgDeviceName);
+ if (err != KErrNone && err != KErrAlreadyExists)
+ {
+ return err;
+ }
+ err = iDevice.Connect();
+ if (err != KErrNone)
+ {
+ return err;
+ }
+ _LIT(KLibOpenVg, "libOpenVG.dll");
+ _LIT(KLibOpenGles, "libGLESv1_CM.dll");
+ _LIT(KLibOpenGles2, "libGLESv2.dll");
+ RLibrary lib;
+ if (lib.Load(KLibOpenVg) == KErrNone)
+ {
+ lib.Close();
+ iHasOpenVg = ETrue;
+ }
+ if (lib.Load(KLibOpenGles) == KErrNone)
+ {
+ lib.Close();
+ iHasOpenGles = ETrue;
+ }
+ if (lib.Load(KLibOpenGles2) == KErrNone)
+ {
+ lib.Close();
+ iHasOpenGles2 = ETrue;
+ }
+ return KErrNone;
+ }
+
+void XSgDriver::Delete()
+ {
+ RHeap* heap = iHeap;
+ this->~XSgDriver();
+ heap->Free(this);
+ __ASSERT_DEBUG(heap->Count() == 0, Panic(ESgPanicUnclosedResources));
+ heap->Close();
+ }
+
+TInt XSgDriver::CreateImage(const TSgImageInfo& aInfo, const TAny* aDataAddress, TInt aDataStride, const TSgAttributeArrayBase* aAttributes, TAny*& aResult)
+ {
+ TInt err = CheckImageInfo(aInfo);
+ if (err != KErrNone)
+ {
+ return err;
+ }
+ TInt minDataStride = SgMinDataStride(aInfo.iSizeInPixels.iWidth, aInfo.iPixelFormat);
+ if (aDataAddress && Abs(aDataStride) < minDataStride)
+ {
+ return KErrArgument;
+ }
+ if (aAttributes)
+ {
+ return KErrNotSupported;
+ }
+ TUint32 attribs = KSgResourceAttributes | MatchingEglConfigUsage(aInfo.iUsage);
+ TPckgBuf<TSgImageMetaData> metaDataPckg;
+ metaDataPckg().iSizeInPixels = aInfo.iSizeInPixels;
+ metaDataPckg().iPixelFormat = aInfo.iPixelFormat;
+ TInt dataStride = SgAlignedDataStride(aInfo.iSizeInPixels.iWidth, aInfo.iPixelFormat);
+ TInt dataSize = dataStride * aInfo.iSizeInPixels.iHeight;
+ TSgDrawableId id;
+ err = iDevice.CreateResource(attribs, metaDataPckg, dataSize, id.iId);
+ if (err != KErrNone)
+ {
+ return err;
+ }
+ iMutex.Wait();
+ XSgImage* imageImpl = static_cast<XSgImage*>(iHeap->Alloc(sizeof(XSgImage)));
+ if (!imageImpl)
+ {
+ (void)iDevice.CloseResource(id.iId);
+ iMutex.Signal();
+ return KErrNoMemory;
+ }
+ new(imageImpl) XSgImage(id, attribs, metaDataPckg(), iDevice.ResourceDataAddress(id.iId), dataStride);
+ RHeap* prevHeap = User::SwitchHeap(iHeap);
+ err = iImagesByAddress.InsertInAddressOrder(imageImpl);
+ if (err == KErrNone)
+ {
+ err = iImagesById.InsertInOrder(imageImpl, XSgImage::Compare);
+ if (err != KErrNone)
+ {
+ iImagesByAddress.Remove(iImagesByAddress.FindInAddressOrder(imageImpl));
+ iImagesByAddress.GranularCompress();
+ }
+ }
+ User::SwitchHeap(prevHeap);
+ if (err == KErrNone)
+ {
+ if (aDataAddress)
+ {
+ const TAny* src = aDataStride > 0 ? aDataAddress : PtrAdd(aDataAddress, -aDataStride * (aInfo.iSizeInPixels.iHeight - 1));
+ TAny* trg = imageImpl->DataAddress();
+ for (TInt y = 0; y < aInfo.iSizeInPixels.iHeight; ++y)
+ {
+ Mem::Copy(trg, src, minDataStride);
+ src = PtrAdd(src, aDataStride);
+ trg = PtrAdd(trg, dataStride);
+ }
+ }
+ aResult = imageImpl;
+ }
+ else
+ {
+ (void)iDevice.CloseResource(id.iId);
+ iHeap->Free(imageImpl);
+ }
+ iMutex.Signal();
+ return err;
+ }
+
+TInt XSgDriver::CreateImage(const TSgImageInfo& aInfo, const XSgImage* aImageImpl, const TSgAttributeArrayBase* aAttributes, TAny*& aResult)
+ {
+ if (!aImageImpl)
+ {
+ return KErrArgument;
+ }
+ __ASSERT_ALWAYS(CheckImage(aImageImpl), Panic(ESgPanicBadDrawableHandle));
+ TSgImageInfo info;
+ aImageImpl->GetInfo(info);
+ if (aInfo.iSizeInPixels != info.iSizeInPixels || aInfo.iPixelFormat != info.iPixelFormat)
+ {
+ return KErrNotSupported;
+ }
+ return CreateImage(aInfo, aImageImpl->DataAddress(), aImageImpl->DataStride(), aAttributes, aResult);
+ }
+
+TInt XSgDriver::FindAndOpenImage(TSgDrawableId aId, const TSgAttributeArrayBase* aAttributes, TAny*& aResult)
+ {
+ if (aId == KSgNullDrawableId)
+ {
+ return KErrArgument;
+ }
+ if (aAttributes)
+ {
+ return KErrNotSupported;
+ }
+ TInt err;
+ iMutex.Wait();
+ TInt indexById = iImagesById.FindInOrder(aId, XSgImage::Compare);
+ if (indexById >= 0)
+ {
+ XSgImage* imageImpl = iImagesById[indexById];
+ err = imageImpl->Open();
+ if (err == KErrNone)
+ {
+ aResult = imageImpl;
+ }
+ }
+ else
+ {
+ err = iDevice.OpenResource(aId.iId);
+ if (err != KErrNone)
+ {
+ iMutex.Signal();
+ return err;
+ }
+ TPckgBuf<TSgImageMetaData> metaDataPckg;
+ err = iDevice.GetResourceMetaData(aId.iId, metaDataPckg);
+ if (metaDataPckg.Size() != sizeof(TSgImageMetaData))
+ {
+ err = KErrGeneral;
+ }
+ TUint32 attribs;
+ if (err == KErrNone)
+ {
+ attribs = iDevice.ResourceAttributes(aId.iId);
+ TSgImageInfo info(metaDataPckg().iSizeInPixels, metaDataPckg().iPixelFormat, attribs & KSgUsageBitMask);
+ if (CheckImageInfo(info) != KErrNone)
+ {
+ err = KErrGeneral;
+ }
+ }
+ TInt dataStride;
+ if (err == KErrNone)
+ {
+ dataStride = SgAlignedDataStride(metaDataPckg().iSizeInPixels.iWidth, metaDataPckg().iPixelFormat);
+ if (iDevice.ResourceDataSize(aId.iId) != dataStride * metaDataPckg().iSizeInPixels.iHeight)
+ {
+ err = KErrGeneral;
+ }
+ }
+ if (err != KErrNone)
+ {
+ (void)iDevice.CloseResource(aId.iId);
+ iMutex.Signal();
+ return err;
+ }
+ XSgImage* imageImpl = static_cast<XSgImage*>(iHeap->Alloc(sizeof(XSgImage)));
+ if (!imageImpl)
+ {
+ (void)iDevice.CloseResource(aId.iId);
+ iMutex.Signal();
+ return KErrNoMemory;
+ }
+ new(imageImpl) XSgImage(aId, attribs, metaDataPckg(), iDevice.ResourceDataAddress(aId.iId), dataStride);
+ RHeap* prevHeap = User::SwitchHeap(iHeap);
+ err = iImagesByAddress.InsertInAddressOrder(imageImpl);
+ if (err == KErrNone)
+ {
+ err = iImagesById.InsertInOrder(imageImpl, XSgImage::Compare);
+ if (err != KErrNone)
+ {
+ iImagesByAddress.Remove(iImagesByAddress.FindInAddressOrder(imageImpl));
+ iImagesByAddress.GranularCompress();
+ }
+ }
+ User::SwitchHeap(prevHeap);
+ if (err == KErrNone)
+ {
+ aResult = imageImpl;
+ }
+ else
+ {
+ (void)iDevice.CloseResource(aId.iId);
+ iHeap->Free(imageImpl);
+ }
+ }
+ iMutex.Signal();
+ return err;
+ }
+
+void XSgDriver::DeleteImage(XSgImage* aImageImpl)
+ {
+ iMutex.Wait();
+ TInt indexByAddress = iImagesByAddress.FindInAddressOrder(aImageImpl);
+ TInt indexById = iImagesById.FindInOrder(aImageImpl, XSgImage::Compare);
+ __ASSERT_DEBUG(indexByAddress >= 0 && indexById >= 0, Panic(ESgPanicBadImagePointer));
+ RHeap* prevHeap = User::SwitchHeap(iHeap);
+ iImagesByAddress.Remove(indexByAddress);
+ iImagesById.Remove(indexById);
+ iImagesByAddress.GranularCompress();
+ iImagesById.GranularCompress();
+ User::SwitchHeap(prevHeap);
+ (void)iDevice.CloseResource(aImageImpl->Id().iId);
+ aImageImpl->~XSgImage();
+ iHeap->Free(aImageImpl);
+ iMutex.Signal();
+ }
+
+TUint32 XSgDriver::MatchingEglConfigUsage(TUint32 aUsage) const
+ {
+ if (aUsage & KSgUsageAllSurfaceTypes)
+ {
+ if (iHasOpenVg)
+ {
+ aUsage |= ESgUsageBitOpenVgSurface;
+ }
+ if (iHasOpenGles)
+ {
+ aUsage |= ESgUsageBitOpenGlesSurface;
+ }
+ if (iHasOpenGles2)
+ {
+ aUsage |= ESgUsageBitOpenGles2Surface;
+ }
+ }
+ return aUsage;
+ }
+
+TInt XSgDriver::CheckImageInfo(const TSgImageInfo& aInfo) const
+ {
+ if (aInfo.iSizeInPixels.iWidth <= 0 || aInfo.iSizeInPixels.iHeight <= 0
+ || aInfo.iPixelFormat == EUidPixelFormatUnknown || aInfo.iUsage == 0)
+ {
+ return KErrArgument;
+ }
+ if (aInfo.iSizeInPixels.iWidth > KMaxTInt16 / 2 || aInfo.iSizeInPixels.iHeight > KMaxTInt16 / 2)
+ {
+ return KErrTooBig;
+ }
+ if (aInfo.iUsage & ~KSgUsageAll)
+ {
+ return KErrNotSupported;
+ }
+ if ((aInfo.iUsage & (ESgUsageBitOpenVgImage | ESgUsageBitOpenVgSurface)) && !iHasOpenVg
+ || (aInfo.iUsage & (ESgUsageBitOpenGlesTexture2D | ESgUsageBitOpenGlesSurface)) && !iHasOpenGles
+ || (aInfo.iUsage & (ESgUsageBitOpenGles2Texture2D | ESgUsageBitOpenGles2Surface)) && !iHasOpenGles2)
+ {
+ return KErrNotSupported;
+ }
+ switch (aInfo.iPixelFormat)
+ {
+ case ESgPixelFormatA_8:
+ if (aInfo.iUsage & KSgUsageAllSurfaceTypes)
+ {
+ return KErrNotSupported;
+ }
+ // coverity[fallthrough]
+ case ESgPixelFormatRGB_565:
+ case ESgPixelFormatXRGB_8888:
+ case ESgPixelFormatARGB_8888:
+ case ESgPixelFormatARGB_8888_PRE:
+ return KErrNone;
+ default:
+ return KErrNotSupported;
+ }
+ }
+
+TBool XSgDriver::CheckImage(const TAny* aImageImpl) const
+ {
+ iMutex.Wait();
+ TInt indexByAddress = iImagesByAddress.FindInAddressOrder(static_cast<const XSgImage*>(aImageImpl));
+ iMutex.Signal();
+ return indexByAddress >= 0;
+ }
+
+TInt XSgDriver::GetInterface(TUid aInterfaceUid, TAny*& aInterfacePtr)
+ {
+ if (aInterfaceUid == KNullUid)
+ {
+ return KErrArgument;
+ }
+ if (aInterfaceUid.iUid == MSgDriver_Profiling::EInterfaceUid)
+ {
+ aInterfacePtr = static_cast<MSgDriver_Profiling*>(this);
+ return KErrNone;
+ }
+#ifdef _DEBUG
+ if (aInterfaceUid.iUid == MSgDriver_Test::EInterfaceUid)
+ {
+ aInterfacePtr = static_cast<MSgDriver_Test*>(this);
+ return KErrNone;
+ }
+#endif
+ return KErrExtensionNotSupported;
+ }
+
+TInt XSgDriver::LocalResourceCount() const
+ {
+ TInt count = 0;
+ iMutex.Wait();
+ TInt n = iImagesByAddress.Count();
+ for (TInt i = 0; i < n; ++i)
+ {
+ count += iImagesByAddress[i]->RefCount();
+ }
+ iMutex.Signal();
+ return count;
+ }
+
+TInt XSgDriver::GlobalResourceCount() const
+ {
+ return iDevice.GlobalResourceCount();
+ }
+
+TInt XSgDriver::LocalGraphicsMemoryUsed() const
+ {
+ return iDevice.LocalGraphicsMemoryUsed();
+ }
+
+TInt XSgDriver::GlobalGraphicsMemoryUsed() const
+ {
+ return iDevice.GlobalGraphicsMemoryUsed();
+ }
+
+#ifdef _DEBUG
+
+void XSgDriver::AllocMarkStart()
+ {
+ iMutex.Wait();
+ iHeap->__DbgMarkStart();
+ iMutex.Signal();
+ }
+
+void XSgDriver::AllocMarkEnd(TInt aCount)
+ {
+ iMutex.Wait();
+ TUint32 badCell = iHeap->__DbgMarkEnd(aCount);
+ iMutex.Signal();
+ if (badCell != 0)
+ {
+ _LIT(KPanicCategoryFormat, "SGALLOC:%08x");
+ TBuf<0x10> category;
+ category.Format(KPanicCategoryFormat, badCell);
+ User::Panic(category, 0);
+ }
+ }
+
+void XSgDriver::SetAllocFail(RAllocator::TAllocFail aType, TInt aRate)
+ {
+ iMutex.Wait();
+ iHeap->__DbgSetAllocFail(aType, aRate);
+ iMutex.Signal();
+ }
+
+#endif // _DEBUG
+
+#ifndef __WINS__
+XSgDriverPls gPls;
+#endif