summaryrefslogtreecommitdiff
path: root/src/lib/evas/filters/evas_filter_private.h
blob: f6faea38385ccdd750e70933ee951cd34b1c31a4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
#ifndef EVAS_FILTER_PRIVATE_H
#define EVAS_FILTER_PRIVATE_H

#include "evas_filter.h"
#include "evas_private.h"

/* logging variables */
extern int _evas_filter_log_dom;
#define EVAS_FILTER_LOG_COLOR EINA_COLOR_LIGHTBLUE

#ifdef ERR
# undef ERR
#endif
#define ERR(...) EINA_LOG_DOM_ERR(_evas_filter_log_dom, __VA_ARGS__)
#ifdef INF
# undef INF
#endif
#define INF(...) EINA_LOG_DOM_INFO(_evas_filter_log_dom, __VA_ARGS__)
#ifdef WRN
# undef WRN
#endif
#define WRN(...) EINA_LOG_DOM_WARN(_evas_filter_log_dom, __VA_ARGS__)
#ifdef CRI
# undef CRI
#endif
#define CRI(...) EINA_LOG_DOM_CRIT(_evas_filter_log_dom, __VA_ARGS__)
#ifdef DBG
# undef DBG
#endif
#define DBG(...) EINA_LOG_DOM_DBG(_evas_filter_log_dom, __VA_ARGS__)

#ifdef FILTERS_DEBUG
# define XDBG(...) DBG(__VA_ARGS__)
#else
# define XDBG(...) do {} while (0)
#endif

// This is a potential optimization.
#define DIV_USING_BITSHIFT 1

#ifdef LITTLE_ENDIAN
#define ALPHA 3
#define RGB0 0
#define RGB3 3
#define RED 2
#define GREEN 1
#define BLUE 0
#else
#define ALPHA 0
#define RGB0 1
#define RGB3 4
#define RED 0
#define GREEN 1
#define BLUE 2
#endif

// RGBA = (((a) << 24) + ((r) << 16) + ((g) << 8) + (b))
#define ALPHA_OF(a) ((a) >> 24)
#define RED_OF(a)   (((a) >> 16) & 0xff)
#define GREEN_OF(a) (((a) >> 8) & 0xff)
#define BLUE_OF(a)  ((a) & 0xff)

// Enable debug if you're working on optimizations
#define DEBUG_TIME 1

// Windows build will break if CLOCK_MONOTONIC is used
#if !defined(_POSIX_MONOTONIC_CLOCK) || (_POSIX_MONOTONIC_CLOCK < 0)
# undef DEBUG_TIME
# define DEBUG_TIME 0
#endif

// The 'restrict' keyword is part of C99
#if __STDC_VERSION__ < 199901L
# define restrict
#endif

// Helpers
#undef ENFN
#undef ENDT
#undef ENC
#define ENFN ctx->evas->engine.func
#define ENDT _evas_default_output_get(ctx->evas)
#define ENC _evas_engine_context(ctx->evas)

#define CMD_ENDT _evas_default_output_get(cmd->ctx->evas)
#define CMD_ENC _evas_engine_context(cmd->ctx->evas)
#define FB_ENC _evas_engine_context(fb->ctx->evas)

#define BUFFERS_LOCK() do { if (cmd->input) cmd->input->locked = 1; if (cmd->output) cmd->output->locked = 1; if (cmd->mask) cmd->mask->locked = 1; } while (0)
#define BUFFERS_UNLOCK() do { if (cmd->input) cmd->input->locked = 0; if (cmd->output) cmd->output->locked = 0; if (cmd->mask) cmd->mask->locked = 0; } while (0)

#if DEBUG_TIME
# define DEBUG_TIME_BEGIN() \
   struct timespec ts1, ts2; \
   clock_gettime(CLOCK_MONOTONIC, &ts1);
# define DEBUG_TIME_END() \
   clock_gettime(CLOCK_MONOTONIC, &ts2); \
   long long int t = 1000000LL * (ts2.tv_sec - ts1.tv_sec) \
   + (ts2.tv_nsec - ts1.tv_nsec) / 1000LL; (void) t; \
   XDBG("TIME SPENT: %lldus", t);
