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, &notification, 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, &notification, 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