/* (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) (c) Copyright 2000-2004 Convergence (integrated media) GmbH All rights reserved. Written by Denis Oliver Kropp , Andreas Hundt , Sven Neumann , Ville Syrjälä and Claudio Ciccani . This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_Graphics, "Core/Graphics", "DirectFB Graphics Core" ); D_DEBUG_DOMAIN( Core_GraphicsOps, "Core/GraphicsOps", "DirectFB Graphics Core Operations" ); D_DEBUG_DOMAIN( Core_GfxState, "Core/GfxState", "DirectFB Graphics Core State" ); DEFINE_MODULE_DIRECTORY( dfb_graphics_drivers, "gfxdrivers", DFB_GRAPHICS_DRIVER_ABI_VERSION ); /**********************************************************************************************************************/ static void dfb_gfxcard_find_driver( CoreDFB *core ); static void dfb_gfxcard_load_driver( void ); static void fill_tri( DFBTriangle *tri, CardState *state, bool accelerated ); /**********************************************************************************************************************/ typedef struct { int magic; /* amount of usable memory */ unsigned int videoram_length; unsigned int auxram_length; unsigned int auxram_offset; char *module_name; GraphicsDriverInfo driver_info; GraphicsDeviceInfo device_info; void *device_data; FusionProperty lock; GraphicsDeviceLockFlags lock_flags; /* * Points to the current state of the graphics card. */ CardState *state; FusionID holder; /* Fusion ID of state owner. */ } DFBGraphicsCoreShared; struct __DFB_DFBGraphicsCore { int magic; CoreDFB *core; DFBGraphicsCoreShared *shared; DirectModuleEntry *module; const GraphicsDriverFuncs *driver_funcs; void *driver_data; void *device_data; /* copy of shared->device_data */ CardCapabilities caps; /* local caps */ CardLimitations limits; /* local limits */ GraphicsDeviceFuncs funcs; }; DFB_CORE_PART( graphics_core, GraphicsCore ); /**********************************************************************************************************************/ static CoreGraphicsDevice *card; /* FIXME */ /* Hook for registering additional screen(s) and layer(s) in app or lib initializing DirectFB. */ void (*__DFB_CoreRegisterHook)( CoreDFB *core, CoreGraphicsDevice *device, void *ctx ) = NULL; void *__DFB_CoreRegisterHookCtx = NULL; /** public **/ static DFBResult dfb_graphics_core_initialize( CoreDFB *core, DFBGraphicsCore *data, DFBGraphicsCoreShared *shared ) { DFBResult ret; int videoram_length; int auxram_length; FusionSHMPoolShared *pool = dfb_core_shmpool( core ); D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_initialize( %p, %p, %p )\n", core, data, shared ); D_ASSERT( data != NULL ); D_ASSERT( shared != NULL ); card = data; /* FIXME */ data->core = core; data->shared = shared; /* fill generic driver info */ gGetDriverInfo( &shared->driver_info ); /* fill generic device info */ gGetDeviceInfo( &shared->device_info ); if (!shared->device_info.limits.dst_max.w) shared->device_info.limits.dst_max.w = INT_MAX; if (!shared->device_info.limits.dst_max.h) shared->device_info.limits.dst_max.h = INT_MAX; /* Limit video ram length */ videoram_length = dfb_system_videoram_length(); if (videoram_length) { if (dfb_config->videoram_limit > 0 && dfb_config->videoram_limit < videoram_length) shared->videoram_length = dfb_config->videoram_limit; else shared->videoram_length = videoram_length; } /* Limit auxiliary memory length (currently only AGP) */ auxram_length = dfb_system_auxram_length(); if (auxram_length) { if (dfb_config->agpmem_limit > 0 && dfb_config->agpmem_limit < auxram_length) shared->auxram_length = dfb_config->agpmem_limit; else shared->auxram_length = auxram_length; } /* Build a list of available drivers. */ direct_modules_explore_directory( &dfb_graphics_drivers ); /* Load driver */ if (dfb_system_caps() & CSCAPS_ACCELERATION) dfb_gfxcard_find_driver( core ); if (data->driver_funcs) { const GraphicsDriverFuncs *funcs = data->driver_funcs; data->driver_data = D_CALLOC( 1, shared->driver_info.driver_data_size ); card->device_data = shared->device_data = SHCALLOC( pool, 1, shared->driver_info.device_data_size ); ret = funcs->InitDriver( card, &card->funcs, card->driver_data, card->device_data, core ); if (ret) { SHFREE( pool, shared->device_data ); SHFREE( pool, shared->module_name ); D_FREE( card->driver_data ); card = NULL; return ret; } ret = funcs->InitDevice( data, &shared->device_info, data->driver_data, data->device_data ); if (ret) { funcs->CloseDriver( card, card->driver_data ); SHFREE( pool, shared->device_data ); SHFREE( pool, shared->module_name ); D_FREE( card->driver_data ); card = NULL; return ret; } if (data->funcs.EngineReset) data->funcs.EngineReset( data->driver_data, data->device_data ); } D_INFO( "DirectFB/Graphics: %s %s %d.%d (%s)\n", shared->device_info.vendor, shared->device_info.name, shared->driver_info.version.major, shared->driver_info.version.minor, shared->driver_info.vendor ); if (dfb_config->software_only) { if (data->funcs.CheckState) { data->funcs.CheckState = NULL; D_INFO( "DirectFB/Graphics: Acceleration disabled (by 'no-hardware')\n" ); } } else { data->caps = shared->device_info.caps; data->limits = shared->device_info.limits; } fusion_property_init( &shared->lock, dfb_core_world(core) ); if (__DFB_CoreRegisterHook) __DFB_CoreRegisterHook( core, card, __DFB_CoreRegisterHookCtx ); D_MAGIC_SET( data, DFBGraphicsCore ); D_MAGIC_SET( shared, DFBGraphicsCoreShared ); return DFB_OK; } static DFBResult dfb_graphics_core_join( CoreDFB *core, DFBGraphicsCore *data, DFBGraphicsCoreShared *shared ) { DFBResult ret; GraphicsDriverInfo driver_info; D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_join( %p, %p, %p )\n", core, data, shared ); D_ASSERT( data != NULL ); D_MAGIC_ASSERT( shared, DFBGraphicsCoreShared ); card = data; /* FIXME */ data->core = core; data->shared = shared; /* Initialize software rasterizer. */ gGetDriverInfo( &driver_info ); /* Build a list of available drivers. */ direct_modules_explore_directory( &dfb_graphics_drivers ); /* Load driver. */ if (dfb_system_caps() & CSCAPS_ACCELERATION) dfb_gfxcard_load_driver(); if (data->driver_funcs) { const GraphicsDriverFuncs *funcs = data->driver_funcs; data->driver_data = D_CALLOC( 1, shared->driver_info.driver_data_size ); data->device_data = shared->device_data; ret = funcs->InitDriver( card, &card->funcs, card->driver_data, card->device_data, core ); if (ret) { D_FREE( data->driver_data ); data = NULL; return ret; } } else if (shared->module_name) { D_ERROR( "DirectFB/Graphics: Could not load driver used by the running session!\n" ); data = NULL; return DFB_UNSUPPORTED; } D_INFO( "DirectFB/Graphics: %s %s %d.%d (%s)\n", shared->device_info.vendor, shared->device_info.name, shared->driver_info.version.major, shared->driver_info.version.minor, shared->driver_info.vendor ); if (dfb_config->software_only) { if (data->funcs.CheckState) { data->funcs.CheckState = NULL; D_INFO( "DirectFB/Graphics: Acceleration disabled (by 'no-hardware')\n" ); } } else { data->caps = shared->device_info.caps; data->limits = shared->device_info.limits; } D_MAGIC_SET( data, DFBGraphicsCore ); return DFB_OK; } static DFBResult dfb_graphics_core_shutdown( DFBGraphicsCore *data, bool emergency ) { DFBGraphicsCoreShared *shared; FusionSHMPoolShared *pool = dfb_core_shmpool( data->core ); D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_shutdown( %p, %semergency )\n", data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBGraphicsCore ); D_MAGIC_ASSERT( data->shared, DFBGraphicsCoreShared ); shared = data->shared; dfb_gfxcard_lock( GDLF_SYNC ); if (data->driver_funcs) { const GraphicsDriverFuncs *funcs = data->driver_funcs; funcs->CloseDevice( data, data->driver_data, data->device_data ); funcs->CloseDriver( data, data->driver_data ); direct_module_unref( data->module ); SHFREE( pool, card->device_data ); D_FREE( card->driver_data ); } fusion_property_destroy( &shared->lock ); if (shared->module_name) SHFREE( pool, shared->module_name ); D_MAGIC_CLEAR( data ); D_MAGIC_CLEAR( shared ); return DFB_OK; } static DFBResult dfb_graphics_core_leave( DFBGraphicsCore *data, bool emergency ) { DFBGraphicsCoreShared *shared; D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_leave( %p, %semergency )\n", data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBGraphicsCore ); D_MAGIC_ASSERT( data->shared, DFBGraphicsCoreShared ); shared = data->shared; if (data->driver_funcs) { data->driver_funcs->CloseDriver( data, data->driver_data ); direct_module_unref( data->module ); D_FREE( data->driver_data ); } D_MAGIC_CLEAR( data ); return DFB_OK; } static DFBResult dfb_graphics_core_suspend( DFBGraphicsCore *data ) { DFBGraphicsCoreShared *shared; D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_suspend( %p )\n", data ); D_MAGIC_ASSERT( data, DFBGraphicsCore ); D_MAGIC_ASSERT( data->shared, DFBGraphicsCoreShared ); shared = data->shared; dfb_gfxcard_lock( GDLF_WAIT | GDLF_SYNC | GDLF_RESET | GDLF_INVALIDATE ); return DFB_OK; } static DFBResult dfb_graphics_core_resume( DFBGraphicsCore *data ) { DFBGraphicsCoreShared *shared; D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_resume( %p )\n", data ); D_MAGIC_ASSERT( data, DFBGraphicsCore ); D_MAGIC_ASSERT( data->shared, DFBGraphicsCoreShared ); shared = data->shared; dfb_gfxcard_unlock(); return DFB_OK; } /**********************************************************************************************************************/ DFBResult dfb_gfxcard_lock( GraphicsDeviceLockFlags flags ) { DFBResult ret; DFBGraphicsCoreShared *shared; GraphicsDeviceFuncs *funcs; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); shared = card->shared; funcs = &card->funcs; if ( ((flags & GDLF_WAIT) ? fusion_property_purchase( &shared->lock ) : fusion_property_lease( &shared->lock )) ) return DFB_FAILURE; if ((flags & GDLF_SYNC) && funcs->EngineSync) { ret = funcs->EngineSync( card->driver_data, card->device_data ); if (ret) { if (funcs->EngineReset) funcs->EngineReset( card->driver_data, card->device_data ); shared->state = NULL; fusion_property_cede( &shared->lock ); return ret; } } if ((shared->lock_flags & GDLF_RESET) && funcs->EngineReset) funcs->EngineReset( card->driver_data, card->device_data ); if (shared->lock_flags & GDLF_INVALIDATE) { if (funcs->InvalidateState) funcs->InvalidateState( card->driver_data, card->device_data ); shared->state = NULL; } shared->lock_flags = flags; return DFB_OK; } void dfb_gfxcard_unlock( void ) { D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); fusion_property_cede( &card->shared->lock ); } void dfb_gfxcard_holdup( void ) { D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); fusion_property_holdup( &card->shared->lock ); } /* * Signal beginning of a sequence of operations using this state. * Any number of states can be 'drawing'. */ void dfb_gfxcard_start_drawing( CoreGraphicsDevice *device, CardState *state ) { D_ASSERT( device != NULL ); D_MAGIC_ASSERT( state, CardState ); if (device->funcs.StartDrawing) device->funcs.StartDrawing( device->driver_data, device->device_data, state ); } /* * Signal end of sequence, i.e. destination surface is consistent again. */ void dfb_gfxcard_stop_drawing( CoreGraphicsDevice *device, CardState *state ) { D_ASSERT( device != NULL ); D_MAGIC_ASSERT( state, CardState ); if (device->funcs.StopDrawing) device->funcs.StopDrawing( device->driver_data, device->device_data, state ); } /* * This function returns non zero if acceleration is available * for the specific function using the given state. */ bool dfb_gfxcard_state_check( CardState *state, DFBAccelerationMask accel ) { CoreSurface *dst; CoreSurface *src; CoreSurfaceBuffer *dst_buffer; CoreSurfaceBuffer *src_buffer; int cx2, cy2; D_ASSERT( card != NULL ); D_MAGIC_ASSERT( state, CardState ); D_MAGIC_ASSERT_IF( state->destination, CoreSurface ); D_MAGIC_ASSERT_IF( state->source, CoreSurface ); D_DEBUG_AT( Core_GraphicsOps, "%s( %p, 0x%08x ) [%d,%d - %d,%d]\n", __FUNCTION__, state, accel, DFB_REGION_VALS( &state->clip ) ); D_ASSERT( state->clip.x2 >= state->clip.x1 ); D_ASSERT( state->clip.y2 >= state->clip.y1 ); D_ASSERT( state->clip.x1 >= 0 ); D_ASSERT( state->clip.y1 >= 0 ); if (DFB_BLITTING_FUNCTION(accel)) { D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x ) blitting %p -> %p\n", __FUNCTION__, state, accel, state->source, state->destination ); } else { D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x ) drawing -> %p\n", __FUNCTION__, state, accel, state->destination ); } if (state->clip.x1 < 0) { state->clip.x1 = 0; state->modified |= SMF_CLIP; } if (state->clip.y1 < 0) { state->clip.y1 = 0; state->modified |= SMF_CLIP; } D_DEBUG_AT( Core_GfxState, " <- checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n", state->checked, state->accel, state->modified, state->mod_hw ); dst = state->destination; src = state->source; /* Destination may have been destroyed. */ if (!dst) { D_BUG( "no destination" ); return false; } /* Source may have been destroyed. */ if (DFB_BLITTING_FUNCTION( accel )) { if (!src) { D_BUG( "no source" ); return false; } /* Mask may have been destroyed. */ if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR) && !state->source_mask) { D_BUG( "no mask" ); return false; } } dst_buffer = dfb_surface_get_buffer( dst, state->to ); D_MAGIC_ASSERT( dst_buffer, CoreSurfaceBuffer ); D_ASSUME( state->clip.x2 < dst->config.size.w ); D_ASSUME( state->clip.y2 < dst->config.size.h ); cx2 = state->destination->config.size.w - 1; cy2 = state->destination->config.size.h - 1; if (state->clip.x2 > cx2) { state->clip.x2 = cx2; if (state->clip.x1 > cx2) state->clip.x1 = cx2; state->modified |= SMF_CLIP; } if (state->clip.y2 > cy2) { state->clip.y2 = cy2; if (state->clip.y1 > cy2) state->clip.y1 = cy2; state->modified |= SMF_CLIP; } /* * If there's no CheckState function there's no acceleration at all. */ if (!card->funcs.CheckState) return false; /* * Check if this function has been disabled temporarily. */ if (state->disabled & accel) return false; /* If destination or blend functions have been changed... */ if (state->modified & (SMF_DESTINATION | SMF_SRC_BLEND | SMF_DST_BLEND | SMF_RENDER_OPTIONS)) { /* ...force rechecking for all functions. */ state->checked = DFXL_NONE; } else { /* If source/mask or blitting flags have been changed... */ if (state->modified & (SMF_SOURCE | SMF_BLITTING_FLAGS | SMF_SOURCE_MASK | SMF_SOURCE_MASK_VALS)) { /* ...force rechecking for all blitting functions. */ state->checked &= ~DFXL_ALL_BLIT; } /* If drawing flags have been changed... */ if (state->modified & SMF_DRAWING_FLAGS) { /* ...force rechecking for all drawing functions. */ state->checked &= ~DFXL_ALL_DRAW; } } D_DEBUG_AT( Core_GfxState, " -> checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n", state->checked, state->accel, state->modified, state->mod_hw ); /* If the function needs to be checked... */ if (!(state->checked & accel)) { /* Unset unchecked functions. */ state->accel &= state->checked; /* Call driver to (re)set the bit if the function is supported. */ card->funcs.CheckState( card->driver_data, card->device_data, state, accel ); /* Add the function to 'checked functions'. */ state->checked |= accel; /* Add additional functions the driver might have checked, too. */ state->checked |= state->accel; } D_DEBUG_AT( Core_GfxState, " -> checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n", state->checked, state->accel, state->modified, state->mod_hw ); /* Move modification flags to the set for drivers. */ state->mod_hw |= state->modified; state->modified = 0; /* * If back_buffer policy is 'system only' there's no acceleration * available. */ if (dst_buffer->policy == CSP_SYSTEMONLY || /* Special check required if driver does not check itself. */ ( !(card->caps.flags & CCF_RENDEROPTS) && (state->render_options & DSRO_MATRIX) )) { /* Clear 'accelerated functions'. */ state->accel = DFXL_NONE; state->checked = DFXL_ALL; } else if (DFB_BLITTING_FUNCTION( accel )) { /* * If the front buffer policy of the source is 'system only' * no accelerated blitting is available. */ src_buffer = dfb_surface_get_buffer( src, state->from ); D_MAGIC_ASSERT( src_buffer, CoreSurfaceBuffer ); if (src_buffer->policy == CSP_SYSTEMONLY && !(card->caps.flags & CCF_READSYSMEM)) { /* Clear 'accelerated blitting functions'. */ state->accel &= ~DFXL_ALL_BLIT; state->checked |= DFXL_ALL_BLIT; } } D_DEBUG_AT( Core_GfxState, " => checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n", state->checked, state->accel, state->modified, state->mod_hw ); /* Return whether the function bit is set. */ return !!(state->accel & accel); } /* * This function returns non zero after successful locking the surface(s) * for access by hardware. Propagate state changes to driver. */ static bool dfb_gfxcard_state_acquire( CardState *state, DFBAccelerationMask accel ) { DFBResult ret; CoreSurface *dst; CoreSurface *src; DFBGraphicsCoreShared *shared; CoreSurfaceAccessFlags access = CSAF_WRITE; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_MAGIC_ASSERT_IF( state->destination, CoreSurface ); D_MAGIC_ASSERT_IF( state->source, CoreSurface ); dst = state->destination; src = state->source; shared = card->shared; /* find locking flags */ if (DFB_BLITTING_FUNCTION( accel )) { if (state->blittingflags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA | DSBLIT_DST_COLORKEY)) access |= CSAF_READ; } else if (state->drawingflags & (DSDRAW_BLEND | DSDRAW_DST_COLORKEY)) access |= CSAF_READ; if (DFB_BLITTING_FUNCTION(accel)) { D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x ) blitting %p -> %p\n", __FUNCTION__, state, accel, state->source, state->destination ); } else { D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x ) drawing -> %p\n", __FUNCTION__, state, accel, state->destination ); } /* lock destination */ ret = dfb_surface_lock_buffer( dst, state->to, CSAID_GPU, access, &state->dst ); if (ret) { D_DEBUG_AT( Core_Graphics, "Could not lock destination for GPU access!\n" ); return false; } /* if blitting... */ if (DFB_BLITTING_FUNCTION( accel )) { /* ...lock source for reading */ ret = dfb_surface_lock_buffer( src, state->from, CSAID_GPU, CSAF_READ, &state->src ); if (ret) { D_DEBUG_AT( Core_Graphics, "Could not lock source for GPU access!\n" ); dfb_surface_unlock_buffer( dst, &state->dst ); return false; } state->flags |= CSF_SOURCE_LOCKED; /* if using a mask... */ if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { /* ...lock source mask for reading */ ret = dfb_surface_lock_buffer( state->source_mask, state->from, CSAID_GPU, CSAF_READ, &state->src_mask ); if (ret) { D_DEBUG_AT( Core_Graphics, "Could not lock source mask for GPU access!\n" ); dfb_surface_unlock_buffer( src, &state->src ); dfb_surface_unlock_buffer( dst, &state->dst ); return false; } state->flags |= CSF_SOURCE_MASK_LOCKED; } } /* * Make sure that state setting with subsequent command execution * isn't done by two processes simultaneously. * * This will timeout if the hardware is locked by another party with * the first argument being true (e.g. DRI). */ if (dfb_gfxcard_lock( GDLF_NONE )) { D_DERROR( ret, "Core/Graphics: Could not lock GPU!\n" ); dfb_surface_unlock_buffer( dst, &state->dst ); if (state->flags & CSF_SOURCE_LOCKED) { dfb_surface_unlock_buffer( src, &state->src ); state->flags &= ~CSF_SOURCE_LOCKED; } /* if source mask got locked this value is true */ if (state->flags & CSF_SOURCE_MASK_LOCKED) { dfb_surface_unlock_buffer( state->source_mask, &state->src_mask ); state->flags &= ~CSF_SOURCE_MASK_LOCKED; } return false; } /* if we are switching to another state... */ if (state != shared->state || state->fusion_id != shared->holder) { D_DEBUG_AT( Core_GfxState, " -> switch from %p [%lu] to %p [%lu]\n", shared->state, shared->holder, state, state->fusion_id ); /* ...set all modification bits and clear 'set functions' */ state->mod_hw |= SMF_ALL; state->set = 0; shared->state = state; shared->holder = state->fusion_id; } dfb_state_update( state, state->flags & (CSF_SOURCE_LOCKED | CSF_SOURCE_MASK_LOCKED) ); D_DEBUG_AT( Core_GfxState, " -> mod_hw 0x%08x, modified 0x%08x\n", state->mod_hw, state->modified ); /* Move modification flags to the set for drivers. */ state->mod_hw |= state->modified; state->modified = SMF_ALL; /* * If function hasn't been set or state is modified, * call the driver function to propagate the state changes. */ D_DEBUG_AT( Core_GfxState, " -> mod_hw 0x%08x, set 0x%08x\n", state->mod_hw, state->set ); if (state->mod_hw || !(state->set & accel)) { card->funcs.SetState( card->driver_data, card->device_data, &card->funcs, state, accel ); D_DEBUG_AT( Core_GfxState, " => mod_hw 0x%08x, set 0x%08x\n", state->mod_hw, state->set ); } if (state->modified != SMF_ALL) D_ONCE( "USING OLD DRIVER! *** Use 'state->mod_hw' NOT 'modified'." ); state->modified = 0; return true; } /* * Unlock destination and possibly the source. */ static void dfb_gfxcard_state_release( CardState *state ) { D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( state->destination != NULL ); /* start command processing if not already running */ if (card->funcs.EmitCommands) card->funcs.EmitCommands( card->driver_data, card->device_data ); /* Store the serial of the operation. */ #if FIXME_SC_2 if (card->funcs.GetSerial) { card->funcs.GetSerial( card->driver_data, card->device_data, &state->serial ); state->destination->back_buffer->video.serial = state->serial; } #endif /* allow others to use the hardware */ dfb_gfxcard_unlock(); /* destination always gets locked during acquisition */ dfb_surface_unlock_buffer( state->destination, &state->dst ); /* if source got locked this value is true */ if (state->flags & CSF_SOURCE_LOCKED) { dfb_surface_unlock_buffer( state->source, &state->src ); state->flags &= ~CSF_SOURCE_LOCKED; } /* if source mask got locked this value is true */ if (state->flags & CSF_SOURCE_MASK_LOCKED) { dfb_surface_unlock_buffer( state->source_mask, &state->src_mask ); state->flags &= ~CSF_SOURCE_MASK_LOCKED; } } /** DRAWING FUNCTIONS **/ #define DFB_TRANSFORM(x, y, m, affine) \ do { \ s32 _x, _y, _w; \ if (affine) { \ _x = ((x) * (m)[0] + (y) * (m)[1] + (m)[2] + 0x8000) >> 16; \ _y = ((x) * (m)[3] + (y) * (m)[4] + (m)[5] + 0x8000) >> 16; \ } \ else { \ _x = ((x) * (m)[0] + (y) * (m)[1] + (m)[2]); \ _y = ((x) * (m)[3] + (y) * (m)[4] + (m)[5]); \ _w = ((x) * (m)[6] + (y) * (m)[7] + (m)[8]); \ if (!_w) { \ _x = (_x < 0) ? -0x7fffffff : 0x7fffffff; \ _y = (_y < 0) ? -0x7fffffff : 0x7fffffff; \ } \ else { \ _x /= _w; \ _y /= _w; \ } \ } \ (x) = _x; \ (y) = _y; \ } while (0) void dfb_gfxcard_fillrectangles( const DFBRectangle *rects, int num, CardState *state ) { D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %p )\n", __FUNCTION__, rects, num, state ); D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( rects != NULL ); D_ASSERT( num > 0 ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state, card ); if (!(state->render_options & DSRO_MATRIX)) { while (num > 0) { if (dfb_rectangle_region_intersects( rects, &state->clip )) break; rects++; num--; } } if (num > 0) { int i = 0; DFBRectangle rect; /* Check for acceleration and setup execution. */ if (dfb_gfxcard_state_check( state, DFXL_FILLRECTANGLE ) && dfb_gfxcard_state_acquire( state, DFXL_FILLRECTANGLE )) { /* * Now everything is prepared for execution of the * FillRectangle driver function. */ for (; irender_options & DSRO_MATRIX) && !dfb_rectangle_region_intersects( &rects[i], &state->clip )) continue; rect = rects[i]; if (rect.w > card->limits.dst_max.w || rect.h > card->limits.dst_max.h) { dfb_clip_rectangle( &state->clip, &rect ); if (rect.w > card->limits.dst_max.w || rect.h > card->limits.dst_max.h) break; } else if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLRECTANGLE )) dfb_clip_rectangle( &state->clip, &rect ); if (!card->funcs.FillRectangle( card->driver_data, card->device_data, &rect )) break; } /* Release after state acquisition. */ dfb_gfxcard_state_release( state ); } if (i < num) { /* Use software fallback. */ if (gAcquire( state, DFXL_FILLRECTANGLE )) { if (!(state->render_options & DSRO_MATRIX)) { for (; iclip, &rect )) gFillRectangle( state, &rect ); } } else if (state->matrix[1] == 0 && state->matrix[3] == 0) { /* Scaled/Translated Rectangle. */ for (; imatrix, state->affine_matrix); DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix); if (x1 < x2) { rect.x = x1; rect.w = x2-x1; } else { rect.x = x2; rect.w = x1-x2; } if (y1 < y2) { rect.y = y1; rect.h = y2-y1; } else { rect.y = y2; rect.h = y1-y2; } if (dfb_clip_rectangle( &state->clip, &rect )) gFillRectangle( state, &rect ); } } else { /* Rotated rectangle. Split into triangles. */ for (; imatrix, state->affine_matrix); DFB_TRANSFORM(tri.x2, tri.y2, state->matrix, state->affine_matrix); DFB_TRANSFORM(tri.x3, tri.y3, state->matrix, state->affine_matrix); dfb_sort_triangle( &tri ); if (tri.y3 - tri.y1 > 0) fill_tri( &tri, state, false ); tri.x1 = rects[i].x; tri.y1 = rects[i].y; tri.x2 = rects[i].x+rects[i].w; tri.y2 = rects[i].y+rects[i].h; tri.x3 = rects[i].x; tri.y3 = rects[i].y+rects[i].h; DFB_TRANSFORM(tri.x1, tri.y1, state->matrix, state->affine_matrix); DFB_TRANSFORM(tri.x2, tri.y2, state->matrix, state->affine_matrix); DFB_TRANSFORM(tri.x3, tri.y3, state->matrix, state->affine_matrix); dfb_sort_triangle( &tri ); if (tri.y3 - tri.y1 > 0) fill_tri( &tri, state, false ); } } gRelease( state ); } } } /* Unlock after execution. */ dfb_state_unlock( state ); } static void build_clipped_rectangle_outlines( DFBRectangle *rect, const DFBRegion *clip, DFBRectangle *ret_outlines, int *ret_num ) { DFBEdgeFlags edges = dfb_clip_edges( clip, rect ); int t = (edges & DFEF_TOP ? 1 : 0); int tb = t + (edges & DFEF_BOTTOM ? 1 : 0); int num = 0; DFB_RECTANGLE_ASSERT( rect ); D_ASSERT( ret_outlines != NULL ); D_ASSERT( ret_num != NULL ); if (edges & DFEF_TOP) { DFBRectangle *out = &ret_outlines[num++]; out->x = rect->x; out->y = rect->y; out->w = rect->w; out->h = 1; } if (rect->h > t) { if (edges & DFEF_BOTTOM) { DFBRectangle *out = &ret_outlines[num++]; out->x = rect->x; out->y = rect->y + rect->h - 1; out->w = rect->w; out->h = 1; } if (rect->h > tb) { if (edges & DFEF_LEFT) { DFBRectangle *out = &ret_outlines[num++]; out->x = rect->x; out->y = rect->y + t; out->w = 1; out->h = rect->h - tb; } if (rect->w > 1 || !(edges & DFEF_LEFT)) { if (edges & DFEF_RIGHT) { DFBRectangle *out = &ret_outlines[num++]; out->x = rect->x + rect->w - 1; out->y = rect->y + t; out->w = 1; out->h = rect->h - tb; } } } } *ret_num = num; } void dfb_gfxcard_drawrectangle( DFBRectangle *rect, CardState *state ) { DFBRectangle rects[4]; bool hw = false; int i = 0, num = 0; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); DFB_RECTANGLE_ASSERT( rect ); D_DEBUG_AT( Core_GraphicsOps, "%s( %d,%d - %dx%d, %p )\n", __FUNCTION__, DFB_RECTANGLE_VALS(rect), state ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state, card ); if (!dfb_rectangle_region_intersects( rect, &state->clip )) { dfb_state_unlock( state ); return; } if (D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) || D_FLAGS_IS_SET( card->caps.clip, DFXL_DRAWRECTANGLE ) || !dfb_clip_needed( &state->clip, rect )) { if (rect->w <= card->limits.dst_max.w && rect->h <= card->limits.dst_max.h && dfb_gfxcard_state_check( state, DFXL_DRAWRECTANGLE ) && dfb_gfxcard_state_acquire( state, DFXL_DRAWRECTANGLE )) { hw = card->funcs.DrawRectangle( card->driver_data, card->device_data, rect ); dfb_gfxcard_state_release( state ); } } if (!hw && !(state->render_options & DSRO_MATRIX)) { build_clipped_rectangle_outlines( rect, &state->clip, rects, &num ); if (!num) { dfb_state_unlock( state ); return; } if (dfb_gfxcard_state_check( state, DFXL_FILLRECTANGLE ) && dfb_gfxcard_state_acquire( state, DFXL_FILLRECTANGLE )) { for (; ilimits.dst_max.w && rects[i].h <= card->limits.dst_max.h && card->funcs.FillRectangle( card->driver_data, card->device_data, &rects[i] ); if (!hw) break; } dfb_gfxcard_state_release( state ); } } if (!hw) { if (!(state->render_options & DSRO_MATRIX)) { if (gAcquire( state, DFXL_FILLRECTANGLE )) { for (; ix; y1 = rect->y; x2 = rect->x+rect->w; y2 = rect->y; x3 = rect->x+rect->w; y3 = rect->y+rect->h; x4 = rect->x; y4 = rect->y+rect->h; DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix); DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix); DFB_TRANSFORM(x3, y3, state->matrix, state->affine_matrix); DFB_TRANSFORM(x4, y4, state->matrix, state->affine_matrix); line = (DFBRegion) { x1, y1, x2, y2 }; if (dfb_clip_line( &state->clip, &line )) gDrawLine( state, &line ); line = (DFBRegion) { x2, y2, x3, y3 }; if (dfb_clip_line( &state->clip, &line )) gDrawLine( state, &line ); line = (DFBRegion) { x3, y3, x4, y4 }; if (dfb_clip_line( &state->clip, &line )) gDrawLine( state, &line ); line = (DFBRegion) { x4, y4, x1, y1 }; if (dfb_clip_line( &state->clip, &line )) gDrawLine( state, &line ); gRelease( state ); } } } dfb_state_unlock( state ); } void dfb_gfxcard_drawlines( DFBRegion *lines, int num_lines, CardState *state ) { int i = 0; D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %p )\n", __FUNCTION__, lines, num_lines, state ); D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( lines != NULL ); D_ASSERT( num_lines > 0 ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state, card ); if (dfb_gfxcard_state_check( state, DFXL_DRAWLINE ) && dfb_gfxcard_state_acquire( state, DFXL_DRAWLINE )) { for (; icaps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_DRAWLINE ) && !dfb_clip_line( &state->clip, &lines[i] )) continue; if (!card->funcs.DrawLine( card->driver_data, card->device_data, &lines[i] )) break; } dfb_gfxcard_state_release( state ); } if (i < num_lines) { if (gAcquire( state, DFXL_DRAWLINE )) { for (; irender_options & DSRO_MATRIX) { DFB_TRANSFORM(lines[i].x1, lines[i].y1, state->matrix, state->affine_matrix); DFB_TRANSFORM(lines[i].x2, lines[i].y2, state->matrix, state->affine_matrix); } if (dfb_clip_line( &state->clip, &lines[i] )) gDrawLine( state, &lines[i] ); } gRelease( state ); } } dfb_state_unlock( state ); } void dfb_gfxcard_fillspans( int y, DFBSpan *spans, int num_spans, CardState *state ) { int i = 0; D_DEBUG_AT( Core_GraphicsOps, "%s( %d, %p [%d], %p )\n", __FUNCTION__, y, spans, num_spans, state ); D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( spans != NULL ); D_ASSERT( num_spans > 0 ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state, card ); if (dfb_gfxcard_state_check( state, DFXL_FILLRECTANGLE ) && dfb_gfxcard_state_acquire( state, DFXL_FILLRECTANGLE )) { for (; i card->limits.dst_max.w || rect.h > card->limits.dst_max.h) { if (!dfb_clip_rectangle( &state->clip, &rect )) continue; if (rect.w > card->limits.dst_max.w || rect.h > card->limits.dst_max.h) break; } else if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLRECTANGLE ) && !dfb_clip_rectangle( &state->clip, &rect )) continue; if (!card->funcs.FillRectangle( card->driver_data, card->device_data, &rect )) break; } dfb_gfxcard_state_release( state ); } if (i < num_spans) { if (gAcquire( state, DFXL_FILLRECTANGLE )) { for (; irender_options & DSRO_MATRIX) { if (state->matrix[1] == 0 && state->matrix[3] == 0) { int x1, y1, x2, y2; x1 = rect.x; y1 = rect.y; x2 = x1+rect.w; y2 = y1+rect.h; DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix); DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix); if (x1 < x2) { rect.x = x1; rect.w = x2-x1; } else { rect.x = x2; rect.w = x1-x2; } if (y1 < y2) { rect.y = y1; rect.h = y2-y1; } else { rect.y = y2; rect.h = y1-y2; } if (dfb_clip_rectangle( &state->clip, &rect )) gFillRectangle( state, &rect ); } else { DFBTriangle tri; tri.x1 = rect.x; tri.y1 = rect.y; tri.x2 = rect.x+rect.w; tri.y2 = rect.y; tri.x3 = rect.x+rect.w; tri.y3 = rect.y+rect.h; DFB_TRANSFORM(tri.x1, tri.y1, state->matrix, state->affine_matrix); DFB_TRANSFORM(tri.x2, tri.y2, state->matrix, state->affine_matrix); DFB_TRANSFORM(tri.x3, tri.y3, state->matrix, state->affine_matrix); dfb_sort_triangle( &tri ); if (tri.y3 - tri.y1 > 0) fill_tri( &tri, state, false ); tri.x1 = rect.x; tri.y1 = rect.y; tri.x2 = rect.x+rect.w; tri.y2 = rect.y+rect.h; tri.x3 = rect.x; tri.y3 = rect.y+rect.h; DFB_TRANSFORM(tri.x1, tri.y1, state->matrix, state->affine_matrix); DFB_TRANSFORM(tri.x2, tri.y2, state->matrix, state->affine_matrix); DFB_TRANSFORM(tri.x3, tri.y3, state->matrix, state->affine_matrix); dfb_sort_triangle( &tri ); if (tri.y3 - tri.y1 > 0) fill_tri( &tri, state, false ); } } else { if (dfb_clip_rectangle( &state->clip, &rect )) gFillRectangle( state, &rect ); } } gRelease( state ); } } dfb_state_unlock( state ); } typedef struct { int xi; int xf; int mi; int mf; int _2dy; } DDA; #define SETUP_DDA(xs,ys,xe,ye,dda) \ do { \ int dx = xe - xs; \ int dy = ye - ys; \ dda.xi = xs; \ if (dy != 0) { \ dda.mi = dx / dy; \ dda.mf = 2*(dx % dy); \ dda.xf = -dy; \ dda._2dy = 2 * dy; \ if (dda.mf < 0) { \ dda.mf += 2 * ABS(dy); \ dda.mi--; \ } \ } \ else { \ dda.mi = 0; \ dda.mf = 0; \ dda.xf = 0; \ dda._2dy = 0; \ } \ } while (0) #define INC_DDA(dda) \ do { \ dda.xi += dda.mi; \ dda.xf += dda.mf; \ if (dda.xf > 0) { \ dda.xi++; \ dda.xf -= dda._2dy; \ } \ } while (0) /** * render a triangle using two parallel DDA's */ static void fill_tri( DFBTriangle *tri, CardState *state, bool accelerated ) { int y, yend; DDA dda1 = { .xi = 0 }, dda2 = { .xi = 0 }; int clip_x1 = state->clip.x1; int clip_x2 = state->clip.x2; D_MAGIC_ASSERT( state, CardState ); y = tri->y1; yend = tri->y3; if (yend > state->clip.y2) yend = state->clip.y2; SETUP_DDA(tri->x1, tri->y1, tri->x3, tri->y3, dda1); SETUP_DDA(tri->x1, tri->y1, tri->x2, tri->y2, dda2); while (y <= yend) { DFBRectangle rect; if (y == tri->y2) { if (tri->y2 == tri->y3) return; SETUP_DDA(tri->x2, tri->y2, tri->x3, tri->y3, dda2); } rect.w = ABS(dda1.xi - dda2.xi); rect.x = MIN(dda1.xi, dda2.xi); if (clip_x2 < rect.x + rect.w) rect.w = clip_x2 - rect.x + 1; if (rect.w > 0) { if (clip_x1 > rect.x) { rect.w -= (clip_x1 - rect.x); rect.x = clip_x1; } rect.y = y; rect.h = 1; if (rect.w > 0 && rect.y >= state->clip.y1) { if (accelerated) card->funcs.FillRectangle( card->driver_data, card->device_data, &rect ); else gFillRectangle( state, &rect ); } } INC_DDA(dda1); INC_DDA(dda2); y++; } } void dfb_gfxcard_filltriangles( const DFBTriangle *tris, int num, CardState *state ) { bool hw = false; int i = 0; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( tris != NULL ); D_ASSERT( num > 0 ); D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %p )\n", __FUNCTION__, tris, num, state ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state, card ); if (dfb_gfxcard_state_check( state, DFXL_FILLTRIANGLE ) && dfb_gfxcard_state_acquire( state, DFXL_FILLTRIANGLE )) { if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLTRIANGLE )) { DFBPoint p[6]; int n; for (; i < num; i++) { /* FIXME: DSRO_MATRIX. */ if (dfb_clip_triangle( &state->clip, &tris[i], p, &n )) { DFBTriangle tri; int j; tri.x1 = p[0].x; tri.y1 = p[0].y; tri.x2 = p[1].x; tri.y2 = p[1].y; tri.x3 = p[2].x; tri.y3 = p[2].y; hw = card->funcs.FillTriangle( card->driver_data, card->device_data, &tri ); if (!hw) break; /* FIXME: return value. */ for (j = 3; j < n; j++) { tri.x1 = p[0].x; tri.y1 = p[0].y; tri.x2 = p[j-1].x; tri.y2 = p[j-1].y; tri.x3 = p[j].x; tri.y3 = p[j].y; card->funcs.FillTriangle( card->driver_data, card->device_data, &tri ); } } } } else { for (; i < num; i++) { DFBTriangle tri = tris[i]; hw = card->funcs.FillTriangle( card->driver_data, card->device_data, &tri ); if (!hw) break; } } dfb_gfxcard_state_release( state ); } if (!hw && i < num) { /* otherwise use the spanline rasterizer (fill_tri) and fill the triangle using a rectangle for each spanline */ /* try hardware accelerated rectangle filling */ if (!(card->caps.flags & CCF_NOTRIEMU) && dfb_gfxcard_state_check( state, DFXL_FILLRECTANGLE ) && dfb_gfxcard_state_acquire( state, DFXL_FILLRECTANGLE )) { for (; i < num; i++) { DFBTriangle tri = tris[i]; dfb_sort_triangle( &tri ); if (tri.y3 - tri.y1 > 0) fill_tri( &tri, state, true ); } dfb_gfxcard_state_release( state ); } else if (gAcquire( state, DFXL_FILLRECTANGLE )) { for (; i < num; i++) { DFBTriangle tri = tris[i]; if (state->render_options & DSRO_MATRIX) { DFB_TRANSFORM(tri.x1, tri.y1, state->matrix, state->affine_matrix); DFB_TRANSFORM(tri.x2, tri.y2, state->matrix, state->affine_matrix); DFB_TRANSFORM(tri.x3, tri.y3, state->matrix, state->affine_matrix); } dfb_sort_triangle( &tri ); if (tri.y3 - tri.y1 > 0) fill_tri( &tri, state, false ); } gRelease( state ); } } dfb_state_unlock( state ); } static void clip_blit_rotated( DFBRectangle *srect, DFBRectangle *drect, const DFBRegion *clip, DFBSurfaceBlittingFlags flags ) { DFBRegion dest = DFB_REGION_INIT_FROM_RECTANGLE( drect ); DFBRegion clipped = dest; if (flags & (DSBLIT_ROTATE90 | DSBLIT_ROTATE270)) { D_ASSERT( srect->w == drect->h ); D_ASSERT( srect->h == drect->w ); } else { D_ASSERT( srect->w == drect->w ); D_ASSERT( srect->h == drect->h ); } dfb_region_region_intersect( &clipped, clip ); dfb_rectangle_from_region( drect, &clipped ); if (flags & DSBLIT_ROTATE90) { srect->x += dest.y2 - clipped.y2; srect->y += clipped.x1 - dest.x1; srect->w = drect->h; srect->h = drect->w; D_DEBUG_AT( Core_GraphicsOps, " => %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d (90°)\n", DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect) ); } else if (flags & DSBLIT_ROTATE180) { srect->x += dest.x2 - clipped.x2; srect->y += dest.y2 - clipped.y2; srect->w = drect->w; srect->h = drect->h; D_DEBUG_AT( Core_GraphicsOps, " => %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d (180°)\n", DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect) ); } else if (flags & DSBLIT_ROTATE270) { srect->x += clipped.y1 - dest.y1; srect->y += dest.x2 - clipped.x2; srect->w = drect->h; srect->h = drect->w; D_DEBUG_AT( Core_GraphicsOps, " => %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d (270°)\n", DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect) ); } else { srect->x += clipped.x1 - dest.x1; srect->y += clipped.y1 - dest.y1; srect->w = drect->w; srect->h = drect->h; D_DEBUG_AT( Core_GraphicsOps, " => %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect) ); } } void dfb_gfxcard_blit( DFBRectangle *rect, int dx, int dy, CardState *state ) { bool hw = false; DFBRectangle drect = { dx, dy, rect->w, rect->h }; if (state->blittingflags & (DSBLIT_ROTATE90 | DSBLIT_ROTATE270)) D_UTIL_SWAP( drect.w, drect.h ); D_DEBUG_AT( Core_GraphicsOps, "%s( %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d, %p )\n", __FUNCTION__, DFB_RECTANGLE_VALS(rect), DFB_RECTANGLE_VALS(&drect), state ); D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( state->source != NULL ); D_ASSERT( rect != NULL ); D_ASSERT( rect->x >= 0 ); D_ASSERT( rect->y >= 0 ); D_ASSERT( rect->x < state->source->config.size.w ); D_ASSERT( rect->y < state->source->config.size.h ); D_ASSERT( rect->x + rect->w - 1 < state->source->config.size.w ); D_ASSERT( rect->y + rect->h - 1 < state->source->config.size.h ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state, card ); if (!(state->render_options & DSRO_MATRIX) && !dfb_clip_blit_precheck( &state->clip, drect.w, drect.h, drect.x, drect.y )) { /* no work at all */ dfb_state_unlock( state ); return; } if (dfb_gfxcard_state_check( state, DFXL_BLIT ) && dfb_gfxcard_state_acquire( state, DFXL_BLIT )) { if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_BLIT )) clip_blit_rotated( rect, &drect, &state->clip, state->blittingflags ); hw = card->funcs.Blit( card->driver_data, card->device_data, rect, drect.x, drect.y ); dfb_gfxcard_state_release( state ); } if (!hw) { if (state->render_options & DSRO_MATRIX) { if (state->matrix[0] < 0 || state->matrix[1] != 0 || state->matrix[3] != 0 || state->matrix[4] < 0 || state->matrix[6] != 0 || state->matrix[7] != 0) { D_WARN( "rotation not yet implemented" ); dfb_state_unlock( state ); return; } if (gAcquire( state, DFXL_STRETCHBLIT )) { DFBRectangle drect; int x1, y1, x2, y2; x1 = dx; y1 = dy; x2 = dx+rect->w; y2 = dy+rect->h; DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix); DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix); drect = (DFBRectangle) { x1, y1, x2-x1, y2-y1 }; if (dfb_clip_blit_precheck( &state->clip, drect.w, drect.h, drect.x, drect.y )) gStretchBlit( state, rect, &drect ); gRelease( state ); } } else { if (gAcquire( state, DFXL_BLIT )) { clip_blit_rotated( rect, &drect, &state->clip, state->blittingflags ); gBlit( state, rect, drect.x, drect.y ); gRelease( state ); } } } dfb_state_unlock( state ); } void dfb_gfxcard_batchblit( DFBRectangle *rects, DFBPoint *points, int num, CardState *state ) { int i = 0; D_DEBUG_AT( Core_GraphicsOps, "%s( %p, %p [%d], %p )\n", __FUNCTION__, rects, points, num, state ); D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( rects != NULL ); D_ASSERT( points != NULL ); D_ASSERT( num > 0 ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state, card ); if (dfb_gfxcard_state_check( state, DFXL_BLIT ) && dfb_gfxcard_state_acquire( state, DFXL_BLIT )) { for (; irender_options & DSRO_MATRIX) || dfb_clip_blit_precheck( &state->clip, rects[i].w, rects[i].h, points[i].x, points[i].y )) { if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_BLIT )) dfb_clip_blit( &state->clip, &rects[i], &points[i].x, &points[i].y ); if (!card->funcs.Blit( card->driver_data, card->device_data, &rects[i], points[i].x, points[i].y )) break; } } dfb_gfxcard_state_release( state ); } if (i < num) { if (state->render_options & DSRO_MATRIX) { if (state->matrix[0] < 0 || state->matrix[1] != 0 || state->matrix[3] != 0 || state->matrix[4] < 0 || state->matrix[6] != 0 || state->matrix[7] != 0) { D_WARN( "rotation not yet implemented" ); dfb_state_unlock( state ); return; } if (gAcquire( state, DFXL_STRETCHBLIT )) { for (; imatrix, state->affine_matrix); DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix); drect = (DFBRectangle) { x1, y1, x2-x1, y2-y1 }; if (dfb_clip_blit_precheck( &state->clip, drect.w, drect.h, drect.x, drect.y )) gStretchBlit( state, &rects[i], &drect ); } gRelease( state ); } } else { if (gAcquire( state, DFXL_BLIT )) { for (; iclip, rects[i].w, rects[i].h, points[i].x, points[i].y )) { dfb_clip_blit( &state->clip, &rects[i], &points[i].x, &points[i].y ); gBlit( state, &rects[i], points[i].x, points[i].y ); } } gRelease( state ); } } } dfb_state_unlock( state ); } void dfb_gfxcard_tileblit( DFBRectangle *rect, int dx1, int dy1, int dx2, int dy2, CardState *state ) { int x, y; int odx; DFBRectangle srect; DFBRegion *clip; D_DEBUG_AT( Core_GraphicsOps, "%s( %d,%d - %d,%d, %p )\n", __FUNCTION__, dx1, dy1, dx2, dy2, state ); D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( rect != NULL ); /* If called with an invalid rectangle, the algorithm goes into an infinite loop. This should never happen but it's safer to check. */ D_ASSERT( rect->w >= 1 ); D_ASSERT( rect->h >= 1 ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state, card ); clip = &state->clip; /* Check if anything is drawn at all. */ if (!(state->render_options & DSRO_MATRIX) && !dfb_clip_blit_precheck( clip, dx2-dx1+1, dy2-dy1+1, dx1, dy1 )) { dfb_state_unlock( state ); return; } /* Remove clipped tiles. */ if (dx1 < clip->x1) { int outer = clip->x1 - dx1; dx1 += outer - (outer % rect->w); } if (dy1 < clip->y1) { int outer = clip->y1 - dy1; dy1 += outer - (outer % rect->h); } if (dx2 > clip->x2) { int outer = clip->x2 - dx2; dx2 -= outer - (outer % rect->w); } if (dy2 > clip->y2) { int outer = clip->y2 - dy2; dy2 -= outer - (outer % rect->h); } odx = dx1; if (dfb_gfxcard_state_check( state, DFXL_BLIT ) && dfb_gfxcard_state_acquire( state, DFXL_BLIT )) { bool hw = true; for (; dy1 < dy2; dy1 += rect->h) { for (; dx1 < dx2; dx1 += rect->w) { if (!dfb_clip_blit_precheck( clip, rect->w, rect->h, dx1, dy1 )) continue; x = dx1; y = dy1; srect = *rect; if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_BLIT )) dfb_clip_blit( clip, &srect, &x, &y ); hw = card->funcs.Blit( card->driver_data, card->device_data, &srect, x, y ); if (!hw) break; } if (!hw) break; dx1 = odx; } dfb_gfxcard_state_release( state ); } if (dy1 < dy2) { if (state->render_options & DSRO_MATRIX) { if (state->matrix[0] < 0 || state->matrix[1] != 0 || state->matrix[3] != 0 || state->matrix[4] < 0 || state->matrix[6] != 0 || state->matrix[7] != 0) { D_WARN( "rotation not yet implemented" ); dfb_state_unlock( state ); return; } if (gAcquire( state, DFXL_STRETCHBLIT )) { for (; dy1 < dy2; dy1 += rect->h) { for (; dx1 < dx2; dx1 += rect->w) { DFBRectangle drect; int x1, y1, x2, y2; x1 = dx1; y1 = dy1; x2 = dx1+rect->w; y2 = dy1+rect->h; DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix); DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix); drect = (DFBRectangle) { x1, y1, x2-x1, y2-y1 }; if (dfb_clip_blit_precheck( &state->clip, drect.w, drect.h, drect.x, drect.y )) gStretchBlit( state, rect, &drect ); } dx1 = odx; } gRelease( state ); } } else { if (gAcquire( state, DFXL_BLIT )) { for (; dy1 < dy2; dy1 += rect->h) { for (; dx1 < dx2; dx1 += rect->w) { if (!dfb_clip_blit_precheck( clip, rect->w, rect->h, dx1, dy1 )) continue; x = dx1; y = dy1; srect = *rect; dfb_clip_blit( clip, &srect, &x, &y ); gBlit( state, &srect, x, y ); } dx1 = odx; } gRelease( state ); } } } dfb_state_unlock( state ); } void dfb_gfxcard_stretchblit( DFBRectangle *srect, DFBRectangle *drect, CardState *state ) { bool hw = false; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( srect != NULL ); D_ASSERT( drect != NULL ); D_DEBUG_AT( Core_GraphicsOps, "%s( %d,%d - %dx%d -> %d,%d - %dx%d, %p )\n", __FUNCTION__, DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect), state ); if (state->blittingflags & (DSBLIT_ROTATE90 | DSBLIT_ROTATE270)) { if (srect->w == drect->h && srect->h == drect->w) { dfb_gfxcard_blit( srect, drect->x, drect->y, state ); return; } } else { if (srect->w == drect->w && srect->h == drect->h) { dfb_gfxcard_blit( srect, drect->x, drect->y, state ); return; } } /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state, card ); if (!(state->render_options & DSRO_MATRIX) && !dfb_clip_blit_precheck( &state->clip, drect->w, drect->h, drect->x, drect->y )) { dfb_state_unlock( state ); return; } if (dfb_gfxcard_state_check( state, DFXL_STRETCHBLIT ) && dfb_gfxcard_state_acquire( state, DFXL_STRETCHBLIT )) { if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_STRETCHBLIT )) dfb_clip_stretchblit( &state->clip, srect, drect ); hw = card->funcs.StretchBlit( card->driver_data, card->device_data, srect, drect ); dfb_gfxcard_state_release( state ); } if (!hw) { if (state->render_options & DSRO_MATRIX) { int x1, y1, x2, y2; if (state->matrix[0] < 0 || state->matrix[1] != 0 || state->matrix[3] != 0 || state->matrix[4] < 0 || state->matrix[6] != 0 || state->matrix[7] != 0) { D_WARN( "rotation not yet implemented" ); dfb_state_unlock( state ); return; } x1 = drect->x; y1 = drect->y; x2 = x1+drect->w; y2 = y1+drect->h; DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix); DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix); drect->x = x1; drect->y = y1; drect->w = x2-x1; drect->h = y2-y1; if (!dfb_clip_blit_precheck( &state->clip, drect->w, drect->h, drect->x, drect->y )) { dfb_state_unlock( state ); return; } } if (gAcquire( state, DFXL_STRETCHBLIT )) { /* Clipping is performed in the following function. */ gStretchBlit( state, srect, drect ); gRelease( state ); } } dfb_state_unlock( state ); } void dfb_gfxcard_texture_triangles( DFBVertex *vertices, int num, DFBTriangleFormation formation, CardState *state ) { bool hw = false; D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %s, %p )\n", __FUNCTION__, vertices, num, (formation == DTTF_LIST) ? "LIST" : (formation == DTTF_STRIP) ? "STRIP" : (formation == DTTF_FAN) ? "FAN" : "unknown formation", state ); D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_ASSERT( vertices != NULL ); D_ASSERT( num >= 3 ); D_MAGIC_ASSERT( state, CardState ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state, card ); if ((D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) || D_FLAGS_IS_SET( card->caps.clip, DFXL_TEXTRIANGLES )) && dfb_gfxcard_state_check( state, DFXL_TEXTRIANGLES ) && dfb_gfxcard_state_acquire( state, DFXL_TEXTRIANGLES )) { hw = card->funcs.TextureTriangles( card->driver_data, card->device_data, vertices, num, formation ); dfb_gfxcard_state_release( state ); } if (!hw) { if (gAcquire( state, DFXL_TEXTRIANGLES )) { //dfb_clip_stretchblit( &state->clip, srect, drect ); //gStretchBlit( state, srect, drect ); gRelease( state ); } } dfb_state_unlock( state ); } void dfb_gfxcard_drawstring( const u8 *text, int bytes, DFBTextEncodingID encoding, int x, int y, CoreFont *font, unsigned int layers, CardState *state ) { unsigned int prev = 0; unsigned int indices[bytes]; int i, l, num; int kern_x; int kern_y; CoreSurface *surface; DFBSurfaceBlittingFlags orig_flags; DFBSurfaceBlendFunction orig_srcblend; DFBSurfaceBlendFunction orig_dstblend; DFBPoint points[50]; DFBRectangle rects[50]; int num_blits = 0; int ox = x; int oy = y; if (encoding == DTEID_UTF8) D_DEBUG_AT( Core_GraphicsOps, "%s( '%s' [%d], %d,%d, %p, %p )\n", __FUNCTION__, text, bytes, x, y, font, state ); else D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %d, %d,%d, %p, %p )\n", __FUNCTION__, text, bytes, encoding, x, y, font, state ); D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( text != NULL ); D_ASSERT( bytes > 0 ); D_ASSERT( font != NULL ); surface = state->destination; D_MAGIC_ASSERT( surface, CoreSurface ); /* simple prechecks */ if (!(state->render_options & DSRO_MATRIX) && (x > state->clip.x2 || y > state->clip.y2 || y + font->ascender - font->descender <= state->clip.y1)) { return; } dfb_font_lock( font ); /* Decode string to character indices. */ dfb_font_decode_text( font, encoding, text, bytes, indices, &num ); orig_flags = state->blittingflags; orig_srcblend = state->src_blend; orig_dstblend = state->dst_blend; if (orig_flags != DSBLIT_INDEX_TRANSLATION) { DFBSurfaceBlittingFlags flags = font->blittingflags; /* additional blending? */ if ((state->drawingflags & DSDRAW_BLEND) && (state->color.a != 0xff)) flags |= DSBLIT_BLEND_COLORALPHA; if (state->drawingflags & DSDRAW_DST_COLORKEY) flags |= DSBLIT_DST_COLORKEY; if (state->drawingflags & DSDRAW_XOR) flags |= DSBLIT_XOR; if (flags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)) { /* Porter/Duff SRC_OVER composition */ if ((DFB_PIXELFORMAT_HAS_ALPHA( surface->config.format ) && (surface->config.caps & DSCAPS_PREMULTIPLIED)) || (font->surface_caps & DSCAPS_PREMULTIPLIED)) { if (font->surface_caps & DSCAPS_PREMULTIPLIED) { if (flags & DSBLIT_BLEND_COLORALPHA) flags |= DSBLIT_SRC_PREMULTCOLOR; } else flags |= DSBLIT_SRC_PREMULTIPLY; dfb_state_set_src_blend( state, DSBF_ONE ); } else dfb_state_set_src_blend( state, DSBF_SRCALPHA ); dfb_state_set_dst_blend( state, DSBF_INVSRCALPHA ); } dfb_state_set_blitting_flags( state, flags ); } for (l=layers-1; l>=0; l--) { x = ox; y = oy; if (layers > 1) { if (num_blits) { dfb_gfxcard_batchblit( rects, points, num_blits, state ); num_blits = 0; } dfb_state_set_color( state, &state->colors[l] ); } /* blit glyphs */ for (i=0; i dfb_font_get_glyph_data() failed! [%s]\n", DirectFBErrorString( ret ) ); prev = current; continue; } if (prev && font->GetKerning && font->GetKerning( font, prev, current, &kern_x, &kern_y) == DFB_OK) { x += kern_x; y += kern_y; } if (glyph->width) { if (glyph->surface != state->source || num_blits == D_ARRAY_SIZE(rects)) { if (num_blits) { dfb_gfxcard_batchblit( rects, points, num_blits, state ); num_blits = 0; } if (glyph->surface != state->source) dfb_state_set_source( state, glyph->surface ); } points[num_blits] = (DFBPoint){ x + glyph->left, y + glyph->top }; rects[num_blits] = (DFBRectangle){ glyph->start, 0, glyph->width, glyph->height }; num_blits++; } x += glyph->xadvance; y += glyph->yadvance; prev = current; } } if (num_blits) { dfb_gfxcard_batchblit( rects, points, num_blits, state ); num_blits = 0; } dfb_font_unlock( font ); if (orig_flags != DSBLIT_INDEX_TRANSLATION) { dfb_state_set_blitting_flags( state, orig_flags ); dfb_state_set_src_blend( state, orig_srcblend ); dfb_state_set_dst_blend( state, orig_dstblend ); } } void dfb_gfxcard_drawglyph( CoreGlyphData **glyph, int x, int y, CoreFont *font, unsigned int layers, CardState *state ) { int l; CoreSurface *surface; DFBSurfaceBlittingFlags orig_flags; DFBSurfaceBlendFunction orig_srcblend; DFBSurfaceBlendFunction orig_dstblend; D_DEBUG_AT( Core_GraphicsOps, "%s( %u, %d,%d, %p, %p )\n", __FUNCTION__, index, x, y, font, state ); D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( font != NULL ); surface = state->destination; D_MAGIC_ASSERT( surface, CoreSurface ); orig_flags = state->blittingflags; orig_srcblend = state->src_blend; orig_dstblend = state->dst_blend; if (orig_flags != DSBLIT_INDEX_TRANSLATION) { DFBSurfaceBlittingFlags flags = font->blittingflags; /* additional blending? */ if ((state->drawingflags & DSDRAW_BLEND) && (state->color.a != 0xff)) flags |= DSBLIT_BLEND_COLORALPHA; if (state->drawingflags & DSDRAW_DST_COLORKEY) flags |= DSBLIT_DST_COLORKEY; if (state->drawingflags & DSDRAW_XOR) flags |= DSBLIT_XOR; if (flags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)) { /* Porter/Duff SRC_OVER composition */ if ((DFB_PIXELFORMAT_HAS_ALPHA( surface->config.format ) && (surface->config.caps & DSCAPS_PREMULTIPLIED)) || (font->surface_caps & DSCAPS_PREMULTIPLIED)) { if (font->surface_caps & DSCAPS_PREMULTIPLIED) { if (flags & DSBLIT_BLEND_COLORALPHA) flags |= DSBLIT_SRC_PREMULTCOLOR; } else flags |= DSBLIT_SRC_PREMULTIPLY; dfb_state_set_src_blend( state, DSBF_ONE ); } else dfb_state_set_src_blend( state, DSBF_SRCALPHA ); dfb_state_set_dst_blend( state, DSBF_INVSRCALPHA ); } dfb_state_set_blitting_flags( state, flags ); } for (l=layers-1; l>=0; l--) { if (layers > 1) dfb_state_set_color( state, &state->colors[l] ); /* blit glyph */ if (glyph[l]->width) { DFBRectangle rect = { glyph[l]->start, 0, glyph[l]->width, glyph[l]->height }; dfb_state_set_source( state, glyph[l]->surface ); dfb_gfxcard_blit( &rect, x + glyph[l]->left, y + glyph[l]->top, state ); } } if (orig_flags != DSBLIT_INDEX_TRANSLATION) { dfb_state_set_blitting_flags( state, orig_flags ); dfb_state_set_src_blend( state, orig_srcblend ); dfb_state_set_dst_blend( state, orig_dstblend ); } } bool dfb_gfxcard_drawstring_check_state( CoreFont *font, CardState *state ) { int i; bool result; CoreSurface *surface; DFBSurfaceBlittingFlags orig_flags; DFBSurfaceBlendFunction orig_srcblend; DFBSurfaceBlendFunction orig_dstblend; CoreGlyphData *data = NULL; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( font != NULL ); D_DEBUG_AT( Core_GfxState, "%s( %p, %p )\n", __FUNCTION__, font, state ); surface = state->destination; D_MAGIC_ASSERT( surface, CoreSurface ); dfb_font_lock( font ); for (i=0; i<128; i++) { if (dfb_font_get_glyph_data (font, i, 0, &data) == DFB_OK) break; } if (!data) { D_DEBUG_AT( Core_GfxState, " -> No font data!\n" ); dfb_font_unlock( font ); return; } orig_flags = state->blittingflags; orig_srcblend = state->src_blend; orig_dstblend = state->dst_blend; if (orig_flags != DSBLIT_INDEX_TRANSLATION) { DFBSurfaceBlittingFlags flags = font->blittingflags; /* additional blending? */ if ((state->drawingflags & DSDRAW_BLEND) && (state->color.a != 0xff)) flags |= DSBLIT_BLEND_COLORALPHA; if (state->drawingflags & DSDRAW_DST_COLORKEY) flags |= DSBLIT_DST_COLORKEY; if (state->drawingflags & DSDRAW_XOR) flags |= DSBLIT_XOR; if (flags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)) { /* Porter/Duff SRC_OVER composition */ if ((DFB_PIXELFORMAT_HAS_ALPHA( surface->config.format ) && (surface->config.caps & DSCAPS_PREMULTIPLIED)) || (font->surface_caps & DSCAPS_PREMULTIPLIED)) { if (font->surface_caps & DSCAPS_PREMULTIPLIED) { if (flags & DSBLIT_BLEND_COLORALPHA) flags |= DSBLIT_SRC_PREMULTCOLOR; } else flags |= DSBLIT_SRC_PREMULTIPLY; dfb_state_set_src_blend( state, DSBF_ONE ); } else dfb_state_set_src_blend( state, DSBF_SRCALPHA ); dfb_state_set_dst_blend( state, DSBF_INVSRCALPHA ); } dfb_state_set_blitting_flags( state, flags ); } /* set the source */ dfb_state_set_source( state, data->surface ); dfb_state_lock( state ); /* check for blitting and report */ result = dfb_gfxcard_state_check( state, DFXL_BLIT ); dfb_state_unlock( state ); dfb_font_unlock( font ); if (orig_flags != DSBLIT_INDEX_TRANSLATION) { dfb_state_set_blitting_flags( state, orig_flags ); dfb_state_set_src_blend( state, orig_srcblend ); dfb_state_set_dst_blend( state, orig_dstblend ); } return result; } DFBResult dfb_gfxcard_sync( void ) { DFBResult ret; D_ASSUME( card != NULL ); if (!card) return DFB_OK; ret = dfb_gfxcard_lock( GDLF_SYNC ); if (ret) return ret; dfb_gfxcard_unlock(); return DFB_OK; } void dfb_gfxcard_invalidate_state( void ) { D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); card->shared->state = NULL; } DFBResult dfb_gfxcard_wait_serial( const CoreGraphicsSerial *serial ) { DFBResult ret; D_ASSERT( serial != NULL ); D_ASSUME( card != NULL ); if (!card) return DFB_OK; D_ASSERT( card->shared != NULL ); ret = dfb_gfxcard_lock( GDLF_NONE ); if (ret) return ret; /* FIXME_SC_2 if (card->funcs.WaitSerial) ret = card->funcs.WaitSerial( card->driver_data, card->device_data, serial ); else*/ if (card->funcs.EngineSync) ret = card->funcs.EngineSync( card->driver_data, card->device_data ); if (ret) { if (card->funcs.EngineReset) card->funcs.EngineReset( card->driver_data, card->device_data ); card->shared->state = NULL; } dfb_gfxcard_unlock(); return ret; } void dfb_gfxcard_flush_texture_cache( void ) { D_ASSUME( card != NULL ); if (card && card->funcs.FlushTextureCache) card->funcs.FlushTextureCache( card->driver_data, card->device_data ); } void dfb_gfxcard_flush_read_cache( void ) { D_ASSUME( card != NULL ); if (card && card->funcs.FlushReadCache) card->funcs.FlushReadCache( card->driver_data, card->device_data ); } void dfb_gfxcard_after_set_var( void ) { D_ASSUME( card != NULL ); if (card && card->funcs.AfterSetVar) card->funcs.AfterSetVar( card->driver_data, card->device_data ); } void dfb_gfxcard_surface_enter( CoreSurfaceBuffer *buffer, DFBSurfaceLockFlags flags ) { D_ASSUME( card != NULL ); if (card && card->funcs.SurfaceEnter) card->funcs.SurfaceEnter( card->driver_data, card->device_data, buffer, flags ); } void dfb_gfxcard_surface_leave( CoreSurfaceBuffer *buffer ) { D_ASSUME( card != NULL ); if (card && card->funcs.SurfaceLeave) card->funcs.SurfaceLeave( card->driver_data, card->device_data, buffer ); } DFBResult dfb_gfxcard_adjust_heap_offset( int offset ) { D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); //FIXME_SMAN return dfb_surfacemanager_adjust_heap_offset( card->shared->surface_manager, offset ); return DFB_OK; } void dfb_gfxcard_get_capabilities( CardCapabilities *ret_caps ) { D_ASSERT( card != NULL ); D_ASSERT( ret_caps != NULL ); *ret_caps = card->caps; } void dfb_gfxcard_get_device_info( GraphicsDeviceInfo *ret_info ) { D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_ASSERT( ret_info != NULL ); *ret_info = card->shared->device_info; } void dfb_gfxcard_get_driver_info( GraphicsDriverInfo *ret_info ) { D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_ASSERT( ret_info != NULL ); *ret_info = card->shared->driver_info; } int dfb_gfxcard_reserve_memory( CoreGraphicsDevice *device, unsigned int size ) { DFBGraphicsCoreShared *shared; D_ASSERT( device != NULL ); D_ASSERT( device->shared != NULL ); shared = device->shared; if (shared->device_info.limits.surface_byteoffset_alignment) { size += shared->device_info.limits.surface_byteoffset_alignment - 1; size -= (size % shared->device_info.limits.surface_byteoffset_alignment); } else D_WARN( "no alignment specified yet?" ); if (shared->videoram_length < size) { D_WARN( "not enough video memory (%u < %u)", shared->videoram_length, size ); return -1; } shared->videoram_length -= size; return shared->videoram_length; } int dfb_gfxcard_reserve_auxmemory( CoreGraphicsDevice *device, unsigned int size ) { DFBGraphicsCoreShared *shared; int offset; D_ASSERT( device != NULL ); D_ASSERT( device->shared != NULL ); shared = device->shared; /* Reserve memory at the beginning of the aperture * to prevent overflows on DMA buffers. */ offset = shared->auxram_offset; if (shared->auxram_length < (offset + size)) return -1; shared->auxram_offset += size; return offset; } unsigned int dfb_gfxcard_memory_length( void ) { D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); return card->shared->videoram_length; } unsigned int dfb_gfxcard_auxmemory_length( void ) { D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); return card->shared->auxram_length; } volatile void * dfb_gfxcard_map_mmio( CoreGraphicsDevice *device, unsigned int offset, int length ) { return dfb_system_map_mmio( offset, length ); } void dfb_gfxcard_unmap_mmio( CoreGraphicsDevice *device, volatile void *addr, int length ) { dfb_system_unmap_mmio( addr, length ); } int dfb_gfxcard_get_accelerator( CoreGraphicsDevice *device ) { return dfb_system_get_accelerator(); } void dfb_gfxcard_get_limits( CoreGraphicsDevice *device, CardLimitations *ret_limits ) { D_ASSERT( device != NULL ); D_ASSERT( ret_limits != NULL ); if (!device) device = card; *ret_limits = device->limits; } void dfb_gfxcard_calc_buffer_size( CoreGraphicsDevice *device, CoreSurfaceBuffer *buffer, int *ret_pitch, int *ret_length ) { int pitch; int length; CoreSurface *surface; D_ASSERT( device != NULL ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); surface = buffer->surface; D_MAGIC_ASSERT( surface, CoreSurface ); /* calculate the required length depending on limitations */ pitch = MAX( surface->config.size.w, surface->config.min_size.w ); if (pitch < device->limits.surface_max_power_of_two_pixelpitch && surface->config.size.h < device->limits.surface_max_power_of_two_height) pitch = 1 << direct_log2( pitch ); if (device->limits.surface_pixelpitch_alignment > 1) { pitch += device->limits.surface_pixelpitch_alignment - 1; pitch -= pitch % device->limits.surface_pixelpitch_alignment; } pitch = DFB_BYTES_PER_LINE( buffer->format, pitch ); if (pitch < device->limits.surface_max_power_of_two_bytepitch && surface->config.size.h < device->limits.surface_max_power_of_two_height) pitch = 1 << direct_log2( pitch ); if (device->limits.surface_bytepitch_alignment > 1) { pitch += device->limits.surface_bytepitch_alignment - 1; pitch -= pitch % device->limits.surface_bytepitch_alignment; } length = DFB_PLANE_MULTIPLY( buffer->format, MAX( surface->config.size.h, surface->config.min_size.h ) * pitch ); /* Add extra space for optimized routines which are now allowed to overrun, e.g. prefetching. */ length += 16; if (device->limits.surface_byteoffset_alignment > 1) { length += device->limits.surface_byteoffset_alignment - 1; length -= length % device->limits.surface_byteoffset_alignment; } if (ret_pitch) *ret_pitch = pitch; if (ret_length) *ret_length = length; } unsigned long dfb_gfxcard_memory_physical( CoreGraphicsDevice *device, unsigned int offset ) { return dfb_system_video_memory_physical( offset ); } void * dfb_gfxcard_memory_virtual( CoreGraphicsDevice *device, unsigned int offset ) { return dfb_system_video_memory_virtual( offset ); } unsigned long dfb_gfxcard_auxmemory_physical( CoreGraphicsDevice *device, unsigned int offset ) { return dfb_system_aux_memory_physical( offset ); } void * dfb_gfxcard_auxmemory_virtual( CoreGraphicsDevice *device, unsigned int offset ) { return dfb_system_aux_memory_virtual( offset ); } void * dfb_gfxcard_get_device_data( void ) { D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); return card->shared->device_data; } void * dfb_gfxcard_get_driver_data( void ) { D_ASSERT( card != NULL ); return card->driver_data; } CoreGraphicsDevice * dfb_gfxcard_get_primary( void ) { return card; } /** internal **/ /* * loads/probes/unloads one driver module after another until a suitable * driver is found and returns its symlinked functions */ static void dfb_gfxcard_find_driver( CoreDFB *core ) { DirectLink *link; FusionSHMPoolShared *pool = dfb_core_shmpool( core ); direct_list_foreach (link, dfb_graphics_drivers.entries) { DirectModuleEntry *module = (DirectModuleEntry*) link; const GraphicsDriverFuncs *funcs = direct_module_ref( module ); if (!funcs) continue; if (!card->module && funcs->Probe( card )) { funcs->GetDriverInfo( card, &card->shared->driver_info ); card->module = module; card->driver_funcs = funcs; card->shared->module_name = SHSTRDUP( pool, module->name ); } else direct_module_unref( module ); } } /* * loads the driver module used by the session */ static void dfb_gfxcard_load_driver( void ) { DirectLink *link; if (!card->shared->module_name) return; direct_list_foreach (link, dfb_graphics_drivers.entries) { DirectModuleEntry *module = (DirectModuleEntry*) link; const GraphicsDriverFuncs *funcs = direct_module_ref( module ); if (!funcs) continue; if (!card->module && !strcmp( module->name, card->shared->module_name )) { card->module = module; card->driver_funcs = funcs; } else direct_module_unref( module ); } }