1 /* This file is an image processing operation for GEGL
3 * GEGL is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 3 of the License, or (at your option) any later version.
8 * GEGL is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
16 * Copyright 2012,2013 Felix Ulber <felix.ulber@gmx.de>
17 * 2013 Øyvind Kolås <pippin@gimp.org>
22 #include <glib/gi18n-lib.h>
24 #ifdef GEGL_PROPERTIES
26 property_double (black_level
, _("Black level"), 0.0)
27 description (_("Adjust the black level"))
28 value_range (-0.1, 0.1)
30 property_double (exposure
, _("Exposure"), 0.0)
31 description (_("Relative brightness change in stops"))
32 ui_range (-10.0, 10.0)
36 #define GEGL_OP_POINT_FILTER
37 #define GEGL_OP_NAME exposure
38 #define GEGL_OP_C_SOURCE exposure.c
41 #include "opencl/gegl-cl.h"
44 #define exp2f (b) ((gfloat) pow (2.0, b))
47 typedef void (*ProcessFunc
) (GeglOperation
*operation
,
51 const GeglRectangle
*roi
,
56 GeglClRunData
**cl_data_ptr
;
58 const char *kernel_name
;
59 const char *kernel_source
;
62 static GeglClRunData
*cl_data_rgb
= NULL
;
63 static GeglClRunData
*cl_data_rgba
= NULL
;
64 static GeglClRunData
*cl_data_y
= NULL
;
65 static GeglClRunData
*cl_data_ya
= NULL
;
67 static const char* kernel_source_rgb
=
68 "__kernel void kernel_exposure_rgb(__global const float *in, \n"
69 " __global float *out, \n"
70 " float black_level, \n"
73 " int gid = get_global_id(0); \n"
74 " int offset = 3 * gid; \n"
75 " float3 in_v = (float3) (in[offset], in[offset + 1], in[offset+2]); \n"
77 " out_v.xyz = ((in_v.xyz - black_level) * gain); \n"
78 " out[offset] = out_v.x; \n"
79 " out[offset + 1] = out_v.y; \n"
80 " out[offset + 2] = out_v.z; \n"
83 static const char* kernel_source_rgba
=
84 "__kernel void kernel_exposure_rgba(__global const float4 *in, \n"
85 " __global float4 *out, \n"
86 " float black_level, \n"
89 " int gid = get_global_id(0); \n"
90 " float4 in_v = in[gid]; \n"
92 " out_v.xyz = ((in_v.xyz - black_level) * gain); \n"
93 " out_v.w = in_v.w; \n"
94 " out[gid] = out_v; \n"
97 static const char* kernel_source_y
=
98 "__kernel void kernel_exposure_y(__global const float *in, \n"
99 " __global float *out, \n"
100 " float black_level, \n"
103 " int gid = get_global_id(0); \n"
104 " float in_v = in[gid]; \n"
106 " out_v = ((in_v - black_level) * gain); \n"
107 " out[gid] = out_v; \n"
110 static const char* kernel_source_ya
=
111 "__kernel void kernel_exposure_ya(__global const float2 *in, \n"
112 " __global float2 *out, \n"
113 " float black_level, \n"
116 " int gid = get_global_id(0); \n"
117 " float2 in_v = in[gid]; \n"
119 " out_v.x = ((in_v.x - black_level) * gain); \n"
120 " out_v.y = in_v.y; \n"
121 " out[gid] = out_v; \n"
125 process_rgb (GeglOperation
*op
,
129 const GeglRectangle
*roi
,
132 GeglProperties
*o
= GEGL_PROPERTIES (op
);
135 gfloat black_level
= (gfloat
) o
->black_level
;
137 gfloat exposure_negated
= (gfloat
) -o
->exposure
;
146 white
= exp2f (exposure_negated
);
147 diff
= MAX (white
- black_level
, 0.000001);
150 for (i
=0; i
<n_pixels
; i
++)
152 out_pixel
[0] = (in_pixel
[0] - black_level
) * gain
;
153 out_pixel
[1] = (in_pixel
[1] - black_level
) * gain
;
154 out_pixel
[2] = (in_pixel
[2] - black_level
) * gain
;
162 process_rgba (GeglOperation
*op
,
166 const GeglRectangle
*roi
,
169 GeglProperties
*o
= GEGL_PROPERTIES (op
);
172 gfloat black_level
= (gfloat
) o
->black_level
;
174 gfloat exposure_negated
= (gfloat
) -o
->exposure
;
183 white
= exp2f (exposure_negated
);
184 diff
= MAX (white
- black_level
, 0.000001);
187 for (i
=0; i
<n_pixels
; i
++)
189 out_pixel
[0] = (in_pixel
[0] - black_level
) * gain
;
190 out_pixel
[1] = (in_pixel
[1] - black_level
) * gain
;
191 out_pixel
[2] = (in_pixel
[2] - black_level
) * gain
;
192 out_pixel
[3] = in_pixel
[3];
200 process_y (GeglOperation
*op
,
204 const GeglRectangle
*roi
,
207 GeglProperties
*o
= GEGL_PROPERTIES (op
);
210 gfloat black_level
= (gfloat
) o
->black_level
;
212 gfloat exposure_negated
= (gfloat
) -o
->exposure
;
221 white
= exp2f (exposure_negated
);
222 diff
= MAX (white
- black_level
, 0.000001);
225 for (i
=0; i
<n_pixels
; i
++)
227 out_pixel
[0] = (in_pixel
[0] - black_level
) * gain
;
235 process_ya (GeglOperation
*op
,
239 const GeglRectangle
*roi
,
242 GeglProperties
*o
= GEGL_PROPERTIES (op
);
245 gfloat black_level
= (gfloat
) o
->black_level
;
247 gfloat exposure_negated
= (gfloat
) -o
->exposure
;
256 white
= exp2f (exposure_negated
);
257 diff
= MAX (white
- black_level
, 0.000001);
260 for (i
=0; i
<n_pixels
; i
++)
262 out_pixel
[0] = (in_pixel
[0] - black_level
) * gain
;
263 out_pixel
[1] = in_pixel
[1];
271 prepare (GeglOperation
*operation
)
273 GeglProperties
*o
= GEGL_PROPERTIES (operation
);
274 const Babl
*space
= gegl_operation_get_source_space (operation
, "input");
277 const Babl
*input_format
;
278 const Babl
*input_model
;
281 if (o
->user_data
== NULL
)
282 o
->user_data
= g_slice_new0 (EParamsType
);
284 params
= (EParamsType
*) o
->user_data
;
286 input_format
= gegl_operation_get_source_format (operation
, "input");
287 if (input_format
== NULL
)
289 format
= babl_format ("RGBA float");
291 params
->process
= process_rgba
;
293 params
->cl_data_ptr
= &cl_data_rgba
;
294 params
->kernel_name
= "kernel_exposure_rgba";
295 params
->kernel_source
= kernel_source_rgba
;
299 input_model
= babl_format_get_model (input_format
);
301 if (babl_format_has_alpha (input_format
))
303 y_model
= babl_model_with_space ("YA", space
);
304 if (input_model
== y_model
)
306 format
= babl_format_with_space ("YA float", space
);
308 params
->process
= process_ya
;
310 params
->cl_data_ptr
= &cl_data_ya
;
311 params
->kernel_name
= "kernel_exposure_ya";
312 params
->kernel_source
= kernel_source_ya
;
316 format
= babl_format_with_space ("RGBA float", space
);
318 params
->process
= process_rgba
;
320 params
->cl_data_ptr
= &cl_data_rgba
;
321 params
->kernel_name
= "kernel_exposure_rgba";
322 params
->kernel_source
= kernel_source_rgba
;
327 y_model
= babl_model_with_space ("Y", space
);
328 if (input_model
== y_model
)
330 format
= babl_format_with_space ("Y float", space
);
332 params
->process
= process_y
;
334 params
->cl_data_ptr
= &cl_data_y
;
335 params
->kernel_name
= "kernel_exposure_y";
336 params
->kernel_source
= kernel_source_y
;
340 format
= babl_format_with_space ("RGB float", space
);
342 params
->process
= process_rgb
;
344 params
->cl_data_ptr
= &cl_data_rgb
;
345 params
->kernel_name
= "kernel_exposure_rgb";
346 params
->kernel_source
= kernel_source_rgb
;
351 gegl_operation_set_format (operation
, "input", format
);
352 gegl_operation_set_format (operation
, "output", format
);
355 /* GeglOperationPointFilter gives us a linear buffer to operate on
356 * in our requested pixel format
359 process (GeglOperation
*operation
,
363 const GeglRectangle
*roi
,
366 GeglProperties
*o
= GEGL_PROPERTIES (operation
);
367 EParamsType
*params
= (EParamsType
*) o
->user_data
;
369 params
->process (operation
, in_buf
, out_buf
, n_pixels
, roi
, level
);
373 /* OpenCL processing function */
375 cl_process (GeglOperation
*op
,
378 size_t global_worksize
,
379 const GeglRectangle
*roi
,
382 /* Retrieve a pointer to GeglProperties structure which contains all the
386 GeglProperties
*o
= GEGL_PROPERTIES (op
);
387 EParamsType
*params
= (EParamsType
*) o
->user_data
;
389 gfloat black_level
= (gfloat
) o
->black_level
;
391 gfloat exposure_negated
= (gfloat
) -o
->exposure
;
395 GeglClRunData
*cl_data_local
;
398 if (*params
->cl_data_ptr
== NULL
)
400 const char *kernel_name
[] = {NULL
, NULL
};
402 kernel_name
[0] = params
->kernel_name
;
403 *params
->cl_data_ptr
= gegl_cl_compile_and_build (params
->kernel_source
, kernel_name
);
405 if (*params
->cl_data_ptr
== NULL
) return 1;
407 cl_data_local
= *params
->cl_data_ptr
;
409 white
= exp2f (exposure_negated
);
410 diff
= MAX (white
- black_level
, 0.000001);
413 cl_err
|= gegl_clSetKernelArg(cl_data_local
->kernel
[0], 0, sizeof(cl_mem
), (void*)&in_tex
);
414 cl_err
|= gegl_clSetKernelArg(cl_data_local
->kernel
[0], 1, sizeof(cl_mem
), (void*)&out_tex
);
415 cl_err
|= gegl_clSetKernelArg(cl_data_local
->kernel
[0], 2, sizeof(cl_float
), (void*)&black_level
);
416 cl_err
|= gegl_clSetKernelArg(cl_data_local
->kernel
[0], 3, sizeof(cl_float
), (void*)&gain
);
417 if (cl_err
!= CL_SUCCESS
) return cl_err
;
419 cl_err
= gegl_clEnqueueNDRangeKernel(gegl_cl_get_command_queue (),
420 cl_data_local
->kernel
[0], 1,
421 NULL
, &global_worksize
, NULL
,
423 if (cl_err
!= CL_SUCCESS
) return cl_err
;
429 finalize (GObject
*object
)
431 GeglOperation
*op
= GEGL_OPERATION (object
);
432 GeglProperties
*o
= GEGL_PROPERTIES (op
);
435 g_slice_free (EParamsType
, o
->user_data
);
437 G_OBJECT_CLASS (gegl_op_parent_class
)->finalize (object
);
441 gegl_op_class_init (GeglOpClass
*klass
)
443 GObjectClass
*object_class
;
444 GeglOperationClass
*operation_class
;
445 GeglOperationPointFilterClass
*point_filter_class
;
447 "<?xml version='1.0' encoding='UTF-8'?>"
449 " <node operation='gegl:crop' width='200' height='200'/>"
450 " <node operation='gegl:over'>"
451 " <node operation='gegl:exposure'>"
453 " <param name='exposure'>1.5</param>"
456 " <node operation='gegl:load' path='standard-input.png'/>"
458 " <node operation='gegl:checkerboard'>"
460 " <param name='color1'>rgb(0.25,0.25,0.25)</param>"
461 " <param name='color2'>rgb(0.75,0.75,0.75)</param>"
466 object_class
= G_OBJECT_CLASS (klass
);
467 operation_class
= GEGL_OPERATION_CLASS (klass
);
468 point_filter_class
= GEGL_OPERATION_POINT_FILTER_CLASS (klass
);
470 object_class
->finalize
= finalize
;
472 operation_class
->opencl_support
= TRUE
;
473 operation_class
->prepare
= prepare
;
475 point_filter_class
->process
= process
;
476 point_filter_class
->cl_process
= cl_process
;
478 gegl_operation_class_set_keys (operation_class
,
479 "name", "gegl:exposure",
480 "title", _("Exposure"),
481 "categories", "color",
482 "reference-hash", "a4ae5d7f933046aa462e0f7659bd1261",
483 "reference-composition", composition
,
484 "description", _("Change exposure of an image in shutter speed stops"),