static GThreadPool *thread_pool (void) { static GThreadPool *pool = NULL; if (!pool) { pool = g_thread_pool_new (thread_process, NULL, gegl_config_threads (), FALSE, NULL); } return pool; }
GeglBufferIterator * gegl_buffer_iterator_empty_new (void) { GeglBufferIterator *iter = g_slice_new (GeglBufferIterator); iter->priv = g_slice_new (GeglBufferIteratorPriv); iter->priv->num_buffers = 0; iter->priv->state = GeglIteratorState_Start; threaded = gegl_config_threads () > 1; return iter; }
void gegl_buffer_sample_cleanup (GeglBuffer *buffer) { gboolean threaded; g_return_if_fail (GEGL_IS_BUFFER (buffer)); if (! buffer->sampler) return; threaded = gegl_config_threads ()>1; if (threaded) g_mutex_lock (&gegl_buffer_sampler_mutex); if (buffer->sampler) { g_object_unref (buffer->sampler); buffer->sampler = NULL; } if (threaded) g_mutex_unlock (&gegl_buffer_sampler_mutex); }
void gegl_buffer_sample_at_level (GeglBuffer *buffer, gdouble x, gdouble y, GeglMatrix2 *scale, gpointer dest, const Babl *format, gint level, GeglSamplerType sampler_type, GeglAbyssPolicy repeat_mode) { /* if (sampler_type == GEGL_SAMPLER_NEAREST && format == buffer->soft_format) { GeglRectangle rect = {floorf (x), floorf(y), 1, 1}; gegl_buffer_get (buffer, &rect, 1, NULL, dest, GEGL_AUTO_ROWSTRIDE, repeat_mode); return; }*/ if (!format) format = buffer->soft_format; if (gegl_cl_is_accelerated ()) { GeglRectangle rect = {floorf (x), floorf(y), 1, 1}; gegl_buffer_cl_cache_flush (buffer, &rect); } /* unset the cached sampler if it dosn't match the needs */ if (buffer->sampler == NULL || (buffer->sampler != NULL && (buffer->sampler_type != sampler_type || buffer->sampler_format != format))) { gboolean threaded = gegl_config_threads () > 1; GType desired_type = gegl_sampler_gtype_from_enum (sampler_type); if (threaded) g_mutex_lock (&gegl_buffer_sampler_mutex); if (buffer->sampler) { g_object_unref (buffer->sampler); buffer->sampler = NULL; buffer->sampler_type = 0; } buffer->sampler_type = sampler_type; buffer->sampler = g_object_new (desired_type, "buffer", buffer, "format", format, "level", level, NULL); buffer->sampler_format = format; gegl_sampler_prepare (buffer->sampler); if (threaded) g_mutex_unlock (&gegl_buffer_sampler_mutex); } buffer->sampler->get(buffer->sampler, x, y, scale, dest, repeat_mode); }
static gboolean gegl_operation_composer3_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { GeglOperationComposer3Class *klass = GEGL_OPERATION_COMPOSER3_GET_CLASS (operation); GeglBuffer *input; GeglBuffer *aux; GeglBuffer *aux2; GeglBuffer *output; gboolean success = FALSE; if (strcmp (output_prop, "output")) { g_warning ("requested processing of %s pad on a composer", output_prop); return FALSE; } if (result->width == 0 || result->height == 0) { output = gegl_operation_context_get_target (context, "output"); return TRUE; } input = gegl_operation_context_get_source (context, "input"); output = gegl_operation_context_get_output_maybe_in_place (operation, context, input, result); aux = gegl_operation_context_get_source (context, "aux"); aux2 = gegl_operation_context_get_source (context, "aux2"); /* A composer with a NULL aux, can still be valid, the * subclass has to handle it. */ if (input != NULL || aux != NULL || aux2 != NULL) { if (gegl_operation_use_threading (operation, result)) { gint threads = gegl_config_threads (); GThreadPool *pool = thread_pool (); ThreadData thread_data[GEGL_MAX_THREADS]; gint pending = threads; if (result->width > result->height) { gint bit = result->width / threads; for (gint j = 0; j < threads; j++) { thread_data[j].roi.y = result->y; thread_data[j].roi.height = result->height; thread_data[j].roi.x = result->x + bit * j; thread_data[j].roi.width = bit; } thread_data[threads-1].roi.width = result->width - (bit * (threads-1)); } else { gint bit = result->height / threads; for (gint j = 0; j < threads; j++) { thread_data[j].roi.x = result->x; thread_data[j].roi.width = result->width; thread_data[j].roi.y = result->y + bit * j; thread_data[j].roi.height = bit; } thread_data[threads-1].roi.height = result->height - (bit * (threads-1)); } for (gint i = 0; i < threads; i++) { thread_data[i].klass = klass; thread_data[i].operation = operation; thread_data[i].input = input; thread_data[i].aux = aux; thread_data[i].aux2 = aux2; thread_data[i].output = output; thread_data[i].pending = &pending; thread_data[i].level = level; thread_data[i].success = TRUE; } for (gint i = 1; i < threads; i++) g_thread_pool_push (pool, &thread_data[i], NULL); thread_process (&thread_data[0], NULL); while (g_atomic_int_get (&pending)) {}; success = thread_data[0].success; } else { success = klass->process (operation, input, aux, aux2, output, result, level); } g_clear_object (&input); g_clear_object (&aux); g_clear_object (&aux2); } else { g_warning ("%s received NULL input, aux, and aux2", gegl_node_get_operation (operation->node)); } return success; }
static void inline gegl_sampler_get_pixel (GeglSampler *sampler, gint x, gint y, gpointer data, GeglAbyssPolicy repeat_mode) { GeglSamplerNearest *nearest_sampler = (GeglSamplerNearest*)(sampler); GeglBuffer *buffer = sampler->buffer; const GeglRectangle *abyss = &buffer->abyss; guchar *buf = data; if (y < abyss->y || x < abyss->x || y >= abyss->y + abyss->height || x >= abyss->x + abyss->width) { switch (repeat_mode) { case GEGL_ABYSS_CLAMP: x = CLAMP (x, abyss->x, abyss->x+abyss->width-1); y = CLAMP (y, abyss->y, abyss->y+abyss->height-1); break; case GEGL_ABYSS_LOOP: x = abyss->x + GEGL_REMAINDER (x - abyss->x, abyss->width); y = abyss->y + GEGL_REMAINDER (y - abyss->y, abyss->height); break; case GEGL_ABYSS_BLACK: { gfloat color[4] = {0.0, 0.0, 0.0, 1.0}; babl_process (babl_fish (gegl_babl_rgba_linear_float (), sampler->format), color, buf, 1); return; } case GEGL_ABYSS_WHITE: { gfloat color[4] = {1.0, 1.0, 1.0, 1.0}; babl_process (babl_fish (gegl_babl_rgba_linear_float (), sampler->format), color, buf, 1); return; } default: case GEGL_ABYSS_NONE: memset (buf, 0x00, babl_format_get_bytes_per_pixel (sampler->format)); return; } } gegl_buffer_lock (sampler->buffer); { gint tile_width = buffer->tile_width; gint tile_height = buffer->tile_height; gint tiledy = y + buffer->shift_y; gint tiledx = x + buffer->shift_x; gint indice_x = gegl_tile_indice (tiledx, tile_width); gint indice_y = gegl_tile_indice (tiledy, tile_height); GeglTile *tile = nearest_sampler->hot_tile; if (!(tile && tile->x == indice_x && tile->y == indice_y)) { if (gegl_config_threads()>1) g_rec_mutex_lock (&buffer->tile_storage->mutex); if (tile) gegl_tile_unref (tile); tile = gegl_tile_source_get_tile ((GeglTileSource *) (buffer), indice_x, indice_y, 0); nearest_sampler->hot_tile = tile; if (gegl_config_threads()>1) g_rec_mutex_unlock (&buffer->tile_storage->mutex); } if (tile) { gint tile_origin_x = indice_x * tile_width; gint tile_origin_y = indice_y * tile_height; gint offsetx = tiledx - tile_origin_x; gint offsety = tiledy - tile_origin_y; guchar *tp = gegl_tile_get_data (tile) + (offsety * tile_width + offsetx) * nearest_sampler->buffer_bpp; babl_process (sampler->fish, tp, buf, 1); } } gegl_buffer_unlock (sampler->buffer); }
static gboolean gegl_operation_filter_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { GeglOperationFilterClass *klass; GeglBuffer *input; GeglBuffer *output; gboolean success = FALSE; klass = GEGL_OPERATION_FILTER_GET_CLASS (operation); g_assert (klass->process); if (strcmp (output_prop, "output")) { g_warning ("requested processing of %s pad on a filter", output_prop); return FALSE; } input = (GeglBuffer*)gegl_operation_context_dup_object (context, "input"); output = gegl_operation_context_get_output_maybe_in_place (operation, context, input, result); if (gegl_operation_use_threading (operation, result)) { gint threads = gegl_config_threads (); GeglSplitStrategy split_strategy = GEGL_SPLIT_STRATEGY_AUTO; GThreadPool *pool = thread_pool (); ThreadData thread_data[GEGL_MAX_THREADS]; gint pending = threads; if (klass->get_split_strategy) { split_strategy = klass->get_split_strategy (operation, context, output_prop, result, level); } if (split_strategy == GEGL_SPLIT_STRATEGY_AUTO) { if (result->width > result->height) split_strategy = GEGL_SPLIT_STRATEGY_VERTICAL; else split_strategy = GEGL_SPLIT_STRATEGY_HORIZONTAL; } if (split_strategy == GEGL_SPLIT_STRATEGY_VERTICAL) { gint bit = result->width / threads; for (gint j = 0; j < threads; j++) { thread_data[j].roi.y = result->y; thread_data[j].roi.height = result->height; thread_data[j].roi.x = result->x + bit * j; thread_data[j].roi.width = bit; } thread_data[threads-1].roi.width = result->width - (bit * (threads-1)); } else if (split_strategy == GEGL_SPLIT_STRATEGY_HORIZONTAL) { gint bit = result->height / threads; for (gint j = 0; j < threads; j++) { thread_data[j].roi.x = result->x; thread_data[j].roi.width = result->width; thread_data[j].roi.y = result->y + bit * j; thread_data[j].roi.height = bit; } thread_data[threads-1].roi.height = result->height - (bit * (threads-1)); } else { g_return_val_if_reached (FALSE); } for (gint i = 0; i < threads; i++) { thread_data[i].klass = klass; thread_data[i].operation = operation; thread_data[i].context = context; thread_data[i].output = output; thread_data[i].pending = &pending; thread_data[i].level = level; thread_data[i].success = TRUE; } for (gint i = 1; i < threads; i++) g_thread_pool_push (pool, &thread_data[i], NULL); thread_process (&thread_data[0], g_object_ref (input)); while (g_atomic_int_get (&pending)) {}; success = thread_data[0].success; } else { success = klass->process (operation, input, output, result, level); } g_clear_object (&input); return success; }