|
Introduction to Writing Windows CE Display Drivers(8)
SCODE NewGPE::SetMode( int modeId, HPALETTE *pPaletteHandle ){ int nModeNum = 0; GPEMode gpeMode; // get mode entry that matches modeId BOOL bDone = FALSE; int nNumModes = NumModes(); while (!bDone) {if (nModeNum>=nNumModes) {// failed to find matching mode entrybDone = TRUE;} else if ((GetModeInfo(&gpeMode, nModeNum)==S_OK) &&(gpeMode.modeId==modeId)) {// found matching mode entrybDone = TRUE;}else {// check next entrynModeNum++;} } // check if mode number is valid if (nModeNum>=nNumModes) {return E_INVALIDARG; } // pass mode info to the hardware specific initialization // function SCODE scInit = ModeInit(&m_gpeModeTable[nModeNum]); if (scInit!=S_OK) {// something failed here, don't go any furtherreturn scInit; } // verify parameters ModeInit is required to initialize if ((m_nLAWPhysical==0) (m_nLAWSize==0) (m_nVideoMemorySize==0) (m_nScreenStride==0)) {// ERROR: ModeInit failed to properly initialize some data//members that are required. These data members need//to be initialized for this function to work.return E_FAIL; } // continue with hardware independent initialization // // Using the following values initialized by ModeInit: // * m_nLAWPhysical // * m_nLAWSize // * m_nVideoMemorySize // * m_nVideoMemoryStart // * m_nScreenStride // * m_bHWCursor (optional) // * m_b555Mode (optional) // // Initialize the remaining values: // * m_pMode // * m_nScreenWidth // * m_nScreenHeight // * m_pLAW // * m_p2DVideoMemory // * m_pPrimanrySurface // * m_ulBitMasks // // And don't forget to initialize the palette parameter // pPaletteHandle. // initialize remaining values // m_pMode = &m_gpeModeTable[nModeNum]; // current mode m_nScreenWidth = m_pMode->width; // current display width m_nScreenHeight = m_pMode->height; // current display height // generate pointer to linear access window // (can't address physical memory directly, but need to //create and map a pointer) m_pLAW = (unsigned char *) VirtualAlloc(NULL, m_nLAWSize, MEM_RESERVE, PAGE_NOACCESS); BOOL bCreateLAW; if (m_nLAWPhysical<0x20000000) { // handle <512MB address differentlybCreateLAW = VirtualCopy(m_pLAW, (LPVOID) (m_nLAWPhysical0x80000000), m_nLAWSize,PAGE_READWRITEPAGE_NOCACHE); } else {bCreateLAW = VirtualCopy(m_pLAW, (LPVOID) (m_nLAWPhysical>>8), m_nLAWSize,PAGE_READWRITEPAGE_NOCACHEPAGE_PHYSICAL); } // check for error creating LAW pointer if (!bCreateLAW) {return E_FAIL; } // create Node2D instance (for managing video memory) m_p2DVideoMemory= new Node2D(m_nScreenWidth, m_nVideoMemorySize/m_nScreenStride,0, 0, 32/m_pMode->Bpp); // check for error creating Node2D instance if (m_p2DVideoMemory==NULL) {return E_FAIL; } // create primary surface SCODE scAlloc = AllocSurface(&m_pPrimarySurface,m_nScreenWidth,m_nScreenHeight,m_pMode->format,GPE_REQUIRE_VIDEO_MEMORY); // check for error allocating primary surface if (scAlloc!=S_OK) {return E_FAIL; } // initialize bitmasks based on current bits per pixel memset(&m_ulBitMasks[0], 0, sizeof(m_ulBitMasks)); if (m_pMode->Bpp==16) {// 16Bpp has two mask optionsif (m_b555Mode) {// 5-5-5 modem_ulBitMasks[0] = 0x7c00; // redm_ulBitMasks[1] = 0x03e0; // greenm_ulBitMasks[2] = 0x001f; // blue}else {// 5-6-5 modem_ulBitMasks[0] = 0xf800; // redm_ulBitMasks[1] = 0x07e0; // greenm_ulBitMasks[2] = 0x001f; // blue} } // create a default palette, if necessary if (pPaletteHandle!=NULL) {// create paletteswitch (m_pMode->Bpp) {case 24:case 32:*pPaletteHandle = EngCreatePalette (PAL_BGR, 0, NULL, 0, 0, 0);break;case 16:*pPaletteHandle = EngCreatePalette(PAL_BITFIELDS, 0, NULL, m_ulBitMasks[0],m_ulBitMasks[1], m_ulBitMasks[2]);break;case 8:*pPaletteHandle = EngCreatePalette(PAL_INDEXED,256,(ULONG *)m_rgbIdentityPal,0,0,0);SetPalette(m_rgbIdentityPal, 0, 256); // palette needs to be set herebreak;case 4:*pPaletteHandle = EngCreatePalette(PAL_INDEXED,16,(ULONG *)m_rgbIdentityPal16,0,0,0);SetPalette(m_rgbIdentityPal16, 0, 16); // palette needs to be setbreak;default:RETAILMSG(1,(TEXT("NewGPE::SetMode Failed to create unknown palette type.\r\n")));break;} } return S_OK;}The base surface class, GPESurf, must be derived from in order to support the creation of video memory surfaces. Since default management of video memory is already defined within the NewGPE class through the Node2D object m_p2DVideoMemory, it makes sense to include support for the creation of video memory surfaces in our derived surface class, NewGPESurf. This is accomplished by providing a constructor that sets the video memory flag and maintains the Node2D instance for the video memory of this surface. The destructor is then responsible for deleting the saved Node2D instance, thus freeing the video memory occupied by this surface. This is all that needs to be done for the NewGPESurf class. NewGPESurf::NewGPESurf( int width, int height, void *pBits, int stride, EGPEFormat format, int offset, Node2D *pNode){ // call general GPESurf initialization Init(width, height, pBits, stride, format); m_pNode2D = pNode; if (pNode!=NULL) {// surface in video memory, set flags and parametersm_fInVideoMemory = TRUE; }}NewGPESurf::~NewGPESurf(){ // free video memory if applicable if (m_fInVideoMemory && (m_pNode2D!=NULL)) {delete m_pNode2D; }}The AllocSurface() function in the NewGPE class is responsible for handling the creation of system and video memory surfaces. It uses m_p2DVideoMemory, the Node2D object previously created in the SetMode() function, for allocating video memory. The surface itself is then created using our derived NewGPESurf class. As was previously noted, video memory surfaces can only be created in the same pixel format as the current display mode due to limitations in Node2D. System memory surfaces are created using the base GPESurf class. SCODE NewGPE::AllocSurface( GPESurf **ppSurf, int width, int height, EGPEFormat format, int surfaceFlags ){ SCODE scRet = S_OK; *ppSurf = NULL; // check parameters are valid: //video memory surface must have same pixel format as display if (surfaceFlags & GPE_REQUIRE_VIDEO_MEMORY) {// video memory surface must have same pixel format as displayif (format!=m_pMode->format)return E_INVALIDARG; } // check if video memory surface requested if ((surfaceFlags & GPE_REQUIRE_VIDEO_MEMORY) ((surfaceFlags & GPE_PREFER_VIDEO_MEMORY) &&(format==m_pMode->format))) {// try allocating out of video memoryNode2D *pNode = m_p2DVideoMemory->Alloc(width, height);if (pNode!=NULL) {// get offset into video memoryDWord dwOffset = (m_nScreenStride * pNode->Top()) + ((pNode->Left() * EGPEFormatToBpp[format]) / 8);// now create a surface for the allocated video memory*ppSurf = new NewGPESurf( width, height, m_pLAW + dwOffset, m_nScreenStride, format, dwOffset, pNode);if (*ppSurf!=NULL) { // video memory surface allocated successfully return S_OK;}// failed creating surface for video memorydelete pNode; // free video memory}// if we got here then unable to allocate out of video memoryif (surfaceFlags & GPE_REQUIRE_VIDEO_MEMORY)return E_OUTOFMEMORY; // fail since surface requires video memory } // Allocate surface from system memory if not in video memory *ppSurf = new GPESurf(width, height, format); if (*ppSurf!=NULL) {// make sure system memory allocatedif ((*ppSurf)->Buffer()!=NULL) {// system memory surface allocated successfullyreturn S_OK;}// system memory surface allocation faileddelete *ppSurf;// just fall through to fail } // if we got here then something failed return E_OUTOFMEMORY;}The most straightforward places to provide default implementations are the line drawing and blit functions. For BltPrepare(), all that needs to be done is to specify the default GPE blit function. For BltComplete(), nothing needs to be done. SCODE NewGPE::BltPrepare( GPEBltParms *pBltParms ){ // use the default blit function pBltParms->pBlt = EmulatedBlt; return S_OK;}SCODE NewGPE::BltComplete( GPEBltParms *pBltParms ){ // don't need to do anything here return S_OK;}As with BltPrepare(), the function Line() can simply specify the default GPE line drawing function. SCODE NewGPE::Line(GPELineParms *pLineParms,EGPEPhase phase /* = gpeSingle */ ){ // use the default line function pLineParms->pLine = EmulatedLine; return S_OK;}For display devices that handle cursors in hardware, the cursor functions SetPointerShape() and MovePointer() need to be changed or overridden to include this support. Since this functionality is not available in all display hardware or only in certain display modes, I have provided software cursor support in the base implementation of these functions. See the provided source file CURSOR.CPP for the details of software cursor support. It should be noted that software cursor management required changes in other sections of the driver as well. Searching the provided source files for the variable m_bHWCursor, the flag for selecting between software and hardware cursor, will highlight these additional changes.
|