gegl-buffer-cl-cache.c 9.69 KB
Newer Older
1 2 3
#include <glib.h>

#include "gegl.h"
4
#include "gegl/gegl-debug.h"
5 6 7 8 9 10 11 12 13 14 15 16 17
#include "gegl-utils.h"
#include "gegl-types-internal.h"
#include "gegl-buffer-types.h"
#include "gegl-buffer.h"
#include "gegl-buffer-private.h"
#include "gegl-buffer-cl-cache.h"
#include "opencl/gegl-cl.h"

typedef struct
{
  GeglBuffer           *buffer;
  GeglRectangle         roi;
  cl_mem                tex;
Victor Oliveira's avatar
Victor Oliveira committed
18
  gboolean              valid;
19 20
} CacheEntry;

21
static GList *cache_entries = NULL;
22 23 24 25 26 27

typedef struct
{
  GeglBuffer   *buffer;
  GeglBuffer   *buffer_origin;
  GeglRectangle roi;
Victor Oliveira's avatar
Victor Oliveira committed
28
  gboolean      valid;
29 30
} CacheBuffer;

31 32 33
static GList *cache_buffer = NULL; /* this is used in color conversions from the cache */

static GStaticMutex cache_mutex = G_STATIC_MUTEX_INIT;
34 35 36 37 38

cl_mem
gegl_buffer_cl_cache_get (GeglBuffer          *buffer,
                          const GeglRectangle *roi)
{
39
  GList *elem;
40

41
  for (elem=cache_entries; elem; elem=elem->next)
42
    {
43
      CacheEntry *e = elem->data;
Victor Oliveira's avatar
Victor Oliveira committed
44 45
      if (e->valid && e->buffer == buffer
          && gegl_rectangle_equal (&e->roi, roi))
46 47 48 49 50 51 52 53 54 55 56 57
        {
          return e->tex;
        }
    }
  return NULL;
}

void
gegl_buffer_cl_cache_new (GeglBuffer            *buffer,
                          const GeglRectangle   *roi,
                          cl_mem                 tex)
{
58
  g_static_mutex_lock (&cache_mutex);
59

60 61
  {
  CacheEntry *e = g_slice_new (CacheEntry);
62

63 64 65 66
  e->buffer =  buffer;
  e->roi    = *roi;
  e->tex    =  tex;
  e->valid  =  TRUE;
67

68 69
  cache_entries = g_list_prepend (cache_entries, e);
  }
70

71
  g_static_mutex_unlock (&cache_mutex);
72 73
}

74
#define CL_ERROR {GEGL_NOTE (GEGL_DEBUG_OPENCL, "Error in %s:%d@%s - %s\n", __FILE__, __LINE__, __func__, gegl_cl_errstring(cl_err)); goto error;}
75

76 77 78 79 80
gboolean
gegl_buffer_cl_cache_merge (GeglBuffer          *buffer,
                            const GeglRectangle *roi)
{
  size_t size;
81
  GList *elem;
82 83 84
  GeglRectangle tmp;
  cl_int cl_err = 0;

85 86 87
  if (!roi)
    roi = &buffer->extent;

Victor Oliveira's avatar
Victor Oliveira committed
88
  gegl_cl_color_babl (buffer->format, &size);
89

90
  for (elem=cache_entries; elem; elem=elem->next)
91
    {
92
      CacheEntry *entry = elem->data;
Victor Oliveira's avatar
Victor Oliveira committed
93 94

      if (entry->valid && entry->buffer == buffer
95
          && (gegl_rectangle_intersect (&tmp, roi, &entry->roi)))
96 97 98 99
        {
          gpointer data;

          data = gegl_clEnqueueMapBuffer(gegl_cl_get_command_queue(), entry->tex, CL_TRUE,
100
                                         CL_MAP_READ, 0, entry->roi.width * entry->roi.height * size,
101
                                         0, NULL, NULL, &cl_err);
102
          if (cl_err != CL_SUCCESS) CL_ERROR;
103 104

          /* tile-ize */
105
          gegl_buffer_set (entry->buffer, &entry->roi, 0, entry->buffer->format, data, GEGL_AUTO_ROWSTRIDE);
106 107 108

          cl_err = gegl_clEnqueueUnmapMemObject (gegl_cl_get_command_queue(), entry->tex, data,
                                                 0, NULL, NULL);
109
          if (cl_err != CL_SUCCESS) CL_ERROR;
110 111 112 113
        }
    }

  return TRUE;
114 115 116 117

error:
  /* XXX : result is corrupted */
  return FALSE;
118 119
}

