os/graphics/graphicsresourceservices/graphicsresourceimplementation/src/sgdriver.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // Graphics Resource - driver implementation
    15 //
    16 
    17 #include "sgdriver.h"
    18 
    19 const TInt KSgMaxLocalChunkSize = 0x100000;
    20 const TInt KSgLocalChunkAlignment = 0x40;
    21 
    22 EXPORT_C TInt RSgDriver::Open()
    23 	{
    24 	if (iImpl)
    25 		{
    26 		return KErrInUse;
    27 		}
    28 	if (gPls.iError != KErrNone)
    29 		{
    30 		return gPls.iError;
    31 		}
    32 	gPls.iMutex.Wait();
    33 	if (gPls.iDriver)
    34 		{
    35 		++gPls.iOpenCount;
    36 		iImpl = gPls.iDriver;
    37 		gPls.iMutex.Signal();
    38 		return KErrNone;
    39 		}
    40 	RChunk chunk;
    41 	TInt err = chunk.CreateLocal(KMinHeapGrowBy, KSgMaxLocalChunkSize, EOwnerProcess);
    42 	if (err != KErrNone)
    43 		{
    44 		gPls.iMutex.Signal();
    45 		return err;
    46 		}
    47 	RHeap* heap = UserHeap::ChunkHeap(chunk, 0, KMinHeapGrowBy, KSgMaxLocalChunkSize, KSgLocalChunkAlignment, ETrue);
    48 	__ASSERT_DEBUG(heap, Panic(ESgPanicResourceImplGeneral));
    49 	XSgDriver* driver = static_cast<XSgDriver*>(heap->Alloc(sizeof(XSgDriver)));
    50 	__ASSERT_DEBUG(driver, Panic(ESgPanicResourceImplGeneral));
    51 	new(driver) XSgDriver(heap);
    52 	err = driver->Construct();
    53 	if (err != KErrNone)
    54 		{
    55 		driver->Delete();
    56 		gPls.iMutex.Signal();
    57 		return err;
    58 		}
    59 	gPls.iOpenCount = 1;
    60 	iImpl = gPls.iDriver = driver;
    61 	gPls.iMutex.Signal();
    62 	return KErrNone;
    63 	}
    64 
    65 EXPORT_C void RSgDriver::Close()
    66 	{
    67 	if (iImpl)
    68 		{
    69 		__ASSERT_DEBUG(gPls.iError == KErrNone, Panic(ESgPanicResourceImplGeneral));
    70 		gPls.iMutex.Wait();
    71 		__ASSERT_DEBUG(gPls.iOpenCount > 0, Panic(ESgPanicResourceImplGeneral));
    72 		if (--gPls.iOpenCount == 0)
    73 			{
    74 			gPls.iDriver->Delete();
    75 			gPls.iDriver = NULL;
    76 			}
    77 		iImpl = NULL;
    78 		gPls.iMutex.Signal();
    79 		}
    80 	}
    81 
    82 EXPORT_C TInt RSgDriver::GetInterface(TUid aInterfaceUid, TAny*& aInterfacePtr) const
    83 	{
    84 	aInterfacePtr = NULL;
    85 	if (!iImpl)
    86 		{
    87 		return KErrBadHandle;
    88 		}
    89 	return static_cast<XSgDriver*>(iImpl)->GetInterface(aInterfaceUid, aInterfacePtr);
    90 	}
    91 
    92 EXPORT_C TVersion RSgDriver::Version()
    93 	{
    94 	return TVersion(1, 1, 1);
    95 	}
    96 
    97 _LIT(KSgResourceImplPanicCategory, "SGRES-IMPL");
    98 
    99 void Panic(TSgResourceImplPanicReason aReason)
   100 	{
   101 	User::Panic(KSgResourceImplPanicCategory, aReason);
   102 	}
   103 
   104 #ifdef SYMBIAN_GRAPHICS_USE_GPU
   105 const TUint32 KSgResourceAttributes = 0;
   106 #else
   107 const TUint32 KSgResourceAttributes = ESgResourceAttrCpuCached;
   108 #endif
   109 
   110 LOCAL_C TInt SgMinDataStride(TInt aWidthInPixels, TInt aPixelFormat)
   111 	{
   112 	switch (aPixelFormat)
   113 		{
   114 	case ESgPixelFormatA_8:
   115 		return aWidthInPixels;
   116 	case ESgPixelFormatRGB_565:
   117 		return aWidthInPixels << 1;
   118 	case ESgPixelFormatXRGB_8888:
   119 	case ESgPixelFormatARGB_8888:
   120 	case ESgPixelFormatARGB_8888_PRE:
   121 		return aWidthInPixels << 2;
   122 	default:
   123 #ifdef _DEBUG
   124 		Panic(ESgPanicResourceImplGeneral);
   125 #endif
   126 		return 0;
   127 		}
   128 	}
   129 
   130 LOCAL_C TInt SgAlignedDataStride(TInt aWidthInPixels, TInt aPixelFormat)
   131 	{
   132 #if defined(SYMBIAN_GRAPHICS_USE_MBX)
   133 	// MBX requires 2^n stride
   134 	for (TInt width = 8; width & KMaxTInt; width <<= 1)
   135 		{
   136 		if (width >= aWidthInPixels)
   137 			{
   138 			aWidthInPixels = width;
   139 			break;
   140 			}
   141 		}
   142 #elif defined(SYMBIAN_GRAPHICS_USE_SGX)
   143 	// SGX requires 32-pixel alignment
   144 	aWidthInPixels = (aWidthInPixels + 31) & ~31;
   145 #endif
   146 	return Align4(SgMinDataStride(aWidthInPixels, aPixelFormat));
   147 	}
   148 
   149 XSgDriverPls::XSgDriverPls()
   150 	{
   151 	iError = iMutex.CreateLocal();
   152 	iOpenCount = 0;
   153 	iDriver = NULL;
   154 	}
   155 
   156 XSgDriver::XSgDriver(RHeap* aHeap)
   157 	: iHeap(aHeap), iHasOpenVg(EFalse), iHasOpenGles(EFalse), iHasOpenGles2(EFalse)
   158 	{
   159 	}
   160 
   161 XSgDriver::~XSgDriver()
   162 	{
   163 	iMutex.Close();
   164 	iDevice.Close();
   165 	__ASSERT_DEBUG(iImagesByAddress.Count() == 0, Panic(ESgPanicUnclosedResources));
   166 	__ASSERT_DEBUG(iImagesById.Count() == 0, Panic(ESgPanicUnclosedResources));
   167 	}
   168 
   169 TInt XSgDriver::Construct()
   170 	{
   171 	TInt err = iMutex.CreateLocal();
   172 	if (err != KErrNone)
   173 		{
   174 		return err;
   175 		}
   176 	err = User::LoadLogicalDevice(KSgDeviceName);
   177 	if (err != KErrNone && err != KErrAlreadyExists)
   178 		{
   179 		return err;
   180 		}
   181 	err = iDevice.Connect();
   182 	if (err != KErrNone)
   183 		{
   184 		return err;
   185 		}
   186 	_LIT(KLibOpenVg, "libOpenVG.dll");
   187 	_LIT(KLibOpenGles, "libGLESv1_CM.dll");
   188 	_LIT(KLibOpenGles2, "libGLESv2.dll");
   189 	RLibrary lib;
   190 	if (lib.Load(KLibOpenVg) == KErrNone)
   191 		{
   192 		lib.Close();
   193 		iHasOpenVg = ETrue;
   194 		}
   195 	if (lib.Load(KLibOpenGles) == KErrNone)
   196 		{
   197 		lib.Close();
   198 		iHasOpenGles = ETrue;
   199 		}
   200 	if (lib.Load(KLibOpenGles2) == KErrNone)
   201 		{
   202 		lib.Close();
   203 		iHasOpenGles2 = ETrue;
   204 		}
   205 	return KErrNone;
   206 	}
   207 
   208 void XSgDriver::Delete()
   209 	{
   210 	RHeap* heap = iHeap;
   211 	this->~XSgDriver();
   212 	heap->Free(this);
   213 	__ASSERT_DEBUG(heap->Count() == 0, Panic(ESgPanicUnclosedResources));
   214 	heap->Close();
   215 	}
   216 
   217 TInt XSgDriver::CreateImage(const TSgImageInfo& aInfo, const TAny* aDataAddress, TInt aDataStride, const TSgAttributeArrayBase* aAttributes, TAny*& aResult)
   218 	{
   219 	TInt err = CheckImageInfo(aInfo);
   220 	if (err != KErrNone)
   221 		{
   222 		return err;
   223 		}
   224 	TInt minDataStride = SgMinDataStride(aInfo.iSizeInPixels.iWidth, aInfo.iPixelFormat);
   225 	if (aDataAddress && Abs(aDataStride) < minDataStride)
   226 		{
   227 		return KErrArgument;
   228 		}
   229 	if (aAttributes)
   230 		{
   231 		return KErrNotSupported;
   232 		}
   233 	TUint32 attribs = KSgResourceAttributes | MatchingEglConfigUsage(aInfo.iUsage);
   234 	TPckgBuf<TSgImageMetaData> metaDataPckg;
   235 	metaDataPckg().iSizeInPixels = aInfo.iSizeInPixels;
   236 	metaDataPckg().iPixelFormat = aInfo.iPixelFormat;
   237 	TInt dataStride = SgAlignedDataStride(aInfo.iSizeInPixels.iWidth, aInfo.iPixelFormat);
   238 	TInt dataSize = dataStride * aInfo.iSizeInPixels.iHeight;
   239 	TSgDrawableId id;
   240 	err = iDevice.CreateResource(attribs, metaDataPckg, dataSize, id.iId);
   241 	if (err != KErrNone)
   242 		{
   243 		return err;
   244 		}
   245 	iMutex.Wait();
   246 	XSgImage* imageImpl = static_cast<XSgImage*>(iHeap->Alloc(sizeof(XSgImage)));
   247 	if (!imageImpl)
   248 		{
   249 		(void)iDevice.CloseResource(id.iId);
   250 		iMutex.Signal();
   251 		return KErrNoMemory;
   252 		}
   253 	new(imageImpl) XSgImage(id, attribs, metaDataPckg(), iDevice.ResourceDataAddress(id.iId), dataStride);
   254 	RHeap* prevHeap = User::SwitchHeap(iHeap);
   255 	err = iImagesByAddress.InsertInAddressOrder(imageImpl);
   256 	if (err == KErrNone)
   257 		{
   258 		err = iImagesById.InsertInOrder(imageImpl, XSgImage::Compare);
   259 		if (err != KErrNone)
   260 			{
   261 			iImagesByAddress.Remove(iImagesByAddress.FindInAddressOrder(imageImpl));
   262 			iImagesByAddress.GranularCompress();
   263 			}
   264 		}
   265 	User::SwitchHeap(prevHeap);
   266 	if (err == KErrNone)
   267 		{
   268 		if (aDataAddress)
   269 			{
   270 			const TAny* src = aDataStride > 0 ? aDataAddress : PtrAdd(aDataAddress, -aDataStride * (aInfo.iSizeInPixels.iHeight - 1));
   271 			TAny* trg = imageImpl->DataAddress();
   272 			for (TInt y = 0; y < aInfo.iSizeInPixels.iHeight; ++y)
   273 				{
   274 				Mem::Copy(trg, src, minDataStride);
   275 				src = PtrAdd(src, aDataStride);
   276 				trg = PtrAdd(trg, dataStride);
   277 				}
   278 			}
   279 		aResult = imageImpl;
   280 		}
   281 	else
   282 		{
   283 		(void)iDevice.CloseResource(id.iId);
   284 		iHeap->Free(imageImpl);
   285 		}
   286 	iMutex.Signal();
   287 	return err;
   288 	}
   289 
   290 TInt XSgDriver::CreateImage(const TSgImageInfo& aInfo, const XSgImage* aImageImpl, const TSgAttributeArrayBase* aAttributes, TAny*& aResult)
   291 	{
   292 	if (!aImageImpl)
   293 		{
   294 		return KErrArgument;
   295 		}
   296 	__ASSERT_ALWAYS(CheckImage(aImageImpl), Panic(ESgPanicBadDrawableHandle));
   297 	TSgImageInfo info;
   298 	aImageImpl->GetInfo(info);
   299 	if (aInfo.iSizeInPixels != info.iSizeInPixels || aInfo.iPixelFormat != info.iPixelFormat)
   300 		{
   301 		return KErrNotSupported;
   302 		}
   303 	return CreateImage(aInfo, aImageImpl->DataAddress(), aImageImpl->DataStride(), aAttributes, aResult);
   304 	}
   305 
   306 TInt XSgDriver::FindAndOpenImage(TSgDrawableId aId, const TSgAttributeArrayBase* aAttributes, TAny*& aResult)
   307 	{
   308 	if (aId == KSgNullDrawableId)
   309 		{
   310 		return KErrArgument;
   311 		}
   312 	if (aAttributes)
   313 		{
   314 		return KErrNotSupported;
   315 		}
   316 	TInt err;
   317 	iMutex.Wait();
   318 	TInt indexById = iImagesById.FindInOrder(aId, XSgImage::Compare);
   319 	if (indexById >= 0)
   320 		{
   321 		XSgImage* imageImpl = iImagesById[indexById];
   322 		err = imageImpl->Open();
   323 		if (err == KErrNone)
   324 			{
   325 			aResult = imageImpl;
   326 			}
   327 		}
   328 	else
   329 		{
   330 		err = iDevice.OpenResource(aId.iId);
   331 		if (err != KErrNone)
   332 			{
   333 			iMutex.Signal();
   334 			return err;
   335 			}
   336 		TPckgBuf<TSgImageMetaData> metaDataPckg;
   337 		err = iDevice.GetResourceMetaData(aId.iId, metaDataPckg);
   338 		if (metaDataPckg.Size() != sizeof(TSgImageMetaData))
   339 			{
   340 			err = KErrGeneral;
   341 			}
   342 		TUint32 attribs;
   343 		if (err == KErrNone)
   344 			{
   345 			attribs = iDevice.ResourceAttributes(aId.iId);
   346 			TSgImageInfo info(metaDataPckg().iSizeInPixels, metaDataPckg().iPixelFormat, attribs & KSgUsageBitMask);
   347 			if (CheckImageInfo(info) != KErrNone)
   348 				{
   349 				err = KErrGeneral;
   350 				}
   351 			}
   352 		TInt dataStride;
   353 		if (err == KErrNone)
   354 			{
   355 			dataStride = SgAlignedDataStride(metaDataPckg().iSizeInPixels.iWidth, metaDataPckg().iPixelFormat);
   356 			if (iDevice.ResourceDataSize(aId.iId) != dataStride * metaDataPckg().iSizeInPixels.iHeight)
   357 				{
   358 				err = KErrGeneral;
   359 				}
   360 			}
   361 		if (err != KErrNone)
   362 			{
   363 			(void)iDevice.CloseResource(aId.iId);
   364 			iMutex.Signal();
   365 			return err;
   366 			}
   367 		XSgImage* imageImpl = static_cast<XSgImage*>(iHeap->Alloc(sizeof(XSgImage)));
   368 		if (!imageImpl)
   369 			{
   370 			(void)iDevice.CloseResource(aId.iId);
   371 			iMutex.Signal();
   372 			return KErrNoMemory;
   373 			}
   374 		new(imageImpl) XSgImage(aId, attribs, metaDataPckg(), iDevice.ResourceDataAddress(aId.iId), dataStride);
   375 		RHeap* prevHeap = User::SwitchHeap(iHeap);
   376 		err = iImagesByAddress.InsertInAddressOrder(imageImpl);
   377 		if (err == KErrNone)
   378 			{
   379 			err = iImagesById.InsertInOrder(imageImpl, XSgImage::Compare);
   380 			if (err != KErrNone)
   381 				{
   382 				iImagesByAddress.Remove(iImagesByAddress.FindInAddressOrder(imageImpl));
   383 				iImagesByAddress.GranularCompress();
   384 				}
   385 			}
   386 		User::SwitchHeap(prevHeap);
   387 		if (err == KErrNone)
   388 			{
   389 			aResult = imageImpl;
   390 			}
   391 		else
   392 			{
   393 			(void)iDevice.CloseResource(aId.iId);
   394 			iHeap->Free(imageImpl);
   395 			}
   396 		}
   397 	iMutex.Signal();
   398 	return err;
   399 	}
   400 
   401 void XSgDriver::DeleteImage(XSgImage* aImageImpl)
   402 	{
   403 	iMutex.Wait();
   404 	TInt indexByAddress = iImagesByAddress.FindInAddressOrder(aImageImpl);
   405 	TInt indexById = iImagesById.FindInOrder(aImageImpl, XSgImage::Compare);
   406 	__ASSERT_DEBUG(indexByAddress >= 0 && indexById >= 0, Panic(ESgPanicBadImagePointer));
   407 	RHeap* prevHeap = User::SwitchHeap(iHeap);
   408 	iImagesByAddress.Remove(indexByAddress);
   409 	iImagesById.Remove(indexById);
   410 	iImagesByAddress.GranularCompress();
   411 	iImagesById.GranularCompress();
   412 	User::SwitchHeap(prevHeap);
   413 	(void)iDevice.CloseResource(aImageImpl->Id().iId);
   414 	aImageImpl->~XSgImage();
   415 	iHeap->Free(aImageImpl);
   416 	iMutex.Signal();
   417 	}
   418 
   419 TUint32 XSgDriver::MatchingEglConfigUsage(TUint32 aUsage) const
   420 	{
   421 	if (aUsage & KSgUsageAllSurfaceTypes)
   422 		{
   423 		if (iHasOpenVg)
   424 			{
   425 			aUsage |= ESgUsageBitOpenVgSurface;
   426 			}
   427 		if (iHasOpenGles)
   428 			{
   429 			aUsage |= ESgUsageBitOpenGlesSurface;
   430 			}
   431 		if (iHasOpenGles2)
   432 			{
   433 			aUsage |= ESgUsageBitOpenGles2Surface;
   434 			}
   435 		}
   436 	return aUsage;
   437 	}
   438 
   439 TInt XSgDriver::CheckImageInfo(const TSgImageInfo& aInfo) const
   440 	{
   441 	if (aInfo.iSizeInPixels.iWidth <= 0 || aInfo.iSizeInPixels.iHeight <= 0
   442 		|| aInfo.iPixelFormat == EUidPixelFormatUnknown || aInfo.iUsage == 0)
   443 		{
   444 		return KErrArgument;
   445 		}
   446 	if (aInfo.iSizeInPixels.iWidth > KMaxTInt16 / 2 || aInfo.iSizeInPixels.iHeight > KMaxTInt16 / 2)
   447 		{
   448 		return KErrTooBig;
   449 		}
   450 	if (aInfo.iUsage & ~KSgUsageAll)
   451 		{
   452 		return KErrNotSupported;
   453 		}
   454 	if ((aInfo.iUsage & (ESgUsageBitOpenVgImage | ESgUsageBitOpenVgSurface)) && !iHasOpenVg
   455 		|| (aInfo.iUsage & (ESgUsageBitOpenGlesTexture2D | ESgUsageBitOpenGlesSurface)) && !iHasOpenGles
   456 		|| (aInfo.iUsage & (ESgUsageBitOpenGles2Texture2D | ESgUsageBitOpenGles2Surface)) && !iHasOpenGles2)
   457 		{
   458 		return KErrNotSupported;
   459 		}
   460 	switch (aInfo.iPixelFormat)
   461 		{
   462 	case ESgPixelFormatA_8:
   463 		if (aInfo.iUsage & KSgUsageAllSurfaceTypes)
   464 			{
   465 			return KErrNotSupported;
   466 			}
   467 		// coverity[fallthrough]
   468 	case ESgPixelFormatRGB_565:
   469 	case ESgPixelFormatXRGB_8888:
   470 	case ESgPixelFormatARGB_8888:
   471 	case ESgPixelFormatARGB_8888_PRE:
   472 		return KErrNone;
   473 	default:
   474 		return KErrNotSupported;
   475 		}
   476 	}
   477 
   478 TBool XSgDriver::CheckImage(const TAny* aImageImpl) const
   479 	{
   480 	iMutex.Wait();
   481 	TInt indexByAddress = iImagesByAddress.FindInAddressOrder(static_cast<const XSgImage*>(aImageImpl));
   482 	iMutex.Signal();
   483 	return indexByAddress >= 0;
   484 	}
   485 
   486 TInt XSgDriver::GetInterface(TUid aInterfaceUid, TAny*& aInterfacePtr)
   487 	{
   488 	if (aInterfaceUid == KNullUid)
   489 		{
   490 		return KErrArgument;
   491 		}
   492 	if (aInterfaceUid.iUid == MSgDriver_Profiling::EInterfaceUid)
   493 		{
   494 		aInterfacePtr = static_cast<MSgDriver_Profiling*>(this);
   495 		return KErrNone;
   496 		}
   497 #ifdef _DEBUG
   498 	if (aInterfaceUid.iUid == MSgDriver_Test::EInterfaceUid)
   499 		{
   500 		aInterfacePtr = static_cast<MSgDriver_Test*>(this);
   501 		return KErrNone;
   502 		}
   503 #endif
   504 	return KErrExtensionNotSupported;
   505 	}
   506 
   507 TInt XSgDriver::LocalResourceCount() const
   508 	{
   509 	TInt count = 0;
   510 	iMutex.Wait();
   511 	TInt n = iImagesByAddress.Count();
   512 	for (TInt i = 0; i < n; ++i)
   513 		{
   514 		count += iImagesByAddress[i]->RefCount();
   515 		}
   516 	iMutex.Signal();
   517 	return count;
   518 	}
   519 
   520 TInt XSgDriver::GlobalResourceCount() const
   521 	{
   522 	return iDevice.GlobalResourceCount();
   523 	}
   524 
   525 TInt XSgDriver::LocalGraphicsMemoryUsed() const
   526 	{
   527 	return iDevice.LocalGraphicsMemoryUsed();
   528 	}
   529 
   530 TInt XSgDriver::GlobalGraphicsMemoryUsed() const
   531 	{
   532 	return iDevice.GlobalGraphicsMemoryUsed();
   533 	}
   534 
   535 #ifdef _DEBUG
   536 
   537 void XSgDriver::AllocMarkStart()
   538 	{
   539 	iMutex.Wait();
   540 	iHeap->__DbgMarkStart();
   541 	iMutex.Signal();
   542 	}
   543 
   544 void XSgDriver::AllocMarkEnd(TInt aCount)
   545 	{
   546 	iMutex.Wait();
   547 	TUint32 badCell = iHeap->__DbgMarkEnd(aCount);
   548 	iMutex.Signal();
   549 	if (badCell != 0)
   550 		{
   551 		_LIT(KPanicCategoryFormat, "SGALLOC:%08x");
   552 		TBuf<0x10> category;
   553 		category.Format(KPanicCategoryFormat, badCell);
   554 		User::Panic(category, 0);
   555 		}
   556 	}
   557 
   558 void XSgDriver::SetAllocFail(RAllocator::TAllocFail aType, TInt aRate)
   559 	{
   560 	iMutex.Wait();
   561 	iHeap->__DbgSetAllocFail(aType, aRate);
   562 	iMutex.Signal();
   563 	}
   564 
   565 #endif // _DEBUG
   566 
   567 #ifndef __WINS__
   568 XSgDriverPls gPls;
   569 #endif