summaryrefslogtreecommitdiff
path: root/Source/DirectFB/src/core/layer_control.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/src/core/layer_control.c')
-rwxr-xr-xSource/DirectFB/src/core/layer_control.c589
1 files changed, 589 insertions, 0 deletions
diff --git a/Source/DirectFB/src/core/layer_control.c b/Source/DirectFB/src/core/layer_control.c
new file mode 100755
index 0000000..b190cc5
--- /dev/null
+++ b/Source/DirectFB/src/core/layer_control.c
@@ -0,0 +1,589 @@
+/*
+ (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 <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <fusion/shmalloc.h>
+#include <fusion/arena.h>
+#include <fusion/property.h>
+
+#include <directfb.h>
+
+#include <core/core.h>
+#include <core/coredefs.h>
+#include <core/coretypes.h>
+
+#include <core/core_parts.h>
+
+#include <core/input.h>
+#include <core/gfxcard.h>
+#include <core/layer_context.h>
+#include <core/layer_control.h>
+#include <core/layer_region.h>
+#include <core/layers.h>
+#include <core/screen.h>
+#include <core/state.h>
+#include <core/palette.h>
+#include <core/system.h>
+#include <core/windows.h>
+
+#include <gfx/convert.h>
+#include <gfx/util.h>
+
+#include <misc/util.h>
+
+#include <direct/debug.h>
+#include <direct/mem.h>
+#include <direct/memcpy.h>
+#include <direct/messages.h>
+
+#include <core/layers_internal.h>
+
+
+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;
+}
+