Writing Windows CE Display Drivers by Jeff Spurgat Listing One NewGPE::NewGPE() { // Flags for hardware features m_bIsVGADevice = TRUE; // default to VGA device m_bHWCursor = FALSE; // default to software cursor m_b555Mode = FALSE; // default to 5-6-5 mode for 16Bpp // NOTE: The following data members are modified to their final values // by the default implementation of SetMode and shouldn't need to // modified here or in ModeInit. // m_pPrimarySurface = NULL; // pointer to primary display surface m_nScreenWidth = 0; // display width m_nScreenHeight = 0; // display height m_pMode = NULL; // pointer to information on current mode m_p2DVideoMemory = NULL; // pointer to video memory manager m_pLAW = NULL; // pointer to linear access window memset(&m_ulBitMasks[0], 0, sizeof(m_ulBitMasks)); // bit masks // NOTE: The following data members MUST be modified to their final // values by the display hardware specific function ModeInit. // m_nLAWPhysical = 0; // the physical address of the linear access // window for accessing the frame buffer m_nLAWSize = 0; // size of linear access window m_nVideoMemorySize = 0; // size of video memory, which can be different // than the linear access window m_nVideoMemoryStart = 0;// offset within the linear access window to the // start of video memory (usually is 0) m_nScreenStride = 0; // number of bytes per display line } Listing Two int NewGPE::NumModes() { // count the number of entries in the mode table BOOL bDone = FALSE; int nIndex = 0; while (!bDone) { if (m_gpeModeTable[nIndex].Bpp==0) { // no more entries in the table bDone = TRUE; } else { // count entry and go to next entry nIndex++; } } return nIndex; } SCODE NewGPE::GetModeInfo(GPEMode *pMode, int modeNo ) { // make sure that the mode is valid (index is zero based) if ((modeNo<0) || (modeNo>=NumModes())) return E_INVALIDARG; // get data from mode table *pMode = m_gpeModeTable[modeNo]; return S_OK; } Listing Three 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 entry bDone = TRUE; } else if ((GetModeInfo(&gpeMode, nModeNum)==S_OK) && (gpeMode.modeId==modeId)) { // found matching mode entry bDone = TRUE; } else { // check next entry nModeNum++; } } // 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 further return 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 differently bCreateLAW = VirtualCopy(m_pLAW, (LPVOID) (m_nLAWPhysical|0x80000000), m_nLAWSize, PAGE_READWRITE|PAGE_NOCACHE); } else { bCreateLAW = VirtualCopy(m_pLAW, (LPVOID) (m_nLAWPhysical>>8), m_nLAWSize, PAGE_READWRITE|PAGE_NOCACHE|PAGE_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 options if (m_b555Mode) { // 5-5-5 mode m_ulBitMasks[0] = 0x7c00; // red m_ulBitMasks[1] = 0x03e0; // green m_ulBitMasks[2] = 0x001f; // blue } else { // 5-6-5 mode m_ulBitMasks[0] = 0xf800; // red m_ulBitMasks[1] = 0x07e0; // green m_ulBitMasks[2] = 0x001f; // blue } } // create a default palette, if necessary if (pPaletteHandle!=NULL) { // create palette switch (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 here break; case 4: *pPaletteHandle = EngCreatePalette(PAL_INDEXED,16, (ULONG *)m_rgbIdentityPal16,0,0,0); SetPalette(m_rgbIdentityPal16, 0, 16); // palette needs to be set break; default: RETAILMSG(1,(TEXT("NewGPE::SetMode Failed to create unknown palette type.\r\n"))); break; } } return S_OK; } Listing Four 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 parameters m_fInVideoMemory = TRUE; } } NewGPESurf::~NewGPESurf() { // free video memory if applicable if (m_fInVideoMemory && (m_pNode2D!=NULL)) { delete m_pNode2D; } } Listing Five 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 display if (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 memory Node2D *pNode = m_p2DVideoMemory->Alloc(width, height); if (pNode!=NULL) { // get offset into video memory DWORD 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 memory delete pNode; // free video memory } // if we got here then unable to allocate out of video memory if (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 allocated if ((*ppSurf)->Buffer()!=NULL) { // system memory surface allocated successfully return S_OK; } // system memory surface allocation failed delete *ppSurf; // just fall through to fail } // if we got here then something failed return E_OUTOFMEMORY; } Listing Six 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; } Listing Seven SCODE NewGPE::Line(GPELineParms *pLineParms,EGPEPhase phase /* = gpeSingle */) { // use the default line function pLineParms->pLine = EmulatedLine; return S_OK; } 6