From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- Source/DirectFB/src/core/gfxcard.c | 2921 ++++++++++++++++++++++++++++++++++++ 1 file changed, 2921 insertions(+) create mode 100755 Source/DirectFB/src/core/gfxcard.c (limited to 'Source/DirectFB/src/core/gfxcard.c') diff --git a/Source/DirectFB/src/core/gfxcard.c b/Source/DirectFB/src/core/gfxcard.c new file mode 100755 index 0000000..84e725c --- /dev/null +++ b/Source/DirectFB/src/core/gfxcard.c @@ -0,0 +1,2921 @@ +/* + (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 ); + } +} + -- cgit