1 /*
2  * Cogl
3  *
4  * A Low Level GPU Graphics and Utilities API
5  *
6  * Copyright (C) 2008,2009,2010,2011 Intel Corporation.
7  *
8  * Permission is hereby granted, free of charge, to any person
9  * obtaining a copy of this software and associated documentation
10  * files (the "Software"), to deal in the Software without
11  * restriction, including without limitation the rights to use, copy,
12  * modify, merge, publish, distribute, sublicense, and/or sell copies
13  * of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be
17  * included in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26  * SOFTWARE.
27  *
28  *
29  *
30  * Authors:
31  *   Robert Bragg <robert@linux.intel.com>
32  */
33 
34 #ifndef __COGL_PIPELINE_LAYER_PRIVATE_H
35 #define __COGL_PIPELINE_LAYER_PRIVATE_H
36 
37 #include "cogl-private.h"
38 #include "cogl-pipeline.h"
39 #include "cogl-node-private.h"
40 #include "cogl-texture.h"
41 #include "cogl-pipeline-layer-state.h"
42 #include "cogl-pipeline-snippet-private.h"
43 #include "cogl-sampler-cache-private.h"
44 
45 #include <glib.h>
46 
47 typedef struct _CoglPipelineLayer     CoglPipelineLayer;
48 #define COGL_PIPELINE_LAYER(OBJECT) ((CoglPipelineLayer *)OBJECT)
49 
50 /* XXX: should I rename these as
51  * COGL_PIPELINE_LAYER_STATE_INDEX_XYZ... ?
52  */
53 typedef enum
54 {
55   /* sparse state */
56   COGL_PIPELINE_LAYER_STATE_UNIT_INDEX,
57   COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX,
58   COGL_PIPELINE_LAYER_STATE_SAMPLER_INDEX,
59   COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX,
60   COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX,
61   COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX,
62   COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX,
63   COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS_INDEX,
64   COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS_INDEX,
65 
66   /* note: layers don't currently have any non-sparse state */
67 
68   COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT,
69   COGL_PIPELINE_LAYER_STATE_COUNT = COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT
70 } CoglPipelineLayerStateIndex;
71 
72 /* XXX: If you add or remove state groups here you may need to update
73  * some of the state masks following this enum too!
74  *
75  * FIXME: perhaps it would be better to rename this enum to
76  * CoglPipelineLayerStateGroup to better convey the fact that a single
77  * enum here can map to multiple properties.
78  */
79 typedef enum
80 {
81   COGL_PIPELINE_LAYER_STATE_UNIT =
82     1L<<COGL_PIPELINE_LAYER_STATE_UNIT_INDEX,
83   COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA =
84     1L<<COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX,
85   COGL_PIPELINE_LAYER_STATE_SAMPLER =
86     1L<<COGL_PIPELINE_LAYER_STATE_SAMPLER_INDEX,
87 
88   COGL_PIPELINE_LAYER_STATE_COMBINE =
89     1L<<COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX,
90   COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT =
91     1L<<COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX,
92   COGL_PIPELINE_LAYER_STATE_USER_MATRIX =
93     1L<<COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX,
94 
95   COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS =
96     1L<<COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX,
97 
98   COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS =
99     1L<<COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS_INDEX,
100   COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS =
101     1L<<COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS_INDEX,
102 
103   /* COGL_PIPELINE_LAYER_STATE_TEXTURE_INTERN   = 1L<<8, */
104 
105 } CoglPipelineLayerState;
106 
107 /*
108  * Various special masks that tag state-groups in different ways...
109  */
110 
111 #define COGL_PIPELINE_LAYER_STATE_ALL \
112   ((1L<<COGL_PIPELINE_LAYER_STATE_COUNT) - 1)
113 
114 #define COGL_PIPELINE_LAYER_STATE_ALL_SPARSE \
115   COGL_PIPELINE_LAYER_STATE_ALL
116 
117 #define COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE \
118   (COGL_PIPELINE_LAYER_STATE_COMBINE | \
119    COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT | \
120    COGL_PIPELINE_LAYER_STATE_USER_MATRIX | \
121    COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS | \
122    COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS | \
123    COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS)
124 
125 #define COGL_PIPELINE_LAYER_STATE_MULTI_PROPERTY \
126   (COGL_PIPELINE_LAYER_STATE_COMBINE | \
127    COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS | \
128    COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS)
129 
130 #define COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN \
131   COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS
132 
133 typedef enum
134 {
135   /* These are the same values as GL */
136   COGL_PIPELINE_COMBINE_FUNC_ADD         = 0x0104,
137   COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED  = 0x8574,
138   COGL_PIPELINE_COMBINE_FUNC_SUBTRACT    = 0x84E7,
139   COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE = 0x8575,
140   COGL_PIPELINE_COMBINE_FUNC_REPLACE     = 0x1E01,
141   COGL_PIPELINE_COMBINE_FUNC_MODULATE    = 0x2100,
142   COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB    = 0x86AE,
143   COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA   = 0x86AF
144 } CoglPipelineCombineFunc;
145 
146 typedef enum
147 {
148   /* Note that these numbers are deliberately not the same as the GL
149      numbers so that we can reserve all numbers > TEXTURE0 to store
150      very large layer numbers */
151   COGL_PIPELINE_COMBINE_SOURCE_TEXTURE,
152   COGL_PIPELINE_COMBINE_SOURCE_CONSTANT,
153   COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR,
154   COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS,
155   COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0
156 } CoglPipelineCombineSource;
157 
158 typedef enum
159 {
160   /* These are the same values as GL */
161   COGL_PIPELINE_COMBINE_OP_SRC_COLOR           = 0x0300,
162   COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR = 0x0301,
163   COGL_PIPELINE_COMBINE_OP_SRC_ALPHA           = 0x0302,
164   COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA = 0x0303
165 } CoglPipelineCombineOp;
166 
167 typedef struct
168 {
169   /* The texture combine state determines how the color of individual
170    * texture fragments are calculated. */
171   CoglPipelineCombineFunc texture_combine_rgb_func;
172   CoglPipelineCombineSource texture_combine_rgb_src[3];
173   CoglPipelineCombineOp texture_combine_rgb_op[3];
174 
175   CoglPipelineCombineFunc texture_combine_alpha_func;
176   CoglPipelineCombineSource texture_combine_alpha_src[3];
177   CoglPipelineCombineOp texture_combine_alpha_op[3];
178 
179   float texture_combine_constant[4];
180 
181   /* The texture matrix dscribes how to transform texture coordinates */
182   graphene_matrix_t matrix;
183 
184   CoglPipelineSnippetList vertex_snippets;
185   CoglPipelineSnippetList fragment_snippets;
186 
187   gboolean point_sprite_coords;
188 } CoglPipelineLayerBigState;
189 
190 struct _CoglPipelineLayer
191 {
192   /* XXX: Please think twice about adding members that *have* be
193    * initialized during a _cogl_pipeline_layer_copy. We are aiming
194    * to have copies be as cheap as possible and copies may be
195    * done by the primitives APIs which means they may happen
196    * in performance critical code paths.
197    *
198    * XXX: If you are extending the state we track please consider if
199    * the state is expected to vary frequently across many pipelines or
200    * if the state can be shared among many derived pipelines instead.
201    * This will determine if the state should be added directly to this
202    * structure which will increase the memory overhead for *all*
203    * layers or if instead it can go under ->big_state.
204    */
205 
206   /* Layers represent their state in a tree structure where some of
207    * the state relating to a given pipeline or layer may actually be
208    * owned by one if is ancestors in the tree. We have a common data
209    * type to track the tree hierarchy so we can share code... */
210   CoglNode _parent;
211 
212   /* Some layers have a pipeline owner, which is to say that the layer
213    * is referenced in that pipelines->layer_differences list.  A layer
214    * doesn't always have an owner and may simply be an ancestor for
215    * other layers that keeps track of some shared state. */
216   CoglPipeline      *owner;
217 
218   /* The lowest index is blended first then others on top */
219   int	             index;
220 
221   /* A mask of which state groups are different in this layer
222    * in comparison to its parent. */
223   unsigned int       differences;
224 
225   /* Common differences
226    *
227    * As a basic way to reduce memory usage we divide the layer
228    * state into two groups; the minimal state modified in 90% of
229    * all layers and the rest, so that the second group can
230    * be allocated dynamically when required.
231    */
232 
233   /* Each layer is directly associated with a single texture unit */
234   int                        unit_index;
235 
236   /* The texture for this layer, or NULL for an empty
237    * layer */
238   CoglTexture               *texture;
239 
240   const CoglSamplerCacheEntry *sampler_cache_entry;
241 
242   /* Infrequent differences aren't currently tracked in
243    * a separate, dynamically allocated structure as they are
244    * for pipelines... */
245   CoglPipelineLayerBigState *big_state;
246 
247   /* bitfields */
248 
249   /* Determines if layer->big_state is valid */
250   unsigned int          has_big_state:1;
251 
252 };
253 
254 typedef gboolean
255 (*CoglPipelineLayerStateComparator) (CoglPipelineLayer *authority0,
256                                      CoglPipelineLayer *authority1);
257 
258 
259 
260 void
261 _cogl_pipeline_init_default_layers (void);
262 
263 static inline CoglPipelineLayer *
_cogl_pipeline_layer_get_parent(CoglPipelineLayer * layer)264 _cogl_pipeline_layer_get_parent (CoglPipelineLayer *layer)
265 {
266   CoglNode *parent_node = COGL_NODE (layer)->parent;
267   return COGL_PIPELINE_LAYER (parent_node);
268 }
269 
270 CoglPipelineLayer *
271 _cogl_pipeline_layer_copy (CoglPipelineLayer *layer);
272 
273 void
274 _cogl_pipeline_layer_resolve_authorities (CoglPipelineLayer *layer,
275                                           unsigned long differences,
276                                           CoglPipelineLayer **authorities);
277 
278 gboolean
279 _cogl_pipeline_layer_equal (CoglPipelineLayer *layer0,
280                             CoglPipelineLayer *layer1,
281                             unsigned long differences_mask,
282                             CoglPipelineEvalFlags flags);
283 
284 CoglPipelineLayer *
285 _cogl_pipeline_layer_pre_change_notify (CoglPipeline *required_owner,
286                                         CoglPipelineLayer *layer,
287                                         CoglPipelineLayerState change);
288 
289 void
290 _cogl_pipeline_layer_prune_redundant_ancestry (CoglPipelineLayer *layer);
291 
292 gboolean
293 _cogl_pipeline_layer_has_alpha (CoglPipelineLayer *layer);
294 
295 gboolean
296 _cogl_pipeline_layer_has_user_matrix (CoglPipeline *pipeline,
297                                       int layer_index);
298 
299 /*
300  * Calls the pre_paint method on the layer texture if there is
301  * one. This will determine whether mipmaps are needed based on the
302  * filter settings.
303  */
304 void
305 _cogl_pipeline_layer_pre_paint (CoglPipelineLayer *layerr);
306 
307 void
308 _cogl_pipeline_layer_get_wrap_modes (CoglPipelineLayer *layer,
309                                      CoglSamplerCacheWrapMode *wrap_mode_s,
310                                      CoglSamplerCacheWrapMode *wrap_mode_t);
311 
312 void
313 _cogl_pipeline_layer_get_filters (CoglPipelineLayer *layer,
314                                   CoglPipelineFilter *min_filter,
315                                   CoglPipelineFilter *mag_filter);
316 
317 const CoglSamplerCacheEntry *
318 _cogl_pipeline_layer_get_sampler_state (CoglPipelineLayer *layer);
319 
320 void
321 _cogl_pipeline_get_layer_filters (CoglPipeline *pipeline,
322                                   int layer_index,
323                                   CoglPipelineFilter *min_filter,
324                                   CoglPipelineFilter *mag_filter);
325 
326 typedef enum
327 {
328   COGL_PIPELINE_LAYER_TYPE_TEXTURE
329 } CoglPipelineLayerType;
330 
331 CoglPipelineLayerType
332 _cogl_pipeline_layer_get_type (CoglPipelineLayer *layer);
333 
334 COGL_EXPORT CoglTexture *
335 _cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer);
336 
337 CoglTexture *
338 _cogl_pipeline_layer_get_texture_real (CoglPipelineLayer *layer);
339 
340 CoglPipelineFilter
341 _cogl_pipeline_layer_get_min_filter (CoglPipelineLayer *layer);
342 
343 CoglPipelineFilter
344 _cogl_pipeline_layer_get_mag_filter (CoglPipelineLayer *layer);
345 
346 CoglPipelineWrapMode
347 _cogl_pipeline_layer_get_wrap_mode_s (CoglPipelineLayer *layer);
348 
349 CoglPipelineWrapMode
350 _cogl_pipeline_layer_get_wrap_mode_t (CoglPipelineLayer *layer);
351 
352 void
353 _cogl_pipeline_layer_copy_differences (CoglPipelineLayer *dest,
354                                        CoglPipelineLayer *src,
355                                        unsigned long differences);
356 
357 unsigned long
358 _cogl_pipeline_layer_compare_differences (CoglPipelineLayer *layer0,
359                                           CoglPipelineLayer *layer1);
360 
361 CoglPipelineLayer *
362 _cogl_pipeline_layer_get_authority (CoglPipelineLayer *layer,
363                                     unsigned long difference);
364 
365 int
366 _cogl_pipeline_layer_get_unit_index (CoglPipelineLayer *layer);
367 
368 gboolean
369 _cogl_pipeline_layer_needs_combine_separate
370                                        (CoglPipelineLayer *combine_authority);
371 
372 #endif /* __COGL_PIPELINE_LAYER_PRIVATE_H */
373