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