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 <string.h>
32 
33 #include <pthread.h>
34 
35 #include <fusion/fusion.h>
36 #include <fusion/reactor.h>
37 
38 #include <directfb.h>
39 
40 #include <core/core.h>
41 #include <core/coretypes.h>
42 
43 #include <core/palette.h>
44 #include <core/state.h>
45 #include <core/surface.h>
46 
47 #include <direct/mem.h>
48 #include <direct/memcpy.h>
49 #include <direct/util.h>
50 
51 #include <misc/conf.h>
52 
53 
54 static inline void
validate_clip(CardState * state,int xmax,int ymax,bool warn)55 validate_clip( CardState *state,
56                int        xmax,
57                int        ymax,
58                bool       warn )
59 {
60      D_MAGIC_ASSERT( state, CardState );
61      DFB_REGION_ASSERT( &state->clip );
62 
63      D_ASSERT( xmax >= 0 );
64      D_ASSERT( ymax >= 0 );
65      D_ASSERT( state->clip.x1 <= state->clip.x2 );
66      D_ASSERT( state->clip.y1 <= state->clip.y2 );
67 
68      if (state->clip.x1 <= xmax &&
69          state->clip.y1 <= ymax &&
70          state->clip.x2 <= xmax &&
71          state->clip.y2 <= ymax)
72           return;
73 
74      if (warn)
75           D_WARN( "Clip %d,%d-%dx%d invalid, adjusting to fit %dx%d",
76                   DFB_RECTANGLE_VALS_FROM_REGION( &state->clip ), xmax+1, ymax+1 );
77 
78      if (state->clip.x1 > xmax)
79           state->clip.x1 = xmax;
80 
81      if (state->clip.y1 > ymax)
82           state->clip.y1 = ymax;
83 
84      if (state->clip.x2 > xmax)
85           state->clip.x2 = xmax;
86 
87      if (state->clip.y2 > ymax)
88           state->clip.y2 = ymax;
89 
90      state->modified |= SMF_CLIP;
91 }
92 
93 int
dfb_state_init(CardState * state,CoreDFB * core)94 dfb_state_init( CardState *state, CoreDFB *core )
95 {
96      D_ASSERT( state != NULL );
97 
98      memset( state, 0, sizeof(CardState) );
99 
100      state->core           = core;
101      state->fusion_id      = fusion_id( dfb_core_world(core) );
102      state->modified       = SMF_ALL;
103      state->src_blend      = DSBF_SRCALPHA;
104      state->dst_blend      = DSBF_INVSRCALPHA;
105      state->render_options = dfb_config->render_options;
106 
107      state->matrix[0] = 0x10000;
108      state->matrix[1] = 0x00000;
109      state->matrix[2] = 0x00000;
110      state->matrix[3] = 0x00000;
111      state->matrix[4] = 0x10000;
112      state->matrix[5] = 0x00000;
113      state->matrix[6] = 0x00000;
114      state->matrix[7] = 0x00000;
115      state->matrix[8] = 0x10000;
116      state->affine_matrix = DFB_TRUE;
117 
118      state->from      = CSBR_FRONT;
119      state->to        = CSBR_BACK;
120 
121      direct_util_recursive_pthread_mutex_init( &state->lock );
122 
123      direct_serial_init( &state->dst_serial );
124      direct_serial_init( &state->src_serial );
125      direct_serial_init( &state->src_mask_serial );
126      direct_serial_init( &state->src2_serial );
127 
128      D_MAGIC_SET( state, CardState );
129 
130      return 0;
131 }
132 
133 void
dfb_state_destroy(CardState * state)134 dfb_state_destroy( CardState *state )
135 {
136      D_MAGIC_ASSERT( state, CardState );
137 
138      D_ASSUME( !(state->flags & CSF_DRAWING) );
139 
140      D_ASSERT( state->destination == NULL );
141      D_ASSERT( state->source == NULL );
142      D_ASSERT( state->source2 == NULL );
143      D_ASSERT( state->source_mask == NULL );
144 
145      D_MAGIC_CLEAR( state );
146 
147      direct_serial_deinit( &state->dst_serial );
148      direct_serial_deinit( &state->src_serial );
149      direct_serial_deinit( &state->src_mask_serial );
150      direct_serial_deinit( &state->src2_serial );
151 
152      if (state->gfxs) {
153           GenefxState *gfxs = state->gfxs;
154 
155           if (gfxs->ABstart)
156                D_FREE( gfxs->ABstart );
157 
158           D_FREE( gfxs );
159      }
160 
161      if (state->num_translation) {
162           D_ASSERT( state->index_translation != NULL );
163 
164           D_FREE( state->index_translation );
165      }
166      else
167           D_ASSERT( state->index_translation == NULL );
168 
169      pthread_mutex_destroy( &state->lock );
170 }
171 
172 DFBResult
dfb_state_set_destination(CardState * state,CoreSurface * destination)173 dfb_state_set_destination( CardState *state, CoreSurface *destination )
174 {
175      D_MAGIC_ASSERT( state, CardState );
176 
177      dfb_state_lock( state );
178 
179      D_ASSUME( !(state->flags & CSF_DRAWING) );
180 
181      if (state->destination != destination) {
182           if (destination) {
183                if (dfb_surface_ref( destination )) {
184                     D_WARN( "could not ref() destination" );
185                     dfb_state_unlock( state );
186                     return DFB_DEAD;
187                }
188 
189                validate_clip( state, destination->config.size.w - 1, destination->config.size.h - 1, false );
190           }
191 
192           if (state->destination) {
193                D_ASSERT( D_FLAGS_IS_SET( state->flags, CSF_DESTINATION ) );
194                dfb_surface_unref( state->destination );
195           }
196 
197           state->destination  = destination;
198           state->modified    |= SMF_DESTINATION;
199 
200           if (destination) {
201                direct_serial_copy( &state->dst_serial, &destination->serial );
202 
203                D_FLAGS_SET( state->flags, CSF_DESTINATION );
204           }
205           else
206                D_FLAGS_CLEAR( state->flags, CSF_DESTINATION );
207      }
208 
209      dfb_state_unlock( state );
210 
211      return DFB_OK;
212 }
213 
214 DFBResult
dfb_state_set_source(CardState * state,CoreSurface * source)215 dfb_state_set_source( CardState *state, CoreSurface *source )
216 {
217      D_MAGIC_ASSERT( state, CardState );
218 
219      dfb_state_lock( state );
220 
221      if (state->source != source) {
222           if (source && dfb_surface_ref( source )) {
223                D_WARN( "could not ref() source" );
224                dfb_state_unlock( state );
225                return DFB_DEAD;
226           }
227 
228           if (state->source) {
229                D_ASSERT( D_FLAGS_IS_SET( state->flags, CSF_SOURCE ) );
230                dfb_surface_unref( state->source );
231           }
232 
233           state->source    = source;
234           state->modified |= SMF_SOURCE;
235 
236           if (source) {
237                direct_serial_copy( &state->src_serial, &source->serial );
238 
239                D_FLAGS_SET( state->flags, CSF_SOURCE );
240           }
241           else
242                D_FLAGS_CLEAR( state->flags, CSF_SOURCE );
243      }
244 
245      dfb_state_unlock( state );
246 
247      return DFB_OK;
248 }
249 
250 DFBResult
dfb_state_set_source2(CardState * state,CoreSurface * source2)251 dfb_state_set_source2( CardState *state, CoreSurface *source2 )
252 {
253      D_MAGIC_ASSERT( state, CardState );
254 
255      dfb_state_lock( state );
256 
257      if (state->source2 != source2) {
258           if (source2 && dfb_surface_ref( source2 )) {
259                D_WARN( "could not ref() source2" );
260                dfb_state_unlock( state );
261                return DFB_DEAD;
262           }
263 
264           if (state->source2) {
265                D_ASSERT( D_FLAGS_IS_SET( state->flags, CSF_SOURCE2 ) );
266                dfb_surface_unref( state->source2 );
267           }
268 
269           state->source2   = source2;
270           state->modified |= SMF_SOURCE2;
271 
272           if (source2) {
273                direct_serial_copy( &state->src2_serial, &source2->serial );
274 
275                D_FLAGS_SET( state->flags, CSF_SOURCE2 );
276           }
277           else
278                D_FLAGS_CLEAR( state->flags, CSF_SOURCE2 );
279      }
280 
281      dfb_state_unlock( state );
282 
283      return DFB_OK;
284 }
285 
286 DFBResult
dfb_state_set_source_mask(CardState * state,CoreSurface * source_mask)287 dfb_state_set_source_mask( CardState *state, CoreSurface *source_mask )
288 {
289      D_MAGIC_ASSERT( state, CardState );
290 
291      dfb_state_lock( state );
292 
293      if (state->source_mask != source_mask) {
294           if (source_mask && dfb_surface_ref( source_mask )) {
295                D_WARN( "could not ref() source mask" );
296                dfb_state_unlock( state );
297                return DFB_DEAD;
298           }
299 
300           if (state->source_mask) {
301                D_ASSERT( D_FLAGS_IS_SET( state->flags, CSF_SOURCE_MASK ) );
302                dfb_surface_unref( state->source_mask );
303           }
304 
305           state->source_mask  = source_mask;
306           state->modified    |= SMF_SOURCE_MASK;
307 
308           if (source_mask) {
309                direct_serial_copy( &state->src_mask_serial, &source_mask->serial );
310 
311                D_FLAGS_SET( state->flags, CSF_SOURCE_MASK );
312           }
313           else
314                D_FLAGS_CLEAR( state->flags, CSF_SOURCE_MASK );
315      }
316 
317      dfb_state_unlock( state );
318 
319      return DFB_OK;
320 }
321 
322 void
dfb_state_update(CardState * state,bool update_sources)323 dfb_state_update( CardState *state, bool update_sources )
324 {
325      CoreSurface *destination;
326 
327      D_MAGIC_ASSERT( state, CardState );
328      DFB_REGION_ASSERT( &state->clip );
329 
330      destination = state->destination;
331 
332      if (D_FLAGS_IS_SET( state->flags, CSF_DESTINATION )) {
333 
334           D_ASSERT( destination != NULL );
335 
336           if (direct_serial_update( &state->dst_serial, &destination->serial )) {
337                validate_clip( state, destination->config.size.w - 1, destination->config.size.h - 1, true );
338 
339                state->modified |= SMF_DESTINATION;
340           }
341      }
342      else if (destination)
343           validate_clip( state, destination->config.size.w - 1, destination->config.size.h - 1, true );
344 
345      if (update_sources && D_FLAGS_IS_SET( state->flags, CSF_SOURCE )) {
346           CoreSurface *source = state->source;
347 
348           D_ASSERT( source != NULL );
349 
350           if (direct_serial_update( &state->src_serial, &source->serial ))
351                state->modified |= SMF_SOURCE;
352      }
353 
354      if (update_sources && D_FLAGS_IS_SET( state->flags, CSF_SOURCE_MASK )) {
355           CoreSurface *source_mask = state->source_mask;
356 
357           D_ASSERT( source_mask != NULL );
358 
359           if (direct_serial_update( &state->src_mask_serial, &source_mask->serial ))
360                state->modified |= SMF_SOURCE_MASK;
361      }
362 
363      if (update_sources && D_FLAGS_IS_SET( state->flags, CSF_SOURCE2 )) {
364           CoreSurface *source2 = state->source2;
365 
366           D_ASSERT( source2 != NULL );
367 
368           if (direct_serial_update( &state->src2_serial, &source2->serial ))
369                state->modified |= SMF_SOURCE2;
370      }
371 }
372 
373 DFBResult
dfb_state_set_index_translation(CardState * state,const int * indices,int num_indices)374 dfb_state_set_index_translation( CardState *state,
375                                  const int *indices,
376                                  int        num_indices )
377 {
378      D_MAGIC_ASSERT( state, CardState );
379 
380      D_ASSERT( indices != NULL || num_indices == 0 );
381 
382      dfb_state_lock( state );
383 
384      if (state->num_translation != num_indices) {
385           int *new_trans = D_REALLOC( state->index_translation,
386                                       num_indices * sizeof(int) );
387 
388           D_ASSERT( num_indices || new_trans == NULL );
389 
390           if (num_indices && !new_trans) {
391                dfb_state_unlock( state );
392                return D_OOM();
393           }
394 
395           state->index_translation = new_trans;
396           state->num_translation   = num_indices;
397      }
398 
399      if (num_indices)
400           direct_memcpy( state->index_translation, indices, num_indices * sizeof(int) );
401 
402      state->modified |= SMF_INDEX_TRANSLATION;
403 
404      dfb_state_unlock( state );
405 
406      return DFB_OK;
407 }
408 
409 void
dfb_state_set_matrix(CardState * state,const s32 * matrix)410 dfb_state_set_matrix( CardState *state,
411                       const s32 *matrix )
412 {
413      D_MAGIC_ASSERT( state, CardState );
414 
415      D_ASSERT( matrix != NULL );
416 
417      if (memcmp( state->matrix, matrix, sizeof(state->matrix) )) {
418           direct_memcpy( state->matrix, matrix, sizeof(state->matrix) );
419 
420           state->affine_matrix = (matrix[6] == 0x00000 &&
421                                   matrix[7] == 0x00000 &&
422                                   matrix[8] == 0x10000);
423 
424           state->modified |= SMF_MATRIX;
425      }
426 }
427 
428 void
dfb_state_set_color_or_index(CardState * state,const DFBColor * color,int index)429 dfb_state_set_color_or_index( CardState      *state,
430                               const DFBColor *color,
431                               int             index )
432 {
433      CoreSurface *destination;
434      CorePalette *palette = NULL;
435 
436      D_MAGIC_ASSERT( state, CardState );
437      D_ASSERT( color != NULL );
438 
439      destination = state->destination;
440      if (destination)
441           palette = destination->palette;
442 
443      if (index < 0) {
444           D_ASSERT( color != NULL );
445 
446           if (palette)
447                dfb_state_set_color_index( state, dfb_palette_search( palette,
448                                                                      color->r, color->g,
449                                                                      color->b, color->a ) );
450 
451           dfb_state_set_color( state, color );
452      }
453      else {
454           dfb_state_set_color_index( state, index );
455 
456           if (palette) {
457                D_ASSERT( palette->num_entries > 0 );
458                D_ASSUME( palette->num_entries > index );
459 
460                dfb_state_set_color( state, &palette->entries[index % palette->num_entries] );
461           }
462      }
463 }
464 
465