sl@0: // Copyright (c) 2008-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 the License "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: // This test should not depend on any external data files and should work with sl@0: // the default (empty) epoc.ini file. sl@0: // The test should be run without the Graphics GCE enabled but with the Base GCE sl@0: // driver enabled. On the emulator this can be done by launcing with -Dtextshell -- sl@0: // and on the H4 build a textshell ROM with -DSYMBIAN_BASE_USE_GCE but NOT sl@0: // -DSYMBIAN_GRAPHICS_USE_GCE sl@0: // In the visual tests some flickering may occur due to updates to the console. On sl@0: // the emulator it is possible to configure a second screen so that the console updates sl@0: // will only happen on one screen. The test automatically runs on every screen available. sl@0: // sl@0: // sl@0: sl@0: #define __E32TEST_EXTENSION__ sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: RTest test(_L("Display Channel device driver unit tests")); sl@0: sl@0: /** Maximum probable pixel resolution width or height */ sl@0: static const TInt KMaxExpectedPixelRes = 10000; sl@0: sl@0: /** Unlikely to ever have a > 1000 Hz refresh rate */ sl@0: static const TInt KMaxExpectedRefreshRate = 1000; sl@0: sl@0: /** Time (in microseconds) for each visual test */ sl@0: static const TInt KDrawWaitTime = 1000000; sl@0: sl@0: /** Array of supported rotations */ sl@0: static const RDisplayChannel::TDisplayRotation KRotations[] = { sl@0: RDisplayChannel::ERotationNormal, sl@0: RDisplayChannel::ERotation90CW, sl@0: RDisplayChannel::ERotation180, sl@0: RDisplayChannel::ERotation270CW}; sl@0: static const TInt KNumRotations = sizeof(KRotations) / sizeof(RDisplayChannel::TDisplayRotation); sl@0: sl@0: /** Array of pixel formats to try for visual test */ sl@0: static const RDisplayChannel::TPixelFormat KPixelFormats[] = { sl@0: EUidPixelFormatYUV_422Interleaved16bit, // not supported on emulator but should not be a fatal error sl@0: EUidPixelFormatXRGB_4444, sl@0: EUidPixelFormatARGB_4444, sl@0: EUidPixelFormatRGB_565, sl@0: EUidPixelFormatXRGB_8888, sl@0: EUidPixelFormatARGB_8888, sl@0: EUidPixelFormatARGB_8888_PRE sl@0: }; sl@0: static const TInt KNumPixelFormats = sizeof(KPixelFormats) / sizeof(RDisplayChannel::TPixelFormat); sl@0: sl@0: /** sl@0: Encapsulates display related HAL information. sl@0: */ sl@0: class THalDisplayInfo sl@0: { sl@0: public: sl@0: TBool iIsMono; sl@0: TBool iIsPalettized; sl@0: TInt iBitsPerPixel; sl@0: TInt iMemoryAddress; sl@0: TInt iMemoryHandle; sl@0: TInt iState; sl@0: TInt iColors; sl@0: TInt iXPixels; sl@0: TInt iYPixels; sl@0: TInt iXTwips; sl@0: TInt iYTwips; sl@0: TInt iNumModes; sl@0: TInt iMode; sl@0: TInt iOffsetBetweenLines; sl@0: TInt iOffsetToFirstPixel; sl@0: TBool iIsPixelOrderRGB; sl@0: TBool iIsPixelOrderLandscape; sl@0: }; sl@0: sl@0: /** sl@0: Helper class that waits for RDisplayChannel asynchronous requests and sl@0: can cancel them if necessary. The purpose of this class is so that the main sl@0: test class can create an asynchronous request and also simulate the completion sl@0: of that request e.g. faking a display change event. sl@0: */ sl@0: class CAsyncHelper : public CActive sl@0: { sl@0: public: sl@0: inline CAsyncHelper(RDisplayChannel& aDisp); sl@0: inline ~CAsyncHelper(); sl@0: inline TRequestStatus& Status(); sl@0: void WaitForOperation(TInt* aResult); sl@0: private: sl@0: // From CActive sl@0: inline void DoCancel(); sl@0: inline void RunL(); sl@0: private: sl@0: RDisplayChannel& iDisp; sl@0: TInt* iResult; sl@0: }; sl@0: sl@0: inline CAsyncHelper::CAsyncHelper(RDisplayChannel& aDisp) : CActive(EPriorityHigh), iDisp(aDisp) {CActiveScheduler::Add(this);} sl@0: inline CAsyncHelper::~CAsyncHelper() {Deque();} sl@0: inline TRequestStatus& CAsyncHelper::Status() {return iStatus;} sl@0: // Writes the iStatus.Int() to the address defined by the client of this AO sl@0: inline void CAsyncHelper::RunL() {*iResult = iStatus.Int();} sl@0: sl@0: void CAsyncHelper::WaitForOperation(TInt* aResult) sl@0: /** sl@0: Invokes SetActive() to wait for the asynchronous operation to complete. The completion sl@0: code is copied to the aResult when RunL is invoked. sl@0: @param aResult out parameter that will be set to iStatus.Int() sl@0: */ sl@0: { sl@0: iResult = aResult; sl@0: // Set the result to default value that is unlikely to be returned by the real API sl@0: *aResult = KMaxTInt; sl@0: SetActive(); sl@0: } sl@0: sl@0: void CAsyncHelper::DoCancel() sl@0: { sl@0: // Driver should fail if cancel is called when there is not standing request sl@0: // so cancel just attempts to cancel everything. sl@0: iDisp.CancelGetCompositionBuffer(); sl@0: iDisp.CancelPostUserBuffer(); sl@0: iDisp.CancelWaitForPost(); sl@0: iDisp.NotifyOnDisplayChangeCancel(); sl@0: } sl@0: sl@0: /** sl@0: Class to test device driver for RDisplayChannel sl@0: */ sl@0: class CDisplayChannelTest : public CActive sl@0: { sl@0: enum TTestState { sl@0: ETestDisplayInfo, sl@0: ETestCompositionBuffers, sl@0: ETestUserBuffers, sl@0: ETestRotations, sl@0: ETestDisplayChange, sl@0: ETestDisplayChangeDoCancel, sl@0: ETestDisplayChangeCheckCancel, sl@0: ETestGetCompositionBufferDoCancel, sl@0: ETestGetCompositionBufferCheckCancel, sl@0: ETestWaitForPostDoCancel, sl@0: ETestWaitForPostCheckCancel, sl@0: ETestResolutions, sl@0: ETestPixelFormats, sl@0: ETestBufferFormats, sl@0: ETestV11inV10, sl@0: EVisualTest, sl@0: ETestSecondHandle, sl@0: ETestBufferTransitions, sl@0: ETestFinished sl@0: }; sl@0: sl@0: public: sl@0: static CDisplayChannelTest* NewLC(TInt aScreenId); sl@0: void Start(); sl@0: ~CDisplayChannelTest(); sl@0: sl@0: private: sl@0: // From CActive sl@0: void DoCancel(); sl@0: TInt RunError(TInt aError); sl@0: void RunL(); sl@0: sl@0: private: sl@0: CDisplayChannelTest(TInt aScreenId); sl@0: void CompleteSelf(TTestState aNextState); sl@0: sl@0: // The tests sl@0: void CheckDisplayInfo(); sl@0: void CheckResolutions(); sl@0: void CheckPixelFormats(); sl@0: void CheckDisplayChange(); sl@0: void CheckCompositionBuffers(); sl@0: void CheckBufferFormat(); sl@0: void CheckUserBuffers(); sl@0: void CheckRotations(); sl@0: TBool IsValidRotation(RDisplayChannel::TDisplayRotation aRotation); sl@0: TBool IsValidPixelFormat(RDisplayChannel::TPixelFormat aPixelFormat); sl@0: void CheckSetRotation(TUint aSupported, RDisplayChannel::TDisplayRotation aNewRotation); sl@0: void CheckV11inV10(); sl@0: void VisualTest(); sl@0: void DrawLegacyBuffer(TInt aStep); sl@0: void DrawFillToMemory(TUint8* aFirstPixelAddr, TInt aOffsetBetweenLines, sl@0: RDisplayChannel::TPixelFormat aPixelFormat, TInt aWidth, TInt aHeight, TInt aStep); sl@0: void DrawCompositionBuffer( sl@0: RDisplayChannel::TPostCount& aPostCount, sl@0: RDisplayChannel::TBufferFormat aBufferFormat, sl@0: RDisplayChannel::TDisplayRotation aRotation, TInt aStep); sl@0: void GetHalDisplayInfo(); sl@0: void CheckSecondHandle(); sl@0: void TestBufferTransitions(); sl@0: sl@0: private: sl@0: RDisplayChannel iDisp; /// handle to display channel device driver sl@0: TVersion iVersion; /// version number of disp channel driver interface sl@0: THalDisplayInfo iHalInfo; /// info about legacy buffer from HAL sl@0: TInt iScreenId; /// run tests on each screen sl@0: TTestState iState; /// the current test sl@0: CAsyncHelper *iAsyncHelper; sl@0: TInt iAsyncHelperResult; /// set to iAyncHelper::iStatus.Int() sl@0: RArray iResolutions; sl@0: RArray iPixelFormats; sl@0: TInt iVisualTestFormatIndex; /// index of the current pixel format in visual test sl@0: TInt iVisualTestRotationIndex; /// index of the current rotation in the visual test sl@0: TUint iDummyCompositionBuffer; /// dummy var used to test cancel of GetCompositionBuffer sl@0: RDisplayChannel::TPostCount iDummyPostCount; /// dummy var used to test CancelWaitForPost sl@0: }; sl@0: sl@0: // Gets a HAL value, logs the result and errors if HAL::Get failed sl@0: #define DBG_HAL(DEVICE, ATT, VAL, ERR, IN) \ sl@0: { \ sl@0: VAL = IN;\ sl@0: ERR = HAL::Get(DEVICE, ATT, VAL); \ sl@0: test.Printf(_L(#ATT)); \ sl@0: test.Printf(_L(" device %d err = %d, val = %d\n"), DEVICE, ERR, VAL); \ sl@0: test_KErrNone(ERR); \ sl@0: } sl@0: sl@0: void CDisplayChannelTest::GetHalDisplayInfo() sl@0: /** sl@0: Retrieves display related HAL settings. This also initialises the legacy buffer by retrieving sl@0: HAL::EDisplayMemoryAddress sl@0: */ sl@0: { sl@0: TInt err = KErrNotSupported; sl@0: sl@0: DBG_HAL(iScreenId, HAL::EDisplayMemoryAddress, iHalInfo.iMemoryAddress, err, 0); sl@0: sl@0: iHalInfo.iMemoryHandle = 0; sl@0: err = HAL::Get(iScreenId, HAL::EDisplayMemoryHandle, iHalInfo.iMemoryHandle); sl@0: test(err == KErrNone || err == KErrNotSupported); sl@0: test.Printf(_L("HAL::EDisplayMemoryHandle returned err %d\n"), err); sl@0: if (err == KErrNone) sl@0: { sl@0: // Handle is not needed so don't leak it sl@0: RHandleBase h; sl@0: h.SetHandle(iHalInfo.iMemoryHandle); sl@0: h.Close(); sl@0: } sl@0: sl@0: // This is mostly for information purposes to ensure the legacy buffer is sane. sl@0: DBG_HAL(iScreenId, HAL::EDisplayState, iHalInfo.iState, err, 0); sl@0: DBG_HAL(iScreenId, HAL::EDisplayColors, iHalInfo.iColors, err, 0); sl@0: DBG_HAL(iScreenId, HAL::EDisplayXPixels, iHalInfo.iXPixels, err, 0); sl@0: DBG_HAL(iScreenId, HAL::EDisplayYPixels, iHalInfo.iYPixels, err, 0); sl@0: DBG_HAL(iScreenId, HAL::EDisplayXTwips, iHalInfo.iXTwips, err, 0); sl@0: DBG_HAL(iScreenId, HAL::EDisplayYTwips, iHalInfo.iYTwips, err, 0); sl@0: DBG_HAL(iScreenId, HAL::EDisplayIsPixelOrderRGB, iHalInfo.iIsPixelOrderRGB, err, 0); sl@0: DBG_HAL(iScreenId, HAL::EDisplayIsPixelOrderLandscape, iHalInfo.iIsPixelOrderLandscape, err, 0); sl@0: sl@0: DBG_HAL(iScreenId, HAL::EDisplayNumModes, iHalInfo.iNumModes, err, 0); sl@0: DBG_HAL(iScreenId, HAL::EDisplayMode, iHalInfo.iMode, err, 0); sl@0: sl@0: // Get info for current display mode sl@0: DBG_HAL(iScreenId, HAL::EDisplayIsMono, iHalInfo.iIsMono, err, iHalInfo.iMode); sl@0: DBG_HAL(iScreenId, HAL::EDisplayBitsPerPixel, iHalInfo.iBitsPerPixel, err, iHalInfo.iMode); sl@0: DBG_HAL(iScreenId, HAL::EDisplayOffsetBetweenLines, iHalInfo.iOffsetBetweenLines, err, iHalInfo.iMode); sl@0: DBG_HAL(iScreenId, HAL::EDisplayOffsetToFirstPixel, iHalInfo.iOffsetToFirstPixel, err, iHalInfo.iMode); sl@0: DBG_HAL(iScreenId, HAL::EDisplayIsPalettized, iHalInfo.iIsPalettized, err, iHalInfo.iMode); sl@0: } sl@0: sl@0: CDisplayChannelTest::CDisplayChannelTest(TInt aScreenId) sl@0: /** sl@0: Constructor sl@0: @param aScreenId the screen number to run the test on sl@0: */ sl@0: : CActive(EPriorityStandard), iScreenId(aScreenId) sl@0: { sl@0: TVersion versionRequired = iDisp.VersionRequired(); sl@0: test.Printf(_L("*** Opening display channel for screen %d. Test compiled against version %d.%d.%d ***\n"), sl@0: iScreenId, versionRequired.iMajor, versionRequired.iMinor, versionRequired.iBuild); sl@0: TInt err = iDisp.Open(iScreenId); sl@0: test_KErrNone(err); sl@0: sl@0: test.Printf(_L("Successfully opened display channel for screen %d\n"), iScreenId); sl@0: sl@0: // This test should be updated if a change to the driver requires a version change sl@0: err = iDisp.Version(iVersion); sl@0: if (err == KErrNotSupported) sl@0: { sl@0: test.Printf(_L("Version API not supported. Assuming v1.0.0\n")); sl@0: iVersion.iMajor = 1; sl@0: iVersion.iMinor = 0; sl@0: iVersion.iBuild = 0; sl@0: } sl@0: else sl@0: { sl@0: test.Printf(_L("Display channel driver version %d.%d.%d\n"), sl@0: iVersion.iMajor, iVersion.iMinor, iVersion.iBuild); sl@0: test_KErrNone(err); sl@0: } sl@0: test(iVersion.iMajor >= 1 && iVersion.iMinor >= 0); sl@0: GetHalDisplayInfo(); sl@0: CActiveScheduler::Add(this); sl@0: sl@0: iAsyncHelper = new CAsyncHelper(iDisp); sl@0: test_NotNull(iAsyncHelper); sl@0: } sl@0: sl@0: CDisplayChannelTest::~CDisplayChannelTest() sl@0: /** sl@0: Destructor sl@0: */ sl@0: { sl@0: Deque(); sl@0: delete iAsyncHelper; sl@0: iPixelFormats.Close(); sl@0: iResolutions.Close(); sl@0: iDisp.Close(); sl@0: } sl@0: sl@0: CDisplayChannelTest* CDisplayChannelTest::NewLC(TInt aScreenId) sl@0: /** sl@0: Factory method that creates a new instance of the screen sl@0: display channel unit test object and places a pointer to this on the cleanup stack sl@0: sl@0: @param aScreenId the screen number to run the test on sl@0: @return a pointer to the new CDisplayTest object. sl@0: */ sl@0: { sl@0: CDisplayChannelTest* self = new(ELeave) CDisplayChannelTest(aScreenId); sl@0: CleanupStack::PushL(self); sl@0: return self; sl@0: } sl@0: sl@0: void CDisplayChannelTest::CheckDisplayInfo() sl@0: /** sl@0: Check the values returned by CheckDisplayInfo sl@0: */ sl@0: { sl@0: test.Next(_L("Test GetDisplayInfo")); sl@0: TPckgBuf infoPkg; sl@0: sl@0: test_KErrNone(iDisp.GetDisplayInfo(infoPkg)); sl@0: sl@0: // This test only works with 24 and 32 BPP displays and crashes otherwise. Test for this and display sl@0: // a nice human readable message rather than just crashing sl@0: if ((infoPkg().iBitsPerPixel != 24) && (infoPkg().iBitsPerPixel != 32)) sl@0: { sl@0: TBuf<256> message; sl@0: sl@0: message.Format(_L("*** Error! %d bits per pixel displays are not supported. ***\n*** Please configure your ROM to use 24 or 32 bits per pixel. ***\n"), infoPkg().iBitsPerPixel); sl@0: test.Printf(message); sl@0: sl@0: // And fail the test for the benefit of automated ONB tests sl@0: test_Equal(infoPkg().iBitsPerPixel, 24); sl@0: } sl@0: sl@0: test_Compare(infoPkg().iBitsPerPixel, >=, 1); sl@0: test_Compare(infoPkg().iAvailableRotations, !=, 0); sl@0: sl@0: // check for invalid rotations i.e. those not defined by TRotation sl@0: test((infoPkg().iAvailableRotations & 0xFFF0) == 0); sl@0: sl@0: // Check that the refresh rate field isn't garbage sl@0: test_Compare(infoPkg().iRefreshRateHz, >=, 1); sl@0: test_Compare(infoPkg().iRefreshRateHz, <=, KMaxExpectedRefreshRate); sl@0: sl@0: // Should always be at least one composition buffer sl@0: test_Compare(infoPkg().iNumCompositionBuffers, >=, 1); sl@0: } sl@0: sl@0: void CDisplayChannelTest::CheckResolutions() sl@0: /** sl@0: Validate that the APIs to get / set resolutions. sl@0: sl@0: Tests
sl@0: NumberOfResolutions, GetResolutions, GetResolution, GetRotation sl@0: */ sl@0: { sl@0: test.Next(_L("Test NumberOfResolutions, GetResolutions, GetResolution, GetRotation")); sl@0: sl@0: // Get and reserve space for expected number of resolutions sl@0: TInt n = iDisp.NumberOfResolutions(); sl@0: test_Compare(n, >=, 1); sl@0: sl@0: iResolutions.Reset(); sl@0: test_KErrNone(iResolutions.Reserve(n)); sl@0: for (TInt i = 0; i < n; ++i) sl@0: { sl@0: test_KErrNone(iResolutions.Append(RDisplayChannel::TResolution(TSize(0,0), TSize(0,0), 0))); sl@0: } sl@0: sl@0: // Retrieve the resolutions and make sure the number of resolutions returned matches the sl@0: // expected number. It is assumed that the display state won't be changed during the execution sl@0: // of this test. sl@0: TInt actualResolutions = 0; sl@0: TPtr8 resPtr(reinterpret_cast(&iResolutions[0]), sl@0: sizeof(RDisplayChannel::TResolution) * n, sizeof(RDisplayChannel::TResolution) * n); sl@0: test_KErrNone(iDisp.GetResolutions(resPtr, actualResolutions)); sl@0: test_Equal(n, actualResolutions); sl@0: sl@0: test.Printf(_L("Supported resolutions")); sl@0: for (TInt res = 0; res < n; ++res) sl@0: { sl@0: RDisplayChannel::TResolution& r = iResolutions[res]; sl@0: test.Printf(_L("pixelX = %d heightX = %d twipsX = %d twipsY = %d flags = 0x%08x\n"), sl@0: r.iPixelSize.iWidth, r.iPixelSize.iHeight, r.iTwipsSize.iWidth, r.iTwipsSize.iHeight, r.iFlags); sl@0: sl@0: // If either pixel height or pixel width is zero then both must be zero sl@0: // If either pixel height or pixel width is non-zero then both must be positive sl@0: test((r.iPixelSize.iHeight == 0 && r.iPixelSize.iWidth == 0) || sl@0: (r.iPixelSize.iHeight > 0 && r.iPixelSize.iWidth > 0)); sl@0: sl@0: // Test resolutions are sane sl@0: test(r.iPixelSize.iHeight <= KMaxExpectedPixelRes && r.iPixelSize.iWidth <= KMaxExpectedPixelRes); sl@0: sl@0: // If either twips height or pixel width is zero then both must be zero sl@0: // If either twips height or pixel width is non-zero then both must be positive sl@0: test((r.iTwipsSize.iHeight == 0 && r.iTwipsSize.iWidth == 0) || sl@0: (r.iTwipsSize.iHeight > 0 && r.iTwipsSize.iWidth > 0)); sl@0: sl@0: // twips resolution can be zero iff pixel resolution is also zero sl@0: test((r.iPixelSize.iHeight == 0 && r.iTwipsSize.iHeight == 0) || sl@0: (r.iPixelSize.iHeight > 0 && r.iTwipsSize.iHeight > 0)); sl@0: sl@0: // At least one rotation must be supported. Ignore other bits in the flags field sl@0: test(r.iFlags & RDisplayChannel::ERotationAll != 0); sl@0: } sl@0: sl@0: // Get current resolution in pixels sl@0: TSize currentResolution; sl@0: test_KErrNone(iDisp.GetResolution(currentResolution)); sl@0: sl@0: // Get current resolution in twips sl@0: TSize currentTwips; sl@0: test_KErrNone(iDisp.GetTwips(currentTwips)); sl@0: sl@0: RDisplayChannel::TDisplayRotation currentRotation = iDisp.CurrentRotation(); sl@0: test(IsValidRotation(currentRotation)); sl@0: sl@0: // The current resolution and rotation must be in the list of supported resolutions sl@0: TBool foundCurrentRes = EFalse; sl@0: for (TInt j = iResolutions.Count() - 1; j >= 0; --j) sl@0: { sl@0: if (iResolutions[j].iPixelSize == currentResolution && sl@0: iResolutions[j].iTwipsSize == currentTwips && sl@0: iResolutions[j].iFlags & currentRotation) sl@0: { sl@0: foundCurrentRes = ETrue; sl@0: break; sl@0: } sl@0: } sl@0: test(foundCurrentRes); sl@0: sl@0: // Now and try every supported resolution sl@0: TInt err; sl@0: for (TInt k = iResolutions.Count() - 1; k >= 0; --k) sl@0: { sl@0: err = iDisp.SetResolution(iResolutions[k].iPixelSize); sl@0: test(err == KErrNone || err == KErrNotSupported); sl@0: } sl@0: // attempt to set back to original resolution, this could fail sl@0: err = iDisp.SetResolution(currentResolution); sl@0: test(err == KErrNone || err == KErrNotSupported); sl@0: } sl@0: sl@0: void CDisplayChannelTest::CheckPixelFormats() sl@0: /** sl@0: Validates that the pixel format APIs are sane/consistent. sl@0: sl@0: In version 1.1 the APIs are just stubs that return KErrNotSupported sl@0: */ sl@0: { sl@0: test.Next(_L("Test NumberOfPixelFormats, GetPixelFormats")); sl@0: sl@0: // At least one pixel format must be supported sl@0: TInt n = iDisp.NumberOfPixelFormats(); sl@0: sl@0: if (iVersion.iMajor == 1 && iVersion.iMinor <= 1) sl@0: { sl@0: test_Compare(n, ==, KErrNotSupported); sl@0: n = 1; // Override return to test stub for GetPixelFormats sl@0: } sl@0: else sl@0: { sl@0: test_Compare(n, >=, 1); sl@0: } sl@0: sl@0: TInt err = iPixelFormats.Reserve(n); sl@0: test_KErrNone(err); sl@0: for (TInt i = 0; i < n; ++i) sl@0: { sl@0: test_KErrNone(iPixelFormats.Append(-1)); sl@0: } sl@0: TPtr8 pixelFormatsPtr(reinterpret_cast(&iPixelFormats[0]), sl@0: sizeof(RDisplayChannel::TPixelFormat) * n, sizeof(RDisplayChannel::TPixelFormat) * n); sl@0: sl@0: TInt actualFormats = -1; sl@0: if (iVersion.iMajor == 1 && iVersion.iMinor <= 1) sl@0: { sl@0: test_Compare(iDisp.GetPixelFormats(pixelFormatsPtr, actualFormats), ==, KErrNotSupported); sl@0: } sl@0: else sl@0: { sl@0: test_KErrNone(iDisp.GetPixelFormats(pixelFormatsPtr, actualFormats)); sl@0: sl@0: // The number of formats shouldn't have changed whilst this test is running sl@0: test_Equal(n, actualFormats); sl@0: RArray pixelFormatsArray( sl@0: reinterpret_cast(&pixelFormatsPtr[0]), actualFormats); sl@0: sl@0: // Check the pixel formats returned are all valid sl@0: for (TInt pf = pixelFormatsArray.Count() - 1; pf >= 0; --pf) sl@0: { sl@0: IsValidPixelFormat(pixelFormatsArray[pf]); sl@0: } sl@0: } sl@0: } sl@0: sl@0: void CDisplayChannelTest::CheckDisplayChange() sl@0: /** sl@0: Register for display change notification then immediately cancel. sl@0: */ sl@0: { sl@0: test.Next(_L("Test NotifyOnDisplayChange, NotifyOnDisplayChangeCancel")); sl@0: // Cancel should be allowed even if NotifyOnyDisplayChange has not been called sl@0: iDisp.NotifyOnDisplayChangeCancel(); sl@0: sl@0: iDisp.NotifyOnDisplayChange(iAsyncHelper->Status()); sl@0: iAsyncHelper->WaitForOperation(&iAsyncHelperResult); sl@0: } sl@0: sl@0: void CDisplayChannelTest::DrawFillToMemory( sl@0: TUint8* aFirstPixelAddr, sl@0: TInt aOffsetBetweenLines, sl@0: RDisplayChannel::TPixelFormat aPixelFormat, sl@0: TInt aWidth, sl@0: TInt aHeight, sl@0: TInt aStep) sl@0: /** sl@0: Draws a shaded fill to a memory region sl@0: @param aFirstPixelAddr the address of the first pixel in the buffer. sl@0: @param aOffsetBetweenLines offset between pixels at the start of each line sl@0: @param aBpp bits per pixel sl@0: @param aWidth width of the region in pixels sl@0: @param aHeight height of the region in pixels sl@0: @aStep aStep integer >= 1 to vary the pattern by test number sl@0: */ { sl@0: test.Printf(_L("DrawFileToMemory\npixelformat = 0x%08x offsetbetweenlines = %d pixel address = 0x%08x width=%d height = %d\n"), sl@0: aPixelFormat, aOffsetBetweenLines, aFirstPixelAddr, aWidth, aHeight); sl@0: sl@0: sl@0: TInt xShadeMax = 0xFF; sl@0: TInt yShadeMax = 0xFF; sl@0: sl@0: if (aPixelFormat == EUidPixelFormatRGB_565) sl@0: { sl@0: xShadeMax = 0x3F; // 6 bits for green sl@0: yShadeMax = 0x1F; sl@0: } sl@0: else if (aPixelFormat == EUidPixelFormatARGB_4444 || aPixelFormat == EUidPixelFormatXRGB_4444) sl@0: { sl@0: xShadeMax = 0x0F; sl@0: yShadeMax = 0x0F; sl@0: } sl@0: sl@0: aStep = Max(1, aStep); sl@0: TUint8* lineAddr = aFirstPixelAddr; sl@0: for (TInt y = 0; y < aHeight; ++y) sl@0: { sl@0: TInt yShade = (y * yShadeMax) / aHeight; sl@0: TUint8* pixelAddr = lineAddr; sl@0: for (TInt x = 0; x < aWidth; ++x) sl@0: { sl@0: TInt xShade = (x * xShadeMax) / aWidth; sl@0: TUint8 red = 0; sl@0: TUint8 green = 0; sl@0: TUint8 blue = 0; sl@0: sl@0: if ( aStep == 0 || y > aStep * 10) sl@0: { sl@0: // Green top left, blue bottom right sl@0: green = static_cast(xShadeMax - xShade); sl@0: blue = static_cast(yShade); sl@0: } sl@0: else sl@0: { sl@0: // The size of the red band indicates different test steps sl@0: red = static_cast((yShadeMax * x) / aWidth); sl@0: } sl@0: sl@0: if (aPixelFormat == EUidPixelFormatRGB_565) sl@0: { sl@0: *pixelAddr++ = static_cast(blue | (green << 5)); sl@0: *pixelAddr++ = static_cast((green >> 3) | (red << 3)); sl@0: } sl@0: else if (aPixelFormat == EUidPixelFormatARGB_4444 || aPixelFormat == EUidPixelFormatXRGB_4444) sl@0: { sl@0: *pixelAddr++ = static_cast(blue | (green << 4)); sl@0: *pixelAddr++ = red; sl@0: } sl@0: else if (aPixelFormat == EUidPixelFormatXRGB_8888 || aPixelFormat == EUidPixelFormatARGB_8888 sl@0: || aPixelFormat == EUidPixelFormatARGB_8888) sl@0: { sl@0: *pixelAddr++ = blue; sl@0: *pixelAddr++ = green; sl@0: *pixelAddr++ = red; sl@0: *pixelAddr++ = 0xFF; // unused sl@0: } sl@0: } sl@0: lineAddr += aOffsetBetweenLines; sl@0: } sl@0: } sl@0: sl@0: void CDisplayChannelTest::DrawLegacyBuffer(TInt aStep) sl@0: { sl@0: test.Printf(_L("DrawLegacyBuffer\n")); sl@0: TInt oldMode; sl@0: TInt err; sl@0: err = HAL::Get(iScreenId, HAL::EDisplayMode, oldMode); sl@0: for (TInt i = 0; i < iHalInfo.iNumModes; ++i) sl@0: { sl@0: // Attempt to set the legacy buffer to a mode supporting 32bit (RGBA or RGBX) sl@0: TInt modeBpp = i; sl@0: err = HAL::Get(iScreenId, HAL::EDisplayBitsPerPixel, modeBpp); sl@0: sl@0: test_KErrNone(err); sl@0: if ((modeBpp == 24 || modeBpp == 32)) sl@0: { sl@0: TInt newMode = i; sl@0: err = HAL::Set(iScreenId, HAL::EDisplayMode, newMode); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: GetHalDisplayInfo(); sl@0: err = HAL::Set(iScreenId, HAL::EDisplayMode, oldMode); sl@0: TUint8* firstPixelAddr = reinterpret_cast(iHalInfo.iMemoryAddress + iHalInfo.iOffsetToFirstPixel); sl@0: TInt offsetBetweenLines = iHalInfo.iOffsetBetweenLines; sl@0: TInt width = iHalInfo.iXPixels; sl@0: TInt height = iHalInfo.iYPixels; sl@0: sl@0: if ((! iHalInfo.iIsPalettized) && iHalInfo.iIsPixelOrderRGB) sl@0: { sl@0: DrawFillToMemory(firstPixelAddr, offsetBetweenLines, sl@0: EUidPixelFormatXRGB_8888, width, height, aStep); sl@0: } sl@0: } sl@0: sl@0: void CDisplayChannelTest::DrawCompositionBuffer( sl@0: RDisplayChannel::TPostCount& aPostCount, sl@0: RDisplayChannel::TBufferFormat aBufferFormat, sl@0: RDisplayChannel::TDisplayRotation aRotation, TInt aStep) sl@0: /** sl@0: Attempts to set the requested buffer format and rotation then draws a shaded fill sl@0: to the buffer returned by RDisplayChannel::GetCompositionBuffer. sl@0: If it is not possible to set the desired buffer format then the actual buffer format sl@0: is used. sl@0: sl@0: @param aPostCount out parameter that is set to the post count returned by PostCompositionBuffer sl@0: @param aBufferFormat the buffer format to use for this test step sl@0: @param aRotation the rotation to set for this test step sl@0: @param aStep test step number sl@0: */ sl@0: { sl@0: test.Printf(_L("DrawCompositionBuffer\n")); sl@0: sl@0: TBool configChanged; sl@0: TInt err; sl@0: sl@0: RDisplayChannel::TBufferFormat actualBufferFormat(TSize(0,0),0); sl@0: if (iVersion.iMajor > 1 || iVersion.iMinor > 0) sl@0: { sl@0: // It should be possible to set the rotation and the buffer format in either order. sl@0: // To test this the order is swapped every test step sl@0: if (aStep % 2 == 0) sl@0: { sl@0: test_KErrNone(iDisp.SetRotation(aRotation, configChanged)); sl@0: err = iDisp.SetBufferFormat(aBufferFormat); sl@0: } sl@0: else sl@0: { sl@0: err = iDisp.SetBufferFormat(aBufferFormat); sl@0: test_KErrNone(iDisp.SetRotation(aRotation, configChanged)); sl@0: } sl@0: if (err != KErrNone) sl@0: { sl@0: test.Printf(_L("Unable to set buffer format 0x%08x width %d height %d"), sl@0: aBufferFormat.iPixelFormat, aBufferFormat.iSize.iWidth, aBufferFormat.iSize.iHeight); sl@0: } sl@0: test_KErrNone(iDisp.GetBufferFormat(actualBufferFormat)); sl@0: } sl@0: else sl@0: { sl@0: // buffer format not switched in v1.1 so test just validates post / wait for post sl@0: TPckgBuf infoPkg; sl@0: test_KErrNone(iDisp.GetDisplayInfo(infoPkg)); sl@0: sl@0: err = iDisp.SetRotation(aRotation, configChanged); sl@0: TInt expectedErr = KErrNone; sl@0: if ((!IsValidRotation(aRotation)) || ((infoPkg().iAvailableRotations & aRotation) == 0)) sl@0: { sl@0: expectedErr = KErrArgument; sl@0: } sl@0: test(err == expectedErr); sl@0: sl@0: actualBufferFormat = aBufferFormat; sl@0: } sl@0: sl@0: // Get the composition buffer index sl@0: TUint bufferIndex; sl@0: TRequestStatus status; sl@0: iDisp.GetCompositionBuffer(bufferIndex, status); sl@0: User::WaitForRequest(status); sl@0: test(status == KErrNone); sl@0: sl@0: // Now get access to the composition buffer sl@0: RChunk compChunk; sl@0: TInt offset = 0; sl@0: err = iDisp.GetCompositionBufferInfo(bufferIndex, compChunk, offset); sl@0: test_KErrNone(err); sl@0: sl@0: TUint8* baseAddr = compChunk.Base(); sl@0: TPckgBuf infoPkg; sl@0: err = iDisp.GetDisplayInfo(infoPkg); sl@0: test_KErrNone(err); sl@0: sl@0: test.Printf(_L("DrawCompositionBuffer::GetCompositionBufferInfo index = 0x%08x base = 0x%08x offset = 0x%08x\n"), sl@0: bufferIndex, baseAddr, offset); sl@0: sl@0: // Find out structure of the buffer sl@0: TUint8* firstPixelAddr = baseAddr + offset; sl@0: sl@0: // Find out current display dimensions sl@0: TInt width; sl@0: TInt height; sl@0: RDisplayChannel::TDisplayRotation currentRotation = iDisp.CurrentRotation(); sl@0: test(IsValidRotation(currentRotation)); sl@0: if (currentRotation == RDisplayChannel::ERotationNormal || sl@0: currentRotation == RDisplayChannel::ERotation180) sl@0: { sl@0: width = actualBufferFormat.iSize.iWidth; sl@0: height = actualBufferFormat.iSize.iHeight; sl@0: } sl@0: else sl@0: { sl@0: height = actualBufferFormat.iSize.iWidth; sl@0: width = actualBufferFormat.iSize.iHeight; sl@0: } sl@0: sl@0: TInt offsetBetweenLines; sl@0: if (iVersion.iMajor > 1 || iVersion.iMinor > 0) sl@0: { sl@0: offsetBetweenLines = iDisp.NextLineOffset(actualBufferFormat, 0); sl@0: } sl@0: else sl@0: { sl@0: // NextLineOffset not supported in v1.0 and displayinfo offset doesn't work on H4 sl@0: offsetBetweenLines = 4 * width; sl@0: } sl@0: DrawFillToMemory(firstPixelAddr, offsetBetweenLines, actualBufferFormat.iPixelFormat, sl@0: width, height, aStep); sl@0: sl@0: err = iDisp.PostCompositionBuffer(NULL, aPostCount); sl@0: test_KErrNone(err); sl@0: User::After(KDrawWaitTime); sl@0: sl@0: compChunk.Close(); sl@0: } sl@0: sl@0: void CDisplayChannelTest::CheckCompositionBuffers() sl@0: /** sl@0: Retrieves the current composition buffer index and checks the information about sl@0: this buffer. sl@0: */ sl@0: { sl@0: test.Next(_L("Test GetCompositionBuffer, CancelGetCompositionBuffer, GetCompositionBufferInfo, PostLegacyBuffer")); sl@0: sl@0: iDisp.CancelGetCompositionBuffer(); // Test cancel without an outstanding call sl@0: sl@0: TUint bufferIndex; sl@0: TRequestStatus status; sl@0: // Get with immediate cancel sl@0: iDisp.GetCompositionBuffer(bufferIndex, status); sl@0: iDisp.CancelGetCompositionBuffer(); sl@0: test(status == KErrNone || status == KErrCancel); sl@0: sl@0: iDisp.GetCompositionBuffer(bufferIndex, status); // Get, no cancel sl@0: User::WaitForRequest(status); sl@0: test(status == KErrNone); sl@0: sl@0: RChunk compChunk; sl@0: TInt offset = 0; sl@0: test_KErrNone(iDisp.GetCompositionBufferInfo(bufferIndex, compChunk, offset)); sl@0: sl@0: // client must be able to read and write to the chunk sl@0: test(compChunk.IsReadable()); sl@0: test(compChunk.IsWritable()); sl@0: test_Compare(offset, >=, 0); sl@0: sl@0: RDisplayChannel::TPostCount postCountA; sl@0: RDisplayChannel::TPostCount postCountB; sl@0: test_KErrNone(iDisp.PostCompositionBuffer(NULL, postCountA)); sl@0: test_KErrNone(iDisp.PostCompositionBuffer(NULL, postCountB)); sl@0: test_Compare(postCountB - postCountA, >=, 1); sl@0: sl@0: // Wait for first postcount value sl@0: iDisp.WaitForPost(postCountA, status); sl@0: User::WaitForRequest(status); sl@0: test(status == KErrNone); sl@0: sl@0: // It should be possible to wait again on postCountA sl@0: // and this should complete immediately with KErrNone. However, there sl@0: // there is bug in the emulator causes this to wait forever. sl@0: sl@0: compChunk.Close(); sl@0: sl@0: // Legacy buffer should have been initialised by retrieval of HAL::EDisplayMemoryAddress sl@0: test_KErrNone(iDisp.PostLegacyBuffer(NULL, postCountA)); sl@0: test_Compare(postCountA - postCountB, >=, 1); sl@0: } sl@0: sl@0: void CDisplayChannelTest::VisualTest() sl@0: /** sl@0: Iterates over the arrays of pixel formats and rotations attempting to sl@0: draw a shaded fill to the composition buffer sl@0: */ sl@0: { sl@0: test.Next(_L("Visual test")); sl@0: sl@0: RDisplayChannel::TPostCount postCount; sl@0: if (iVisualTestFormatIndex < KNumPixelFormats) sl@0: { sl@0: RDisplayChannel::TBufferFormat bufferFormat(TSize(0,0), 0); sl@0: if (iVersion.iMajor == 1 && iVersion.iMinor == 0) sl@0: { sl@0: // only one format supported in v1.0 so only one loop needed sl@0: bufferFormat.iPixelFormat = EUidPixelFormatXRGB_8888; sl@0: iVisualTestFormatIndex = KNumPixelFormats - 1; sl@0: TPckgBuf infoPkg; sl@0: iDisp.GetDisplayInfo(infoPkg); sl@0: bufferFormat.iSize.iWidth = infoPkg().iNormal.iWidth; sl@0: bufferFormat.iSize.iHeight = infoPkg().iNormal.iHeight; sl@0: } sl@0: else sl@0: { sl@0: test_KErrNone(iDisp.GetBufferFormat(bufferFormat)); sl@0: bufferFormat.iPixelFormat = KPixelFormats[iVisualTestFormatIndex]; sl@0: } sl@0: DrawCompositionBuffer(postCount, bufferFormat, KRotations[iVisualTestRotationIndex], iVisualTestRotationIndex); sl@0: iVisualTestRotationIndex++; sl@0: if (iVisualTestRotationIndex >= KNumRotations) sl@0: { sl@0: iVisualTestRotationIndex = 0; sl@0: iVisualTestFormatIndex++; sl@0: } sl@0: iDisp.WaitForPost(postCount, iStatus); sl@0: SetActive(); sl@0: } sl@0: else sl@0: { sl@0: // Test drawing to the legacy buffer sl@0: test.Printf(_L("Drawing to legacy buffer\n")); sl@0: sl@0: TBool configChanged; sl@0: iDisp.SetRotation(KRotations[0], configChanged); sl@0: DrawLegacyBuffer(20); // Make legacy buffer obviously different sl@0: test_KErrNone(iDisp.PostLegacyBuffer(NULL, postCount)); sl@0: CompleteSelf(ETestSecondHandle); sl@0: User::After(KDrawWaitTime); sl@0: } sl@0: } sl@0: sl@0: void CDisplayChannelTest::CheckBufferFormat() sl@0: /** sl@0: Tests the APIs for getting and setting the buffer format. sl@0: In version 1.1 these APIs are only stubs that return KErrNotSupported sl@0: sl@0: @pre CheckResolutions must have called prior to calling this method sl@0: @pre CheckPixelFormats must have been called prior to calling this method. sl@0: */ sl@0: { sl@0: test.Next(_L("Test GetBufferFormat, SetBufferFormat, NextLineOffset, NextPlaneOffset")); sl@0: sl@0: RDisplayChannel::TBufferFormat bufferFormat(TSize(0,0), 0); sl@0: TInt err = iDisp.GetBufferFormat(bufferFormat); sl@0: if (iVersion.iMajor == 1 && iVersion.iMinor <= 1) sl@0: { sl@0: test_Compare(err, ==, KErrNotSupported); sl@0: } sl@0: else sl@0: { sl@0: test(IsValidPixelFormat(bufferFormat.iPixelFormat)); sl@0: test(bufferFormat.iSize.iHeight > 0 && bufferFormat.iSize.iHeight > 0); sl@0: // Check that the buffer is at least as large as the current pixel resolution sl@0: TSize resSize; sl@0: test_KErrNone(iDisp.GetResolution(resSize)); sl@0: test(bufferFormat.iSize.iHeight >= resSize.iHeight && bufferFormat.iSize.iWidth >= resSize.iWidth); sl@0: } sl@0: sl@0: RDisplayChannel::TBufferFormat newBufferFormat(TSize(iHalInfo.iXPixels, iHalInfo.iYPixels), 0); sl@0: if (iVersion.iMajor == 1 && iVersion.iMinor <= 1) sl@0: { sl@0: // API not support in 1.1 sl@0: test_Compare(iDisp.SetBufferFormat(newBufferFormat), ==, KErrNotSupported); sl@0: } sl@0: else sl@0: { sl@0: // Tests assumes that 32bpp XRGB888 is supported on most hardware sl@0: RDisplayChannel::TBufferFormat newBufferFormat(TSize(0,0), EUidPixelFormatXRGB_8888); sl@0: test_Compare(iDisp.SetBufferFormat(newBufferFormat), ==, KErrArgument); // buffer must be large enough for resolution sl@0: sl@0: // Should be able to current buffer format sl@0: test_KErrNone(iDisp.SetBufferFormat(bufferFormat)); sl@0: } sl@0: sl@0: // Get current information and check this against new APIs that give sl@0: // line and plane information for any mode. sl@0: TSize currentPixelRes; sl@0: TSize currentTwipRes; sl@0: RDisplayChannel::TDisplayRotation currentRotation = iDisp.CurrentRotation(); sl@0: RDisplayChannel::TBufferFormat currentBufferFormat(TSize(0,0), 0); sl@0: sl@0: test_KErrNone(iDisp.GetResolution(currentPixelRes)); sl@0: test_KErrNone(iDisp.GetTwips(currentTwipRes)); sl@0: test_KErrNone(iDisp.GetBufferFormat(currentBufferFormat)); sl@0: RDisplayChannel::TResolution res(currentPixelRes, currentTwipRes, currentRotation); sl@0: sl@0: TInt planeOffset = iDisp.NextPlaneOffset(currentBufferFormat, 0); sl@0: if (iVersion.iMajor == 1 && iVersion.iMinor <= 1) sl@0: { sl@0: test_Compare(planeOffset, ==, KErrNotSupported); sl@0: } sl@0: else sl@0: { sl@0: // Supported in v1.1 sl@0: test_Compare(planeOffset, >=, 0); sl@0: sl@0: if (iVersion.iMajor > 1 || iVersion.iMinor > 1) sl@0: { sl@0: // Extended API in v1.2 sl@0: test.Printf(_L("Check that planeoffset APIs match")); sl@0: TInt planeOffset2 = iDisp.NextPlaneOffset(currentBufferFormat, res, currentRotation, 0); sl@0: test_Compare(planeOffset, ==, planeOffset2); sl@0: sl@0: // check that invalid buffer formats are rejected sl@0: RDisplayChannel::TBufferFormat badBufferFormat(currentBufferFormat); sl@0: badBufferFormat.iPixelFormat = -1; sl@0: test(iDisp.NextPlaneOffset(badBufferFormat, res, currentRotation, 0) == KErrArgument); sl@0: } sl@0: } sl@0: sl@0: TInt lineOffset = iDisp.NextLineOffset(currentBufferFormat, 0); sl@0: if (iVersion.iMajor == 1 && iVersion.iMinor <= 1) sl@0: { sl@0: test_Compare(lineOffset, ==, KErrNotSupported); sl@0: } sl@0: else sl@0: { sl@0: test_Compare(lineOffset, >, 0); // supported in v1.1 sl@0: sl@0: if (iVersion.iMajor > 1 || iVersion.iMinor > 1) sl@0: { sl@0: // Extended API in v1.2 sl@0: test.Printf(_L("Check that lineoffset APIs match")); sl@0: TInt lineOffset2 = iDisp.NextLineOffset(currentBufferFormat, res, currentRotation, 0); sl@0: // stride values must be the same and > 0 for any non-zero resolution and the current sl@0: // resolution should not be zero in size. sl@0: sl@0: test_Compare(lineOffset, ==, lineOffset2); sl@0: // check that invalid buffer formats are rejected sl@0: RDisplayChannel::TBufferFormat badBufferFormat(currentBufferFormat); sl@0: badBufferFormat.iPixelFormat = -1; sl@0: test(iDisp.NextLineOffset(badBufferFormat, res, currentRotation, 0) == KErrArgument); sl@0: } sl@0: } sl@0: } sl@0: sl@0: void CDisplayChannelTest::CheckUserBuffers() sl@0: /** sl@0: Test APIs that manage user composition buffers. Since this unit test doesn't sl@0: have access to the real surfaces the tests are mostly robustness tests. sl@0: */ sl@0: { sl@0: test.Next(_L("Test WaitForPost, DeRegisterUserBuffer")); sl@0: sl@0: // Cancel should not fail even if WaitForPost has not been called sl@0: iDisp.CancelWaitForPost(); sl@0: sl@0: // Check that cancelling a non-existent post request doesn't fail sl@0: iDisp.CancelPostUserBuffer(); sl@0: sl@0: // Make sure wait immediately followed by cancel doesn't crash sl@0: TRequestStatus status; sl@0: RDisplayChannel::TPostCount postCount = 0; sl@0: iDisp.WaitForPost(postCount, status); sl@0: iDisp.CancelWaitForPost(); sl@0: test(status == KErrNone || status == KErrCancel); sl@0: sl@0: // De-register a non-existent buffer id sl@0: RDisplayChannel::TBufferId badBufferId(42); sl@0: TInt err = iDisp.DeregisterUserBuffer(badBufferId); sl@0: // emulator KErrArugment but on H4 KErrNotFound sl@0: test(err == KErrArgument || err == KErrNotFound); sl@0: sl@0: // Create and use a new buffer, should fail because chunk must be a SHARED chunk sl@0: RChunk myChunk; sl@0: const TInt chunkSize = 320 * 200 * 4; // actual size is not important because this should fail sl@0: err = myChunk.CreateGlobal(KNullDesC, chunkSize, chunkSize, EOwnerProcess); sl@0: test_KErrNone(err); // Allocation should not fail under normal conditions sl@0: RDisplayChannel::TBufferId myBufferId; sl@0: err = iDisp.RegisterUserBuffer(myBufferId, myChunk, 0); sl@0: // emulator KErrBadHandle but on H4 KErrArgument sl@0: test(err == KErrBadHandle || err == KErrArgument); sl@0: myChunk.Close(); sl@0: sl@0: // Try to post a request from a bad buffer id sl@0: iDisp.PostUserBuffer(badBufferId, status, NULL, postCount); sl@0: User::WaitForRequest(status); sl@0: // Emulator KErrArgument H4 KErrNotFound sl@0: test(status.Int() == KErrArgument || status.Int() == KErrNotFound); sl@0: sl@0: // Attempt to register an already existing buffer as a user buffer sl@0: TUint compId; sl@0: iDisp.GetCompositionBuffer(compId, status); sl@0: User::WaitForRequest(status); sl@0: RChunk compChunk; sl@0: TInt offset; sl@0: test_KErrNone(iDisp.GetCompositionBufferInfo(compId, compChunk, offset)); sl@0: test_KErrNone(iDisp.RegisterUserBuffer(myBufferId, compChunk, offset)); sl@0: err = iDisp.DeregisterUserBuffer(myBufferId); sl@0: test(err == KErrNone || err == KErrInUse); sl@0: compChunk.Close(); sl@0: } sl@0: sl@0: TBool CDisplayChannelTest::IsValidPixelFormat(RDisplayChannel::TPixelFormat aPixelFormat) sl@0: /** sl@0: Validates whether the value of aPixelFormat corresponds to a valid enum in TUidPixelFormat sl@0: @param aPixelFormat the pixel format value to test sl@0: @return ETrue if aPixelFormat is valid; otherwise, EFalse is returned. sl@0: */ sl@0: { sl@0: switch (aPixelFormat) sl@0: { sl@0: case EUidPixelFormatUnknown: sl@0: case EUidPixelFormatXRGB_8888: sl@0: case EUidPixelFormatBGRX_8888: sl@0: case EUidPixelFormatXBGR_8888: sl@0: case EUidPixelFormatBGRA_8888: sl@0: case EUidPixelFormatARGB_8888: sl@0: case EUidPixelFormatABGR_8888: sl@0: case EUidPixelFormatARGB_8888_PRE: sl@0: case EUidPixelFormatABGR_8888_PRE: sl@0: case EUidPixelFormatBGRA_8888_PRE: sl@0: case EUidPixelFormatARGB_2101010: sl@0: case EUidPixelFormatABGR_2101010: sl@0: case EUidPixelFormatBGR_888: sl@0: case EUidPixelFormatRGB_888: sl@0: case EUidPixelFormatRGB_565: sl@0: case EUidPixelFormatBGR_565: sl@0: case EUidPixelFormatARGB_1555: sl@0: case EUidPixelFormatXRGB_1555: sl@0: case EUidPixelFormatARGB_4444: sl@0: case EUidPixelFormatARGB_8332: sl@0: case EUidPixelFormatBGRX_5551: sl@0: case EUidPixelFormatBGRA_5551: sl@0: case EUidPixelFormatBGRA_4444: sl@0: case EUidPixelFormatBGRX_4444: sl@0: case EUidPixelFormatAP_88: sl@0: case EUidPixelFormatXRGB_4444: sl@0: case EUidPixelFormatXBGR_4444: sl@0: case EUidPixelFormatRGB_332: sl@0: case EUidPixelFormatA_8: sl@0: case EUidPixelFormatBGR_332: sl@0: case EUidPixelFormatP_8: sl@0: case EUidPixelFormatP_4: sl@0: case EUidPixelFormatP_2: sl@0: case EUidPixelFormatP_1: sl@0: case EUidPixelFormatYUV_420Interleaved: sl@0: case EUidPixelFormatYUV_420Planar: sl@0: case EUidPixelFormatYUV_420PlanarReversed: sl@0: case EUidPixelFormatYUV_420SemiPlanar: sl@0: case EUidPixelFormatYUV_422Interleaved: sl@0: case EUidPixelFormatYUV_422Planar: sl@0: case EUidPixelFormatYUV_422Reversed: sl@0: case EUidPixelFormatYUV_422SemiPlanar: sl@0: case EUidPixelFormatYUV_422InterleavedReversed: sl@0: case EUidPixelFormatYUV_422Interleaved16bit: sl@0: case EUidPixelFormatYUV_444Interleaved: sl@0: case EUidPixelFormatYUV_444Planar: sl@0: case EUidPixelFormatL_8: sl@0: case EUidPixelFormatL_4: sl@0: case EUidPixelFormatL_2: sl@0: case EUidPixelFormatL_1: sl@0: case EUidPixelFormatSpeedTaggedJPEG: sl@0: case EUidPixelFormatJPEG: sl@0: return ETrue; sl@0: default: sl@0: return EFalse; sl@0: } sl@0: } sl@0: sl@0: TBool CDisplayChannelTest::IsValidRotation(RDisplayChannel::TDisplayRotation aRotation) sl@0: /** sl@0: Checks whether the supplied rotation is a valid rotation.
sl@0: N.B. Only single rotations are accepted so EFalse is returned for ERotationAll. sl@0: @param aRotation the rotation to validate sl@0: @return ETrue if the supplied rotation is valid; otherwise, EFalse is returned. sl@0: */ sl@0: { sl@0: switch (aRotation) sl@0: { sl@0: case RDisplayChannel::ERotationNormal: sl@0: case RDisplayChannel::ERotation90CW: sl@0: case RDisplayChannel::ERotation180: sl@0: case RDisplayChannel::ERotation270CW: sl@0: return ETrue; sl@0: default: sl@0: return EFalse; sl@0: } sl@0: } sl@0: sl@0: void CDisplayChannelTest::CheckSetRotation(TUint aSupported, RDisplayChannel::TDisplayRotation aNewRotation) sl@0: /** sl@0: Tests the SetRotation API attempting to set the requested resolution. If the resolution is supported sl@0: then SetRotation should succeed and the CurrentRotation should change. Otherwise, SetResolution should sl@0: fail and the current rotation should be unchanged. sl@0: sl@0: @param aSupported The set of supported resolutions for TDisplayInfo sl@0: @param aNewRotation The new rotation to set sl@0: */ sl@0: { sl@0: RDisplayChannel::TDisplayRotation currentRotation = iDisp.CurrentRotation(); sl@0: test(IsValidRotation(currentRotation)); sl@0: sl@0: TBool displayConfigChanged = EFalse; sl@0: TInt err = iDisp.SetRotation(aNewRotation, displayConfigChanged); sl@0: TInt expectedErr = KErrNone; sl@0: if ((!IsValidRotation(aNewRotation)) || ((aSupported & aNewRotation) == 0)) sl@0: { sl@0: expectedErr = KErrArgument; sl@0: } sl@0: test(err == expectedErr); sl@0: sl@0: // Check whether the rotation should / shouldn't have changed sl@0: test (iDisp.CurrentRotation() == (err == KErrNone ? aNewRotation : currentRotation)); sl@0: } sl@0: sl@0: void CDisplayChannelTest::CheckRotations() sl@0: /** sl@0: Tests the SetRotation and GetRotation APIs by attempting to set each valid rotation sl@0: plus some invalid rotation values. sl@0: If a rotation is valid but not supported then KErrNotSupported should be returned. sl@0: */ sl@0: { sl@0: test.Next(_L("Test CurrentRotation, SetRotation")); sl@0: sl@0: // Find out supported resolutions sl@0: TPckgBuf infoPkg; sl@0: test_KErrNone(iDisp.GetDisplayInfo(infoPkg)); sl@0: sl@0: CheckSetRotation(infoPkg().iAvailableRotations, RDisplayChannel::ERotationNormal); sl@0: CheckSetRotation(infoPkg().iAvailableRotations, RDisplayChannel::ERotation90CW); sl@0: CheckSetRotation(infoPkg().iAvailableRotations, RDisplayChannel::ERotation180); sl@0: CheckSetRotation(infoPkg().iAvailableRotations, RDisplayChannel::ERotation270CW); sl@0: CheckSetRotation(infoPkg().iAvailableRotations, RDisplayChannel::ERotationNormal); sl@0: CheckSetRotation(infoPkg().iAvailableRotations, static_cast(-1)); sl@0: CheckSetRotation(infoPkg().iAvailableRotations, static_cast(0)); sl@0: } sl@0: sl@0: void CDisplayChannelTest::CheckV11inV10() sl@0: /** sl@0: The purpose of this test is to verify that v1.0 of the display channel driver sl@0: returns KErrNotSupported for methods that only exist in newer versions as opposed sl@0: to panicking. sl@0: To run this test for real t_display needs to be built against v1.1 and then copied sl@0: to a v1.0 environment. sl@0: sl@0: If the version number is > 1.0 then this method does nothing. sl@0: */ sl@0: { sl@0: if (iVersion.iMajor > 1 || iVersion.iMinor > 0) sl@0: { sl@0: return; sl@0: } sl@0: sl@0: test.Next(_L("Test check v1.1 functions fail gracefully in v1.0")); sl@0: sl@0: // APIs should fail before evaluating parameters sl@0: TInt intDummy; sl@0: TInt err; sl@0: TBuf8<256> buf; sl@0: TSize size; sl@0: sl@0: test.Printf(_L("Testing display change APIs\n")); sl@0: iDisp.NotifyOnDisplayChangeCancel(); sl@0: TRequestStatus status; sl@0: iDisp.NotifyOnDisplayChange(status); sl@0: test(status == KErrNotSupported); sl@0: sl@0: err = iDisp.NumberOfResolutions(); sl@0: test(err == KErrNotSupported); sl@0: sl@0: err = iDisp.GetResolutions(buf, intDummy); sl@0: test(err == KErrNotSupported); sl@0: sl@0: err = iDisp.GetResolution(size); sl@0: test(err == KErrNotSupported); sl@0: sl@0: err = iDisp.GetTwips(size); sl@0: test(err == KErrNotSupported); sl@0: sl@0: err = iDisp.NumberOfPixelFormats(); sl@0: test(err == KErrNotSupported); sl@0: sl@0: err = iDisp.GetPixelFormats(buf, intDummy); sl@0: test(err == KErrNotSupported); sl@0: sl@0: RDisplayChannel::TBufferFormat bufferFormat(TSize(0,0),0); sl@0: err = iDisp.GetBufferFormat(bufferFormat); sl@0: test(err == KErrNotSupported); sl@0: sl@0: err = iDisp.SetBufferFormat(bufferFormat); sl@0: test(err == KErrNotSupported); sl@0: sl@0: err = iDisp.NextPlaneOffset(bufferFormat, 0); sl@0: test(err == KErrNotSupported); sl@0: sl@0: err = iDisp.NextLineOffset(bufferFormat, 0); sl@0: test(err == KErrNotSupported); sl@0: } sl@0: sl@0: void CDisplayChannelTest::CheckSecondHandle() sl@0: /** sl@0: Opens a second RDisplayChannel. sl@0: The driver may not support this but must not crash. sl@0: */ sl@0: { sl@0: test.Next(_L("Open a second handle")); sl@0: RDisplayChannel disp2; sl@0: TInt err = disp2.Open(iScreenId); sl@0: test(err == KErrNone || err == KErrInUse); sl@0: disp2.Close(); sl@0: } sl@0: sl@0: void CDisplayChannelTest::TestBufferTransitions() sl@0: /** sl@0: Because different buffer types (ie. composition, legacy and user) complete differently, we must test sl@0: switching between those different types of buffers to ensure that this is taken into account. sl@0: */ sl@0: { sl@0: // The support code required for this test exists only in the separated GCE display LDD, not in the sl@0: // legacy monolithic WINSCW LDD sl@0: #if defined(_DEBUG) && !defined(__WINS__) sl@0: test.Next(_L("Test transitions between buffer types")); sl@0: sl@0: TPckgBuf displayInfo; sl@0: test_KErrNone(iDisp.GetDisplayInfo(displayInfo)); sl@0: sl@0: RChunk chunk; sl@0: RDisplayChannel::TBufferFormat bufferFormat(TSize(iHalInfo.iXPixels, iHalInfo.iYPixels), displayInfo().iPixelFormat); sl@0: sl@0: test.Next(_L("Get the LDD to create a user buffer")); sl@0: TInt err = iDisp.CreateUserBuffer(bufferFormat, chunk); sl@0: test_KErrNone(err); sl@0: sl@0: test.Next(_L("Register a user buffer")); sl@0: RDisplayChannel::TBufferId bufferId; sl@0: err = iDisp.RegisterUserBuffer(bufferId, chunk, 0); sl@0: test_KErrNone(err); sl@0: sl@0: test.Next(_L("Post a user buffer")); sl@0: TRequestStatus status; sl@0: RDisplayChannel::TPostCount postCount; sl@0: iDisp.PostUserBuffer(bufferId, status, NULL, postCount); sl@0: iDisp.PostLegacyBuffer(NULL, postCount); sl@0: sl@0: test.Printf(_L("Waiting for user buffer\n")); sl@0: User::WaitForRequest(status); sl@0: test(status.Int() == KErrNone || status.Int() == KErrCancel); sl@0: test.Printf(_L("Waiting for legacy buffer\n")); sl@0: iDisp.WaitForPost(postCount, status); sl@0: User::WaitForRequest(status); sl@0: test_KErrNone(status.Int()); sl@0: sl@0: test.Printf(_L("Getting composition buffer\n")); sl@0: TUint bufferIndex; sl@0: iDisp.GetCompositionBuffer(bufferIndex, status); sl@0: User::WaitForRequest(status); sl@0: test_KErrNone(status.Int()); sl@0: sl@0: iDisp.PostUserBuffer(bufferId, status, NULL, postCount); sl@0: iDisp.PostCompositionBuffer(NULL, postCount); sl@0: sl@0: test.Printf(_L("Waiting for user buffer\n")); sl@0: User::WaitForRequest(status); sl@0: test(status.Int() == KErrNone || status.Int() == KErrCancel); sl@0: test.Printf(_L("Waiting for composition buffer\n")); sl@0: iDisp.WaitForPost(postCount, status); sl@0: User::WaitForRequest(status); sl@0: test_KErrNone(status.Int()); sl@0: sl@0: test.Printf(_L("Deregistering user buffers\n")); sl@0: err = iDisp.DeregisterUserBuffer(bufferId); sl@0: test_KErrNone(err); sl@0: sl@0: test.Printf(_L("Done, closing shared chunk\n")); sl@0: chunk.Close(); sl@0: #endif // defined(_DEBUG) && !defined(__WINS__) sl@0: } sl@0: sl@0: void CDisplayChannelTest::Start() sl@0: /** sl@0: Run all of the test cases sl@0: */ sl@0: { sl@0: CompleteSelf(ETestDisplayInfo); sl@0: } sl@0: sl@0: void CDisplayChannelTest::CompleteSelf(TTestState aNextState) sl@0: /* sl@0: Advances to the next test state for test steps that don't invoke sl@0: asynchronous requests on this AO. sl@0: */ sl@0: { sl@0: iState = aNextState; sl@0: TRequestStatus* status = &iStatus; sl@0: SetActive(); sl@0: User::RequestComplete(status, KErrNone); sl@0: } sl@0: sl@0: void CDisplayChannelTest::DoCancel() sl@0: { sl@0: iAsyncHelper->Cancel(); sl@0: } sl@0: sl@0: TInt CDisplayChannelTest::RunError(TInt aError) sl@0: { sl@0: test_KErrNone(aError); sl@0: return KErrNone; sl@0: } sl@0: sl@0: void CDisplayChannelTest::RunL() sl@0: /** sl@0: Run all of the tests where the API is defined for that version. sl@0: */ sl@0: { sl@0: test_KErrNone(iStatus.Int()); sl@0: sl@0: test.Printf(_L("Test state %d\n"), iState); sl@0: switch (iState) sl@0: { sl@0: case ETestDisplayInfo: sl@0: CheckDisplayInfo(); sl@0: CompleteSelf(ETestCompositionBuffers); sl@0: break; sl@0: case ETestCompositionBuffers: sl@0: CheckCompositionBuffers(); sl@0: CompleteSelf(ETestUserBuffers); sl@0: break; sl@0: case ETestUserBuffers: sl@0: CheckUserBuffers(); sl@0: CompleteSelf(ETestRotations); sl@0: break; sl@0: case ETestRotations: sl@0: CheckRotations(); sl@0: CompleteSelf(ETestWaitForPostDoCancel); sl@0: break; sl@0: case ETestWaitForPostDoCancel: sl@0: // Post the composition buffer, register wait and cancel wait. sl@0: iDisp.PostCompositionBuffer(NULL, iDummyPostCount); sl@0: iDisp.WaitForPost(iDummyPostCount, iAsyncHelper->Status()); sl@0: iAsyncHelper->WaitForOperation(&iAsyncHelperResult); sl@0: iDisp.CancelWaitForPost(); sl@0: CompleteSelf(ETestWaitForPostCheckCancel); sl@0: break; sl@0: case ETestWaitForPostCheckCancel: sl@0: test(iAsyncHelperResult == KErrCancel || iAsyncHelperResult == KErrNone); sl@0: CompleteSelf(ETestGetCompositionBufferDoCancel); sl@0: break; sl@0: case ETestGetCompositionBufferDoCancel: sl@0: iDisp.GetCompositionBuffer(iDummyCompositionBuffer, iAsyncHelper->Status()); sl@0: iAsyncHelper->WaitForOperation(&iAsyncHelperResult); sl@0: iDisp.CancelGetCompositionBuffer(); sl@0: CompleteSelf(ETestGetCompositionBufferCheckCancel); sl@0: break; sl@0: case ETestGetCompositionBufferCheckCancel: sl@0: test(iAsyncHelperResult == KErrCancel || iAsyncHelperResult == KErrNone); sl@0: sl@0: if (iVersion.iMajor == 1 && iVersion.iMinor == 0) sl@0: { sl@0: CompleteSelf(ETestV11inV10); sl@0: } sl@0: else sl@0: { sl@0: CompleteSelf(ETestDisplayChange); sl@0: } sl@0: break; sl@0: case ETestDisplayChange: // API in v1.1 + sl@0: CheckDisplayChange(); sl@0: CompleteSelf(ETestDisplayChangeDoCancel); sl@0: break; sl@0: case ETestDisplayChangeDoCancel: // API in v1.1 + sl@0: iDisp.NotifyOnDisplayChangeCancel(); sl@0: CompleteSelf(ETestDisplayChangeCheckCancel); sl@0: break; sl@0: case ETestDisplayChangeCheckCancel: // API in v1.1 + sl@0: test(iAsyncHelperResult == KErrCancel); // display should not have changed sl@0: CompleteSelf(ETestResolutions); sl@0: break; sl@0: case ETestResolutions: // API in v1.1 + sl@0: CheckResolutions(); sl@0: CompleteSelf(ETestPixelFormats); sl@0: break; sl@0: case ETestPixelFormats: // API in v1.1 + sl@0: CheckPixelFormats(); sl@0: CompleteSelf(ETestBufferFormats); sl@0: break; sl@0: case ETestBufferFormats: // API in v1.1 + sl@0: CheckBufferFormat(); sl@0: CompleteSelf(EVisualTest); sl@0: break; sl@0: case ETestV11inV10: sl@0: CheckV11inV10(); sl@0: CompleteSelf(EVisualTest); sl@0: break; sl@0: case EVisualTest: sl@0: VisualTest(); // visual test is async because of WaitForPost sl@0: break; sl@0: case ETestSecondHandle: sl@0: CheckSecondHandle(); sl@0: CompleteSelf(ETestBufferTransitions); sl@0: break; sl@0: case ETestBufferTransitions: sl@0: TestBufferTransitions(); sl@0: CompleteSelf(ETestFinished); sl@0: break; sl@0: case ETestFinished: sl@0: CActiveScheduler::Stop(); sl@0: break; sl@0: default: sl@0: test(EFalse); sl@0: } sl@0: } sl@0: sl@0: void MainL() sl@0: /** sl@0: Initialise RTest and run the tests sl@0: */ sl@0: { sl@0: test.Start(_L("Testing display channel driver")); sl@0: sl@0: // If the device driver does not exist then this is considered a pass sl@0: // because the display channel is not a mandatory part of the base port sl@0: _LIT(KLdd, "display0.ldd"); sl@0: test.Printf(_L("Loading logical %S\n"), &KLdd); sl@0: TInt err = User::LoadLogicalDevice(KLdd); sl@0: test(err == KErrNone || err == KErrAlreadyExists || err == KErrNotFound); sl@0: sl@0: // Only test for kenel memory leaks for non WINSCW builds as the WINSCW LDD is obsolete and would sl@0: // take forever to debug sl@0: #ifndef __WINS__ sl@0: __KHEAP_MARK; sl@0: #endif // ! __WINS__ sl@0: sl@0: if (err == KErrNone || err == KErrAlreadyExists) sl@0: { sl@0: TInt numberOfScreens; sl@0: User::LeaveIfError(HAL::Get(HAL::EDisplayNumberOfScreens, numberOfScreens)); sl@0: for (TInt screenNum = 0; screenNum < numberOfScreens; ++screenNum) sl@0: { sl@0: CActiveScheduler* s = new(ELeave) CActiveScheduler(); sl@0: CActiveScheduler::Install(s); sl@0: CleanupStack::PushL(s); sl@0: CDisplayChannelTest* displayTest = CDisplayChannelTest::NewLC(screenNum); sl@0: displayTest->Start(); sl@0: s->Start(); sl@0: CleanupStack::PopAndDestroy(2, s); // s, displayTest sl@0: } sl@0: } sl@0: else sl@0: { sl@0: test.Printf(_L("display0.ldd not present. Finishing test.\n")); sl@0: } sl@0: sl@0: #ifndef __WINS__ sl@0: __KHEAP_MARKEND; sl@0: #endif // ! __WINS__ sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: TInt E32Main() sl@0: /** sl@0: Create cleanup stack, initialise memory checks and run the tests. sl@0: */ sl@0: { sl@0: CTrapCleanup* cleanup = CTrapCleanup::New(); sl@0: if (!cleanup) sl@0: { sl@0: return KErrNoMemory; sl@0: } sl@0: __UHEAP_MARK; sl@0: test.Title(); sl@0: TRAPD(err, MainL()); sl@0: test.Close(); sl@0: __UHEAP_MARKEND; sl@0: delete cleanup; sl@0: return err; sl@0: }