[shotwell] Parallelize color transformations
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [shotwell] Parallelize color transformations
- Date: Thu, 9 Nov 2017 13:02:16 +0000 (UTC)
commit d71dd2276dbfa6bfec36a275617e9b0de06a19ec
Author: Jens Georg <mail jensge org>
Date: Sun Nov 5 19:06:36 2017 +0100
Parallelize color transformations
src/ColorTransformation.vala | 108 +++++++++++++++++++++++++++++-------------
src/graphics-processor.vala | 4 +-
2 files changed, 78 insertions(+), 34 deletions(-)
---
diff --git a/src/ColorTransformation.vala b/src/ColorTransformation.vala
index a9f26c5..8d9ea8f 100644
--- a/src/ColorTransformation.vala
+++ b/src/ColorTransformation.vala
@@ -770,31 +770,52 @@ public class PixelTransformer {
int dest_num_channels = dest.get_n_channels();
int dest_rowstride = dest.get_rowstride();
unowned uchar[] dest_pixels = dest.get_pixels();
-
- int cache_pixel_ticker = 0;
- for (int j = 0; j < dest_height; j++) {
- int row_start_index = j * dest_rowstride;
- int row_end_index = row_start_index + (dest_width * dest_num_channels);
- for (int i = row_start_index; i < row_end_index; i += dest_num_channels) {
- RGBAnalyticPixel pixel = RGBAnalyticPixel.from_components(
- fp_pixel_cache[cache_pixel_ticker],
- fp_pixel_cache[cache_pixel_ticker + 1],
- fp_pixel_cache[cache_pixel_ticker + 2]);
+ var jobs = (int) GLib.get_num_processors() - 1;
+
+ uint slice_length = dest_height;
+ if (jobs > 0) {
+ slice_length = dest_height / jobs;
+ }
- cache_pixel_ticker += 3;
+ var threads = new GLib.Thread<void *>[jobs];
+
+ unowned float[] cache = fp_pixel_cache;
+ for (var job = 0; job < jobs; job++) {
+ var row = job * slice_length;
+ var slice_height = (row + slice_length).clamp(0, dest_height);
+ threads[job] = new GLib.Thread<void*>("shotwell-worker", () => {
+ uint cache_pixel_ticker = row * dest_width * dest_num_channels;
+ for (uint j = row; j < slice_height; j++) {
+ uint row_start_index = j * dest_rowstride;
+ uint row_end_index = row_start_index + (dest_width * dest_num_channels);
+ for (uint i = row_start_index; i < row_end_index; i += dest_num_channels) {
+ RGBAnalyticPixel pixel = RGBAnalyticPixel.from_components(
+ cache[cache_pixel_ticker],
+ cache[cache_pixel_ticker + 1],
+ cache[cache_pixel_ticker + 2]);
+
+ cache_pixel_ticker += 3;
+
+ pixel = apply_transformations(pixel);
+
+ dest_pixels[i] = (uchar) (pixel.red * 255.0f);
+ dest_pixels[i + 1] = (uchar) (pixel.green * 255.0f);
+ dest_pixels[i + 2] = (uchar) (pixel.blue * 255.0f);
+ }
+ }
- pixel = apply_transformations(pixel);
+ return null;
+ });
+ }
- dest_pixels[i] = (uchar) (pixel.red * 255.0f);
- dest_pixels[i + 1] = (uchar) (pixel.green * 255.0f);
- dest_pixels[i + 2] = (uchar) (pixel.blue * 255.0f);
- }
+ foreach (var thread in threads) {
+ thread.join();
}
}
public void transform_to_other_pixbuf(Gdk.Pixbuf source, Gdk.Pixbuf dest,
- Cancellable? cancellable = null) {
+ Cancellable? cancellable = null, int jobs = -1) {
if (source.width != dest.width)
error("PixelTransformer: source and destination pixbufs must have the same width");
@@ -815,26 +836,47 @@ public class PixelTransformer {
int rowbytes = n_channels * width;
unowned uchar[] source_pixels = source.get_pixels();
unowned uchar[] dest_pixels = dest.get_pixels();
- for (int j = 0; j < height; j++) {
- int row_start_index = j * rowstride;
- int row_end_index = row_start_index + rowbytes;
- for (int i = row_start_index; i < row_end_index; i += n_channels) {
- RGBAnalyticPixel current_pixel = RGBAnalyticPixel.from_quantized_components(
- source_pixels[i], source_pixels[i + 1], source_pixels[i + 2]);
+ if (jobs == -1) {
+ jobs = (int) GLib.get_num_processors() - 1;
+ }
- current_pixel = apply_transformations(current_pixel);
+ uint slice_length = height;
+ if (jobs > 0) {
+ slice_length = height / jobs;
+ }
- dest_pixels[i] = (uchar) (current_pixel.red * 255.0f);
- dest_pixels[i + 1] = (uchar) (current_pixel.green * 255.0f);
- dest_pixels[i + 2] = (uchar) (current_pixel.blue * 255.0f);
- }
+ var threads = new GLib.Thread<void*>[jobs];
- if ((cancellable != null) && (cancellable.is_cancelled())) {
- return;
- }
+ for (var job = 0; job < jobs; job++) {
+ var row = job * slice_length;
+ var slice_height = (row + slice_length).clamp(0, height);
+
+ threads[job] = new GLib.Thread<void*>("shotwell-worker", () => {
+ for (var j = row; j < slice_height; j++) {
+ this.apply_transformation(j, rowstride, rowbytes, n_channels, source_pixels,
+ dest_pixels);
+
+ if ((cancellable != null) && (cancellable.is_cancelled())) {
+ break;
+ }
+ }
+
+ return null;
+ });
+ }
+
+ foreach (var thread in threads) {
+ thread.join();
}
}
+ private extern void apply_transformation(uint row,
+ int rowstride,
+ int rowbytes,
+ int n_channels,
+ uchar[] source_pixels,
+ uchar[] dest_pixels);
+
}
public class RGBHistogram {
diff --git a/src/graphics-processor.vala b/src/graphics-processor.vala
index 401deb5..dc46845 100644
--- a/src/graphics-processor.vala
+++ b/src/graphics-processor.vala
@@ -3,6 +3,7 @@ static string? output_file = null;
static string? pipeline = null;
static bool auto_enhance = false;
static string? format = null;
+static int jobs = -1;
const GLib.OptionEntry[] options = {
{ "input", 'i', 0, GLib.OptionArg.FILENAME, ref input_file, "FILE to process", "FILE" },
@@ -10,6 +11,7 @@ const GLib.OptionEntry[] options = {
{ "pipeline", 'p', 0, GLib.OptionArg.FILENAME, ref pipeline, "graphics PIPELINE to run", "PIPELINE" },
{ "auto-enance", 'a', 0, GLib.OptionArg.NONE, ref auto_enhance, "run auto-enhance on input file", null },
{ "format", 'f', 0, GLib.OptionArg.STRING, ref format, "Save output file in specific format [png, jpeg
(default)]", null},
+ { "jobs", 'j', 0, GLib.OptionArg.INT, ref jobs, "Number of parallel jobs to run on an image", null },
{ null, 0, 0, GLib.OptionArg.NONE, null, null, null }
};
@@ -100,7 +102,7 @@ int main(string[] args) {
var transformer = adjustments.generate_transformer();
var timer = new Timer();
- transformer.transform_to_other_pixbuf(src, output, null);
+ transformer.transform_to_other_pixbuf(src, output, null, jobs);
var elapsed = timer.elapsed();
print("Transformation took %f\n", elapsed);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]