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/layer_region.c | 1129 +++++++++++++++++++++++++++++++ 1 file changed, 1129 insertions(+) create mode 100755 Source/DirectFB/src/core/layer_region.c (limited to 'Source/DirectFB/src/core/layer_region.c') diff --git a/Source/DirectFB/src/core/layer_region.c b/Source/DirectFB/src/core/layer_region.c new file mode 100755 index 0000000..b96e742 --- /dev/null +++ b/Source/DirectFB/src/core/layer_region.c @@ -0,0 +1,1129 @@ +/* + (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 + + +D_DEBUG_DOMAIN( Core_Layers, "Core/Layers", "DirectFB Display Layer Core" ); + + +static DFBResult region_buffer_lock( CoreLayerRegion *region, + CoreSurface *surface, + CoreSurfaceBufferRole role ); + +static DFBResult set_region ( CoreLayerRegion *region, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags flags, + CoreSurface *surface ); + +static DFBResult realize_region ( CoreLayerRegion *region ); + +static DFBResult unrealize_region( CoreLayerRegion *region ); + +/******************************************************************************/ + +static void +region_destructor( FusionObject *object, bool zombie, void *ctx ) +{ + CoreLayerRegion *region = (CoreLayerRegion*) object; + CoreLayerContext *context = region->context; + CoreLayer *layer = dfb_layer_at( context->layer_id ); + CoreLayerShared *shared = layer->shared; + + D_DEBUG_AT( Core_Layers, "destroying region %p (%s, %dx%d, " + "%s, %s, %s, %s%s)\n", region, shared->description.name, + region->config.width, region->config.height, + D_FLAGS_IS_SET( region->state, + CLRSF_CONFIGURED ) ? "configured" : "unconfigured", + D_FLAGS_IS_SET( region->state, + CLRSF_ENABLED ) ? "enabled" : "disabled", + D_FLAGS_IS_SET( region->state, + CLRSF_ACTIVE ) ? "active" : "inactive", + D_FLAGS_IS_SET( region->state, + CLRSF_REALIZED ) ? "realized" : "not realized", + zombie ? " - ZOMBIE" : "" ); + + /* Hide region etc. */ + if (D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) + dfb_layer_region_disable( region ); + + /* Remove the region from the context. */ + dfb_layer_context_remove_region( region->context, region ); + + /* Throw away its surface. */ + if (region->surface) { + /* Detach the global listener. */ + dfb_surface_detach_global( region->surface, + ®ion->surface_reaction ); + + /* Unlink from structure. */ + dfb_surface_unlink( ®ion->surface ); + } + + /* Unlink the context from the structure. */ + dfb_layer_context_unlink( ®ion->context ); + + /* Free driver's region data. */ + if (region->region_data) + SHFREE( shared->shmpool, region->region_data ); + + /* Deinitialize the lock. */ + fusion_skirmish_destroy( ®ion->lock ); + + /* Destroy the object. */ + fusion_object_destroy( object ); +} + +/******************************************************************************/ + +FusionObjectPool * +dfb_layer_region_pool_create( const FusionWorld *world ) +{ + return fusion_object_pool_create( "Layer Region Pool", + sizeof(CoreLayerRegion), + sizeof(CoreLayerRegionNotification), + region_destructor, NULL, world ); +} + +/******************************************************************************/ + +DFBResult +dfb_layer_region_create( CoreLayerContext *context, + CoreLayerRegion **ret_region ) +{ + CoreLayer *layer; + CoreLayerRegion *region; + + D_ASSERT( context != NULL ); + D_ASSERT( ret_region != NULL ); + + layer = dfb_layer_at( context->layer_id ); + + /* Create the object. */ + region = dfb_core_create_layer_region( layer->core ); + if (!region) + return DFB_FUSION; + + /* Link the context into the structure. */ + if (dfb_layer_context_link( ®ion->context, context )) { + fusion_object_destroy( ®ion->object ); + return DFB_FUSION; + } + + /* Initialize the lock. */ + if (fusion_skirmish_init( ®ion->lock, "Layer Region", dfb_core_world(layer->core) )) { + dfb_layer_context_unlink( ®ion->context ); + fusion_object_destroy( ®ion->object ); + return DFB_FUSION; + } + + /* Change global reaction lock. */ + fusion_object_set_lock( ®ion->object, ®ion->lock ); + + region->state = CLRSF_FROZEN; + + /* Activate the object. */ + fusion_object_activate( ®ion->object ); + + /* Add the region to the context. */ + dfb_layer_context_add_region( context, region ); + + /* Return the new region. */ + *ret_region = region; + + return DFB_OK; +} + +DFBResult +dfb_layer_region_activate( CoreLayerRegion *region ) +{ + DFBResult ret; + + D_ASSERT( region != NULL ); + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + D_ASSUME( ! D_FLAGS_IS_SET( region->state, CLRSF_ACTIVE ) ); + + if (D_FLAGS_IS_SET( region->state, CLRSF_ACTIVE )) { + dfb_layer_region_unlock( region ); + return DFB_OK; + } + + /* Realize the region if it's enabled. */ + if (D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) { + ret = realize_region( region ); + if (ret) { + dfb_layer_region_unlock( region ); + return ret; + } + } + + /* Update the region's state. */ + D_FLAGS_SET( region->state, CLRSF_ACTIVE ); + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return DFB_OK; +} + +DFBResult +dfb_layer_region_deactivate( CoreLayerRegion *region ) +{ + DFBResult ret; + + D_ASSERT( region != NULL ); + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + D_ASSUME( D_FLAGS_IS_SET( region->state, CLRSF_ACTIVE ) ); + + if (! D_FLAGS_IS_SET( region->state, CLRSF_ACTIVE )) { + dfb_layer_region_unlock( region ); + return DFB_OK; + } + + /* Unrealize the region? */ + if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { + ret = unrealize_region( region ); + if (ret) + return ret; + } + + /* Update the region's state. */ + D_FLAGS_CLEAR( region->state, CLRSF_ACTIVE ); + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return DFB_OK; +} + +DFBResult +dfb_layer_region_enable( CoreLayerRegion *region ) +{ + DFBResult ret; + + D_ASSERT( region != NULL ); + D_ASSERT( region->context != NULL ); + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + D_ASSUME( ! D_FLAGS_IS_SET( region->state, CLRSF_ENABLED ) ); + + if (D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) { + dfb_layer_region_unlock( region ); + return DFB_OK; + } + + /* Realize the region if it's active. */ + if (D_FLAGS_IS_SET( region->state, CLRSF_ACTIVE )) { + ret = realize_region( region ); + if (ret) { + dfb_layer_region_unlock( region ); + return ret; + } + } + + /* Update the region's state. */ + D_FLAGS_SET( region->state, CLRSF_ENABLED ); + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return DFB_OK; +} + +DFBResult +dfb_layer_region_disable( CoreLayerRegion *region ) +{ + DFBResult ret; + + D_ASSERT( region != NULL ); + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + D_ASSUME( D_FLAGS_IS_SET( region->state, CLRSF_ENABLED ) ); + + if (! D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) { + dfb_layer_region_unlock( region ); + return DFB_OK; + } + + /* Unrealize the region? */ + if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { + ret = unrealize_region( region ); + if (ret) + return ret; + } + + /* Update the region's state. */ + D_FLAGS_CLEAR( region->state, CLRSF_ENABLED ); + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return DFB_OK; +} + +DFBResult +dfb_layer_region_set_surface( CoreLayerRegion *region, + CoreSurface *surface ) +{ + DFBResult ret; + + D_ASSERT( region != NULL ); + D_ASSERT( surface != NULL ); + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + if (region->surface != surface) { + /* Setup hardware for the new surface if the region is realized. */ + if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { + ret = set_region( region, ®ion->config, CLRCF_SURFACE | CLRCF_PALETTE, surface ); + if (ret) { + dfb_layer_region_unlock( region ); + return ret; + } + } + + /* Throw away the old surface. */ + if (region->surface) { + /* Detach the global listener. */ + dfb_surface_detach_global( region->surface, + ®ion->surface_reaction ); + + /* Unlink surface from structure. */ + dfb_surface_unlink( ®ion->surface ); + } + + /* Take the new surface. */ + if (surface) { + /* Link surface into structure. */ + if (dfb_surface_link( ®ion->surface, surface )) { + D_WARN( "region lost it's surface" ); + dfb_layer_region_unlock( region ); + return DFB_FUSION; + } + + /* Attach the global listener. */ + dfb_surface_attach_global( region->surface, + DFB_LAYER_REGION_SURFACE_LISTENER, + region, ®ion->surface_reaction ); + } + } + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return DFB_OK; +} + +DFBResult +dfb_layer_region_get_surface( CoreLayerRegion *region, + CoreSurface **ret_surface ) +{ + D_ASSERT( region != NULL ); + D_ASSERT( ret_surface != NULL ); + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + D_ASSUME( region->surface != NULL ); + + /* Check for NULL surface. */ + if (!region->surface) { + dfb_layer_region_unlock( region ); + return DFB_UNSUPPORTED; + } + + /* Increase the surface's reference counter. */ + if (dfb_surface_ref( region->surface )) { + dfb_layer_region_unlock( region ); + return DFB_FUSION; + } + + /* Return the surface. */ + *ret_surface = region->surface; + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return DFB_OK; +} + +DFBResult +dfb_layer_region_flip_update( CoreLayerRegion *region, + const DFBRegion *update, + DFBSurfaceFlipFlags flags ) +{ + DFBResult ret = DFB_OK; + DFBRegion unrotated; + DFBRegion rotated; + CoreLayer *layer; + CoreLayerContext *context; + CoreSurface *surface; + const DisplayLayerFuncs *funcs; + + if (update) + D_DEBUG_AT( Core_Layers, + "dfb_layer_region_flip_update( %p, %p, 0x%08x ) <- [%d, %d - %dx%d]\n", + region, update, flags, DFB_RECTANGLE_VALS_FROM_REGION( update ) ); + else + D_DEBUG_AT( Core_Layers, + "dfb_layer_region_flip_update( %p, %p, 0x%08x )\n", region, update, flags ); + + + D_ASSERT( region != NULL ); + D_ASSERT( region->context != NULL ); + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + D_ASSUME( region->surface != NULL ); + + /* Check for NULL surface. */ + if (!region->surface) { + D_DEBUG_AT( Core_Layers, " -> No surface => no update!\n" ); + dfb_layer_region_unlock( region ); + return DFB_UNSUPPORTED; + } + + context = region->context; + surface = region->surface; + layer = dfb_layer_at( context->layer_id ); + + D_ASSERT( layer->funcs != NULL ); + + funcs = layer->funcs; + + /* Unfreeze region? */ + if (D_FLAGS_IS_SET( region->state, CLRSF_FROZEN )) { + D_FLAGS_CLEAR( region->state, CLRSF_FROZEN ); + + if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { + ret = set_region( region, ®ion->config, CLRCF_ALL, surface ); + if (ret) + D_DERROR( ret, "Core/LayerRegion: set_region() in dfb_layer_region_flip_update() failed!\n" ); + } + else if (D_FLAGS_ARE_SET( region->state, CLRSF_ENABLED | CLRSF_ACTIVE )) { + ret = realize_region( region ); + if (ret) + D_DERROR( ret, "Core/LayerRegion: realize_region() in dfb_layer_region_flip_update() failed!\n" ); + } + + if (ret) { + dfb_layer_region_unlock( region ); + return ret; + } + } + + /* Depending on the buffer mode... */ + switch (region->config.buffermode) { + case DLBM_TRIPLE: + case DLBM_BACKVIDEO: + /* Check if simply swapping the buffers is possible... */ + if (!(flags & DSFLIP_BLIT) && !surface->rotation && + (!update || (update->x1 == 0 && + update->y1 == 0 && + update->x2 == surface->config.size.w - 1 && + update->y2 == surface->config.size.h - 1))) + { + D_DEBUG_AT( Core_Layers, " -> Going to swap buffers...\n" ); + + /* Use the driver's routine if the region is realized. */ + if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { + D_ASSUME( funcs->FlipRegion != NULL ); + + ret = region_buffer_lock( region, surface, CSBR_BACK ); + if (ret) { + dfb_layer_region_unlock( region ); + return ret; + } + + D_DEBUG_AT( Core_Layers, " -> Flipping region using driver...\n" ); + + if (funcs->FlipRegion) + ret = funcs->FlipRegion( layer, + layer->driver_data, + layer->layer_data, + region->region_data, + surface, flags, ®ion->surface_lock ); + + dfb_surface_unlock( surface ); + } + else { + D_DEBUG_AT( Core_Layers, " -> Flipping region not using driver...\n" ); + + /* Just do the hardware independent work. */ + dfb_surface_lock( surface ); + dfb_surface_flip( surface, false ); + dfb_surface_unlock( surface ); + } + break; + } + + /* fall through */ + + case DLBM_BACKSYSTEM: + D_DEBUG_AT( Core_Layers, " -> Going to copy portion...\n" ); + + if ((flags & DSFLIP_WAITFORSYNC) == DSFLIP_WAITFORSYNC) { + D_DEBUG_AT( Core_Layers, " -> Waiting for VSync...\n" ); + + dfb_layer_wait_vsync( layer ); + } + + D_DEBUG_AT( Core_Layers, " -> Copying content from back to front buffer...\n" ); + + /* ...or copy updated contents from back to front buffer. */ + dfb_back_to_front_copy_rotation( surface, update, surface->rotation ); + + if ((flags & DSFLIP_WAITFORSYNC) == DSFLIP_WAIT) { + D_DEBUG_AT( Core_Layers, " -> Waiting for VSync...\n" ); + + dfb_layer_wait_vsync( layer ); + } + + /* fall through */ + + case DLBM_FRONTONLY: + /* Tell the driver about the update if the region is realized. */ + if (funcs->UpdateRegion && D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { + if (surface) { + CoreSurfaceAllocation *allocation; + + allocation = region->surface_lock.allocation; + D_ASSERT( allocation != NULL ); + + /* If hardware has written or is writing... */ + if (allocation->accessed[CSAID_GPU] & CSAF_WRITE) { + D_DEBUG_AT( Core_Layers, " -> Waiting for pending writes...\n" ); + + /* ...wait for the operation to finish. */ + if (!(flags & DSFLIP_PIPELINE)) + dfb_gfxcard_sync(); /* TODO: wait for serial instead */ + + allocation->accessed[CSAID_GPU] &= ~CSAF_WRITE; + } + + dfb_surface_lock( surface ); + dfb_surface_allocation_update( allocation, CSAF_READ ); + dfb_surface_unlock( surface ); + } + + D_DEBUG_AT( Core_Layers, " -> Notifying driver about updated content...\n" ); + + if( !update ) { + unrotated = DFB_REGION_INIT_FROM_RECTANGLE_VALS( 0, 0, + region->config.width, region->config.height ); + update = &unrotated; + } + dfb_region_from_rotated( &rotated, update, &surface->config.size, surface->rotation ); + + ret = funcs->UpdateRegion( layer, + layer->driver_data, + layer->layer_data, + region->region_data, + surface, &rotated, ®ion->surface_lock ); + } + break; + + default: + D_BUG("unknown buffer mode"); + ret = DFB_BUG; + } + + D_DEBUG_AT( Core_Layers, " -> done.\n" ); + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return ret; +} + +DFBResult +dfb_layer_region_set_configuration( CoreLayerRegion *region, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags flags ) +{ + DFBResult ret; + CoreLayer *layer; + const DisplayLayerFuncs *funcs; + CoreLayerRegionConfig new_config; + + D_ASSERT( region != NULL ); + D_ASSERT( region->context != NULL ); + D_ASSERT( config != NULL ); + D_ASSERT( config->buffermode != DLBM_WINDOWS ); + D_ASSERT( (flags == CLRCF_ALL) || (region->state & CLRSF_CONFIGURED) ); + + D_ASSUME( flags != CLRCF_NONE ); + D_ASSUME( ! (flags & ~CLRCF_ALL) ); + + layer = dfb_layer_at( region->context->layer_id ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->funcs != NULL ); + D_ASSERT( layer->funcs->TestRegion != NULL ); + + funcs = layer->funcs; + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + /* Full configuration supplied? */ + if (flags == CLRCF_ALL) { + new_config = *config; + } + else { + /* Use the current configuration. */ + new_config = region->config; + + /* Update each modified entry. */ + if (flags & CLRCF_WIDTH) + new_config.width = config->width; + + if (flags & CLRCF_HEIGHT) + new_config.height = config->height; + + if (flags & CLRCF_FORMAT) + new_config.format = config->format; + + if (flags & CLRCF_SURFACE_CAPS) + new_config.surface_caps = config->surface_caps; + + if (flags & CLRCF_BUFFERMODE) + new_config.buffermode = config->buffermode; + + if (flags & CLRCF_OPTIONS) + new_config.options = config->options; + + if (flags & CLRCF_SOURCE_ID) + new_config.source_id = config->source_id; + + if (flags & CLRCF_SOURCE) + new_config.source = config->source; + + if (flags & CLRCF_DEST) + new_config.dest = config->dest; + + if (flags & CLRCF_OPACITY) + new_config.opacity = config->opacity; + + if (flags & CLRCF_ALPHA_RAMP) { + new_config.alpha_ramp[0] = config->alpha_ramp[0]; + new_config.alpha_ramp[1] = config->alpha_ramp[1]; + new_config.alpha_ramp[2] = config->alpha_ramp[2]; + new_config.alpha_ramp[3] = config->alpha_ramp[3]; + } + + if (flags & CLRCF_SRCKEY) + new_config.src_key = config->src_key; + + if (flags & CLRCF_DSTKEY) + new_config.dst_key = config->dst_key; + + if (flags & CLRCF_PARITY) + new_config.parity = config->parity; + + if (flags & CLRCF_CLIPS) { + new_config.clips = config->clips; + new_config.num_clips = config->num_clips; + new_config.positive = config->positive; + } + } + + /* Check if the new configuration is supported. */ + ret = funcs->TestRegion( layer, layer->driver_data, layer->layer_data, + &new_config, NULL ); + if (ret) { + dfb_layer_region_unlock( region ); + return ret; + } + + /* Check if the region should be frozen, thus requiring to apply changes explicitly. */ + if (flags & CLRCF_FREEZE) + region->state |= CLRSF_FROZEN; + + /* Propagate new configuration to the driver if the region is realized. */ + if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { + ret = set_region( region, &new_config, flags, region->surface ); + if (ret) { + dfb_layer_region_unlock( region ); + return ret; + } + } + + /* Update the region's current configuration. */ + region->config = new_config; + + /* Update the region's state. */ + D_FLAGS_SET( region->state, CLRSF_CONFIGURED ); + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return DFB_OK; +} + +DFBResult +dfb_layer_region_get_configuration( CoreLayerRegion *region, + CoreLayerRegionConfig *config ) +{ + D_ASSERT( region != NULL ); + D_ASSERT( config != NULL ); + + D_ASSERT( D_FLAGS_IS_SET( region->state, CLRSF_CONFIGURED ) ); + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + /* Return the current configuration. */ + *config = region->config; + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return DFB_OK; +} + +DirectResult +dfb_layer_region_lock( CoreLayerRegion *region ) +{ + D_ASSERT( region != NULL ); + + return fusion_skirmish_prevail( ®ion->lock ); +} + +DirectResult +dfb_layer_region_unlock( CoreLayerRegion *region ) +{ + D_ASSERT( region != NULL ); + + return fusion_skirmish_dismiss( ®ion->lock ); +} + +/******************************************************************************/ + +/* + * listen to the layer's surface + */ +ReactionResult +_dfb_layer_region_surface_listener( const void *msg_data, void *ctx ) +{ + CoreSurfaceNotificationFlags flags; + CoreSurface *surface; + CoreLayer *layer; + CoreLayerShared *shared; + const DisplayLayerFuncs *funcs; + const CoreSurfaceNotification *notification = msg_data; + CoreLayerRegion *region = ctx; + + D_ASSERT( notification != NULL ); + D_ASSERT( region != NULL ); + D_ASSERT( region->context != NULL ); + + D_DEBUG_AT( Core_Layers, "_dfb_layer_region_surface_listener( %p, %p ) <- 0x%08x\n", + notification, region, notification->flags ); + + D_ASSERT( notification->surface != NULL ); + + D_ASSUME( notification->surface == region->surface ); + + if (notification->surface != region->surface) + return RS_OK; + + layer = dfb_layer_at( region->context->layer_id ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->funcs != NULL ); + D_ASSERT( layer->funcs->SetRegion != NULL ); + D_ASSERT( layer->shared != NULL ); + + funcs = layer->funcs; + shared = layer->shared; + + flags = notification->flags; + surface = notification->surface; + + if (flags & CSNF_DESTROY) { + D_WARN( "layer region surface destroyed" ); + region->surface = NULL; + return RS_REMOVE; + } + + if (dfb_layer_region_lock( region )) + return RS_OK; + + if (D_FLAGS_ARE_SET( region->state, CLRSF_REALIZED | CLRSF_CONFIGURED ) && + !D_FLAGS_IS_SET( region->state, CLRSF_FROZEN )) + { + if (D_FLAGS_IS_SET( flags, CSNF_PALETTE_CHANGE | CSNF_PALETTE_UPDATE )) { + if (surface->palette) + funcs->SetRegion( layer, + layer->driver_data, layer->layer_data, + region->region_data, ®ion->config, + CLRCF_PALETTE, surface, surface->palette, + ®ion->surface_lock ); + } + + if ((flags & CSNF_FIELD) && funcs->SetInputField) + funcs->SetInputField( layer, + layer->driver_data, layer->layer_data, + region->region_data, surface->field ); + + if ((flags & CSNF_ALPHA_RAMP) && (shared->description.caps & DLCAPS_ALPHA_RAMP)) { + region->config.alpha_ramp[0] = surface->alpha_ramp[0]; + region->config.alpha_ramp[1] = surface->alpha_ramp[1]; + region->config.alpha_ramp[2] = surface->alpha_ramp[2]; + region->config.alpha_ramp[3] = surface->alpha_ramp[3]; + + funcs->SetRegion( layer, + layer->driver_data, layer->layer_data, + region->region_data, ®ion->config, + CLRCF_ALPHA_RAMP, surface, surface->palette, + ®ion->surface_lock ); + } + } + + dfb_layer_region_unlock( region ); + + return RS_OK; +} + +/******************************************************************************/ + +static DFBResult +region_buffer_lock( CoreLayerRegion *region, + CoreSurface *surface, + CoreSurfaceBufferRole role ) +{ + DFBResult ret; + CoreSurfaceBuffer *buffer; + CoreSurfaceAllocation *allocation; + CoreLayerContext *context; + + D_ASSERT( region != NULL ); + D_MAGIC_ASSERT( surface, CoreSurface ); + + context = region->context; + D_MAGIC_ASSERT( context, CoreLayerContext ); + + /* First unlock any previously locked buffer. */ + if (region->surface_lock.buffer) { + D_MAGIC_ASSERT( region->surface_lock.buffer, CoreSurfaceBuffer ); + + dfb_surface_unlock_buffer( region->surface_lock.buffer->surface, ®ion->surface_lock ); + } + + if (dfb_surface_lock( surface )) + return DFB_FUSION; + + buffer = dfb_surface_get_buffer( surface, role ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + /* Lock the surface buffer. */ + ret = dfb_surface_buffer_lock( buffer, CSAID_LAYER0 + context->layer_id, CSAF_READ, ®ion->surface_lock ); + if (ret) { + D_DERROR( ret, "Core/LayerRegion: Could not lock region surface for SetRegion()!\n" ); + dfb_surface_unlock( surface ); + return ret; + } + + allocation = region->surface_lock.allocation; + D_ASSERT( allocation != NULL ); + + /* If hardware has written or is writing... */ + if (allocation->accessed[CSAID_GPU] & CSAF_WRITE) { + D_DEBUG_AT( Core_Layers, " -> Waiting for pending writes...\n" ); + + /* ...wait for the operation to finish. */ + dfb_gfxcard_sync(); /* TODO: wait for serial instead */ + + allocation->accessed[CSAID_GPU] &= ~CSAF_WRITE; + } + + /* surface is unlocked by caller */ + + return DFB_OK; +} + +static DFBResult +set_region( CoreLayerRegion *region, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags flags, + CoreSurface *surface ) +{ + DFBResult ret; + CoreLayer *layer; + CoreLayerShared *shared; + const DisplayLayerFuncs *funcs; + + D_DEBUG_AT( Core_Layers, "%s( %p, %p, 0x%08x, %p )\n", __FUNCTION__, region, config, flags, surface ); + + DFB_CORE_LAYER_REGION_CONFIG_DEBUG_AT( Core_Layers, config ); + + D_DEBUG_AT( Core_Layers, " -> state 0x%08x\n", region->state ); + + D_ASSERT( region != NULL ); + D_ASSERT( region->context != NULL ); + D_ASSERT( config != NULL ); + D_ASSERT( config->buffermode != DLBM_WINDOWS ); + + D_ASSERT( D_FLAGS_IS_SET( region->state, CLRSF_REALIZED ) ); + + layer = dfb_layer_at( region->context->layer_id ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( layer->funcs != NULL ); + D_ASSERT( layer->funcs->SetRegion != NULL ); + + if (region->state & CLRSF_FROZEN) { + D_DEBUG_AT( Core_Layers, " -> FROZEN!\n" ); + return DFB_OK; + } + + shared = layer->shared; + funcs = layer->funcs; + + if (surface) { + if (flags & (CLRCF_SURFACE | CLRCF_WIDTH | CLRCF_HEIGHT | CLRCF_FORMAT)) { + ret = region_buffer_lock( region, surface, CSBR_FRONT ); + if (ret) + return ret; + + dfb_surface_unlock( surface ); + } + + D_ASSERT( region->surface_lock.buffer != NULL ); + } + else if (region->surface_lock.buffer) { + D_MAGIC_ASSERT( region->surface_lock.buffer, CoreSurfaceBuffer ); + + dfb_surface_unlock_buffer( region->surface_lock.buffer->surface, ®ion->surface_lock ); + } + + D_DEBUG_AT( Core_Layers, " => setting region of '%s'\n", shared->description.name ); + + /* Setup hardware. */ + return funcs->SetRegion( layer, layer->driver_data, layer->layer_data, + region->region_data, config, flags, + surface, surface ? surface->palette : NULL, ®ion->surface_lock ); +} + +static DFBResult +realize_region( CoreLayerRegion *region ) +{ + DFBResult ret; + CoreLayer *layer; + CoreLayerShared *shared; + const DisplayLayerFuncs *funcs; + + D_DEBUG_AT( Core_Layers, "%s( %p )\n", __FUNCTION__, region ); + + D_ASSERT( region != NULL ); + + DFB_CORE_LAYER_REGION_CONFIG_DEBUG_AT( Core_Layers, ®ion->config ); + + D_DEBUG_AT( Core_Layers, " -> state 0x%08x\n", region->state ); + + D_ASSERT( region->context != NULL ); + D_ASSERT( D_FLAGS_IS_SET( region->state, CLRSF_CONFIGURED ) ); + D_ASSERT( ! D_FLAGS_IS_SET( region->state, CLRSF_REALIZED ) ); + + layer = dfb_layer_at( region->context->layer_id ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( layer->funcs != NULL ); + + shared = layer->shared; + funcs = layer->funcs; + + D_ASSERT( ! fusion_vector_contains( &shared->added_regions, region ) ); + + if (region->state & CLRSF_FROZEN) { + D_DEBUG_AT( Core_Layers, " -> FROZEN!\n" ); + return DFB_OK; + } + + /* Allocate the driver's region data. */ + if (funcs->RegionDataSize) { + int size = funcs->RegionDataSize(); + + if (size > 0) { + region->region_data = SHCALLOC( shared->shmpool, 1, size ); + if (!region->region_data) + return D_OOSHM(); + } + } + + D_DEBUG_AT( Core_Layers, " => adding region to '%s'\n", shared->description.name ); + + /* Add the region to the driver. */ + if (funcs->AddRegion) { + ret = funcs->AddRegion( layer, + layer->driver_data, layer->layer_data, + region->region_data, ®ion->config ); + if (ret) { + D_DERROR( ret, "Core/Layers: Could not add region!\n" ); + + if (region->region_data) { + SHFREE( shared->shmpool, region->region_data ); + region->region_data = NULL; + } + + return ret; + } + } + + /* Add the region to the 'added' list. */ + fusion_vector_add( &shared->added_regions, region ); + + /* Update the region's state. */ + D_FLAGS_SET( region->state, CLRSF_REALIZED ); + + /* Initially setup hardware. */ + ret = set_region( region, ®ion->config, CLRCF_ALL, region->surface ); + if (ret) { + unrealize_region( region ); + return ret; + } + + return DFB_OK; +} + +static DFBResult +unrealize_region( CoreLayerRegion *region ) +{ + DFBResult ret; + int index; + CoreLayer *layer; + CoreLayerShared *shared; + const DisplayLayerFuncs *funcs; + + D_DEBUG_AT( Core_Layers, "%s( %p )\n", __FUNCTION__, region ); + + D_ASSERT( region != NULL ); + + DFB_CORE_LAYER_REGION_CONFIG_DEBUG_AT( Core_Layers, ®ion->config ); + + D_DEBUG_AT( Core_Layers, " -> state 0x%08x\n", region->state ); + + D_ASSERT( region->context != NULL ); + D_ASSERT( D_FLAGS_IS_SET( region->state, CLRSF_REALIZED ) ); + + layer = dfb_layer_at( region->context->layer_id ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( layer->funcs != NULL ); + + shared = layer->shared; + funcs = layer->funcs; + + D_ASSERT( fusion_vector_contains( &shared->added_regions, region ) ); + + index = fusion_vector_index_of( &shared->added_regions, region ); + + D_DEBUG_AT( Core_Layers, " => removing region from '%s'\n", shared->description.name ); + + /* Remove the region from hardware and driver. */ + if (funcs->RemoveRegion) { + ret = funcs->RemoveRegion( layer, layer->driver_data, + layer->layer_data, region->region_data ); + if (ret) { + D_DERROR( ret, "Core/Layers: Could not remove region!\n" ); + return ret; + } + } + + /* Remove the region from the 'added' list. */ + fusion_vector_remove( &shared->added_regions, index ); + + /* Deallocate the driver's region data. */ + if (region->region_data) { + SHFREE( shared->shmpool, region->region_data ); + region->region_data = NULL; + } + + /* Update the region's state. */ + D_FLAGS_CLEAR( region->state, CLRSF_REALIZED ); + D_FLAGS_SET( region->state, CLRSF_FROZEN ); + + if (region->surface && region->surface_lock.buffer) { + dfb_surface_unlock_buffer( region->surface, ®ion->surface_lock ); + // PR brg36mgr#147044: [550r3cr1][CRASH][UI]set crashes when going through settings assistant + // This is because the YUV layer buffer is allocated in memory recuperated from the video flow + // and is only valid in the JPEG usecase. + // When the application destroys its window (on leaving the usecase),the layer buffer must + // also be removed. + dfb_surface_destroy_buffers( region->surface ); + } + + return DFB_OK; +} + -- cgit