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 <directfb.h>
32 
33 #include <direct/debug.h>
34 #include <direct/mem.h>
35 #include <direct/memcpy.h>
36 #include <direct/messages.h>
37 
38 #include <fusion/shmalloc.h>
39 
40 #include <core/CoreScreen.h>
41 
42 #include <core/core.h>
43 #include <core/core_parts.h>
44 
45 #include <core/screen.h>
46 #include <core/screens.h>
47 #include <core/screens_internal.h>
48 
49 #include <core/layers.h>
50 
51 #include <misc/conf.h>
52 
53 
54 D_DEBUG_DOMAIN( Core_Screen, "Core/Screen", "DirectFB Screen Core" );
55 
56 /**********************************************************************************************************************/
57 
58 typedef struct {
59      int                  magic;
60 
61 
62      int                  num;
63      CoreScreenShared    *screens[MAX_SCREENS];
64 } DFBScreenCoreShared;
65 
66 struct __DFB_DFBScreenCore {
67      int                  magic;
68 
69      CoreDFB             *core;
70 
71      DFBScreenCoreShared *shared;
72 };
73 
74 
75 DFB_CORE_PART( screen_core, ScreenCore );
76 
77 /**********************************************************************************************************************/
78 
79 static DFBScreenCoreShared *core_screens = NULL;       /* FIXME */
80 
81 static int          num_screens          = 0;          /* FIXME */
82 static CoreScreen  *screens[MAX_SCREENS] = { NULL };   /* FIXME */
83 
84 
85 static DFBResult
dfb_screen_core_initialize(CoreDFB * core,DFBScreenCore * data,DFBScreenCoreShared * shared)86 dfb_screen_core_initialize( CoreDFB             *core,
87                             DFBScreenCore       *data,
88                             DFBScreenCoreShared *shared )
89 {
90      int                  i;
91      DFBResult            ret;
92      FusionSHMPoolShared *pool;
93 
94      D_DEBUG_AT( Core_Screen, "dfb_screen_core_initialize( %p, %p, %p )\n", core, data, shared );
95 
96      D_ASSERT( data != NULL );
97      D_ASSERT( shared != NULL );
98 
99      data->core   = core;
100      data->shared = shared;
101 
102      core_screens = shared;   /* FIXME */
103 
104      pool = dfb_core_shmpool( core );
105 
106      /* Initialize all registered screens. */
107      for (i=0; i<num_screens; i++) {
108           char                  buf[24];
109           CoreScreenShared     *sshared;
110           CoreScreen           *screen = screens[i];
111           ScreenFuncs          *funcs  = screen->funcs;
112           DFBScreenDescription  desc   = { .caps = DSCCAPS_NONE };
113 
114           /* Allocate shared data. */
115           sshared = SHCALLOC( pool, 1, sizeof(CoreScreenShared) );
116 
117           /* Assign ID (zero based index). */
118           sshared->screen_id = i;
119 
120           snprintf( buf, sizeof(buf), "Screen %d", i );
121 
122           /* Initialize the lock. */
123           if (fusion_skirmish_init( &sshared->lock, buf, dfb_core_world(core) )) {
124                SHFREE( pool, sshared );
125                return DFB_FUSION;
126           }
127 
128           /* Allocate driver's screen data. */
129           if (funcs->ScreenDataSize) {
130                int size = funcs->ScreenDataSize();
131 
132                if (size > 0) {
133                     sshared->screen_data = SHCALLOC( pool, 1, size );
134                     if (!sshared->screen_data) {
135                          fusion_skirmish_destroy( &sshared->lock );
136                          SHFREE( pool, sshared );
137                          return D_OOSHM();
138                     }
139                }
140           }
141 
142           /* Initialize the screen and get the screen description. */
143           ret = funcs->InitScreen( screen,
144                                    screen->device,
145                                    screen->driver_data,
146                                    sshared->screen_data,
147                                    &desc );
148           if (ret) {
149                D_ERROR("DirectFB/Core/screens: "
150                         "Failed to initialize screen %d!\n", sshared->screen_id);
151 
152                fusion_skirmish_destroy( &sshared->lock );
153 
154                if (sshared->screen_data)
155                     SHFREE( pool, sshared->screen_data );
156 
157                SHFREE( pool, sshared );
158 
159                return ret;
160           }
161 
162           D_ASSUME( desc.mixers  > 0 || !(desc.caps & DSCCAPS_MIXERS) );
163           D_ASSUME( desc.mixers == 0 ||  (desc.caps & DSCCAPS_MIXERS) );
164 
165           D_ASSUME( desc.encoders  > 0 || !(desc.caps & DSCCAPS_ENCODERS) );
166           D_ASSUME( desc.encoders == 0 ||  (desc.caps & DSCCAPS_ENCODERS) );
167 
168           D_ASSUME( desc.outputs  > 0 || !(desc.caps & DSCCAPS_OUTPUTS) );
169           D_ASSUME( desc.outputs == 0 ||  (desc.caps & DSCCAPS_OUTPUTS) );
170 
171           D_ASSERT( desc.mixers >= 0 );
172           D_ASSERT( desc.mixers <= 32 );
173           D_ASSERT( desc.encoders >= 0 );
174           D_ASSERT( desc.encoders <= 32 );
175           D_ASSERT( desc.outputs >= 0 );
176           D_ASSERT( desc.outputs <= 32 );
177 
178           /* Store description in sshared memory. */
179           sshared->description = desc;
180 
181           /* Initialize mixers. */
182           if (sshared->description.mixers) {
183                int i;
184 
185                D_ASSERT( funcs->InitMixer != NULL );
186                D_ASSERT( funcs->SetMixerConfig != NULL );
187 
188                sshared->mixers = SHCALLOC( pool, sshared->description.mixers,
189                                            sizeof(CoreScreenMixer) );
190                for (i=0; i<sshared->description.mixers; i++) {
191                     funcs->InitMixer( screen,
192                                       screen->driver_data,
193                                       sshared->screen_data, i,
194                                       &sshared->mixers[i].description,
195                                       &sshared->mixers[i].configuration );
196                     funcs->SetMixerConfig( screen,
197                                            screen->driver_data,
198                                            sshared->screen_data, i,
199                                            &sshared->mixers[i].configuration );
200                }
201           }
202 
203           /* Initialize encoders. */
204           if (sshared->description.encoders) {
205                int i;
206 
207                D_ASSERT( funcs->InitEncoder != NULL );
208                D_ASSERT( funcs->SetEncoderConfig != NULL );
209 
210                sshared->encoders = SHCALLOC( pool, sshared->description.encoders,
211                                              sizeof(CoreScreenEncoder) );
212                for (i=0; i<sshared->description.encoders; i++) {
213                     funcs->InitEncoder( screen,
214                                         screen->driver_data,
215                                         sshared->screen_data, i,
216                                         &sshared->encoders[i].description,
217                                         &sshared->encoders[i].configuration );
218                     funcs->SetEncoderConfig( screen,
219                                              screen->driver_data,
220                                              sshared->screen_data, i,
221                                              &sshared->encoders[i].configuration );
222                }
223           }
224 
225           /* Initialize outputs. */
226           if (sshared->description.outputs) {
227                int i;
228 
229                D_ASSERT( funcs->InitOutput != NULL );
230                D_ASSERT( funcs->SetOutputConfig != NULL );
231 
232                sshared->outputs = SHCALLOC( pool, sshared->description.outputs,
233                                             sizeof(CoreScreenOutput) );
234                for (i=0; i<sshared->description.outputs; i++) {
235                     funcs->InitOutput( screen,
236                                        screen->driver_data,
237                                        sshared->screen_data, i,
238                                        &sshared->outputs[i].description,
239                                        &sshared->outputs[i].configuration );
240                     funcs->SetOutputConfig( screen,
241                                             screen->driver_data,
242                                             sshared->screen_data, i,
243                                             &sshared->outputs[i].configuration );
244                }
245           }
246 
247           /* Make a copy for faster access. */
248           screen->screen_data = sshared->screen_data;
249 
250           /* Store pointer to sshared data and core. */
251           screen->shared = sshared;
252           screen->core   = core;
253 
254           CoreScreen_Init_Dispatch( core, screen, &sshared->call );
255 
256           fusion_call_add_permissions( &sshared->call, 0, FUSION_CALL_PERMIT_EXECUTE );
257 
258           /* Add the screen to the sshared list. */
259           core_screens->screens[ core_screens->num++ ] = sshared;
260      }
261 
262 
263      D_MAGIC_SET( data, DFBScreenCore );
264      D_MAGIC_SET( shared, DFBScreenCoreShared );
265 
266      return DFB_OK;
267 }
268 
269 static DFBResult
dfb_screen_core_join(CoreDFB * core,DFBScreenCore * data,DFBScreenCoreShared * shared)270 dfb_screen_core_join( CoreDFB             *core,
271                       DFBScreenCore       *data,
272                       DFBScreenCoreShared *shared )
273 {
274      int i;
275 
276      D_DEBUG_AT( Core_Screen, "dfb_screen_core_join( %p, %p, %p )\n", core, data, shared );
277 
278      D_ASSERT( data != NULL );
279      D_MAGIC_ASSERT( shared, DFBScreenCoreShared );
280 
281      data->core   = core;
282      data->shared = shared;
283 
284      core_screens = shared;   /* FIXME */
285 
286      if (num_screens != core_screens->num) {
287           D_ERROR("DirectFB/core/screens: Number of screens does not match!\n");
288           return DFB_BUG;
289      }
290 
291      for (i=0; i<num_screens; i++) {
292           CoreScreen       *screen = screens[i];
293           CoreScreenShared *shared = core_screens->screens[i];
294 
295           /* Make a copy for faster access. */
296           screen->screen_data = shared->screen_data;
297 
298           /* Store pointer to shared data and core. */
299           screen->shared = shared;
300           screen->core   = core;
301      }
302 
303 
304      D_MAGIC_SET( data, DFBScreenCore );
305 
306      return DFB_OK;
307 }
308 
309 static DFBResult
dfb_screen_core_shutdown(DFBScreenCore * data,bool emergency)310 dfb_screen_core_shutdown( DFBScreenCore *data,
311                           bool           emergency )
312 {
313      int                  i;
314      FusionSHMPoolShared *pool;
315      DFBScreenCoreShared *shared;
316 
317      D_DEBUG_AT( Core_Screen, "dfb_screen_core_shutdown( %p, %semergency )\n", data, emergency ? "" : "no " );
318 
319      D_MAGIC_ASSERT( data, DFBScreenCore );
320      D_MAGIC_ASSERT( data->shared, DFBScreenCoreShared );
321 
322      shared = data->shared;
323 
324      pool = dfb_core_shmpool( data->core );
325 
326      /* Begin with the most recently added screen. */
327      for (i=num_screens-1; i>=0; i--) {
328           CoreScreen       *screen = screens[i];
329           ScreenFuncs      *funcs  = screen->funcs;
330           CoreScreenShared *shared = screen->shared;
331 
332           /* Shut the screen down. */
333           if (funcs->ShutdownScreen)
334                if( funcs->ShutdownScreen( screen,
335                                           screen->driver_data,
336                                           shared->screen_data ) )
337                     D_ERROR("DirectFB/Core/screens: "
338                              "Failed to shutdown screen %d!\n", shared->screen_id);
339 
340           CoreScreen_Deinit_Dispatch( &shared->call );
341 
342           /* Deinitialize the lock. */
343           fusion_skirmish_destroy( &shared->lock );
344 
345           /* Free the driver's screen data. */
346           if (shared->screen_data)
347                SHFREE( pool, shared->screen_data );
348 
349           /* Free mixer data. */
350           if (shared->mixers)
351                SHFREE( pool, shared->mixers );
352 
353           /* Free encoder data. */
354           if (shared->encoders)
355                SHFREE( pool, shared->encoders );
356 
357           /* Free output data. */
358           if (shared->outputs)
359                SHFREE( pool, shared->outputs );
360 
361           /* Free the shared screen data. */
362           SHFREE( pool, shared );
363 
364           /* Free the local screen data. */
365           D_FREE( screen );
366      }
367 
368      core_screens = NULL;
369      num_screens  = 0;
370 
371 
372      D_MAGIC_CLEAR( data );
373      D_MAGIC_CLEAR( shared );
374 
375      return DFB_OK;
376 }
377 
378 static DFBResult
dfb_screen_core_leave(DFBScreenCore * data,bool emergency)379 dfb_screen_core_leave( DFBScreenCore *data,
380                        bool           emergency )
381 {
382      int                  i;
383      DFBScreenCoreShared *shared;
384 
385      D_DEBUG_AT( Core_Screen, "dfb_screen_core_leave( %p, %semergency )\n", data, emergency ? "" : "no " );
386 
387      D_MAGIC_ASSERT( data, DFBScreenCore );
388      D_MAGIC_ASSERT( data->shared, DFBScreenCoreShared );
389 
390      shared = data->shared;
391 
392 
393      /* Deinitialize all local stuff only. */
394      for (i=0; i<num_screens; i++) {
395           CoreScreen *screen = screens[i];
396 
397           /* Free local screen data. */
398           D_FREE( screen );
399      }
400 
401      core_screens = NULL;
402      num_screens  = 0;
403 
404 
405      D_MAGIC_CLEAR( data );
406 
407      return DFB_OK;
408 }
409 
410 static DFBResult
dfb_screen_core_suspend(DFBScreenCore * data)411 dfb_screen_core_suspend( DFBScreenCore *data )
412 {
413      int                  i;
414      DFBScreenCoreShared *shared;
415 
416      D_DEBUG_AT( Core_Screen, "dfb_screen_core_suspend( %p )\n", data );
417 
418      D_MAGIC_ASSERT( data, DFBScreenCore );
419      D_MAGIC_ASSERT( data->shared, DFBScreenCoreShared );
420 
421      shared = data->shared;
422 
423      for (i=num_screens-1; i>=0; i--)
424           dfb_screen_suspend( screens[i] );
425 
426      return DFB_OK;
427 }
428 
429 static DFBResult
dfb_screen_core_resume(DFBScreenCore * data)430 dfb_screen_core_resume( DFBScreenCore *data )
431 {
432      int                  i;
433      DFBScreenCoreShared *shared;
434 
435      D_DEBUG_AT( Core_Screen, "dfb_screen_core_resume( %p )\n", data );
436 
437      D_MAGIC_ASSERT( data, DFBScreenCore );
438      D_MAGIC_ASSERT( data->shared, DFBScreenCoreShared );
439 
440      shared = data->shared;
441 
442      for (i=0; i<num_screens; i++)
443           dfb_screen_resume( screens[i] );
444 
445      return DFB_OK;
446 }
447 
448 /**********************************************************************************************************************/
449 
450 CoreScreen *
dfb_screens_register(CoreGraphicsDevice * device,void * driver_data,ScreenFuncs * funcs)451 dfb_screens_register( CoreGraphicsDevice *device,
452                       void               *driver_data,
453                       ScreenFuncs        *funcs )
454 {
455      CoreScreen *screen;
456 
457      D_ASSERT( funcs != NULL );
458 
459      if (num_screens == MAX_SCREENS) {
460           D_ERROR( "DirectFB/Core/screen: "
461                     "Maximum number of screens reached!\n" );
462           return NULL;
463      }
464 
465      /* allocate local data */
466      screen = D_CALLOC( 1, sizeof(CoreScreen) );
467 
468      /* assign local pointers */
469      screen->device      = device;
470      screen->driver_data = driver_data;
471      screen->funcs       = funcs;
472 
473      /* add it to the local list */
474      screens[num_screens++] = screen;
475 
476      return screen;
477 }
478 
479 typedef void (*AnyFunc)( void );
480 
481 CoreScreen *
dfb_screens_hook_primary(CoreGraphicsDevice * device,void * driver_data,ScreenFuncs * funcs,ScreenFuncs * primary_funcs,void ** primary_driver_data)482 dfb_screens_hook_primary( CoreGraphicsDevice  *device,
483                           void                *driver_data,
484                           ScreenFuncs         *funcs,
485                           ScreenFuncs         *primary_funcs,
486                           void               **primary_driver_data )
487 {
488      int         i;
489      int         entries;
490      CoreScreen *primary = screens[0];
491 
492      D_ASSERT( primary != NULL );
493      D_ASSERT( device != NULL );
494      D_ASSERT( funcs != NULL );
495 
496      /* copy content of original function table */
497      if (primary_funcs)
498           direct_memcpy( primary_funcs, primary->funcs, sizeof(ScreenFuncs) );
499 
500      /* copy pointer to original driver data */
501      if (primary_driver_data)
502           *primary_driver_data = primary->driver_data;
503 
504      /* replace all entries in the old table that aren't NULL in the new one */
505      entries = sizeof(ScreenFuncs) / sizeof(void(*)( void ));
506      for (i=0; i<entries; i++) {
507           AnyFunc *newfuncs = (AnyFunc*) funcs;
508           AnyFunc *oldfuncs = (AnyFunc*) primary->funcs;
509 
510           if (newfuncs[i])
511                oldfuncs[i] = newfuncs[i];
512      }
513 
514      /* replace device and driver data pointer */
515      primary->device      = device;
516      primary->driver_data = driver_data;
517 
518      return primary;
519 }
520 
521 CoreScreen *
dfb_screens_register_primary(CoreGraphicsDevice * device,void * driver_data,ScreenFuncs * funcs)522 dfb_screens_register_primary( CoreGraphicsDevice *device,
523                               void               *driver_data,
524                               ScreenFuncs        *funcs )
525 {
526      CoreScreen *primary = screens[0];
527 
528      D_ASSERT( primary != NULL );
529      D_ASSERT( funcs != NULL );
530      D_ASSERT( num_screens > 0 );
531 
532      /* replace device, function table and driver data pointer */
533      primary->device      = device;
534      primary->funcs       = funcs;
535      primary->driver_data = driver_data;
536 
537      return primary;
538 }
539 
540 void
dfb_screens_enumerate(CoreScreenCallback callback,void * ctx)541 dfb_screens_enumerate( CoreScreenCallback  callback,
542                        void               *ctx )
543 {
544      int i;
545 
546      D_ASSERT( core_screens != NULL );
547      D_ASSERT( callback != NULL );
548 
549      for (i=0; i<num_screens; i++) {
550           if (callback( screens[i], ctx ) == DFENUM_CANCEL)
551                break;
552      }
553 }
554 
555 unsigned int
dfb_screens_num()556 dfb_screens_num()
557 {
558      return num_screens;
559 }
560 
561 CoreScreen *
dfb_screens_at(DFBScreenID screen_id)562 dfb_screens_at( DFBScreenID screen_id )
563 {
564      D_ASSERT( screen_id >= 0);
565      D_ASSERT( screen_id < num_screens);
566 
567      return screens[screen_id];
568 }
569 
570 CoreScreen *
dfb_screens_at_translated(DFBScreenID screen_id)571 dfb_screens_at_translated( DFBScreenID screen_id )
572 {
573      CoreScreen *primary;
574 
575      D_ASSERT( screen_id >= 0);
576      D_ASSERT( screen_id < num_screens);
577 
578      if (dfb_config->primary_layer > 0) {
579           primary = dfb_layer_screen( dfb_layer_at_translated( DLID_PRIMARY ) );
580 
581           if (screen_id == DSCID_PRIMARY)
582                return primary;
583 
584           if (screen_id == primary->shared->screen_id)
585                return dfb_screens_at( DSCID_PRIMARY );
586      }
587 
588      return dfb_screens_at( screen_id );
589 }
590 
591 DFBScreenID
dfb_screen_id(const CoreScreen * screen)592 dfb_screen_id( const CoreScreen *screen )
593 {
594      CoreScreenShared *shared;
595 
596      D_ASSERT( screen != NULL );
597      D_ASSERT( screen->shared != NULL );
598 
599      shared = screen->shared;
600 
601      return shared->screen_id;
602 }
603 
604 DFBScreenID
dfb_screen_id_translated(const CoreScreen * screen)605 dfb_screen_id_translated( const CoreScreen *screen )
606 {
607      CoreScreenShared *shared;
608      CoreScreen       *primary;
609 
610      D_ASSERT( screen != NULL );
611      D_ASSERT( screen->shared != NULL );
612 
613      shared = screen->shared;
614 
615      if (dfb_config->primary_layer > 0) {
616           primary = dfb_layer_screen( dfb_layer_at_translated( DLID_PRIMARY ) );
617 
618           if (shared->screen_id == DSCID_PRIMARY)
619                return primary->shared->screen_id;
620 
621           if (shared->screen_id == primary->shared->screen_id)
622                return DSCID_PRIMARY;
623      }
624 
625      return shared->screen_id;
626 }
627 
628