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 //#define DIRECT_ENABLE_DEBUG
30 
31 #include <config.h>
32 
33 #include <direct/debug.h>
34 #include <direct/hash.h>
35 #include <direct/mem.h>
36 
37 #include <fusion/shmalloc.h>
38 
39 #include <core/surface_pool.h>
40 
41 #include "x11.h"
42 #include "x11image.h"
43 #include "x11_surface_pool.h"
44 
45 D_DEBUG_DOMAIN( X11_Surfaces, "X11/Surfaces", "X11 System Surface Pool" );
46 
47 /**********************************************************************************************************************/
48 
49 typedef struct {
50 } x11PoolData;
51 
52 typedef struct {
53      pthread_mutex_t  lock;
54      DirectHash      *hash;
55 
56      DFBX11          *x11;
57 } x11PoolLocalData;
58 
59 /**********************************************************************************************************************/
60 
61 static int
x11PoolDataSize(void)62 x11PoolDataSize( void )
63 {
64      return sizeof(x11PoolData);
65 }
66 
67 static int
x11PoolLocalDataSize(void)68 x11PoolLocalDataSize( void )
69 {
70      return sizeof(x11PoolLocalData);
71 }
72 
73 static int
x11AllocationDataSize(void)74 x11AllocationDataSize( void )
75 {
76      return sizeof(x11AllocationData);
77 }
78 
79 static DFBResult
x11InitPool(CoreDFB * core,CoreSurfacePool * pool,void * pool_data,void * pool_local,void * system_data,CoreSurfacePoolDescription * ret_desc)80 x11InitPool( CoreDFB                    *core,
81              CoreSurfacePool            *pool,
82              void                       *pool_data,
83              void                       *pool_local,
84              void                       *system_data,
85              CoreSurfacePoolDescription *ret_desc )
86 {
87      DFBResult         ret;
88      x11PoolLocalData *local = pool_local;
89      DFBX11           *x11   = system_data;
90 
91      D_DEBUG_AT( X11_Surfaces, "%s()\n", __FUNCTION__ );
92 
93      D_MAGIC_ASSERT( pool, CoreSurfacePool );
94      D_ASSERT( ret_desc != NULL );
95 
96      local->x11 = x11;
97 
98      ret_desc->caps              = CSPCAPS_VIRTUAL;
99      ret_desc->access[CSAID_CPU] = CSAF_READ | CSAF_WRITE | CSAF_SHARED;
100      ret_desc->types             = CSTF_LAYER | CSTF_WINDOW | CSTF_CURSOR | CSTF_FONT | CSTF_SHARED | CSTF_EXTERNAL;
101      ret_desc->priority          = CSPP_DEFAULT;
102 
103      /* For showing our X11 window */
104      ret_desc->access[CSAID_LAYER0] = CSAF_READ;
105      ret_desc->access[CSAID_LAYER1] = CSAF_READ;
106      ret_desc->access[CSAID_LAYER2] = CSAF_READ;
107 
108      snprintf( ret_desc->name, DFB_SURFACE_POOL_DESC_NAME_LENGTH, "X11 Shm Images" );
109 
110      ret = direct_hash_create( 7, &local->hash );
111      if (ret) {
112           D_DERROR( ret, "X11/Surfaces: Could not create local hash table!\n" );
113           return ret;
114      }
115 
116      pthread_mutex_init( &local->lock, NULL );
117 
118      return DFB_OK;
119 }
120 
121 static DFBResult
x11JoinPool(CoreDFB * core,CoreSurfacePool * pool,void * pool_data,void * pool_local,void * system_data)122 x11JoinPool( CoreDFB                    *core,
123              CoreSurfacePool            *pool,
124              void                       *pool_data,
125              void                       *pool_local,
126              void                       *system_data )
127 {
128      DFBResult         ret;
129      x11PoolLocalData *local = pool_local;
130      DFBX11           *x11   = system_data;
131 
132      D_DEBUG_AT( X11_Surfaces, "%s()\n", __FUNCTION__ );
133 
134      D_MAGIC_ASSERT( pool, CoreSurfacePool );
135 
136      local->x11 = x11;
137 
138      ret = direct_hash_create( 7, &local->hash );
139      if (ret) {
140           D_DERROR( ret, "X11/Surfaces: Could not create local hash table!\n" );
141           return ret;
142      }
143 
144      pthread_mutex_init( &local->lock, NULL );
145 
146      return DFB_OK;
147 }
148 
149 static DFBResult
x11DestroyPool(CoreSurfacePool * pool,void * pool_data,void * pool_local)150 x11DestroyPool( CoreSurfacePool *pool,
151                 void            *pool_data,
152                 void            *pool_local )
153 {
154      x11PoolLocalData *local = pool_local;
155 
156      D_DEBUG_AT( X11_Surfaces, "%s()\n", __FUNCTION__ );
157 
158      D_MAGIC_ASSERT( pool, CoreSurfacePool );
159 
160      pthread_mutex_destroy( &local->lock );
161 
162      direct_hash_destroy( local->hash );
163 
164      return DFB_OK;
165 }
166 
167 static DFBResult
x11LeavePool(CoreSurfacePool * pool,void * pool_data,void * pool_local)168 x11LeavePool( CoreSurfacePool *pool,
169               void            *pool_data,
170               void            *pool_local )
171 {
172      x11PoolLocalData *local = pool_local;
173 
174      D_DEBUG_AT( X11_Surfaces, "%s()\n", __FUNCTION__ );
175 
176      D_MAGIC_ASSERT( pool, CoreSurfacePool );
177 
178      pthread_mutex_destroy( &local->lock );
179 
180      direct_hash_destroy( local->hash );
181 
182      return DFB_OK;
183 }
184 
185 static DFBResult
x11TestConfig(CoreSurfacePool * pool,void * pool_data,void * pool_local,CoreSurfaceBuffer * buffer,const CoreSurfaceConfig * config)186 x11TestConfig( CoreSurfacePool         *pool,
187                void                    *pool_data,
188                void                    *pool_local,
189                CoreSurfaceBuffer       *buffer,
190                const CoreSurfaceConfig *config )
191 {
192      x11PoolLocalData *local  = pool_local;
193      DFBX11           *x11    = local->x11;
194      DFBX11Shared     *shared = x11->shared;
195 
196      /* Provide a fallback only if no virtual physical pool is allocated... */
197      if (!shared->vpsmem_length)
198           return DFB_OK;
199 
200      /* Pass NULL image for probing */
201      return x11ImageInit( x11, NULL, config->size.w, config->size.h, config->format );
202 }
203 
204 static DFBResult
x11AllocateBuffer(CoreSurfacePool * pool,void * pool_data,void * pool_local,CoreSurfaceBuffer * buffer,CoreSurfaceAllocation * allocation,void * alloc_data)205 x11AllocateBuffer( CoreSurfacePool       *pool,
206                    void                  *pool_data,
207                    void                  *pool_local,
208                    CoreSurfaceBuffer     *buffer,
209                    CoreSurfaceAllocation *allocation,
210                    void                  *alloc_data )
211 {
212      CoreSurface       *surface;
213      x11AllocationData *alloc = alloc_data;
214      x11PoolLocalData  *local = pool_local;
215      DFBX11            *x11   = local->x11;
216 
217      D_DEBUG_AT( X11_Surfaces, "%s()\n", __FUNCTION__ );
218 
219      D_MAGIC_ASSERT( pool, CoreSurfacePool );
220      D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );
221 
222      surface = buffer->surface;
223      D_MAGIC_ASSERT( surface, CoreSurface );
224 
225      if (x11ImageInit( x11, &alloc->image, surface->config.size.w, surface->config.size.h, surface->config.format ) == DFB_OK) {
226           alloc->real  = true;
227           alloc->pitch = alloc->image.pitch;
228 
229           allocation->size = surface->config.size.h * alloc->image.pitch;
230      }
231      else
232           dfb_surface_calc_buffer_size( surface, 8, 2, &alloc->pitch, &allocation->size );
233 
234      return DFB_OK;
235 }
236 
237 static DFBResult
x11DeallocateBuffer(CoreSurfacePool * pool,void * pool_data,void * pool_local,CoreSurfaceBuffer * buffer,CoreSurfaceAllocation * allocation,void * alloc_data)238 x11DeallocateBuffer( CoreSurfacePool       *pool,
239                      void                  *pool_data,
240                      void                  *pool_local,
241                      CoreSurfaceBuffer     *buffer,
242                      CoreSurfaceAllocation *allocation,
243                      void                  *alloc_data )
244 {
245      x11AllocationData *alloc  = alloc_data;
246      x11PoolLocalData  *local  = pool_local;
247      DFBX11            *x11    = local->x11;
248      DFBX11Shared      *shared = x11->shared;
249 
250      D_DEBUG_AT( X11_Surfaces, "%s()\n", __FUNCTION__ );
251 
252      D_MAGIC_ASSERT( pool, CoreSurfacePool );
253 
254      CORE_SURFACE_ALLOCATION_ASSERT( allocation );
255 
256      if (alloc->real)
257           return x11ImageDestroy( x11, &alloc->image );
258 
259      if (alloc->ptr)
260           SHFREE( shared->data_shmpool, alloc->ptr );
261 
262      return DFB_OK;
263 }
264 
265 static DFBResult
x11Lock(CoreSurfacePool * pool,void * pool_data,void * pool_local,CoreSurfaceAllocation * allocation,void * alloc_data,CoreSurfaceBufferLock * lock)266 x11Lock( CoreSurfacePool       *pool,
267          void                  *pool_data,
268          void                  *pool_local,
269          CoreSurfaceAllocation *allocation,
270          void                  *alloc_data,
271          CoreSurfaceBufferLock *lock )
272 {
273      DFBResult          ret;
274      x11PoolLocalData  *local  = pool_local;
275      x11AllocationData *alloc  = alloc_data;
276      DFBX11            *x11    = local->x11;
277      DFBX11Shared      *shared = x11->shared;
278 
279      D_DEBUG_AT( X11_Surfaces, "%s( %p )\n", __FUNCTION__, allocation );
280 
281      D_MAGIC_ASSERT( pool, CoreSurfacePool );
282      D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation );
283      D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock );
284 
285      D_ASSERT( local->hash != NULL );
286 
287      pthread_mutex_lock( &local->lock );
288 
289      if (alloc->real) {
290           void *addr = direct_hash_lookup( local->hash, alloc->image.seginfo.shmid );
291 
292           if (!addr) {
293                ret = x11ImageAttach( &alloc->image, &addr );
294                if (ret) {
295                     D_DERROR( ret, "X11/Surfaces: x11ImageAttach() failed!\n" );
296                     pthread_mutex_unlock( &local->lock );
297                     return ret;
298                }
299 
300                direct_hash_insert( local->hash, alloc->image.seginfo.shmid, addr );
301 
302                /* FIXME: When to remove/detach? */
303           }
304 
305           lock->addr   = addr;
306           lock->handle = &alloc->image;
307      }
308      else {
309           if (!alloc->ptr) {
310                alloc->ptr = SHCALLOC( shared->data_shmpool, 1, allocation->size );
311                if (!alloc->ptr) {
312                     pthread_mutex_unlock( &local->lock );
313                     return D_OOSHM();
314                }
315           }
316 
317           lock->addr = alloc->ptr;
318      }
319 
320      lock->pitch = alloc->pitch;
321 
322      pthread_mutex_unlock( &local->lock );
323 
324      return DFB_OK;
325 }
326 
327 static DFBResult
x11Unlock(CoreSurfacePool * pool,void * pool_data,void * pool_local,CoreSurfaceAllocation * allocation,void * alloc_data,CoreSurfaceBufferLock * lock)328 x11Unlock( CoreSurfacePool       *pool,
329            void                  *pool_data,
330            void                  *pool_local,
331            CoreSurfaceAllocation *allocation,
332            void                  *alloc_data,
333            CoreSurfaceBufferLock *lock )
334 {
335      D_DEBUG_AT( X11_Surfaces, "%s( %p )\n", __FUNCTION__, allocation );
336 
337      D_MAGIC_ASSERT( pool, CoreSurfacePool );
338      D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation );
339      D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock );
340 
341      /* FIXME: Check overhead of attach/detach per lock/unlock. */
342 
343      return DFB_OK;
344 }
345 
346 const SurfacePoolFuncs x11SurfacePoolFuncs = {
347      .PoolDataSize       = x11PoolDataSize,
348      .PoolLocalDataSize  = x11PoolLocalDataSize,
349      .AllocationDataSize = x11AllocationDataSize,
350 
351      .InitPool           = x11InitPool,
352      .JoinPool           = x11JoinPool,
353      .DestroyPool        = x11DestroyPool,
354      .LeavePool          = x11LeavePool,
355 
356      .TestConfig         = x11TestConfig,
357 
358      .AllocateBuffer     = x11AllocateBuffer,
359      .DeallocateBuffer   = x11DeallocateBuffer,
360 
361      .Lock               = x11Lock,
362      .Unlock             = x11Unlock,
363 };
364 
365