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