1 /* This file is an image processing operation for GEGL
2  *
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.
7  *
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.
12  *
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/>.
15  *
16  * Copyright 2006 Øyvind Kolås <pippin@gimp.org>
17  */
18 
19 #include "config.h"
20 #include <glib/gi18n-lib.h>
21 
22 
23 #ifdef GEGL_PROPERTIES
24 
25 property_object (buffer, _("Buffer location"), GEGL_TYPE_BUFFER)
26     description(_("A pre-existing GeglBuffer to write incoming buffer data to."))
27 
28 #else
29 
30 #define GEGL_OP_SINK
31 #define GEGL_OP_C_SOURCE write-buffer.c
32 #define GEGL_OP_NAME     write_buffer
33 
34 #include "gegl-op.h"
35 
36 #include "gegl/gegl-debug.h"
37 #include "opencl/gegl-cl.h"
38 #include "gegl-buffer-cl-iterator.h"
39 
40 typedef struct
41 {
42   GeglBuffer *input;
43   GeglBuffer *output;
44 } ThreadData;
45 
46 static void
47 thread_process (const GeglRectangle *area,
48                 ThreadData          *data)
49 {
50   gegl_buffer_copy (data->input,  area, GEGL_ABYSS_NONE,
51                     data->output, area);
52 }
53 
54 static gboolean
55 process (GeglOperation       *operation,
56          GeglBuffer          *input,
57          const GeglRectangle *result,
58          gint                 level)
59 {
60   GeglProperties *o = GEGL_PROPERTIES (operation);
61 
62   if (o->buffer)
63     {
64       GeglBuffer *output = GEGL_BUFFER (o->buffer);
65       const Babl *in_format = gegl_buffer_get_format (input);
66       const Babl *out_format = gegl_buffer_get_format (output);
67 
68       if (gegl_operation_use_opencl (operation)
69           && gegl_cl_color_supported (in_format, out_format) == GEGL_CL_COLOR_CONVERT)
70         {
71           size_t size;
72           gboolean err;
73           cl_int cl_err = 0;
74 
75           GeglBufferClIterator *i = gegl_buffer_cl_iterator_new (output,
76                                                                  result,
77                                                                  out_format,
78                                                                  GEGL_CL_BUFFER_WRITE);
79 
80           gint read = gegl_buffer_cl_iterator_add (i,
81                                                    input,
82                                                    result,
83                                                    out_format,
84                                                    GEGL_CL_BUFFER_READ,
85                                                    GEGL_ABYSS_NONE);
86 
87           gegl_cl_color_babl (out_format, &size);
88 
89           GEGL_NOTE (GEGL_DEBUG_OPENCL,
90                      "write-buffer: "
91                      "%p %p %s %s {%d %d %d %d}",
92                      input,
93                      output,
94                      babl_get_name (in_format),
95                      babl_get_name (out_format),
96                      result->x,
97                      result->y,
98                      result->width,
99                      result->height);
100 
101           while (gegl_buffer_cl_iterator_next (i, &err))
102             {
103               if (err) break;
104 
105               cl_err = gegl_clEnqueueCopyBuffer (gegl_cl_get_command_queue (),
106                                                  i->tex[read],
107                                                  i->tex[0],
108                                                  0,
109                                                  0,
110                                                  i->size[0] * size,
111                                                  0,
112                                                  NULL,
113                                                  NULL);
114 
115               if (cl_err != CL_SUCCESS)
116                 {
117                   GEGL_NOTE (GEGL_DEBUG_OPENCL, "Error: %s", gegl_cl_errstring (cl_err));
118                   break;
119                 }
120             }
121 
122           if (! (cl_err || err))
123             return TRUE;
124         }
125 
126       if (in_format == out_format)
127         {
128           gegl_buffer_copy (input,  result, GEGL_ABYSS_NONE,
129                             output, result);
130         }
131       else
132         {
133           ThreadData data;
134 
135           data.input  = input;
136           data.output = output;
137 
138           gegl_parallel_distribute_area (
139             result,
140             gegl_operation_get_pixels_per_thread (operation),
141             GEGL_SPLIT_STRATEGY_AUTO,
142             (GeglParallelDistributeAreaFunc) thread_process,
143             &data);
144         }
145     }
146 
147   return TRUE;
148 }
149 
150 static void
151 dispose (GObject *object)
152 {
153   GeglProperties *o = GEGL_PROPERTIES (object);
154 
155   g_clear_object (&o->buffer);
156 
157   G_OBJECT_CLASS (gegl_op_parent_class)->dispose (object);
158 }
159 
160 static void
161 gegl_op_class_init (GeglOpClass *klass)
162 {
163   GeglOperationClass     *operation_class;
164   GeglOperationSinkClass *sink_class;
165 
166   operation_class = GEGL_OPERATION_CLASS (klass);
167   sink_class      = GEGL_OPERATION_SINK_CLASS (klass);
168 
169   sink_class->process = process;
170   sink_class->needs_full = FALSE;
171 
172   G_OBJECT_CLASS (klass)->dispose = dispose;
173 
174   gegl_operation_class_set_keys (operation_class,
175     "name",        "gegl:write-buffer",
176     "title",       _("Write Buffer"),
177     "categories" , "programming:output",
178     "description", _("Write input data into an existing GEGL buffer destination surface."),
179     NULL);
180 }
181 
182 #endif
183