1 /*
2 (c) Copyright 2001-2010 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 <direct/debug.h>
32
33 #include <core/core.h>
34 #include <core/palette.h>
35 #include <core/surface.h>
36 #include <core/surface_pool.h>
37
38 #include <core/system.h>
39
40 #include <fusion/conf.h>
41 #include <fusion/shmalloc.h>
42
43 #include <core/layers_internal.h>
44 #include <core/windows_internal.h>
45
46 #include <core/CoreDFB.h>
47 #include <core/CoreSurface.h>
48
49 #include <gfx/convert.h>
50 #include <gfx/util.h>
51
52
53 D_DEBUG_DOMAIN( Core_Surface, "Core/Surface", "DirectFB Core Surface" );
54
55 /**********************************************************************************************************************/
56
57 static const ReactionFunc dfb_surface_globals[] = {
58 /* 0 */ _dfb_layer_region_surface_listener,
59 /* 1 */ _dfb_windowstack_background_image_listener,
60 NULL
61 };
62
63 static void
surface_destructor(FusionObject * object,bool zombie,void * ctx)64 surface_destructor( FusionObject *object, bool zombie, void *ctx )
65 {
66 int i;
67 CoreSurface *surface = (CoreSurface*) object;
68
69 D_MAGIC_ASSERT( surface, CoreSurface );
70
71 D_DEBUG_AT( Core_Surface, "destroying %p (%dx%d%s)\n", surface,
72 surface->config.size.w, surface->config.size.h, zombie ? " ZOMBIE" : "");
73
74 Core_Resource_RemoveSurface( surface );
75
76 CoreSurface_Deinit_Dispatch( &surface->call );
77
78 dfb_surface_lock( surface );
79
80 surface->state |= CSSF_DESTROYED;
81
82 /* announce surface destruction */
83 dfb_surface_notify( surface, CSNF_DESTROY );
84
85 /* unlink palette */
86 if (surface->palette) {
87 dfb_palette_detach_global( surface->palette, &surface->palette_reaction );
88 dfb_palette_unlink( &surface->palette );
89 }
90
91 /* destroy buffers */
92 for (i=0; i<MAX_SURFACE_BUFFERS; i++) {
93 if (surface->buffers[i])
94 dfb_surface_buffer_decouple( surface->buffers[i] );
95 }
96
97 dfb_system_surface_data_destroy( surface, surface->data );
98
99 /* release the system driver specific surface data */
100 if (surface->data) {
101 SHFREE( surface->shmpool, surface->data );
102 surface->data = NULL;
103 }
104
105 direct_serial_deinit( &surface->serial );
106
107 dfb_surface_unlock( surface );
108
109 fusion_skirmish_destroy( &surface->lock );
110
111 D_MAGIC_CLEAR( surface );
112
113 fusion_object_destroy( object );
114 }
115
116 FusionObjectPool *
dfb_surface_pool_create(const FusionWorld * world)117 dfb_surface_pool_create( const FusionWorld *world )
118 {
119 FusionObjectPool *pool;
120
121 pool = fusion_object_pool_create( "Surface Pool",
122 sizeof(CoreSurface),
123 sizeof(CoreSurfaceNotification),
124 surface_destructor, NULL, world );
125
126 return pool;
127 }
128
129 /**********************************************************************************************************************/
130
131 DFBResult
dfb_surface_create(CoreDFB * core,const CoreSurfaceConfig * config,CoreSurfaceTypeFlags type,unsigned long resource_id,CorePalette * palette,CoreSurface ** ret_surface)132 dfb_surface_create( CoreDFB *core,
133 const CoreSurfaceConfig *config,
134 CoreSurfaceTypeFlags type,
135 unsigned long resource_id,
136 CorePalette *palette,
137 CoreSurface **ret_surface )
138 {
139 DFBResult ret = DFB_BUG;
140 int i, data_size;
141 int buffers;
142 CoreSurface *surface;
143 char buf[64];
144
145 D_ASSERT( core != NULL );
146 D_FLAGS_ASSERT( type, CSTF_ALL );
147 D_MAGIC_ASSERT_IF( palette, CorePalette );
148 D_ASSERT( ret_surface != NULL );
149
150 D_DEBUG_AT( Core_Surface, "dfb_surface_create( %p, %p, %p )\n", core, config, ret_surface );
151
152 surface = dfb_core_create_surface( core );
153 if (!surface)
154 return DFB_FUSION;
155
156 surface->data = NULL;
157
158 if (config) {
159 D_FLAGS_ASSERT( config->flags, CSCONF_ALL );
160
161 surface->config.flags = config->flags;
162
163 if (config->flags & CSCONF_SIZE) {
164 D_DEBUG_AT( Core_Surface, " -> %dx%d\n", config->size.w, config->size.h );
165
166 surface->config.size = config->size;
167 }
168
169 if (config->flags & CSCONF_FORMAT) {
170 D_DEBUG_AT( Core_Surface, " -> %s\n", dfb_pixelformat_name( config->format ) );
171
172 surface->config.format = config->format;
173 }
174
175 if (config->flags & CSCONF_CAPS) {
176 D_DEBUG_AT( Core_Surface, " -> caps 0x%08x\n", config->caps );
177
178 if (config->caps & DSCAPS_ROTATED)
179 D_UNIMPLEMENTED();
180
181 surface->config.caps = config->caps & ~DSCAPS_ROTATED;
182 }
183
184 if (config->flags & CSCONF_PREALLOCATED) {
185 D_DEBUG_AT( Core_Surface, " -> prealloc %p [%d]\n",
186 config->preallocated[0].addr,
187 config->preallocated[0].pitch );
188
189 direct_memcpy( surface->config.preallocated, config->preallocated, sizeof(config->preallocated) );
190
191 surface->config.preallocated_pool_id = config->preallocated_pool_id;
192
193 type |= CSTF_PREALLOCATED;
194 }
195 }
196
197 if (surface->config.caps & DSCAPS_SYSTEMONLY)
198 surface->type = (type & ~CSTF_EXTERNAL) | CSTF_INTERNAL;
199 else if (surface->config.caps & DSCAPS_VIDEOONLY)
200 surface->type = (type & ~CSTF_INTERNAL) | CSTF_EXTERNAL;
201 else
202 surface->type = type & ~(CSTF_INTERNAL | CSTF_EXTERNAL);
203
204 if (surface->config.caps & DSCAPS_SHARED)
205 surface->type |= CSTF_SHARED;
206
207 surface->resource_id = resource_id;
208
209 if (surface->config.caps & DSCAPS_TRIPLE)
210 buffers = 3;
211 else if (surface->config.caps & DSCAPS_DOUBLE)
212 buffers = 2;
213 else {
214 buffers = 1;
215
216 surface->config.caps &= ~DSCAPS_ROTATED;
217 }
218
219 surface->notifications = CSNF_ALL & ~CSNF_FLIP;
220
221 surface->alpha_ramp[0] = 0x00;
222 surface->alpha_ramp[1] = 0x55;
223 surface->alpha_ramp[2] = 0xaa;
224 surface->alpha_ramp[3] = 0xff;
225
226
227 if (surface->config.caps & DSCAPS_STATIC_ALLOC)
228 surface->config.min_size = surface->config.size;
229
230 surface->shmpool = dfb_core_shmpool( core );
231
232 direct_serial_init( &surface->serial );
233
234 snprintf( buf, sizeof(buf), "Surface %dx%d %s", surface->config.size.w,
235 surface->config.size.h, dfb_pixelformat_name(surface->config.format) );
236
237 fusion_ref_set_name( &surface->object.ref, buf );
238
239 fusion_skirmish_init2( &surface->lock, buf, dfb_core_world(core), fusion_config->secure_fusion );
240
241 // fusion_skirmish_add_permissions( &surface->lock, 0, FUSION_SKIRMISH_PERMIT_PREVAIL | FUSION_SKIRMISH_PERMIT_DISMISS );
242
243 D_MAGIC_SET( surface, CoreSurface );
244
245
246 if (dfb_config->warn.flags & DCWF_CREATE_SURFACE &&
247 dfb_config->warn.create_surface.min_size.w <= surface->config.size.w &&
248 dfb_config->warn.create_surface.min_size.h <= surface->config.size.h)
249 D_WARN( "create-surface %4dx%4d %6s, buffers %d, caps 0x%08x, type 0x%08x",
250 surface->config.size.w, surface->config.size.h, dfb_pixelformat_name(surface->config.format),
251 buffers, surface->config.caps, surface->type );
252
253
254 if (palette) {
255 dfb_surface_set_palette( surface, palette );
256 }
257 else if (DFB_PIXELFORMAT_IS_INDEXED( surface->config.format )) {
258 ret = dfb_surface_init_palette( core, surface );
259 if (ret)
260 goto error;
261 }
262
263 /* Create the system driver specific surface data information */
264 data_size = dfb_system_surface_data_size();
265
266 if (data_size) {
267 surface->data = SHCALLOC( surface->shmpool, 1, data_size );
268 if (!surface->data) {
269 ret = D_OOSHM();
270 goto error;
271 }
272 }
273
274 dfb_system_surface_data_init(surface,surface->data);
275
276 dfb_surface_lock( surface );
277
278 /* Create the Surface Buffers. */
279 for (i=0; i<buffers; i++) {
280 ret = dfb_surface_buffer_create( core, surface, CSBF_NONE, &surface->buffers[i] );
281 if (ret) {
282 D_DERROR( ret, "Core/Surface: Error creating surface buffer!\n" );
283 goto error;
284 }
285
286 surface->num_buffers++;
287
288 dfb_surface_buffer_globalize( surface->buffers[i] );
289
290 switch (i) {
291 case 0:
292 surface->buffer_indices[CSBR_FRONT] = i;
293 case 1:
294 surface->buffer_indices[CSBR_BACK] = i;
295 case 2:
296 surface->buffer_indices[CSBR_IDLE] = i;
297 }
298 }
299
300 dfb_surface_unlock( surface );
301
302
303 CoreSurface_Init_Dispatch( core, surface, &surface->call );
304
305 fusion_object_activate( &surface->object );
306
307 *ret_surface = surface;
308
309 return DFB_OK;
310
311 error:
312 for (i=0; i<MAX_SURFACE_BUFFERS; i++) {
313 if (surface->buffers[i])
314 dfb_surface_buffer_decouple( surface->buffers[i] );
315 }
316
317 /* release the system driver specific surface data */
318 if (surface->data) {
319 dfb_system_surface_data_destroy( surface, surface->data );
320 SHFREE( surface->shmpool, surface->data );
321 surface->data = NULL;
322 }
323
324 fusion_skirmish_destroy( &surface->lock );
325
326 direct_serial_deinit( &surface->serial );
327
328 D_MAGIC_CLEAR( surface );
329
330 fusion_object_destroy( &surface->object );
331
332 return ret;
333 }
334
335 DFBResult
dfb_surface_create_simple(CoreDFB * core,int width,int height,DFBSurfacePixelFormat format,DFBSurfaceCapabilities caps,CoreSurfaceTypeFlags type,unsigned long resource_id,CorePalette * palette,CoreSurface ** ret_surface)336 dfb_surface_create_simple ( CoreDFB *core,
337 int width,
338 int height,
339 DFBSurfacePixelFormat format,
340 DFBSurfaceCapabilities caps,
341 CoreSurfaceTypeFlags type,
342 unsigned long resource_id,
343 CorePalette *palette,
344 CoreSurface **ret_surface )
345 {
346 CoreSurfaceConfig config;
347
348 D_DEBUG_AT( Core_Surface, "%s( %p, %dx%d %s, %p )\n", __FUNCTION__, core, width, height,
349 dfb_pixelformat_name( format ), ret_surface );
350
351 D_ASSERT( core != NULL );
352 D_ASSERT( ret_surface != NULL );
353
354 config.flags = CSCONF_SIZE | CSCONF_FORMAT | CSCONF_CAPS;
355 config.size.w = width;
356 config.size.h = height;
357 config.format = format;
358 config.caps = caps;
359
360 return CoreDFB_CreateSurface( core, &config, type, resource_id, palette, ret_surface );
361 }
362
363 DFBResult
dfb_surface_init_palette(CoreDFB * core,CoreSurface * surface)364 dfb_surface_init_palette( CoreDFB *core,
365 CoreSurface *surface )
366 {
367 DFBResult ret;
368 CorePalette *palette;
369
370 ret = dfb_palette_create( core,
371 1 << DFB_COLOR_BITS_PER_PIXEL( surface->config.format ),
372 &palette );
373 if (ret) {
374 D_DERROR( ret, "Core/Surface: Error creating palette!\n" );
375 return ret;
376 }
377
378 switch (surface->config.format) {
379 case DSPF_LUT8:
380 dfb_palette_generate_rgb332_map( palette );
381 break;
382
383 case DSPF_ALUT44:
384 dfb_palette_generate_rgb121_map( palette );
385 break;
386
387 default:
388 break;
389 }
390
391 dfb_surface_set_palette( surface, palette );
392
393 dfb_palette_unref( palette );
394
395 return DFB_OK;
396 }
397
398
399 DFBResult
dfb_surface_notify(CoreSurface * surface,CoreSurfaceNotificationFlags flags)400 dfb_surface_notify( CoreSurface *surface,
401 CoreSurfaceNotificationFlags flags)
402 {
403 CoreSurfaceNotification notification;
404
405 D_MAGIC_ASSERT( surface, CoreSurface );
406 FUSION_SKIRMISH_ASSERT( &surface->lock );
407 D_FLAGS_ASSERT( flags, CSNF_ALL );
408
409 direct_serial_increase( &surface->serial );
410
411 if (!(surface->state & CSSF_DESTROYED)) {
412 if (!(surface->notifications & flags))
413 return DFB_OK;
414 }
415
416 notification.flags = flags;
417 notification.surface = surface;
418
419 return dfb_surface_dispatch( surface, ¬ification, dfb_surface_globals );
420 }
421
422 DFBResult
dfb_surface_notify_display(CoreSurface * surface,CoreSurfaceBuffer * buffer)423 dfb_surface_notify_display( CoreSurface *surface,
424 CoreSurfaceBuffer *buffer )
425 {
426 CoreSurfaceNotification notification;
427
428 D_MAGIC_ASSERT( surface, CoreSurface );
429 D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );
430
431 direct_serial_increase( &surface->serial );
432
433 notification.flags = CSNF_DISPLAY;
434 notification.surface = surface;
435 notification.index = dfb_surface_buffer_index( buffer );
436
437 return dfb_surface_dispatch( surface, ¬ification, dfb_surface_globals );
438 }
439
440 DFBResult
dfb_surface_flip(CoreSurface * surface,bool swap)441 dfb_surface_flip( CoreSurface *surface, bool swap )
442 {
443 unsigned int back, front;
444
445 D_MAGIC_ASSERT( surface, CoreSurface );
446
447 FUSION_SKIRMISH_ASSERT( &surface->lock );
448
449 if (surface->num_buffers == 0)
450 return DFB_SUSPENDED;
451
452 back = (surface->flips + CSBR_BACK) % surface->num_buffers;
453 front = (surface->flips + CSBR_FRONT) % surface->num_buffers;
454
455 D_ASSERT( surface->buffer_indices[back] < surface->num_buffers );
456 D_ASSERT( surface->buffer_indices[front] < surface->num_buffers );
457
458 if (surface->buffers[surface->buffer_indices[back]]->policy !=
459 surface->buffers[surface->buffer_indices[front]]->policy || (surface->config.caps & DSCAPS_ROTATED))
460 return DFB_UNSUPPORTED;
461
462 if (swap) {
463 int tmp = surface->buffer_indices[back];
464 surface->buffer_indices[back] = surface->buffer_indices[front];
465 surface->buffer_indices[front] = tmp;
466 }
467 else
468 surface->flips++;
469
470 dfb_surface_notify( surface, CSNF_FLIP );
471
472 return DFB_OK;
473 }
474
475 DFBResult
dfb_surface_reconfig(CoreSurface * surface,const CoreSurfaceConfig * config)476 dfb_surface_reconfig( CoreSurface *surface,
477 const CoreSurfaceConfig *config )
478 {
479 int i, buffers;
480 DFBResult ret;
481 CoreSurfaceConfig new_config;
482
483 D_DEBUG_AT( Core_Surface, "%s( %p, %dx%d %s -> %dx%d %s )\n", __FUNCTION__, surface,
484 surface->config.size.w, surface->config.size.h, dfb_pixelformat_name( surface->config.format ),
485 (config->flags & CSCONF_SIZE) ? config->size.w : surface->config.size.w,
486 (config->flags & CSCONF_SIZE) ? config->size.h : surface->config.size.h,
487 (config->flags & CSCONF_FORMAT) ? dfb_pixelformat_name( config->format ) :
488 dfb_pixelformat_name( surface->config.format ) );
489
490 D_MAGIC_ASSERT( surface, CoreSurface );
491 D_ASSERT( config != NULL );
492
493 if (config->flags & CSCONF_PREALLOCATED)
494 return DFB_UNSUPPORTED;
495
496 if (fusion_skirmish_prevail( &surface->lock ))
497 return DFB_FUSION;
498
499 if (surface->type & CSTF_PREALLOCATED) {
500 fusion_skirmish_dismiss( &surface->lock );
501 return DFB_UNSUPPORTED;
502 }
503
504 if ( (config->flags == CSCONF_SIZE ||
505 ((config->flags == (CSCONF_SIZE | CSCONF_FORMAT)) && (config->format == surface->config.format))) &&
506 config->size.w <= surface->config.min_size.w &&
507 config->size.h <= surface->config.min_size.h)
508 {
509 surface->config.size = config->size;
510
511 fusion_skirmish_dismiss( &surface->lock );
512 return DFB_OK;
513 }
514
515 new_config = surface->config;
516
517 if (config->flags & CSCONF_SIZE)
518 new_config.size = config->size;
519
520 if (config->flags & CSCONF_FORMAT)
521 new_config.format = config->format;
522
523 if (config->flags & CSCONF_CAPS) {
524 if (config->caps & DSCAPS_ROTATED)
525 D_UNIMPLEMENTED();
526
527 new_config.caps = config->caps & ~DSCAPS_ROTATED;
528 }
529
530 if (new_config.caps & DSCAPS_SYSTEMONLY)
531 surface->type = (surface->type & ~CSTF_EXTERNAL) | CSTF_INTERNAL;
532 else if (new_config.caps & DSCAPS_VIDEOONLY)
533 surface->type = (surface->type & ~CSTF_INTERNAL) | CSTF_EXTERNAL;
534 else
535 surface->type = surface->type & ~(CSTF_INTERNAL | CSTF_EXTERNAL);
536
537 if (new_config.caps & DSCAPS_TRIPLE)
538 buffers = 3;
539 else if (new_config.caps & DSCAPS_DOUBLE)
540 buffers = 2;
541 else {
542 buffers = 1;
543
544 new_config.caps &= ~DSCAPS_ROTATED;
545 }
546
547 ret = Core_Resource_CheckSurfaceUpdate( surface, &new_config );
548 if (ret)
549 return ret;
550
551 /* Destroy the Surface Buffers. */
552 for (i=0; i<surface->num_buffers; i++) {
553 dfb_surface_buffer_decouple( surface->buffers[i] );
554 surface->buffers[i] = NULL;
555 }
556
557 surface->num_buffers = 0;
558
559 Core_Resource_UpdateSurface( surface, &new_config );
560
561 surface->config = new_config;
562
563 /* Recreate the Surface Buffers. */
564 for (i=0; i<buffers; i++) {
565 CoreSurfaceBuffer *buffer;
566
567 ret = dfb_surface_buffer_create( core_dfb, surface, CSBF_NONE, &buffer );
568 if (ret) {
569 D_DERROR( ret, "Core/Surface: Error creating surface buffer!\n" );
570 goto error;
571 }
572
573 dfb_surface_buffer_globalize( buffer );
574
575 surface->buffers[surface->num_buffers++] = buffer;
576
577 switch (i) {
578 case 0:
579 surface->buffer_indices[CSBR_FRONT] = i;
580 case 1:
581 surface->buffer_indices[CSBR_BACK] = i;
582 case 2:
583 surface->buffer_indices[CSBR_IDLE] = i;
584 }
585 }
586
587 dfb_surface_notify( surface, CSNF_SIZEFORMAT );
588
589 fusion_skirmish_dismiss( &surface->lock );
590
591 return DFB_OK;
592
593 error:
594 D_UNIMPLEMENTED();
595
596 fusion_skirmish_dismiss( &surface->lock );
597
598 return ret;
599 }
600
601 DFBResult
dfb_surface_destroy_buffers(CoreSurface * surface)602 dfb_surface_destroy_buffers( CoreSurface *surface )
603 {
604 int i;
605
606 D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface );
607
608 D_MAGIC_ASSERT( surface, CoreSurface );
609
610 if (fusion_skirmish_prevail( &surface->lock ))
611 return DFB_FUSION;
612
613 if (surface->type & CSTF_PREALLOCATED) {
614 fusion_skirmish_dismiss( &surface->lock );
615 return DFB_UNSUPPORTED;
616 }
617
618 /* Destroy the Surface Buffers. */
619 for (i=0; i<surface->num_buffers; i++) {
620 dfb_surface_buffer_decouple( surface->buffers[i] );
621 surface->buffers[i] = NULL;
622 }
623
624 surface->num_buffers = 0;
625
626 fusion_skirmish_dismiss( &surface->lock );
627
628 return DFB_OK;
629 }
630
631 DFBResult
dfb_surface_deallocate_buffers(CoreSurface * surface)632 dfb_surface_deallocate_buffers( CoreSurface *surface )
633 {
634 int i;
635
636 D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface );
637
638 D_MAGIC_ASSERT( surface, CoreSurface );
639
640 if (fusion_skirmish_prevail( &surface->lock ))
641 return DFB_FUSION;
642
643 if (surface->type & CSTF_PREALLOCATED) {
644 fusion_skirmish_dismiss( &surface->lock );
645 return DFB_UNSUPPORTED;
646 }
647
648 /* Deallocate the Surface Buffers. */
649 for (i = 0; i < surface->num_buffers; i++)
650 dfb_surface_buffer_deallocate( surface->buffers[i] );
651
652 fusion_skirmish_dismiss( &surface->lock );
653
654 return DFB_OK;
655 }
656
657 DFBResult
dfb_surface_lock_buffer(CoreSurface * surface,CoreSurfaceBufferRole role,CoreSurfaceAccessorID accessor,CoreSurfaceAccessFlags access,CoreSurfaceBufferLock * ret_lock)658 dfb_surface_lock_buffer( CoreSurface *surface,
659 CoreSurfaceBufferRole role,
660 CoreSurfaceAccessorID accessor,
661 CoreSurfaceAccessFlags access,
662 CoreSurfaceBufferLock *ret_lock )
663 {
664 DFBResult ret;
665 CoreSurfaceAllocation *allocation;
666
667 D_MAGIC_ASSERT( surface, CoreSurface );
668
669 D_DEBUG_AT( Core_Surface, "%s( 0x%02x 0x%02x ) <- %dx%d %s [%d]\n", __FUNCTION__, accessor, access,
670 surface->config.size.w, surface->config.size.h, dfb_pixelformat_name(surface->config.format),
671 role );
672
673 ret = CoreSurface_PreLockBuffer2( surface, role, accessor, access, true, &allocation );
674 if (ret)
675 return ret;
676
677 D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation );
678
679 D_DEBUG_AT( Core_Surface, " -> PreLockBuffer returned allocation %p (%s)\n", allocation, allocation->pool->desc.name );
680
681 /* Lock the allocation. */
682 dfb_surface_buffer_lock_init( ret_lock, accessor, access );
683
684 ret = dfb_surface_pool_lock( allocation->pool, allocation, ret_lock );
685 if (ret) {
686 D_DERROR( ret, "Core/SurfBuffer: Locking allocation failed! [%s]\n",
687 allocation->pool->desc.name );
688 dfb_surface_buffer_lock_deinit( ret_lock );
689
690 dfb_surface_allocation_unref( allocation );
691 return ret;
692 }
693
694 return DFB_OK;
695 }
696
697 DFBResult
dfb_surface_unlock_buffer(CoreSurface * surface,CoreSurfaceBufferLock * lock)698 dfb_surface_unlock_buffer( CoreSurface *surface,
699 CoreSurfaceBufferLock *lock )
700 {
701 DFBResult ret;
702
703 D_MAGIC_ASSERT( surface, CoreSurface );
704
705 ret = dfb_surface_buffer_unlock( lock );
706
707 return ret;
708 }
709
710 DFBResult
dfb_surface_read_buffer(CoreSurface * surface,CoreSurfaceBufferRole role,void * destination,int pitch,const DFBRectangle * prect)711 dfb_surface_read_buffer( CoreSurface *surface,
712 CoreSurfaceBufferRole role,
713 void *destination,
714 int pitch,
715 const DFBRectangle *prect )
716 {
717 DFBResult ret;
718 int y;
719 int bytes;
720 DFBRectangle rect;
721 DFBSurfacePixelFormat format;
722 CoreSurfaceAllocation *allocation;
723
724 D_MAGIC_ASSERT( surface, CoreSurface );
725 D_ASSERT( destination != NULL );
726 D_ASSERT( pitch > 0 );
727 DFB_RECTANGLE_ASSERT_IF( prect );
728
729 D_DEBUG_AT( Core_Surface, "%s( %p, %p [%d] )\n", __FUNCTION__, surface, destination, pitch );
730
731 /* Determine area. */
732 rect.x = 0;
733 rect.y = 0;
734 rect.w = surface->config.size.w;
735 rect.h = surface->config.size.h;
736
737 if (prect && (!dfb_rectangle_intersect( &rect, prect ) || !DFB_RECTANGLE_EQUAL( rect, *prect )))
738 return DFB_INVAREA;
739
740 /* Calculate bytes per read line. */
741 format = surface->config.format;
742 bytes = DFB_BYTES_PER_LINE( format, rect.w );
743
744 D_DEBUG_AT( Core_Surface, " -> %d,%d - %dx%d (%s)\n", DFB_RECTANGLE_VALS(&rect),
745 dfb_pixelformat_name( format ) );
746
747 ret = CoreSurface_PreLockBuffer2( surface, role, CSAID_CPU, CSAF_READ, false, &allocation );
748 if (ret == DFB_NOALLOCATION) {
749 for (y=0; y<rect.h; y++) {
750 memset( destination, 0, bytes );
751
752 destination += pitch;
753 }
754
755 return DFB_OK;
756 }
757 if (ret)
758 return ret;
759
760 D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation );
761
762 D_DEBUG_AT( Core_Surface, " -> PreLockBuffer returned allocation %p (%s)\n", allocation, allocation->pool->desc.name );
763
764 /* Try reading from allocation directly... */
765 ret = dfb_surface_pool_read( allocation->pool, allocation, destination, pitch, &rect );
766 if (ret) {
767 /* ...otherwise use fallback method via locking if possible. */
768 if (allocation->access[CSAID_CPU] & CSAF_READ) {
769 CoreSurfaceBufferLock lock;
770
771 /* Lock the allocation. */
772 dfb_surface_buffer_lock_init( &lock, CSAID_CPU, CSAF_READ );
773
774 ret = dfb_surface_pool_lock( allocation->pool, allocation, &lock );
775 if (ret) {
776 D_DERROR( ret, "Core/SurfBuffer: Locking allocation failed! [%s]\n",
777 allocation->pool->desc.name );
778 dfb_surface_buffer_lock_deinit( &lock );
779 dfb_surface_allocation_unref( allocation );
780 return ret;
781 }
782
783 /* Move to start of read. */
784 lock.addr += DFB_BYTES_PER_LINE( format, rect.x ) + rect.y * lock.pitch;
785
786 /* Copy the data. */
787 for (y=0; y<rect.h; y++) {
788 direct_memcpy( destination, lock.addr, bytes );
789
790 destination += pitch;
791 lock.addr += lock.pitch;
792 }
793
794 /* Unlock the allocation. */
795 ret = dfb_surface_pool_unlock( allocation->pool, allocation, &lock );
796 if (ret)
797 D_DERROR( ret, "Core/SurfBuffer: Unlocking allocation failed! [%s]\n", allocation->pool->desc.name );
798
799 dfb_surface_buffer_lock_deinit( &lock );
800 }
801 }
802
803 dfb_surface_allocation_unref( allocation );
804
805 return DFB_OK;
806 }
807
808 DFBResult
dfb_surface_write_buffer(CoreSurface * surface,CoreSurfaceBufferRole role,const void * source,int pitch,const DFBRectangle * prect)809 dfb_surface_write_buffer( CoreSurface *surface,
810 CoreSurfaceBufferRole role,
811 const void *source,
812 int pitch,
813 const DFBRectangle *prect )
814 {
815 DFBResult ret;
816 int bytes;
817 DFBRectangle rect;
818 DFBSurfacePixelFormat format;
819 CoreSurfaceAllocation *allocation;
820
821 D_MAGIC_ASSERT( surface, CoreSurface );
822 D_ASSERT( pitch > 0 || source == NULL );
823 DFB_RECTANGLE_ASSERT_IF( prect );
824
825 D_DEBUG_AT( Core_Surface, "%s( %p, %p [%d] )\n", __FUNCTION__, surface, source, pitch );
826
827 /* Determine area. */
828 rect.x = 0;
829 rect.y = 0;
830 rect.w = surface->config.size.w;
831 rect.h = surface->config.size.h;
832
833 if (prect) {
834 if (!dfb_rectangle_intersect( &rect, prect )) {
835 D_DEBUG_AT( Core_Surface, " -> no intersection!\n" );
836 return DFB_INVAREA;
837 }
838
839 if (!DFB_RECTANGLE_EQUAL( rect, *prect )) {
840 D_DEBUG_AT( Core_Surface, " -> got clipped to %d,%d-%dx%d!\n", DFB_RECTANGLE_VALS(&rect) );
841 return DFB_INVAREA;
842 }
843 }
844
845 /* Calculate bytes per read line. */
846 format = surface->config.format;
847 bytes = DFB_BYTES_PER_LINE( format, rect.w );
848
849 D_DEBUG_AT( Core_Surface, " -> %d,%d - %dx%d (%s)\n", DFB_RECTANGLE_VALS(&rect),
850 dfb_pixelformat_name( format ) );
851
852 ret = CoreSurface_PreLockBuffer2( surface, role, CSAID_CPU, CSAF_WRITE, false, &allocation );
853 if (ret)
854 return ret;
855
856 D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation );
857
858 D_DEBUG_AT( Core_Surface, " -> PreLockBuffer returned allocation %p (%s)\n", allocation, allocation->pool->desc.name );
859
860 /* Try writing to allocation directly... */
861 ret = source ? dfb_surface_pool_write( allocation->pool, allocation, source, pitch, &rect ) : DFB_UNSUPPORTED;
862 if (ret) {
863 /* ...otherwise use fallback method via locking if possible. */
864 if (allocation->access[CSAID_CPU] & CSAF_WRITE) {
865 int y;
866 int bytes;
867 DFBSurfacePixelFormat format;
868 CoreSurfaceBufferLock lock;
869
870 /* Calculate bytes per written line. */
871 format = surface->config.format;
872 bytes = DFB_BYTES_PER_LINE( format, rect.w );
873
874 /* Lock the allocation. */
875 dfb_surface_buffer_lock_init( &lock, CSAID_CPU, CSAF_WRITE );
876
877 ret = dfb_surface_pool_lock( allocation->pool, allocation, &lock );
878 if (ret) {
879 D_DERROR( ret, "Core/SurfBuffer: Locking allocation failed! [%s]\n",
880 allocation->pool->desc.name );
881 dfb_surface_buffer_lock_deinit( &lock );
882 dfb_surface_allocation_unref( allocation );
883 return ret;
884 }
885
886 /* Move to start of write. */
887 lock.addr += DFB_BYTES_PER_LINE( format, rect.x ) + rect.y * lock.pitch;
888
889 /* Copy the data. */
890 for (y=0; y<rect.h; y++) {
891 if (source) {
892 direct_memcpy( lock.addr, source, bytes );
893
894 source += pitch;
895 }
896 else
897 memset( lock.addr, 0, bytes );
898
899 lock.addr += lock.pitch;
900 }
901
902 /* Unlock the allocation. */
903 ret = dfb_surface_pool_unlock( allocation->pool, allocation, &lock );
904 if (ret)
905 D_DERROR( ret, "Core/SurfBuffer: Unlocking allocation failed! [%s]\n", allocation->pool->desc.name );
906
907 dfb_surface_buffer_lock_deinit( &lock );
908 }
909 }
910
911 dfb_surface_allocation_unref( allocation );
912
913 return DFB_OK;
914 }
915
916 DFBResult
dfb_surface_clear_buffers(CoreSurface * surface)917 dfb_surface_clear_buffers( CoreSurface *surface )
918 {
919 DFBResult ret = DFB_OK;
920
921 D_MAGIC_ASSERT( surface, CoreSurface );
922
923 if (surface->num_buffers == 0)
924 return DFB_SUSPENDED;
925
926 if (fusion_skirmish_prevail( &surface->lock ))
927 return DFB_FUSION;
928
929 dfb_gfx_clear( surface, CSBR_FRONT );
930
931 if (surface->config.caps & DSCAPS_FLIPPING)
932 dfb_gfx_clear( surface, CSBR_BACK );
933
934 if (surface->config.caps & DSCAPS_TRIPLE)
935 dfb_gfx_clear( surface, CSBR_IDLE );
936
937 fusion_skirmish_dismiss( &surface->lock );
938
939 return ret;
940 }
941
942
943 DFBResult
dfb_surface_dump_buffer(CoreSurface * surface,CoreSurfaceBufferRole role,const char * path,const char * prefix)944 dfb_surface_dump_buffer( CoreSurface *surface,
945 CoreSurfaceBufferRole role,
946 const char *path,
947 const char *prefix )
948 {
949 DFBResult ret;
950 CoreSurfaceBuffer *buffer;
951
952 D_MAGIC_ASSERT( surface, CoreSurface );
953 D_ASSERT( path != NULL );
954 D_ASSERT( prefix != NULL );
955
956 if (fusion_skirmish_prevail( &surface->lock ))
957 return DFB_FUSION;
958
959 if (surface->num_buffers == 0) {
960 fusion_skirmish_dismiss( &surface->lock );
961 return DFB_SUSPENDED;
962 }
963
964 buffer = dfb_surface_get_buffer( surface, role );
965 D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );
966
967 ret = dfb_surface_buffer_dump( buffer, path, prefix );
968
969 fusion_skirmish_dismiss( &surface->lock );
970
971 return ret;
972 }
973
974 DFBResult
dfb_surface_set_palette(CoreSurface * surface,CorePalette * palette)975 dfb_surface_set_palette( CoreSurface *surface,
976 CorePalette *palette )
977 {
978 D_MAGIC_ASSERT( surface, CoreSurface );
979 D_MAGIC_ASSERT_IF( palette, CorePalette );
980
981 if (fusion_skirmish_prevail( &surface->lock ))
982 return DFB_FUSION;
983
984 if (surface->palette != palette) {
985 if (surface->palette) {
986 dfb_palette_detach_global( surface->palette, &surface->palette_reaction );
987 dfb_palette_unlink( &surface->palette );
988 }
989
990 if (palette) {
991 dfb_palette_link( &surface->palette, palette );
992 dfb_palette_attach_global( palette, DFB_SURFACE_PALETTE_LISTENER,
993 surface, &surface->palette_reaction );
994 }
995
996 dfb_surface_notify( surface, CSNF_PALETTE_CHANGE );
997 }
998
999 fusion_skirmish_dismiss( &surface->lock );
1000
1001 return DFB_OK;
1002 }
1003
1004 DFBResult
dfb_surface_set_field(CoreSurface * surface,int field)1005 dfb_surface_set_field( CoreSurface *surface,
1006 int field )
1007 {
1008 D_MAGIC_ASSERT( surface, CoreSurface );
1009
1010 if (fusion_skirmish_prevail( &surface->lock ))
1011 return DFB_FUSION;
1012
1013 surface->field = field;
1014
1015 dfb_surface_notify( surface, CSNF_FIELD );
1016
1017 fusion_skirmish_dismiss( &surface->lock );
1018
1019 return DFB_OK;
1020 }
1021
1022 DFBResult
dfb_surface_set_alpha_ramp(CoreSurface * surface,u8 a0,u8 a1,u8 a2,u8 a3)1023 dfb_surface_set_alpha_ramp( CoreSurface *surface,
1024 u8 a0,
1025 u8 a1,
1026 u8 a2,
1027 u8 a3 )
1028 {
1029 D_MAGIC_ASSERT( surface, CoreSurface );
1030
1031 if (fusion_skirmish_prevail( &surface->lock ))
1032 return DFB_FUSION;
1033
1034 surface->alpha_ramp[0] = a0;
1035 surface->alpha_ramp[1] = a1;
1036 surface->alpha_ramp[2] = a2;
1037 surface->alpha_ramp[3] = a3;
1038
1039 dfb_surface_notify( surface, CSNF_ALPHA_RAMP );
1040
1041 fusion_skirmish_dismiss( &surface->lock );
1042
1043 return DFB_OK;
1044 }
1045
1046 ReactionResult
_dfb_surface_palette_listener(const void * msg_data,void * ctx)1047 _dfb_surface_palette_listener( const void *msg_data,
1048 void *ctx )
1049 {
1050 const CorePaletteNotification *notification = msg_data;
1051 CoreSurface *surface = ctx;
1052
1053 if (notification->flags & CPNF_DESTROY)
1054 return RS_REMOVE;
1055
1056 if (notification->flags & CPNF_ENTRIES) {
1057 if (fusion_skirmish_prevail( &surface->lock ))
1058 return RS_OK;
1059
1060 dfb_surface_notify( surface, CSNF_PALETTE_UPDATE );
1061
1062 fusion_skirmish_dismiss( &surface->lock );
1063 }
1064
1065 return RS_OK;
1066 }
1067
1068