1 /*
2    (c) Copyright 2001-2009  The world wide DirectFB Open Source Community (directfb.org)
3    (c) Copyright 2000-2004  Convergence (integrated media) GmbH
4 
5    All rights reserved.
6 
7    Written by Denis Oliver Kropp <dok@directfb.org>,
8               Andreas Hundt <andi@fischlustig.de>,
9               Sven Neumann <neo@directfb.org>,
10               Ville Syrjälä <syrjala@sci.fi> and
11               Claudio Ciccani <klan@users.sf.net>.
12 
13    This library is free software; you can redistribute it and/or
14    modify it under the terms of the GNU Lesser General Public
15    License as published by the Free Software Foundation; either
16    version 2 of the License, or (at your option) any later version.
17 
18    This library is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    Lesser General Public License for more details.
22 
23    You should have received a copy of the GNU Lesser General Public
24    License along with this library; if not, write to the
25    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26    Boston, MA 02111-1307, USA.
27 */
28 
29 #include <config.h>
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <errno.h>
35 
36 #include <directfb.h>
37 
38 #include <direct/debug.h>
39 #include <direct/mem.h>
40 #include <direct/memcpy.h>
41 #include <direct/messages.h>
42 
43 #include <fusion/shmalloc.h>
44 #include <fusion/arena.h>
45 #include <fusion/property.h>
46 
47 #include <core/CoreLayer.h>
48 
49 #include <core/core.h>
50 #include <core/coredefs.h>
51 #include <core/coretypes.h>
52 
53 #include <core/core_parts.h>
54 
55 #include <core/input.h>
56 #include <core/gfxcard.h>
57 #include <core/layer_context.h>
58 #include <core/layer_control.h>
59 #include <core/layer_region.h>
60 #include <core/layers.h>
61 #include <core/state.h>
62 #include <core/palette.h>
63 #include <core/system.h>
64 #include <core/windows.h>
65 
66 #include <gfx/convert.h>
67 #include <gfx/util.h>
68 
69 #include <misc/conf.h>
70 #include <misc/util.h>
71 
72 #include <core/layers_internal.h>
73 #include <core/screens_internal.h>
74 
75 
76 D_DEBUG_DOMAIN( Core_Layer, "Core/Layer", "DirectFB Display Layer Core" );
77 
78 /**********************************************************************************************************************/
79 
80 typedef struct {
81      int               magic;
82 
83      int               num;
84      CoreLayerShared  *layers[MAX_LAYERS];
85 } DFBLayerCoreShared;
86 
87 struct __DFB_DFBLayerCore {
88      int                 magic;
89 
90      CoreDFB            *core;
91 
92      DFBLayerCoreShared *shared;
93 };
94 
95 
96 DFB_CORE_PART( layer_core, LayerCore );
97 
98 /**********************************************************************************************************************/
99 
100 static int           dfb_num_layers;
101 static CoreLayer    *dfb_layers[MAX_LAYERS];
102 
103 /** FIXME: Add proper error paths! **/
104 
105 static DFBResult
dfb_layer_core_initialize(CoreDFB * core,DFBLayerCore * data,DFBLayerCoreShared * shared)106 dfb_layer_core_initialize( CoreDFB            *core,
107                            DFBLayerCore       *data,
108                            DFBLayerCoreShared *shared )
109 {
110      int                  i;
111      DFBResult            ret;
112      FusionSHMPoolShared *pool;
113 
114      D_DEBUG_AT( Core_Layer, "dfb_layer_core_initialize( %p, %p, %p )\n", core, data, shared );
115 
116      D_ASSERT( data != NULL );
117      D_ASSERT( shared != NULL );
118 
119      data->core   = core;
120      data->shared = shared;
121 
122 
123      pool = dfb_core_shmpool( core );
124 
125      /* Initialize all registered layers. */
126      for (i=0; i<dfb_num_layers; i++) {
127           char                     buf[24];
128           CoreLayerShared         *lshared;
129           CoreLayer               *layer = dfb_layers[i];
130           const DisplayLayerFuncs *funcs = layer->funcs;
131 
132           /* Allocate shared data. */
133           lshared = SHCALLOC( pool, 1, sizeof(CoreLayerShared) );
134 
135           /* Assign ID (zero based index). */
136           lshared->layer_id = i;
137           lshared->shmpool  = pool;
138 
139           snprintf( buf, sizeof(buf), "Display Layer %d", i );
140 
141           /* Initialize the lock. */
142           ret = fusion_skirmish_init( &lshared->lock, buf, dfb_core_world(core) );
143           if (ret)
144                return ret;
145 
146           /* Allocate driver's layer data. */
147           if (funcs->LayerDataSize) {
148                int size = funcs->LayerDataSize();
149 
150                if (size > 0) {
151                     lshared->layer_data = SHCALLOC( pool, 1, size );
152                     if (!lshared->layer_data)
153                          return D_OOSHM();
154                }
155           }
156 
157           /* Initialize the layer, get the layer description,
158              the default configuration and default color adjustment. */
159           ret = funcs->InitLayer( layer,
160                                   layer->driver_data,
161                                   lshared->layer_data,
162                                   &lshared->description,
163                                   &lshared->default_config,
164                                   &lshared->default_adjustment );
165           if (ret) {
166                D_DERROR( ret, "DirectFB/Core/layers: "
167                          "Failed to initialize layer %d!\n", lshared->layer_id );
168                return ret;
169           }
170 
171           if (lshared->description.caps & DLCAPS_SOURCES) {
172                int n;
173 
174                lshared->sources = SHCALLOC( pool, lshared->description.sources, sizeof(CoreLayerSource) );
175                if (!lshared->sources)
176                     return D_OOSHM();
177 
178                for (n=0; n<lshared->description.sources; n++) {
179                     CoreLayerSource *source = &lshared->sources[n];
180 
181                     source->index = n;
182 
183                     ret = funcs->InitSource( layer, layer->driver_data,
184                                              lshared->layer_data, n, &source->description );
185                     if (ret) {
186                          D_DERROR( ret, "DirectFB/Core/layers: Failed to initialize source %d "
187                                    "of layer %d!\n", n, lshared->layer_id );
188                          return ret;
189                     }
190                }
191           }
192 
193           if (D_FLAGS_IS_SET( lshared->description.caps, DLCAPS_SCREEN_LOCATION ))
194                D_FLAGS_SET( lshared->description.caps, DLCAPS_SCREEN_POSITION | DLCAPS_SCREEN_SIZE );
195 
196           if (D_FLAGS_ARE_SET( lshared->description.caps,
197                                DLCAPS_SCREEN_POSITION | DLCAPS_SCREEN_SIZE ))
198                D_FLAGS_SET( lshared->description.caps, DLCAPS_SCREEN_LOCATION );
199 
200           /* Initialize the vector for the contexts. */
201           fusion_vector_init( &lshared->contexts.stack, 4, pool );
202 
203           /* Initialize the vector for realized (added) regions. */
204           fusion_vector_init( &lshared->added_regions, 4, pool );
205 
206           /* No active context by default. */
207           lshared->contexts.active = -1;
208 
209           /* Store layer data. */
210           layer->layer_data = lshared->layer_data;
211 
212           /* Store pointer to shared data and core. */
213           layer->shared = lshared;
214           layer->core   = core;
215 
216           CoreLayer_Init_Dispatch( core, layer, &lshared->call );
217 
218           fusion_call_add_permissions( &lshared->call, 0, FUSION_CALL_PERMIT_EXECUTE );
219 
220           /* Add the layer to the shared list. */
221           shared->layers[ shared->num++ ] = lshared;
222      }
223 
224 
225      D_MAGIC_SET( data, DFBLayerCore );
226      D_MAGIC_SET( shared, DFBLayerCoreShared );
227 
228      return DFB_OK;
229 }
230 
231 static DFBResult
dfb_layer_core_join(CoreDFB * core,DFBLayerCore * data,DFBLayerCoreShared * shared)232 dfb_layer_core_join( CoreDFB            *core,
233                      DFBLayerCore       *data,
234                      DFBLayerCoreShared *shared )
235 {
236      int i;
237 
238      D_DEBUG_AT( Core_Layer, "dfb_layer_core_join( %p, %p, %p )\n", core, data, shared );
239 
240      D_ASSERT( data != NULL );
241      D_MAGIC_ASSERT( shared, DFBLayerCoreShared );
242 
243      data->core   = core;
244      data->shared = shared;
245 
246 
247      if (dfb_num_layers != shared->num) {
248           D_ERROR("DirectFB/core/layers: Number of layers does not match!\n");
249           return DFB_BUG;
250      }
251 
252      for (i=0; i<dfb_num_layers; i++) {
253           CoreLayer       *layer   = dfb_layers[i];
254           CoreLayerShared *lshared = shared->layers[i];
255 
256           /* make a copy for faster access */
257           layer->layer_data = lshared->layer_data;
258 
259           /* store pointer to shared data and core */
260           layer->shared = lshared;
261           layer->core   = core;
262      }
263 
264 
265      D_MAGIC_SET( data, DFBLayerCore );
266 
267      return DFB_OK;
268 }
269 
270 static DFBResult
dfb_layer_core_shutdown(DFBLayerCore * data,bool emergency)271 dfb_layer_core_shutdown( DFBLayerCore *data,
272                          bool          emergency )
273 {
274      int                 i;
275      DFBResult           ret;
276      DFBLayerCoreShared *shared;
277 
278      D_DEBUG_AT( Core_Layer, "dfb_layer_core_shutdown( %p, %semergency )\n", data, emergency ? "" : "no " );
279 
280      D_MAGIC_ASSERT( data, DFBLayerCore );
281      D_MAGIC_ASSERT( data->shared, DFBLayerCoreShared );
282 
283      shared = data->shared;
284 
285 
286      /* Begin with the most recently added layer. */
287      for (i=dfb_num_layers-1; i>=0; i--) {
288           CoreLayer               *layer  = dfb_layers[i];
289           CoreLayerShared         *shared = layer->shared;
290           const DisplayLayerFuncs *funcs  = layer->funcs;
291 
292           D_ASSUME( emergency || fusion_vector_is_empty( &shared->added_regions ) );
293 
294           /* Remove all regions during emergency shutdown. */
295           if (emergency && funcs->RemoveRegion) {
296                int              n;
297                CoreLayerRegion *region;
298 
299                fusion_vector_foreach( region, n, shared->added_regions ) {
300                    D_DEBUG_AT( Core_Layer, "Removing region (%d, %d - %dx%d) from '%s'.\n",
301                                DFB_RECTANGLE_VALS( &region->config.dest ),
302                                shared->description.name );
303 
304                    ret = funcs->RemoveRegion( layer, layer->driver_data,
305                                               layer->layer_data, region->region_data );
306                    if (ret)
307                         D_DERROR( ret, "Core/Layers: Could not remove region!\n" );
308                }
309           }
310 
311           /* Shut the layer down. */
312           if (funcs->ShutdownLayer) {
313                ret = funcs->ShutdownLayer( layer,
314                                            layer->driver_data,
315                                            shared->layer_data );
316                if (ret)
317                     D_DERROR( ret, "DirectFB/Core/layers: "
318                                    "Failed to shutdown layer %d!\n", shared->layer_id );
319           }
320 
321           CoreLayer_Deinit_Dispatch( &shared->call );
322 
323           /* Deinitialize the lock. */
324           fusion_skirmish_destroy( &shared->lock );
325 
326           /* Deinitialize the state for window stack repaints. */
327           dfb_state_destroy( &layer->state );
328 
329           /* Deinitialize the vector for the contexts. */
330           fusion_vector_destroy( &shared->contexts.stack );
331 
332           /* Deinitialize the vector for the realized (added) regions. */
333           fusion_vector_destroy( &shared->added_regions );
334 
335           /* Free the driver's layer data. */
336           if (shared->layer_data)
337                SHFREE( shared->shmpool, shared->layer_data );
338 
339           /* Free the shared layer data. */
340           SHFREE( shared->shmpool, shared );
341 
342           /* Free the local layer data. */
343           D_FREE( layer );
344      }
345 
346      dfb_num_layers = 0;
347 
348 
349      D_MAGIC_CLEAR( data );
350      D_MAGIC_CLEAR( shared );
351 
352      return DFB_OK;
353 }
354 
355 static DFBResult
dfb_layer_core_leave(DFBLayerCore * data,bool emergency)356 dfb_layer_core_leave( DFBLayerCore *data,
357                       bool          emergency )
358 {
359      int                 i;
360      DFBLayerCoreShared *shared;
361 
362      D_DEBUG_AT( Core_Layer, "dfb_layer_core_leave( %p, %semergency )\n", data, emergency ? "" : "no " );
363 
364      D_MAGIC_ASSERT( data, DFBLayerCore );
365      D_MAGIC_ASSERT( data->shared, DFBLayerCoreShared );
366 
367      shared = data->shared;
368 
369 
370      /* Deinitialize all local stuff. */
371      for (i=0; i<dfb_num_layers; i++) {
372           CoreLayer *layer = dfb_layers[i];
373 
374           /* Deinitialize the state for window stack repaints. */
375           dfb_state_destroy( &layer->state );
376 
377           /* Free local layer data. */
378           D_FREE( layer );
379      }
380 
381      dfb_num_layers = 0;
382 
383 
384      D_MAGIC_CLEAR( data );
385 
386      return DFB_OK;
387 }
388 
389 static DFBResult
dfb_layer_core_suspend(DFBLayerCore * data)390 dfb_layer_core_suspend( DFBLayerCore *data )
391 {
392      int                 i;
393      DFBLayerCoreShared *shared;
394 
395      D_DEBUG_AT( Core_Layer, "dfb_layer_core_suspend( %p )\n", data );
396 
397      D_MAGIC_ASSERT( data, DFBLayerCore );
398      D_MAGIC_ASSERT( data->shared, DFBLayerCoreShared );
399 
400      shared = data->shared;
401 
402      for (i=dfb_num_layers-1; i>=0; i--)
403           dfb_layer_suspend( dfb_layers[i] );
404 
405      return DFB_OK;
406 }
407 
408 static DFBResult
dfb_layer_core_resume(DFBLayerCore * data)409 dfb_layer_core_resume( DFBLayerCore *data )
410 {
411      int                 i;
412      DFBLayerCoreShared *shared;
413 
414      D_DEBUG_AT( Core_Layer, "dfb_layer_core_resume( %p )\n", data );
415 
416      D_MAGIC_ASSERT( data, DFBLayerCore );
417      D_MAGIC_ASSERT( data->shared, DFBLayerCoreShared );
418 
419      shared = data->shared;
420 
421      for (i=0; i<dfb_num_layers; i++)
422           dfb_layer_resume( dfb_layers[i] );
423 
424      return DFB_OK;
425 }
426 
427 /**********************************************************************************************************************/
428 
429 CoreLayer *
dfb_layers_register(CoreScreen * screen,void * driver_data,const DisplayLayerFuncs * funcs)430 dfb_layers_register( CoreScreen              *screen,
431                      void                    *driver_data,
432                      const DisplayLayerFuncs *funcs )
433 {
434      CoreLayer *layer;
435 
436      D_ASSERT( screen != NULL );
437      D_ASSERT( funcs != NULL );
438 
439      if (dfb_num_layers == MAX_LAYERS) {
440           D_ERROR( "DirectFB/Core/Layers: "
441                     "Maximum number of layers reached!\n" );
442           return NULL;
443      }
444 
445      /* allocate local data */
446      layer = D_CALLOC( 1, sizeof(CoreLayer) );
447 
448      /* assign local pointers */
449      layer->device      = screen->device;
450      layer->screen      = screen;
451      layer->driver_data = driver_data;
452      layer->funcs       = funcs;
453 
454      /* Initialize the state for window stack repaints */
455      dfb_state_init( &layer->state, NULL );
456 
457      /* add it to the local list */
458      dfb_layers[dfb_num_layers++] = layer;
459 
460      return layer;
461 }
462 
463 typedef void (*AnyFunc)( void );
464 
465 CoreLayer *
dfb_layers_hook_primary(CoreGraphicsDevice * device,void * driver_data,DisplayLayerFuncs * funcs,DisplayLayerFuncs * primary_funcs,void ** primary_driver_data)466 dfb_layers_hook_primary( CoreGraphicsDevice *device,
467                          void               *driver_data,
468                          DisplayLayerFuncs  *funcs,
469                          DisplayLayerFuncs  *primary_funcs,
470                          void              **primary_driver_data )
471 {
472      int        i;
473      int        entries;
474      CoreLayer *primary = dfb_layers[0];
475 
476      D_ASSERT( primary != NULL );
477      D_ASSERT( device != NULL );
478      D_ASSERT( funcs != NULL );
479 
480      /* copy content of original function table */
481      if (primary_funcs)
482           direct_memcpy( primary_funcs, primary->funcs, sizeof(DisplayLayerFuncs) );
483 
484      /* copy pointer to original driver data */
485      if (primary_driver_data)
486           *primary_driver_data = primary->driver_data;
487 
488      /* replace all entries in the old table that aren't NULL in the new one */
489      entries = sizeof(DisplayLayerFuncs) / sizeof(void(*)( void ));
490      for (i=0; i<entries; i++) {
491           AnyFunc *newfuncs = (AnyFunc*) funcs;
492           AnyFunc *oldfuncs = (AnyFunc*) primary->funcs;
493 
494           if (newfuncs[i])
495                oldfuncs[i] = newfuncs[i];
496      }
497 
498      /* replace device and driver data pointer */
499      primary->device      = device;
500      primary->driver_data = driver_data;
501 
502      return primary;
503 }
504 
505 CoreLayer *
dfb_layers_replace_primary(CoreGraphicsDevice * device,void * driver_data,DisplayLayerFuncs * funcs)506 dfb_layers_replace_primary( CoreGraphicsDevice *device,
507                             void               *driver_data,
508                             DisplayLayerFuncs  *funcs )
509 {
510      CoreLayer *primary = dfb_layers[0];
511 
512      D_ASSERT( primary != NULL );
513      D_ASSERT( device != NULL );
514      D_ASSERT( funcs != NULL );
515 
516      /* replace device, function table and driver data pointer */
517      primary->device      = device;
518      primary->funcs       = funcs;
519      primary->driver_data = driver_data;
520 
521      return primary;
522 }
523 
524 void
dfb_layers_enumerate(DisplayLayerCallback callback,void * ctx)525 dfb_layers_enumerate( DisplayLayerCallback  callback,
526                       void                 *ctx )
527 {
528      int i;
529 
530      D_ASSERT( callback != NULL );
531 
532      for (i=0; i<dfb_num_layers; i++) {
533           if (callback( dfb_layers[i], ctx ) == DFENUM_CANCEL)
534                break;
535      }
536 }
537 
538 int
dfb_layer_num(void)539 dfb_layer_num( void )
540 {
541      return dfb_num_layers;
542 }
543 
544 CoreLayer *
dfb_layer_at(DFBDisplayLayerID id)545 dfb_layer_at( DFBDisplayLayerID id )
546 {
547      D_ASSERT( id >= 0);
548      D_ASSERT( id < dfb_num_layers);
549 
550      return dfb_layers[id];
551 }
552 
553 CoreLayer *
dfb_layer_at_translated(DFBDisplayLayerID id)554 dfb_layer_at_translated( DFBDisplayLayerID id )
555 {
556      D_ASSERT( id >= 0);
557      D_ASSERT( id < dfb_num_layers);
558      D_ASSERT( dfb_config != NULL );
559 
560      if (dfb_config->primary_layer > 0 &&
561          dfb_config->primary_layer < dfb_num_layers)
562      {
563           if (id == DLID_PRIMARY)
564                return dfb_layer_at( dfb_config->primary_layer );
565 
566           if (id == dfb_config->primary_layer)
567                return dfb_layer_at( DLID_PRIMARY );
568      }
569 
570      return dfb_layer_at( id );
571 }
572 
573 void
dfb_layer_get_description(const CoreLayer * layer,DFBDisplayLayerDescription * desc)574 dfb_layer_get_description( const CoreLayer            *layer,
575                            DFBDisplayLayerDescription *desc )
576 {
577      D_ASSERT( layer != NULL );
578      D_ASSERT( layer->shared != NULL );
579      D_ASSERT( desc != NULL );
580 
581      *desc = layer->shared->description;
582 }
583 
584 CoreScreen *
dfb_layer_screen(const CoreLayer * layer)585 dfb_layer_screen( const CoreLayer *layer )
586 {
587      D_ASSERT( layer != NULL );
588 
589      return layer->screen;
590 }
591 
592 CardState *
dfb_layer_state(CoreLayer * layer)593 dfb_layer_state( CoreLayer *layer )
594 {
595      D_ASSERT( layer != NULL );
596 
597      return &layer->state;
598 }
599 
600 DFBDisplayLayerID
dfb_layer_id(const CoreLayer * layer)601 dfb_layer_id( const CoreLayer *layer )
602 {
603      D_ASSERT( layer != NULL );
604      D_ASSERT( layer->shared != NULL );
605 
606      return layer->shared->layer_id;
607 }
608 
609 DFBDisplayLayerID
dfb_layer_id_translated(const CoreLayer * layer)610 dfb_layer_id_translated( const CoreLayer *layer )
611 {
612      CoreLayerShared *shared;
613 
614      D_ASSERT( layer != NULL );
615      D_ASSERT( layer->shared != NULL );
616      D_ASSERT( dfb_config != NULL );
617 
618      shared = layer->shared;
619 
620      if (dfb_config->primary_layer > 0 &&
621          dfb_config->primary_layer < dfb_num_layers)
622      {
623           if (shared->layer_id == DLID_PRIMARY)
624                return dfb_config->primary_layer;
625 
626           if (shared->layer_id == dfb_config->primary_layer)
627                return DLID_PRIMARY;
628      }
629 
630      return shared->layer_id;
631 }
632 
633 DFBDisplayLayerID
dfb_layer_id_translate(DFBDisplayLayerID layer_id)634 dfb_layer_id_translate( DFBDisplayLayerID layer_id )
635 {
636      D_ASSERT( dfb_config != NULL );
637 
638      if (dfb_config->primary_layer > 0 &&
639          dfb_config->primary_layer < dfb_num_layers)
640      {
641           if (layer_id == DLID_PRIMARY)
642                return dfb_config->primary_layer;
643 
644           if (layer_id == dfb_config->primary_layer)
645                return DLID_PRIMARY;
646      }
647 
648      return layer_id;
649 }
650 
651 DFBSurfacePixelFormat
dfb_primary_layer_pixelformat(void)652 dfb_primary_layer_pixelformat( void )
653 {
654      CoreLayerShared *shared;
655      CoreLayer       *layer = dfb_layer_at_translated(DLID_PRIMARY);
656 
657      D_ASSERT( layer != NULL );
658 
659      shared = layer->shared;
660      D_ASSERT( shared != NULL );
661 
662      return shared->pixelformat;
663 }
664 
665