#else
# define DEBUG_TIME_BEGIN() do {} while(0)
# define DEBUG_TIME_END() do {} while(0)
#endif

#if DIV_USING_BITSHIFT
# define DEFINE_DIVIDER(div) const int pow2 = evas_filter_smallest_pow2_larger_than((div) << 10); const int numerator = (1 << pow2) / (div);
# define DIVIDE(val) (((val) * numerator) >> pow2)
#else
# define DEFINE_DIVIDER(div) const int divider = (div);
# define DIVIDE(val) ((val) / divider)
#endif

typedef enum _Evas_Filter_Interpolation_Mode Evas_Filter_Interpolation_Mode;

typedef Evas_Filter_Buffer * (*evas_filter_buffer_scaled_get_func)(Evas_Filter_Context *ctx, Evas_Filter_Buffer *src, unsigned w, unsigned h);


struct _Evas_Filter_Context
{
   Evas_Public_Data *evas;
   Eina_Inlist *commands;
   Eina_List *buffers; // Evas_Filter_Buffer *
   int last_buffer_id;
   int last_command_id;
   void *user_data; // used by textblock

   // ugly hack (dlsym fail)
   evas_filter_buffer_scaled_get_func buffer_scaled_get;

   // Variables changing at each run
   int x, y; // Position of the object (for GL downscaling of snapshots)
   int w, h; // Dimensions of the input/output buffers

   struct {
      // Padding in the current input/output buffers
      Evas_Filter_Padding calculated, final;
   } pad;

   struct {
      // Useless region: obscured by other objects
      Eina_Rectangle real, effective;
   } obscured;

   struct
   {
      /** Post-processing callback. The context can be safely destroyed here. */
      Evas_Filter_Cb cb;
      void *data;
   } post_run;

   struct
   {
      void *surface;
      int x, y;
      int cx, cy, cw, ch; // clip
      int r, g, b, a; // clip color
      void *mask; // mask
      int mask_x, mask_y; // mask offset
      Evas_Render_Op rop;
      RGBA_Map *map;
      Eina_Bool clip_use : 1;
      Eina_Bool color_use : 1;
   } target;

   int          run_count;

   Eina_Bool running : 1;
   Eina_Bool delete_me : 1;
   Eina_Bool async : 1;
   Eina_Bool has_proxies : 1;
   Eina_Bool gl : 1;

};

struct _Evas_Filter_Command
{
   EINA_INLIST;

   int id;
   Evas_Filter_Mode mode;
   Evas_Filter_Context *ctx;

   Evas_Filter_Buffer *input;
   Evas_Filter_Buffer *mask;
   Evas_Filter_Buffer *output;

   union
   {
      struct
      {
         float dx, dy;
         int count;
         Evas_Filter_Blur_Type type;
         Eina_Bool auto_count : 1; // If true, BOX blur will be smooth using
      } blur;

      struct
      {
         DATA8 *data; // Pointer to 256 char array
         Evas_Filter_Channel channel;
      } curve;

      struct
      {
         // mask contains the map data
         Evas_Filter_Displacement_Flags flags;
         int intensity; // Max displacement in pixels
      } displacement;

      struct
      {
         float xyangle; // in degrees: 0-360 (modulo)
         float zangle;  // degrees: 0-90 (defaults to 0)
         float specular_factor; // range TBD: 0-...
         float elevation;
         DATA32 dark;
         DATA32 color;
         DATA32 white;
         Eina_Bool compensate : 1; // Compensate for darkening
         //Eina_Bool specular : 1; // Use specular light as well (needs specular_factor > 0)
      } bump;

      struct
      {
         Evas_Filter_Transform_Flags flags;
      } transform;
   };