Victor Oliveira's avatar
Victor Oliveira committed
120
static gboolean
121
cache_buffer_find_invalid (gpointer *data)
Victor Oliveira's avatar
Victor Oliveira committed
122
{
123 124 125
  GList *elem;

  for (elem=cache_buffer; elem; elem=elem->next)
Victor Oliveira's avatar
Victor Oliveira committed
126
    {
127
      CacheBuffer *cb = elem->data;
Victor Oliveira's avatar
Victor Oliveira committed
128 129
      if (!cb->valid)
        {
130
          *data = cb;
Victor Oliveira's avatar
Victor Oliveira committed
131 132 133 134
          return TRUE;
        }
    }

135
  *data = NULL;
Victor Oliveira's avatar
Victor Oliveira committed
136 137 138
  return FALSE;
}

139

Victor Oliveira's avatar
Victor Oliveira committed
140
static gboolean
141
cache_entry_find_invalid (gpointer *data)
Victor Oliveira's avatar
Victor Oliveira committed
142
{
143 144 145
  GList *elem;

  for (elem=cache_entries; elem; elem=elem->next)
Victor Oliveira's avatar
Victor Oliveira committed
146
    {
147 148
      CacheEntry *cb = elem->data;
      if (!cb->valid)
Victor Oliveira's avatar
Victor Oliveira committed
149
        {
150
          *data = cb;
Victor Oliveira's avatar
Victor Oliveira committed
151 152 153 154
          return TRUE;
        }
    }

155
  *data = NULL;
Victor Oliveira's avatar
Victor Oliveira committed
156 157 158
  return FALSE;
}

159 160 161 162 163
void
gegl_buffer_cl_cache_remove (GeglBuffer          *buffer,
                             const GeglRectangle *roi)
{
  GeglRectangle tmp;
164 165
  GList *elem;
  gpointer data;
Victor Oliveira's avatar
Victor Oliveira committed
166

167
  for (elem=cache_buffer; elem; elem=elem->next)
168
    {
169
      CacheBuffer *cb = elem->data;
Victor Oliveira's avatar
Victor Oliveira committed
170
      if (cb->valid && cb->buffer_origin == buffer
171
          && (!roi || gegl_rectangle_intersect (&tmp, &cb->roi, roi)))
Victor Oliveira's avatar
Victor Oliveira committed
172 173 174 175
        {
          gegl_buffer_destroy (cb->buffer);
          cb->valid = FALSE;
        }
176 177
    }

178
  for (elem=cache_entries; elem; elem=elem->next)
179
    {
180
      CacheEntry *e = elem->data;
Victor Oliveira's avatar
Victor Oliveira committed
181
      if (e->valid && e->buffer == buffer
182
          && (!roi || gegl_rectangle_intersect (&tmp, roi, &e->roi)))
183
        {
Victor Oliveira's avatar
Victor Oliveira committed
184 185
          gegl_clReleaseMemObject (e->tex);
          e->valid = FALSE;
186 187
        }
    }
Victor Oliveira's avatar
Victor Oliveira committed
188

189
  g_static_mutex_lock (&cache_mutex);
Victor Oliveira's avatar
Victor Oliveira committed
190

191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
  while (cache_buffer_find_invalid (&data))
    {
      g_slice_free (CacheBuffer, data);
      cache_buffer = g_list_remove (cache_buffer, data);
    }

  while (cache_entry_find_invalid (&data))
    {
      g_slice_free (CacheEntry, data);
      cache_entries = g_list_remove (cache_entries, data);
    }

  g_static_mutex_unlock (&cache_mutex);

#if 0
  g_printf ("-- ");
  for (elem=cache_buffer; elem; elem=elem->next)
    {
      CacheBuffer *cb = elem->data;
      g_printf ("%p %p {%d, %d, %d, %d} %d | ", cb->buffer, cb->buffer_origin, cb->roi.x, cb->roi.y, cb->roi.width, cb->roi.height, cb->valid);
    }
  g_printf ("\n");
#endif
Victor Oliveira's avatar
Victor Oliveira committed
214

215 216 217 218 219 220
}

void
gegl_buffer_cl_cache_invalidate (GeglBuffer          *buffer,
                                 const GeglRectangle *roi)
{
221 222 223
  gegl_buffer_cl_cache_merge (buffer, roi);
  gegl_clFinish (gegl_cl_get_command_queue ());
  gegl_buffer_cl_cache_remove (buffer, roi);
224 225 226 227 228 229 230 231 232 233 234
}

