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