/* * The Syllable appserver * Example appserver video driver */ #include #include #include using namsespace os; using namespace std; /* Initialisation methods */ Fire::Fire( int nFd ) { m_hFrameBufferArea = -1; m_hRegisterArea = -1; /* Get some device information from the kernel driver */ PCI_Info_s sInfo; if( ioctl( nFd, PCI_GFX_GET_PCI_INFO, &sInfo ) != 0 ) { dbprintf( "Error: Failed to call PCI_GFX_GET_PCI_INFO\n" ); return; } /* sInfo now contains the PCI device information for this hardware */ /* * Get the device register address and size. The address is usually taken from one of the PCI base address registers, E.g: * * nRegisterBase = sInfo.u.h0.nBase1 & PCI_ADDRESS_MEMORY_32_MASK; * * but this is hardware dependent to some degree. Even if your card does use the PCI base registers, it may not use nBase0 * for the register address; check the documentation! * * The size of the device register area is generally fixed, but the size will be hardware dependent. */ uint32 nRegisterBase = /* Physical base address of the device registers */ size_t nRegisterSize = /* Size of the device registers */ /* Create an area the size of the device registers and remap it to the device registers */ uint8 * pnRegisterAddr; /* Logical base address of the device registers, which will be set by remap_area() */ m_hRegisterArea = create_area( "fire_device_registers", (void**)&pnRegisterAddr, nRegisterSize, AREA_FULL_ACCESS, AREA_NO_LOCK ); if( remap_area( m_hRegisterArea, (void*)&nRegisterBase ) != EOK ) { dbprintf( "Error: Failed to remap device registers.\n" ); return; } /* pnRegisterAddr now points to the device registers */ /* * With the device registers mapped you are now free to perform any hardware specific initialisation that require device * register accesses. */ /* * Get the video memory address and size. The address is usually taken from one of the PCI base address registers, E.g: * * nVideoMemoryBase = sInfo.u.h0.nBase0 & PCI_ADDRESS_MEMORY_32_MASK; * * but this is hardware dependent to some degree. Even if your card does use the PCI base registers, it may not use nBase0 * for the framebuffer address; check the documentation! * * Obtaining the size of the video memory is hardware dependent. */ uint32 nVideoMemoryBase = /* Physical base address of the video memory */ size_t nVideoMemorySize = /* Total available size of the video memory */ /* Create an area the size of the total available video memory and remap it to the hardware video memory */ uint8 * pnVideoMemoryAddr; /* Logical base address of the video memory, which will be set by remap_area() */ /* Note the use of AREA_WRCOMB, which enables MTRR Write Combining for the video memory */ m_hFrameBufferArea = create_area( "fire_video_memory", (void**)&pnVideoMemoryAddr, nVideoMemorySize, AREA_FULL_ACCESS | AREA_WRCOMB, AREA_NO_LOCK ); if( remap_area( m_hFrameBufferArea, (void*)&nVideoMemoryBase ) != EOK ) { dbprintf( "Error: Failed to remap video memory.\n" ); return; } /* pnVideoMemoryAddr now points to the video memory */ /* * If your driver does not use the VESA BIOS, you must create a list of available video modes. I would personally recomend * using and STL std::vector E.g: * * std::vectorm_cModes; * */ /* * If your driver supports off-screen bitmaps then you must intialise the memory allocator. */ uint32 nOffScreenOffset = /* * Calculate the maximum possible memory that can be used for the framebuffer. This is usually the * maximum resolution supported by the device, using: * * size = (max_x * max_y) * max_depth_bytes; * * E.g. if your hardware supports a maximum 1024x768 resolution in 32bit colour (4bytes per. pixel) it * would be: * * 3145728 = (1024 * 768) * 4; * * Once you know where the framebuffer ends, you can calculate the start and size of the off-screen * video memory. */ uint32 nOffScreenSize = nVideoMemorySize - nOffScreenOffset; uint32 nMemObjAlign = /* Hardware dependent, but 4095 (I.e. 4096 - 1) is used by a lot of hardware */ uint32 nRowObjAlign = /* Hardware dependent, but 63 (I.e. 64 - 1) is used by a lot of hardware */ /* Initialise the off-screen memory allocator */ InitMemory( nOffScreenOffset, nOffScreenSize, nMemObjAlign, nRowObjAlign ); /* Hardware initialisation is complete */ m_bInited = true; } Fire::~Fire( void ) { /* Delete any areas that this driver has created */ if( m_hFrameBufferArea != -1 ) delete_area( m_hFrameBufferArea ); /* Ensure that you have completed any device register accesse before deleting the device register area */ if( m_hRegisterArea != -1 ) delete_area( m_hRegisterArea ); } bool Fire::IsInitiated( void ) { return m_bInited; } /* Framebuffer & screen mode methods */ area_id Fire::Open( void ) { /* Additional hardware-specific code may be needed */ return m_hFrameBufferArea; } int Fire::GetScreenModeCount( void ) { return m_cModes.size(); } bool Fire::GetScreenModeDesc( int nIndex, os::screen_mode * psMode ) { if( nIndex < 0 || nIndex > (int)m_cModes.size() ) return false; *psMode = m_cModes[nIndex]; return true; } int Fire::SetScreenMode( os::screen_mode sMode ) { /* * sMode describes the desired screen mode. Setting the screen mode is hardware dependent. */ } /* Accelerated rendering methods */ void Fire::LockBitmap( SrvBitmap* pcDstBitmap, SrvBitmap* pcSrcBitmap, IRect cSrcRect, IRect cDstRect ) { if( ( pcDstBitmap->m_bVideoMem == false && ( pcSrcBitmap == NULL || pcSrcBitmap->m_bVideoMem == false ) ) || ( m_bEngineDirty == false ) return; /* * The hardware FIFO is marked as busy, wait for it to empty. How your driver does this is hardware dependent. */ m_bEngineDirty = false; return true; } bool Fire::DrawLine( SrvBitmap *pcBitmap, const IRect &cClipRect, const IPoint &cPnt1, const IPoint &cPnt2, const Color32_s &sColor, int nMode ) { if( pcBitMap->m_bVideoMem == false ) return( DisplayDriver::DrawLine( pcBitMap, cClipRect, cPnt1, cPnt2, sColor, nMode ) ); /* Program the hardware to draw a line on pcBitmap */ /* Most hardware places the commands in a FIFO. Flag the graphics engine as "dirty" to ensure LockBitmap() waits for the FIFO to empty. */ m_bEngineDirty = true; return true; } bool Fire::FillRect( SrvBitmap *pcBitmap, const IRect &cRect, const Color32_s &sColor, int nMode ) { if( pcBitMap->m_bVideoMem == false ) return( DisplayDriver::FillRect( pcBitMap, cRect, sColor, nMode ) ); /* Program the hardware to draw a filled rect on pcBitmap */ /* Most hardware places the commands in a FIFO. Flag the graphics engine as "dirty" to ensure LockBitmap() waits for the FIFO to empty. */ m_bEngineDirty = true; return true; } bool Fire::BltBitmap( SrvBitmap *pcDstBitmap, SrvBitmap *pcSrcBitmap, IRect cSrcRect, IRect cDstRect, int nMode, int nAlpha ) { if( pcSrcBitMap->m_bVideoMem == false || pcDstBitMap->m_bVideoMem == false ) return( DisplayDriver::BltBitmap( pcDstBitmap, pcSrcBitmap, cSrcRect, cDstRect, nMode, nAlpha ) ); /* Your driver might only support DM_COPY blits */ if( nMode != DM_COPY ) return( DisplayDriver::BltBitmap( pcDstBitmap, pcSrcBitmap, cSrcRect, cDstRect, nMode, nAlpha ) ); /* Program the hardware to blit pcSrcBitmap to pcDstBitmap */ /* Most hardware places the commands in a FIFO. Flag the graphics engine as "dirty" to ensure LockBitmap() waits for the FIFO to empty. */ m_bEngineDirty = true; return true; } /* Video overlay methods */ bool Fire::CreateVideoOverlay( const IPoint& cSize, const IRect& cDst, color_space eFormat, Color32_s sColorKey, area_id *pBuffer ) { /* * If your video driver uses off-screen memory, you can use AllocateMemory() to obtain memory for the video overlay. If not * you will have to create a new area using create_area() */ uint32 nOverlaySize = /* Usually ( cSize.x * cSize.y ) * pitch */ uint32 nOverlayOffset; /* Offset of the video overlay within the video memory, given to us by AllocateMemory() */ if( AllocateMemory( nOverlaySize, &nOverlayOffset ) != EOK ) { dbprintf( "Error: No memory for video overlay.\n" ); m_bVideoOverlayUsed = false; } /* We'll have to remember the offset returned by AllocateMemory() so that it can be freed by DeleteVideoOverlay() */ m_nOverlayOffset = nOverlayOffset; /* Create a new area for the video overlay data and remap it onto the video memory at the location given to us by AllocateMemory() */ *phArea = create_area( "fire_video_overlay", NULL, PAGE_ALIGN( nOverlaySize ), AREA_FULL_ACCESS, AREA_NO_LOCK ); remap_area( *phArea, (void*)( m_nFrameBufferAddr + nOverlayOffset ) ); /* * Hardware specific code will be required to create the video overlay. */ /* The video overlay has been initialised */ m_bVideoOverlayUsed = true; return true; } bool Fire::RecreateVideoOverlay( const IPoint& cSize, const IRect& cDst, color_space eFormat, area_id *pBuffer ) { if( m_bVideoOverlayUsed == false ) return false; /* Recreating the overlay is the same as deleting & then creating it with the new parameters */ if( DeleteVideoOverlay( pBuffer ) == true ) return CreateVideoOverlay( cSize, cDst, eFormat, pBuffer ): } void Fire::DeleteVideoOverlay( area_id *pBuffer ) { if( m_bVideoOverlayUsed == false ) return; /* * Hardware specific code will be required to destroy the video overlay. */ /* The video overlay is no longer in use */ m_bVideoOverlayUsed = false; delete_area( *pBuffer ); FreeMemory( m_nOverlayOffset ); } extern "C" DisplayDriver *init_gfx_driver( int nFd ) { dbprintf( "Initialising Fire driver\n" ); Fire *pcDriver = new Fire( nFd ); if( pcDriver->IsInited() == false ) { delete( pcDriver ); pcDriver = NULL; } return pcDriver; }