graphicsresourceservices/graphicsresourceadaptation/src/sgdriverimpl.cpp
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graphicsresourceservices/graphicsresourceadaptation/src/sgdriverimpl.cpp	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,813 @@
+// 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:
+//
+
+#include <e32math.h>
+#include "sgdriverimpl.h"
+#include "sgimageimpl.h"
+#include "sgimagecollectionimpl.h"
+
+
+TInt SgAlignedDataStride(TInt aWidthInPixels, TUidPixelFormat 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 a 32 pixel alignment. 
+	aWidthInPixels = (aWidthInPixels + 31) & ~31;
+#endif
+	return Align4(SgMinDataStride(aWidthInPixels, aPixelFormat));
+	}
+
+
+TInt SgOffsetToFirstBuffer(TInt aMetaDataSize)
+	{
+#if defined(SYMBIAN_GRAPHICS_USE_MBX) || defined(SYMBIAN_GRAPHICS_USE_SGX)
+	return (aMetaDataSize + 127) & ~127;
+#else
+	return Align4(aMetaDataSize);
+#endif
+	}
+
+
+TInt SgOffsetBetweenBuffers(TInt aDataStride, TInt aScanLineCount)
+	{
+#if defined(SYMBIAN_GRAPHICS_USE_MBX)
+	for (TInt count = 16; count & KMaxTInt; count <<= 1)
+		{
+		if (count >= aScanLineCount)
+			{
+			aScanLineCount = count;
+			break;
+			}
+		}
+#endif
+	return aDataStride * aScanLineCount;
+	}
+
+
+TBool SgIsValidImageInfo(const TSgImageInfo& aInfo)
+	{
+	return aInfo.iSizeInPixels.iWidth > 0 && aInfo.iSizeInPixels.iHeight > 0
+		&& (aInfo.iUsage & ESgUsageScreenSource ? aInfo.iScreenId >= KSgScreenIdMain : aInfo.iScreenId >= KSgScreenIdAny)
+		&& (aInfo.iUserAttributes ? aInfo.iUserAttributeCount > 0 : aInfo.iUserAttributeCount == 0);
+	}
+
+
+TBool SgIsMutableImage(const TSgImageInfo& aInfo)
+	{
+	return (aInfo.iCpuAccess & ESgCpuAccessWritable) || (aInfo.iUsage & KSgUsageAllTargets);
+	}
+
+
+TBool SgIsCachedImage(const TSgImageInfo& aInfo)
+	{
+#ifdef SYMBIAN_GRAPHICS_USE_GPU
+#ifdef SYMBIAN_GRAPHICS_USE_CACHE
+	return aInfo.iCpuAccess != ESgCpuAccessNone;
+#else
+	(void)aInfo;
+	return EFalse;
+#endif
+#else
+	(void)aInfo;
+	return ETrue;
+#endif
+	}
+
+
+// TSgPixelFormatTableEntry
+
+TBool TSgPixelFormatTableEntry::IsMatch(const TSgImageInfo& aInfo) const
+	{
+	return iPixelFormat == aInfo.iPixelFormat
+		&& !(~iUsage & aInfo.iUsage)
+		&& !(~iCpuAccess & aInfo.iCpuAccess)
+		&& (iScreenId == KSgScreenIdAny || iScreenId == aInfo.iScreenId);
+	}
+
+
+TBool TSgPixelFormatTableEntry::IsMatchIgnoringPixelFormat(const TSgImageInfo& aInfo) const
+	{
+	return !(~iUsage & aInfo.iUsage)
+		&& !(~iCpuAccess & aInfo.iCpuAccess)
+		&& (iScreenId == KSgScreenIdAny || iScreenId == aInfo.iScreenId);
+	}
+
+
+TBool TSgPixelFormatTableEntry::IsMatchIgnoringUsage(const TSgImageInfo& aInfo) const
+	{
+	return iPixelFormat == aInfo.iPixelFormat
+		&& !(~iCpuAccess & aInfo.iCpuAccess)
+		&& (iScreenId == KSgScreenIdAny || iScreenId == aInfo.iScreenId);
+	}
+
+
+// XSgBase
+
+XSgBase::~XSgBase()
+	{
+	__ASSERT_DEBUG(iDriverImpl.IsMutexHeld(), Panic(ESgPanicMutexNotHeld));
+	__ASSERT_DEBUG(iRefCount == 0, Panic(ESgPanicBadReferenceCount));
+	}
+
+
+void XSgBase::Delete()
+	{
+	XSgDriverImpl& driverImpl = iDriverImpl;
+	this->~XSgBase();
+	driverImpl.Free(this);
+	}
+
+
+// XSgDriverImpl
+
+TInt XSgDriverImpl::Construct()
+	{
+	TInt err = iMutex.CreateLocal();
+	if (err != KErrNone)
+		{
+		return err;
+		}
+	err = iSurfaceManager.Open();
+	if (err != KErrNone)
+		{
+		return err;
+		}
+	return ConstructPixelFormatTable();
+	}
+
+
+XSgDriverImpl::~XSgDriverImpl()
+	{
+	__ASSERT_DEBUG(iImages.Count() == 0, Panic(ESgPanicUnclosedResources));
+	__ASSERT_DEBUG(iImageCollections.Count() == 0, Panic(ESgPanicUnclosedResources));
+	iMutex.Close();
+	iSurfaceManager.Close();
+	RHeap* prevHeap = User::SwitchHeap(iHeap);
+	iPixelFormatTable.Close();
+	iLastPixelFormats.Close();
+	User::SwitchHeap(prevHeap);
+	}
+
+
+void XSgDriverImpl::Delete()
+	{
+	RHeap* heap = iHeap;
+	this->~XSgDriverImpl();
+	heap->Free(this);
+	__ASSERT_DEBUG(heap->Count() == 0, Panic(ESgPanicUnclosedResources));
+	heap->Close();
+	}
+
+
+TInt XSgDriverImpl::MapSurface(const TSurfaceId& aSurfaceId, RChunk& aChunk)
+	{
+	RChunk chunk;
+	TInt err = iSurfaceManager.MapSurface(aSurfaceId, chunk);
+	if (err != KErrNone)
+		{
+		return err;
+		}
+	aChunk = chunk;
+	err = aChunk.Duplicate(RThread()); // Get a process-wide handle
+	chunk.Close();
+	return err;
+	}
+
+
+TArray<TSgPixelFormatTableEntry> XSgDriverImpl::PixelFormatTable() const
+	{
+	return iPixelFormatTable.Array();
+	}
+
+
+TInt XSgDriverImpl::CanCreateImage(const TSgImageInfo& aInfo) const
+	{
+	__ASSERT_DEBUG(SgIsValidImageInfo(aInfo), Panic(ESgPanicBadImageInfo));
+	if (aInfo.iSizeInPixels.iWidth > KMaxTInt16 / 2 || aInfo.iSizeInPixels.iHeight > KMaxTInt16 / 2)
+		{
+		return KErrTooBig;
+		}
+	TArray<TSgPixelFormatTableEntry> pixelFormatTable = PixelFormatTable();
+	TInt n = pixelFormatTable.Count();
+	for (TInt i = 0; i < n; ++i)
+		{
+		if (pixelFormatTable[i].IsMatch(aInfo))
+			{
+			return SgMinDataStride(aInfo.iSizeInPixels.iWidth, aInfo.iPixelFormat) > 0 ? KErrNone : KErrNotSupported;
+			}
+		}
+	return KErrNotSupported;
+	}
+
+
+TInt XSgDriverImpl::GetPixelFormats(const TSgImageInfo& aInfo, TUidPixelFormat* aPixelFormats, TInt& aCount)
+	{
+	if (!SgIsValidImageInfo(aInfo) || (aPixelFormats && aCount < 0))
+		{
+		return KErrArgument;
+		}
+	iMutex.Wait();
+	if (aInfo.iSizeInPixels != iLastSizeInPixels
+		|| aInfo.iUsage != iLastUsage
+		|| aInfo.iCpuAccess != iLastCpuAccess
+		|| aInfo.iScreenId != iLastScreenId)
+		{
+		iLastSizeInPixels = aInfo.iSizeInPixels;
+		iLastUsage = aInfo.iUsage;
+		iLastCpuAccess = aInfo.iCpuAccess;
+		iLastScreenId = aInfo.iScreenId;
+		RHeap* prevHeap = User::SwitchHeap(iHeap);
+		iLastPixelFormats.Reset();
+		User::SwitchHeap(prevHeap);
+		TArray<TSgPixelFormatTableEntry> pixelFormatTable = PixelFormatTable();
+		TInt n = pixelFormatTable.Count();
+		for (TInt i = 0; i < n; ++i)
+			{
+			const TSgPixelFormatTableEntry& entry = pixelFormatTable[i];
+			if (entry.IsMatchIgnoringPixelFormat(aInfo) && iLastPixelFormats.Find(entry.iPixelFormat) == KErrNotFound)
+				{
+				User::SwitchHeap(iHeap);
+				TInt err = iLastPixelFormats.Append(entry.iPixelFormat);
+				User::SwitchHeap(prevHeap);
+				if (err != KErrNone)
+					{
+					iLastSizeInPixels = TSize(0, 0);
+					iLastUsage = ESgUsageNone;
+					iLastCpuAccess = ESgCpuAccessNone;
+					iLastScreenId = KSgScreenIdMain;
+					User::SwitchHeap(iHeap);
+					iLastPixelFormats.Reset();
+					User::SwitchHeap(prevHeap);
+					iMutex.Signal();
+					return err;
+					}
+				}
+			}
+		}
+	TInt err = KErrNone;
+	if (aPixelFormats)
+		{
+		TInt n = Min(aCount, iLastPixelFormats.Count());
+		for (TInt i = 0; i < n; ++i)
+			{
+			aPixelFormats[i] = iLastPixelFormats[i];
+			}
+		if (aCount < iLastPixelFormats.Count())
+			{
+			err = KErrOverflow;
+			}
+		}
+	aCount = iLastPixelFormats.Count();
+	iMutex.Signal();
+	return err;
+	}
+
+
+TInt XSgDriverImpl::CreateImage(const TSgImageInfo& aInfo, const TAny* aDataAddress, TInt aDataStride, MSgDrawableAdapter*& aResult)
+	{
+	if (!SgIsValidImageInfo(aInfo))
+		{
+		return KErrArgument;
+		}
+	if (aResult)
+		{
+		return KErrInUse;
+		}
+	if (!aDataAddress && !SgIsMutableImage(aInfo))
+		{
+		return KErrNoInitializationData;
+		}
+	TInt err = CanCreateImage(aInfo);
+	if (err != KErrNone)
+		{
+		return err;
+		}
+#if !defined(SYMBIAN_GRAPHICS_USE_GPU) && !defined(__WINS__)
+	if (!aInfo.iShareable)
+		{
+		iMutex.Wait();
+		union
+			{
+			TSgDrawableId id;
+			TSgImageId_SwLocal id_SwLocal;
+			};
+		do
+			{
+			id_SwLocal.iProcessId = RProcess().Id();
+			id_SwLocal.iRandom[0] = Math::Random();
+			id_SwLocal.iRandom[1] = Math::Random();
+			id_SwLocal.iMinusOne = KErrNotFound;
+			id_SwLocal.iFlags = 0;
+			}
+		while (iImages.FindInOrder(id, XSgImageImplBase::Compare) != KErrNotFound);
+		XSgImageImpl_SwLocal* impl;
+		err = XSgImageImpl_SwLocal::New(impl, *this, id, aInfo, aDataAddress, aDataStride);
+		if (err != KErrNone)
+			{
+			iMutex.Signal();
+			return err;
+			}
+		RHeap* prevHeap = User::SwitchHeap(iHeap);
+		err = iImages.InsertInOrder(impl, XSgImageImplBase::Compare);
+		User::SwitchHeap(prevHeap);
+		if (err != KErrNone)
+			{
+			impl->Delete();
+			iMutex.Signal();
+			return err;
+			}
+		impl->IncRefCount();
+		aResult = impl;
+		iMutex.Signal();
+		return KErrNone;
+		}
+#endif
+	iMutex.Wait();
+	XSgImageImpl_SurfaceManager* impl;
+	err = XSgImageImpl_SurfaceManager::New(impl, *this, aInfo, SgIsCachedImage(aInfo), aDataAddress, aDataStride);
+	if (err != KErrNone)
+		{
+		iMutex.Signal();
+		return err;
+		}
+	RHeap* prevHeap = User::SwitchHeap(iHeap);
+	err = iImages.InsertInOrder(impl, XSgImageImplBase::Compare);
+	User::SwitchHeap(prevHeap);
+	if (err != KErrNone)
+		{
+		impl->Delete();
+		iMutex.Signal();
+		return err;
+		}
+	impl->IncRefCount();
+	aResult = impl;
+	iMutex.Signal();
+	return KErrNone;
+	}
+
+
+TInt XSgDriverImpl::CreateImage(const TSgImageInfo& aInfo, MSgImageAdapter* aImage, MSgDrawableAdapter*& aResult)
+	{
+	if (!aImage)
+		{
+		return KErrArgument;
+		}
+	__ASSERT_DEBUG(CheckImage(*aImage), Panic(ESgPanicBadImageHandle));
+	XSgImageImplBase& impl = static_cast<XSgImageImplBase&>(*aImage);
+	if (aInfo.iSizeInPixels != impl.MetaData().iSizeInPixels
+		|| aInfo.iPixelFormat != impl.MetaData().iPixelFormat)
+		{
+		return KErrNotSupported;
+		}
+	TInt err = impl.BeginDataAccess(ESgCpuAccessReadOnly);
+	if (err != KErrNone)
+		{
+		return err;
+		}
+	err = CreateImage(aInfo, impl.DataAddress(), impl.DataStride(), aResult);
+	impl.EndDataAccess();
+	return err;
+	}
+
+
+TInt XSgDriverImpl::CreateImageCollection(const TSgImageInfo& aInfo, TInt aImageCount, MSgImageCollectionAdapter*& aResult)
+	{
+	if (!SgIsValidImageInfo(aInfo) || aImageCount <= 0)
+		{
+		return KErrArgument;
+		}
+	if (aResult)
+		{
+		return KErrInUse;
+		}
+	if (!SgIsMutableImage(aInfo))
+		{
+		return KErrNotSupported;
+		}
+	TInt err = CanCreateImage(aInfo);
+	if (err != KErrNone)
+		{
+		return err;
+		}
+	iMutex.Wait();
+	XSgImageCollectionImpl* impl;
+	const TInt stride = SgAlignedDataStride(aInfo.iSizeInPixels.iWidth, aInfo.iPixelFormat);
+	const TInt offsetToFirst = SgOffsetToFirstBuffer(sizeof(TSgImageMetaData));
+	const TInt offsetBetween = SgOffsetBetweenBuffers(stride, aInfo.iSizeInPixels.iHeight);
+	
+	err = XSgImageCollectionImpl::New(impl, *this, aInfo, aImageCount, SgIsCachedImage(aInfo), stride, offsetToFirst, offsetBetween);
+	if (err != KErrNone)
+		{
+		iMutex.Signal();
+		return err;
+		}
+	RHeap* prevHeap = User::SwitchHeap(iHeap);
+	err = iImageCollections.InsertInAddressOrder(impl);
+	User::SwitchHeap(prevHeap);
+	if (err != KErrNone)
+		{
+		impl->Delete();
+		iMutex.Signal();
+		return err;
+		}
+	impl->IncRefCount();
+	aResult = impl;
+	iMutex.Signal();
+	return KErrNone;
+	}
+
+TInt XSgDriverImpl::GetBufferOffset(const TSurfaceId& aSurfaceID, TInt aBuffer, TInt &aOffset)
+	{
+	return iSurfaceManager.GetBufferOffset(aSurfaceID,aBuffer,aOffset);
+	}
+
+TInt XSgDriverImpl::GetSurfaceManagerAttrib(RSurfaceManager::TSurfaceManagerAttrib aAttrib, TInt& aValue)
+	{
+	return iSurfaceManager.GetSurfaceManagerAttrib(aAttrib,aValue);
+	}
+
+TInt XSgDriverImpl::CreateImageCollections(const TSgImageInfo aInfos[], TInt aImageCount,
+                                           MSgImageCollectionAdapter* aCollections[], TInt aCollectionCount)
+	{
+	if (aImageCount <= 0 || aCollectionCount <= 0)
+		{
+		return KErrArgument;
+		}
+	TBool isCached = EFalse;
+	TInt offsetToFirstBuffer = SgOffsetToFirstBuffer(aCollectionCount * sizeof(TSgImageMetaData));
+	TInt maxOffsetBetweenBuffers = 0;
+	for (TInt i = 0; i < aCollectionCount; ++i)
+		{
+		const TSgImageInfo& info = aInfos[i];
+		if (!SgIsValidImageInfo(info))
+			{
+			return KErrArgument;
+			}
+		if (aCollections[i])
+			{
+			return KErrInUse;
+			}
+		if (!SgIsMutableImage(info))
+			{
+			return KErrNotSupported;
+			}
+		TInt err = CanCreateImage(info);
+		if (err != KErrNone)
+			{
+			return err;
+			}
+		if (SgIsCachedImage(info))
+			{
+			isCached = ETrue;
+			}
+		TInt stride = SgAlignedDataStride(info.iSizeInPixels.iWidth, info.iPixelFormat);
+		TInt offsetBetweenBuffers = SgOffsetBetweenBuffers(stride, info.iSizeInPixels.iHeight);
+		if (offsetBetweenBuffers > maxOffsetBetweenBuffers)
+			{
+			maxOffsetBetweenBuffers = offsetBetweenBuffers;
+			}
+		}
+	iMutex.Wait();
+	XSgImageCollectionImpl* firstImpl = NULL;
+	for (TInt i = 0; i < aCollectionCount; ++i)
+		{
+		const TInt stride = SgAlignedDataStride(aInfos[i].iSizeInPixels.iWidth, aInfos[i].iPixelFormat);
+		XSgImageCollectionImpl* impl;
+		TInt err = XSgImageCollectionImpl::New(impl, *this, aInfos[i], aImageCount, isCached,
+		                                       stride, offsetToFirstBuffer, maxOffsetBetweenBuffers, i, firstImpl);
+		if (err == KErrNone)
+			{
+			if (i == 0)
+				{
+				firstImpl = impl;
+				RSurfaceManager::TInfoBuf info;
+				TSurfaceId surface=impl->SurfaceId();
+				err = SurfaceInfo(surface, info);
+				if (err == KErrNone)
+				    {
+				    // get the actual value used for offset to first buffer
+				    err = iSurfaceManager.GetBufferOffset(surface, 0, offsetToFirstBuffer);
+				    // get the actual value used for offset between buffers
+				    if (aImageCount>1)
+				    	{
+				    	TInt offsetToSecondBuffer;
+				    	err = iSurfaceManager.GetBufferOffset(surface, 1, offsetToSecondBuffer);
+				    	maxOffsetBetweenBuffers = offsetToSecondBuffer - offsetToFirstBuffer;
+				    	}
+				    else
+				    	{
+				    	maxOffsetBetweenBuffers = 0;
+				    	}
+				    }       
+				if (err != KErrNone)
+				    {
+				    impl->Delete();
+				    iMutex.Signal();
+				    return err;
+				    } 					
+				}
+			RHeap* prevHeap = User::SwitchHeap(iHeap);
+			err = iImageCollections.InsertInAddressOrder(impl);
+			User::SwitchHeap(prevHeap);
+			if (err == KErrNone)
+				{
+				impl->IncRefCount();
+				aCollections[i] = impl;
+				}
+			else
+				{
+				impl->Delete();
+				}
+			}
+		if (err != KErrNone)
+			{
+			while (--i >= 0)
+				{
+				aCollections[i]->Close();
+				aCollections[i] = NULL;
+				}
+			iMutex.Signal();
+			return err;
+			}
+		}
+	iMutex.Signal();
+	return KErrNone;
+	}
+
+
+TInt XSgDriverImpl::OpenDrawable(const TSgDrawableId& aId, TUint32 aMode, TUid aHandleType, MSgDrawableAdapter*& aResult)
+	{
+	if (aHandleType == KSgImageTypeUid || aHandleType == KSgDrawableTypeUid)
+		{
+		return OpenImage(aId, aMode, aResult);
+		}
+	return KErrNotSupported;
+	}
+
+
+TInt XSgDriverImpl::OpenImage(const TSgDrawableId& aId, TUint32 aMode, MSgDrawableAdapter*& aResult)
+	{
+	if (aResult)
+		{
+		return KErrInUse;
+		}
+	iMutex.Wait();
+	TSgDrawableId id = aId;
+	id.iId[KSgImageIdFlagsIndex] |= aMode;
+	TInt i = iImages.FindInOrder(id, XSgImageImplBase::CompareIgnoringFlags);
+	if (i != KErrNotFound)
+		{
+		XSgImageImplBase* impl;
+		TInt j = iImages.FindInOrder(id, XSgImageImplBase::Compare);
+		if (j != KErrNotFound)
+			{
+			impl = iImages[j];
+			}
+		else
+			{
+			impl = iImages[i];
+#ifndef SYMBIAN_GRAPHICS_USE_GPU
+			if (TSgImageId_SwLocal::IsMatch(id))
+				{
+				XSgImageImpl_SwLocal* impl2;
+				TInt err = XSgImageImpl_SwLocal::New(impl2, *static_cast<XSgImageImpl_SwLocal*>(impl), id.iId[KSgImageIdFlagsIndex]);
+				if (err != KErrNone)
+					{
+					iMutex.Signal();
+					return err;
+					}
+				impl = impl2;
+				}
+			else
+#endif
+			if (TSgImageId_SurfaceManager::IsMatch(id))
+				{
+				XSgImageImpl_SurfaceManager* impl2;
+				TInt err = XSgImageImpl_SurfaceManager::New(impl2, *static_cast<XSgImageImpl_SurfaceManager*>(impl), id.iId[KSgImageIdFlagsIndex]);
+				if (err != KErrNone)
+					{
+					iMutex.Signal();
+					return err;
+					}
+				impl = impl2;
+				}
+			else
+				{
+				iMutex.Signal();
+				return KErrNotFound;
+				}
+			RHeap* prevHeap = User::SwitchHeap(iHeap);
+			TInt err = iImages.InsertInOrder(impl, XSgImageImplBase::Compare);
+			User::SwitchHeap(prevHeap);
+			if (err != KErrNone)
+				{
+				impl->Delete();
+				iMutex.Signal();
+				return err;
+				}
+			}
+		impl->IncRefCount();
+		aResult = impl;
+		iMutex.Signal();
+		return KErrNone;
+		}
+	TInt err = KErrNotFound;
+	if (TSgImageId_SurfaceManager::IsMatch(id))
+		{
+		XSgImageImpl_SurfaceManager* impl;
+		err = XSgImageImpl_SurfaceManager::New(impl, *this, id);
+		if (err != KErrNone)
+			{
+			iMutex.Signal();
+			return err;
+			}
+		if (!impl->MetaData().iShareable && impl->MetaData().iCreatorProcess != RProcess().Id())
+			{
+			impl->Delete();
+			iMutex.Signal();
+			return KErrPermissionDenied;
+			}
+		RHeap* prevHeap = User::SwitchHeap(iHeap);
+		err = iImages.InsertInOrder(impl, XSgImageImplBase::Compare);
+		User::SwitchHeap(prevHeap);
+		if (err != KErrNone)
+			{
+			impl->Delete();
+			iMutex.Signal();
+			return err;
+			}
+		impl->IncRefCount();
+		aResult = impl;
+		}
+	iMutex.Signal();
+	return err;
+	}
+
+
+void XSgDriverImpl::DeleteImage(XSgImageImplBase* aImage)
+	{
+	__ASSERT_DEBUG(iMutex.IsHeld(), Panic(ESgPanicMutexNotHeld));
+	TInt i = iImages.FindInOrder(aImage, XSgImageImplBase::Compare);
+	__ASSERT_DEBUG(i != KErrNotFound, Panic(ESgPanicBadImageHandle));
+	RHeap* prevHeap = User::SwitchHeap(iHeap);
+	iImages.Remove(i);
+	iImages.GranularCompress();
+	User::SwitchHeap(prevHeap);
+	aImage->Delete();
+	}
+
+
+void XSgDriverImpl::DeleteImageCollection(XSgImageCollectionImpl* aImageCollection)
+	{
+	__ASSERT_DEBUG(iMutex.IsHeld(), Panic(ESgPanicMutexNotHeld));
+	TInt i = iImageCollections.FindInAddressOrder(aImageCollection);
+	__ASSERT_DEBUG(i != KErrNotFound, Panic(ESgPanicBadImageCollectionHandle));
+	RHeap* prevHeap = User::SwitchHeap(iHeap);
+	iImageCollections.Remove(i);
+	iImageCollections.GranularCompress();
+	User::SwitchHeap(prevHeap);
+	aImageCollection->Delete();
+	}
+
+
+TBool XSgDriverImpl::CheckDrawable(const MSgResourceAdapter& aDrawable) const
+	{
+	iMutex.Wait();
+	TInt i = iImages.Find(&static_cast<const XSgImageImplBase&>(aDrawable));
+	iMutex.Signal();
+	return i != KErrNotFound;
+	}
+
+
+TBool XSgDriverImpl::CheckImage(const MSgResourceAdapter& aImage) const
+	{
+	iMutex.Wait();
+	TInt i = iImages.Find(&static_cast<const XSgImageImplBase&>(aImage));
+	iMutex.Signal();
+	return i != KErrNotFound;
+	}
+
+
+TBool XSgDriverImpl::CheckImageCollection(const MSgResourceAdapter& aImageCollection) const
+	{
+	iMutex.Wait();
+	TInt i = iImageCollections.Find(&static_cast<const XSgImageCollectionImpl&>(aImageCollection));
+	iMutex.Signal();
+	return i != KErrNotFound;
+	}
+
+
+TInt XSgDriverImpl::ResourceCount() const
+	{
+	iMutex.Wait();
+	TInt count = 0;
+	for (TInt i = 0; i < iImages.Count(); ++i)
+		{
+		count += iImages[i]->RefCount();
+		}
+	for (TInt i = 0; i < iImageCollections.Count(); ++i)
+		{
+		count += iImageCollections[i]->RefCount();
+		}
+	iMutex.Signal();
+	return count;
+	}
+
+
+#ifdef _DEBUG
+
+void XSgDriverImpl::AllocMarkStart()
+	{
+	iMutex.Wait();
+	iHeap->__DbgMarkStart();
+	iMutex.Signal();
+	}
+
+
+void XSgDriverImpl::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 XSgDriverImpl::SetAllocFail(RAllocator::TAllocFail aType, TInt aRate)
+	{
+	iMutex.Wait();
+	iHeap->__DbgSetAllocFail(aType, aRate);
+	iMutex.Signal();
+	}
+
+#else
+
+void XSgDriverImpl::AllocMarkStart()
+	{
+	}
+
+
+void XSgDriverImpl::AllocMarkEnd(TInt /*aCount*/)
+	{
+	}
+
+
+void XSgDriverImpl::SetAllocFail(RAllocator::TAllocFail /*aType*/, TInt /*aRate*/)
+	{
+	}
+
+#endif
+
+
+// MSgDriverAdapter::New()
+
+EXPORT_C TInt MSgDriverAdapter::New(MSgDriverAdapter*& aPtr)
+	{
+	RHeap* heap = UserHeap::ChunkHeap(NULL, 0, KSgMaxLocalChunkSize);
+	if (!heap)
+		{
+		return KErrNoMemory;
+		}
+	XSgDriverImpl* driverImpl = static_cast<XSgDriverImpl*>(heap->Alloc(sizeof(XSgDriverImpl)));
+	if (!driverImpl)
+		{
+		heap->Close();
+		return KErrNoMemory;
+		}
+	new(driverImpl) XSgDriverImpl(heap);
+	TInt err = driverImpl->Construct();
+	if (err != KErrNone)
+		{
+		driverImpl->Delete();
+		return err;
+		}
+	aPtr = driverImpl;
+	return KErrNone;
+	}