gboolean
gegl_buffer_cl_cache_from (GeglBuffer          *buffer,
                           const GeglRectangle *roi,
                           gpointer             dest_buf,
                           const Babl          *format,
                           gint                 rowstride)
{
  size_t buf_size, dest_size;
  cl_mem tex_dest = NULL;
235
  GList *elem_cache, *elem_buffer;
236 237

  gegl_cl_color_op conv = gegl_cl_color_supported (buffer->format, format);
Victor Oliveira's avatar
Victor Oliveira committed
238 239
  gegl_cl_color_babl (buffer->format, &buf_size);
  gegl_cl_color_babl (format,         &dest_size);
240

241
  for (elem_cache=cache_entries; elem_cache; elem_cache=elem_cache->next)
242
    {
243
      CacheEntry *entry = elem_cache->data;
244

Victor Oliveira's avatar
Victor Oliveira committed
245 246
      if (entry->valid && entry->buffer == buffer
          && gegl_rectangle_contains (&entry->roi, roi))
Victor Oliveira's avatar
Victor Oliveira committed
247 248
        {
          cl_int cl_err;
249

Victor Oliveira's avatar
Victor Oliveira committed
250 251 252 253
          switch (conv)
            {
              case GEGL_CL_COLOR_NOT_SUPPORTED:
              case GEGL_CL_COLOR_EQUAL:
254 255

              {
Victor Oliveira's avatar
Victor Oliveira committed
256
              gegl_buffer_cl_cache_invalidate (buffer, &entry->roi);
257

Victor Oliveira's avatar
Victor Oliveira committed
258 259
              return FALSE;
              }
260

Victor Oliveira's avatar
Victor Oliveira committed
261
              case GEGL_CL_COLOR_CONVERT:
262

Victor Oliveira's avatar
Victor Oliveira committed
263
              {
264

265
              for (elem_buffer=cache_buffer; elem_buffer; elem_buffer=elem_buffer->next)
266
                {
267
                  CacheBuffer *cb = elem_buffer->data;
Victor Oliveira's avatar
Victor Oliveira committed
268
                  if (cb->valid && cb->buffer &&
Victor Oliveira's avatar
Victor Oliveira committed
269 270 271 272 273 274
                      cb->buffer_origin == buffer &&
                      cb->buffer->format == format &&
                      gegl_rectangle_contains (&cb->roi, roi))
                    {
                      gegl_buffer_get (cb->buffer,
                                       roi,
275
                                       1.0,
Victor Oliveira's avatar
Victor Oliveira committed
276 277 278 279 280 281
                                       format,
                                       dest_buf,
                                       rowstride);
                      return TRUE;
                    }
                }
282 283

                {
Victor Oliveira's avatar
Victor Oliveira committed
284
                  gpointer data;
285 286 287 288 289 290 291 292 293 294 295 296
                  CacheBuffer *cb;

                  g_static_mutex_lock (&cache_mutex);
                  {
                  cb = g_slice_new (CacheBuffer);
                  cb->buffer        = gegl_buffer_new (&entry->roi, format);
                  cb->buffer_origin = buffer;
                  cb->roi           = entry->roi;
                  cb->valid         = TRUE;
                  cache_buffer = g_list_prepend (cache_buffer, cb);
                  }
                  g_static_mutex_unlock (&cache_mutex);
Victor Oliveira's avatar
Victor Oliveira committed
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312

                  tex_dest = gegl_clCreateBuffer (gegl_cl_get_context (),
                                                  CL_MEM_WRITE_ONLY,
                                                  entry->roi.width * entry->roi.height * dest_size,
                                                  NULL, &cl_err);
                  if (cl_err != CL_SUCCESS) CL_ERROR;

                  cl_err = gegl_cl_color_conv (entry->tex, tex_dest, entry->roi.width * entry->roi.height, buffer->format, format);
                  if (cl_err == FALSE) CL_ERROR;

                  data = gegl_clEnqueueMapBuffer(gegl_cl_get_command_queue(), tex_dest, CL_TRUE,
                                                 CL_MAP_READ,
                                                 0, entry->roi.width * entry->roi.height * dest_size,
                                                 0, NULL, NULL, &cl_err);
                  if (cl_err != CL_SUCCESS) CL_ERROR;

313
                  gegl_buffer_set (cb->buffer, &entry->roi, 0, format, data, GEGL_AUTO_ROWSTRIDE);
Victor Oliveira's avatar
Victor Oliveira committed
314 315 316 317 318 319 320 321

                  cl_err = gegl_clEnqueueUnmapMemObject (gegl_cl_get_command_queue(), tex_dest, data,
                                                         0, NULL, NULL);
                  if (cl_err != CL_SUCCESS) CL_ERROR;

                  cl_err = gegl_clFinish(gegl_cl_get_command_queue());
                  if (cl_err != CL_SUCCESS) CL_ERROR;

322
                  gegl_buffer_get (cb->buffer,
Victor Oliveira's avatar
Victor Oliveira committed
323
                                   roi,
324
                                   1.0,
Victor Oliveira's avatar
Victor Oliveira committed
325 326 327 328 329 330 331
                                   format,
                                   dest_buf,
                                   rowstride);

                  if (tex_dest) gegl_clReleaseMemObject (tex_dest);

                  return TRUE;
332 333
                }
              }
Victor Oliveira's avatar
Victor Oliveira committed
334 335 336
            }
        }
    }
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352

  gegl_buffer_cl_cache_invalidate (buffer, roi);

  return FALSE;

error:

  /* this function isn`t supposed to fail, there is no memory alloc here */
  gegl_buffer_cl_cache_invalidate (buffer, roi);

  if (tex_dest) gegl_clReleaseMemObject (tex_dest);

  return FALSE;
}

#undef CL_ERROR