   struct {
      Efl_Gfx_Render_Op rop;
      int R, G, B, A;
      int ox, oy;
      union {
         struct {
            int x, y, w, h;
         };
         struct {
            int l, r, t, b;
         };
      } clip;
      struct {
         int factor_x, factor_y;
         int pad_x, pad_y;
         Eina_Bool down;
      } scale;
      Evas_Filter_Fill_Mode fillmode;
      Eina_Bool clip_use : 1;
      Eina_Bool clip_mode_lrtb : 1;
      Eina_Bool need_temp_buffer : 1;
      Eina_Bool output_was_dirty : 1;
   } draw;
};

struct _Evas_Filter_Buffer
{
   EINA_REFCOUNT;

   int id;
   Evas_Filter_Context *ctx;

   Evas_Object *source;
   Eina_Stringshare *source_name;
   Ector_Buffer *buffer;
   int w, h;

   Eina_Bool used : 1;        // This buffer is in use (useful for reuse of context)
   Eina_Bool alpha_only : 1;  // 1 channel (A) instead of 4 (RGBA)
   Eina_Bool transient : 1;   // temporary buffer (automatic allocation)
   Eina_Bool locked : 1;      // internal flag
   Eina_Bool dirty : 1;       // Marked as dirty as soon as a command writes to it
   Eina_Bool is_render : 1;   // Is render target of a filter using engine functions (ie. needs FBO in GL)
   Eina_Bool cleanup : 1;     // Needs cleaning up if not allocated
};

enum _Evas_Filter_Interpolation_Mode
{
   EVAS_FILTER_INTERPOLATION_MODE_NONE,
   EVAS_FILTER_INTERPOLATION_MODE_LINEAR
};

enum _Evas_Filter_Support
{
   EVAS_FILTER_SUPPORT_NONE = 0,
   EVAS_FILTER_SUPPORT_CPU,
   EVAS_FILTER_SUPPORT_GL
};

void                     evas_filter_mixin_init(void);
void                     evas_filter_mixin_shutdown(void);

void                     evas_filter_context_clear(Evas_Filter_Context *ctx, Eina_Bool keep_buffers);
void                     evas_filter_context_source_set(Evas_Filter_Context *ctx, Evas_Object *eo_proxy, Evas_Object *eo_source, int bufid, Eina_Stringshare *name);

/* Utility functions */
void _clip_to_target(int *sx, int *sy, int sw, int sh, int ox, int oy, int dw, int dh, int *dx, int *dy, int *rows, int *cols);
Eina_Bool evas_filter_buffer_alloc(Evas_Filter_Buffer *fb, int w, int h);
Evas_Filter_Buffer *_filter_buffer_get(Evas_Filter_Context *ctx, int bufid);
Evas_Filter_Buffer *evas_filter_temporary_buffer_get(Evas_Filter_Context *ctx, int w, int h, Eina_Bool alpha_only, Eina_Bool clean);
Evas_Filter_Buffer *evas_filter_buffer_scaled_get(Evas_Filter_Context *ctx, Evas_Filter_Buffer *src, unsigned w, unsigned h);
Eina_Bool           evas_filter_interpolate(DATA8* output /* 256 values */, int *points /* 256 values */, Evas_Filter_Interpolation_Mode mode);
int evas_filter_smallest_pow2_larger_than(int val);

void _evas_filter_context_program_reuse(Evas_Filter_Context *ctx);
void evas_filter_parser_shutdown(void);

#define E_READ  ECTOR_BUFFER_ACCESS_FLAG_READ
#define E_WRITE ECTOR_BUFFER_ACCESS_FLAG_WRITE
#define E_ALPHA EFL_GFX_COLORSPACE_GRY8
#define E_ARGB  EFL_GFX_COLORSPACE_ARGB8888

static inline void *
_buffer_map_all(Ector_Buffer *buf, unsigned int *len, Ector_Buffer_Access_Flag mode, Efl_Gfx_Colorspace cspace, unsigned int *stride)
{
   void *ret = NULL;
   int w, h;
   if (!buf) return NULL;
   ector_buffer_size_get(buf, &w, &h);
   ret = ector_buffer_map(buf, len, mode, 0, 0, w, h, cspace, stride);
   return ret;
}

#endif // EVAS_FILTER_PRIVATE_H