graphicsresourceservices/graphicsresourceadaptation/src/sgdriverimpl.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 01:47:50 +0200
changeset 0 5d03bc08d59c
permissions -rw-r--r--
Revision: 201003 Kit: 201005

// 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;
	}