/* (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 D_DEBUG_DOMAIN( Core_Layers, "Core/Layers", "DirectFB Display Layer Core" ); /** public **/ DFBResult dfb_layer_suspend( CoreLayer *layer ) { CoreLayerShared *shared; CoreLayerContexts *contexts; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); shared = layer->shared; contexts = &shared->contexts; /* Lock the layer. */ if (fusion_skirmish_prevail( &shared->lock )) return DFB_FUSION; D_ASSUME( !shared->suspended ); if (shared->suspended) { fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } /* Deactivate current context. */ if (contexts->active >= 0) { DFBResult ret; CoreLayerContext *current = fusion_vector_at( &contexts->stack, contexts->active ); ret = dfb_layer_context_deactivate( current ); if (ret) { D_ERROR("DirectFB/Core/layer: " "Could not deactivate current context of '%s'! (%s)\n", shared->description.name, DirectFBErrorString( ret )); } } shared->suspended = true; /* Unlock the layer. */ fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } DFBResult dfb_layer_resume( CoreLayer *layer ) { CoreLayerShared *shared; CoreLayerContexts *contexts; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); shared = layer->shared; contexts = &shared->contexts; /* Lock the layer. */ if (fusion_skirmish_prevail( &shared->lock )) return DFB_FUSION; D_ASSUME( shared->suspended ); if (!shared->suspended) { fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } /* (Re)Activate current context. */ if (contexts->active >= 0) { DFBResult ret; CoreLayerContext *current = fusion_vector_at( &contexts->stack, contexts->active ); ret = dfb_layer_context_activate( current ); if (ret) { D_ERROR("DirectFB/Core/layer: " "Could not activate current context of '%s'! (%s)\n", shared->description.name, DirectFBErrorString( ret )); } } shared->suspended = false; /* Unlock the layer. */ fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } DFBResult dfb_layer_create_context( CoreLayer *layer, CoreLayerContext **ret_context ) { DFBResult ret; CoreLayerShared *shared; CoreLayerContexts *contexts; CoreLayerContext *context = NULL; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( ret_context != NULL ); shared = layer->shared; contexts = &shared->contexts; D_DEBUG_AT( Core_Layers, "%s (%s)\n", __FUNCTION__, shared->description.name ); /* Create the object. */ context = dfb_core_create_layer_context( layer->core ); if (!context) return DFB_FUSION; /* Lock the layer. */ if (fusion_skirmish_prevail( &shared->lock )) { fusion_object_destroy( &context->object ); return DFB_FUSION; } /* Initialize the new context. */ ret = dfb_layer_context_init( context, layer ); if (ret) { fusion_skirmish_dismiss( &shared->lock ); return ret; } /* Add it to the context stack. */ if (fusion_vector_add( &contexts->stack, context )) { dfb_layer_context_unref( context ); fusion_skirmish_dismiss( &shared->lock ); return DFB_FUSION; } /* Unlock the layer. */ fusion_skirmish_dismiss( &shared->lock ); /* Return the context. */ *ret_context = context; return DFB_OK; } DFBResult dfb_layer_get_active_context( CoreLayer *layer, CoreLayerContext **ret_context ) { CoreLayerShared *shared; CoreLayerContexts *contexts; CoreLayerContext *context; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( ret_context != NULL ); shared = layer->shared; contexts = &shared->contexts; D_DEBUG_AT( Core_Layers, "%s (%s)\n", __FUNCTION__, shared->description.name ); /* Lock the layer. */ if (fusion_skirmish_prevail( &shared->lock )) return DFB_FUSION; /* Check for active context. */ if (contexts->active < 0) { fusion_skirmish_dismiss( &shared->lock ); return DFB_NOCONTEXT; } /* Fetch active context. */ context = fusion_vector_at( &contexts->stack, contexts->active ); /* Increase the context's reference counter. */ if (dfb_layer_context_ref( context )) { fusion_skirmish_dismiss( &shared->lock ); return DFB_FUSION; } D_DEBUG_AT( Core_Layers, " => %p [%4dx%4d %8s]\n", context, context->config.width, context->config.height, dfb_pixelformat_name( context->config.pixelformat ) ); /* Return the context. */ *ret_context = context; /* Unlock the layer. */ fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } DFBResult dfb_layer_get_primary_context( CoreLayer *layer, bool activate, CoreLayerContext **ret_context ) { DFBResult ret; CoreLayerShared *shared; CoreLayerContexts *contexts; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( ret_context != NULL ); shared = layer->shared; contexts = &shared->contexts; /* Lock the layer. */ if (fusion_skirmish_prevail( &shared->lock )) return DFB_FUSION; D_DEBUG_AT( Core_Layers, "%s (%s, %sactivate) <- active: %d\n", __FUNCTION__, shared->description.name, activate ? "" : "don't ", contexts->active ); /* Check for primary context. */ if (contexts->primary) { /* Increase the context's reference counter. */ if (dfb_layer_context_ref( contexts->primary )) { fusion_skirmish_dismiss( &shared->lock ); return DFB_FUSION; } } else { CoreLayerContext *primary; /* Unlock the layer. */ fusion_skirmish_dismiss( &shared->lock ); /* Create the primary (shared) context. */ ret = dfb_layer_create_context( layer, &primary ); if (ret) return ret; /* Lock the layer again. */ if (fusion_skirmish_prevail( &shared->lock )) { dfb_layer_context_unref( primary ); return DFB_FUSION; } /* Check if there was a race. */ if (contexts->primary) { /* Throw away ours, the other was faster. */ dfb_layer_context_unref( primary ); /* Increase the context's reference counter. */ if (dfb_layer_context_ref( contexts->primary )) { fusion_skirmish_dismiss( &shared->lock ); return DFB_FUSION; } } else contexts->primary = primary; } /* Activate if no context is active? */ if (contexts->active < 0 && activate) { ret = dfb_layer_activate_context( layer, contexts->primary ); if (ret) { dfb_layer_context_unref( contexts->primary ); fusion_skirmish_dismiss( &shared->lock ); return ret; } } /* Return the context. */ *ret_context = contexts->primary; /* Unlock the layer. */ fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } DFBResult dfb_layer_activate_context( CoreLayer *layer, CoreLayerContext *context ) { DFBResult ret = DFB_OK; int index; CoreLayerShared *shared; CoreLayerContexts *ctxs; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( context != NULL ); shared = layer->shared; ctxs = &shared->contexts; /* Lock the layer. */ if (fusion_skirmish_prevail( &shared->lock )) return DFB_FUSION; D_DEBUG_AT( Core_Layers, "%s (%s, %p)\n", __FUNCTION__, shared->description.name, context ); D_ASSERT( fusion_vector_contains( &ctxs->stack, context ) ); /* Lookup the context in the context stack. */ index = fusion_vector_index_of( &ctxs->stack, context ); /* Lock the context. */ if (dfb_layer_context_lock( context )) { fusion_skirmish_dismiss( &shared->lock ); return DFB_FUSION; } /* Need to activate? */ if (ctxs->active != index) { DFBResult ret; /* Another context currently active? */ if (ctxs->active >= 0) { CoreLayerContext *current = fusion_vector_at( &ctxs->stack, ctxs->active ); /* Deactivate current context. */ if (!shared->suspended) { ret = dfb_layer_context_deactivate( current ); if (ret) goto error; } /* No active context. */ ctxs->active = -1; } /* Activate context now. */ if (!shared->suspended) { ret = dfb_layer_context_activate( context ); if (ret) goto error; } ctxs->active = index; } /* Unlock the context. */ dfb_layer_context_unlock( context ); /* Unlock the layer. */ fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; error: dfb_layer_context_unlock( context ); fusion_skirmish_dismiss( &shared->lock ); return ret; } DFBResult dfb_layer_remove_context( CoreLayer *layer, CoreLayerContext *context ) { int index; CoreLayerShared *shared; CoreLayerContexts *ctxs; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( context != NULL ); shared = layer->shared; ctxs = &shared->contexts; /* Lock the layer. */ if (fusion_skirmish_prevail( &shared->lock )) return DFB_FUSION; D_DEBUG_AT( Core_Layers, "%s (%s, %p)\n", __FUNCTION__, shared->description.name, context ); D_ASSUME( fusion_vector_contains( &ctxs->stack, context ) ); /* Lookup the context in the context stack. */ index = fusion_vector_index_of( &ctxs->stack, context ); if (index < 0) { fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } /* Lock the context. */ if (dfb_layer_context_lock( context )) { fusion_skirmish_dismiss( &shared->lock ); return DFB_FUSION; } /* Remove context from context stack. */ fusion_vector_remove( &ctxs->stack, index ); /* Check if the primary context is removed. */ if (context == ctxs->primary) ctxs->primary = NULL; /* Need to deactivate? */ if (ctxs->active == index) { /* Deactivate the context. */ if (!shared->suspended) dfb_layer_context_deactivate( context ); /* There's no active context anymore. */ ctxs->active = -1; if (ctxs->primary) D_ASSERT( fusion_vector_contains( &ctxs->stack, ctxs->primary ) ); if (fusion_vector_has_elements( &ctxs->stack )) { CoreLayerContext *ctx; /* Activate most recent context. */ index = fusion_vector_size( &ctxs->stack ) - 1; ctx = fusion_vector_at( &ctxs->stack, index ); if (shared->suspended || dfb_layer_context_activate( ctx ) == DFB_OK) ctxs->active = index; } } else if (ctxs->active > index) { /* Adjust index of active context due to the removed context. */ ctxs->active--; } /* Unlock the context. */ dfb_layer_context_unlock( context ); /* Unlock the layer. */ fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } DFBResult dfb_layer_get_current_output_field( CoreLayer *layer, int *field ) { DFBResult ret; D_ASSERT( layer != NULL ); D_ASSERT( layer->funcs != NULL ); D_ASSERT( field != NULL ); if (!layer->funcs->GetCurrentOutputField) return DFB_UNSUPPORTED; ret = layer->funcs->GetCurrentOutputField( layer, layer->driver_data, layer->layer_data, field ); if (ret) return ret; return DFB_OK; } DFBResult dfb_layer_get_level( CoreLayer *layer, int *ret_level ) { const DisplayLayerFuncs *funcs; D_ASSERT( layer != NULL ); D_ASSERT( layer->funcs != NULL ); D_ASSERT( ret_level != NULL ); funcs = layer->funcs; if (!funcs->GetLevel) return DFB_UNSUPPORTED; return funcs->GetLevel( layer, layer->driver_data, layer->layer_data, ret_level ); } DFBResult dfb_layer_set_level( CoreLayer *layer, int level ) { const DisplayLayerFuncs *funcs; D_ASSERT( layer != NULL ); D_ASSERT( layer->funcs != NULL ); funcs = layer->funcs; if (!funcs->SetLevel) return DFB_UNSUPPORTED; return funcs->SetLevel( layer, layer->driver_data, layer->layer_data, level ); } DFBResult dfb_layer_wait_vsync( CoreLayer *layer ) { D_ASSERT( layer != NULL ); D_ASSERT( layer->screen != NULL ); return dfb_screen_wait_vsync( layer->screen ); } DFBResult dfb_layer_get_source_info( CoreLayer *layer, int source, DFBDisplayLayerSourceDescription *ret_desc ) { D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( source >= 0 ); D_ASSERT( source < layer->shared->description.sources ); D_ASSERT( ret_desc != NULL ); *ret_desc = layer->shared->sources[source].description; return DFB_OK; }