--- /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 <dispchannel.h>
+#include <e32std.h>
+#include <e32std_private.h>
+#include <e32svr.h>
+#include <e32test.h>
+#include <pixelformats.h>
+#include <hal.h>
+
+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<RDisplayChannel::TResolution> iResolutions;
+ RArray<RDisplayChannel::TPixelFormat> 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<RDisplayChannel::TDisplayInfo> 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<br>
+ 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<TUint8*>(&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<TUint8*>(&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<RDisplayChannel::TPixelFormat> pixelFormatsArray(
+ reinterpret_cast<RDisplayChannel::TPixelFormat*>(&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<TUint8>(xShadeMax - xShade);
+ blue = static_cast<TUint8>(yShade);
+ }
+ else
+ {
+ // The size of the red band indicates different test steps
+ red = static_cast<TUint8>((yShadeMax * x) / aWidth);
+ }
+
+ if (aPixelFormat == EUidPixelFormatRGB_565)
+ {
+ *pixelAddr++ = static_cast<TUint8>(blue | (green << 5));
+ *pixelAddr++ = static_cast<TUint8>((green >> 3) | (red << 3));
+ }
+ else if (aPixelFormat == EUidPixelFormatARGB_4444 || aPixelFormat == EUidPixelFormatXRGB_4444)
+ {
+ *pixelAddr++ = static_cast<TUint8>(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<TUint8*>(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<RDisplayChannel::TDisplayInfo> 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<RDisplayChannel::TDisplayInfo> 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. <br>
+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<RDisplayChannel::TDisplayInfo> 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<RDisplayChannel::TDisplayRotation>(-1));
+ CheckSetRotation(infoPkg().iAvailableRotations, static_cast<RDisplayChannel::TDisplayRotation>(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;
+ }