From a3114e93874e19e072780a9bb82bb47ae35b6886 Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 26 May 2024 14:49:29 +0100 Subject: [PATCH] Read each strip in a separate thread --- src/tiff/tiffread.c | 177 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 143 insertions(+), 34 deletions(-) diff --git a/src/tiff/tiffread.c b/src/tiff/tiffread.c index 747d38d..1f9473a 100644 --- a/src/tiff/tiffread.c +++ b/src/tiff/tiffread.c @@ -4,8 +4,10 @@ #include "image.h" #include "mem_arena.h" #include +#include #include #include +#include #include #include #include @@ -200,6 +202,7 @@ struct tiff_image { typedef struct tiff_reader TiffReader; struct tiff_reader { + const char *filename; FILE *fp; TiffHdr header; TiffIFD ifd; @@ -214,7 +217,8 @@ internal void read_alpha(TiffReader *reader); internal void read_bits_per_sample(TiffReader *reader); internal bool read_image_pixels(TiffReader *reader, Arena *arena); internal bool read_strip_data(TiffReader *reader, Arena *arena); -internal void read_strips(TiffReader *reader); +internal bool read_strips(TiffReader *reader); +internal void *read_strip(void *arg); internal void read_strip_data_field(const TiffReader *reader, StripDataField *field); internal bool read_field(const TiffField *field, TiffImage *img); @@ -231,7 +235,7 @@ Image *read_baseline_tiff(const char *file, Arena *arena) { goto READ_BASELINE_RETURN_IMG; } - TiffReader reader = {.fp = fopen(file, "rb")}; + TiffReader reader = {.filename = file, .fp = fopen(file, "rb")}; if (!reader.fp) { goto READ_BASELINE_RETURN_IMG; } @@ -534,9 +538,7 @@ internal bool read_image_pixels(TiffReader *reader, Arena *arena) { return false; } - read_strips(reader); - - return true; + return read_strips(reader); } internal bool read_strip_data(TiffReader *reader, Arena *arena) { @@ -585,42 +587,149 @@ internal bool read_strip_data(TiffReader *reader, Arena *arena) { return true; } -internal void read_strips(TiffReader *reader) { - u64 position = 0; - u64 main_samples = reader->img.sample_count - reader->img.extra_samples_count; - TiffAlpha alpha = reader->img.alpha; +// internal void read_strips(TiffReader *reader) { +// u64 position = 0; +// u64 main_samples = reader->img.sample_count - +// reader->img.extra_samples_count; TiffAlpha alpha = reader->img.alpha; - Pixel *p; - u64 start_offset; - u64 alpha_offset; +// Pixel *p; +// u64 start_offset; +// u64 alpha_offset; + +// for (u64 i = 0; i < reader->img.strip_count; ++i) { +// const TiffStrip *strip = &(reader->img.strips[i]); + +// for (u64 j = 0; j < strip->byte_count / reader->img.sample_count; ++j) { +// p = &(reader->pixels[position]); +// start_offset = strip->offset + j * reader->img.sample_count; +// alpha_offset = start_offset + main_samples + alpha.sample_offset; + +// fread_with_offset(reader->fp, p, main_samples, start_offset); + +// if (alpha.type == ALPHA_TYPE_UNDEFINED) { +// p->a = 255; +// } else { +// fread_with_offset(reader->fp, &(p->a), 1, alpha_offset); + +// if (alpha.type == ALPHA_TYPE_UNASSOCIATED) { +// f32 a_norm = u8_normalise(p->a); + +// p->r = u8_denormalise(u8_normalise(p->r) * a_norm); +// p->g = u8_denormalise(u8_normalise(p->g) * a_norm); +// p->b = u8_denormalise(u8_normalise(p->b) * a_norm); +// } +// } + +// ++position; +// } +// } +// } + +typedef struct strip_reader_args StripReaderArgs; +struct strip_reader_args { + FILE *fp; + const TiffStrip *strip; + u64 pixel_count; + u64 samples_per_pixel; + u64 main_samples; + TiffAlpha alpha; + Pixel *pixel_write_start; +}; + +internal bool read_strips(TiffReader *reader) { + bool output = true; + + u64 position = 0; + u64 strips_read = 0; + u64 threads_created = 0; + StripReaderArgs args[reader->img.strip_count]; + pthread_t threads[reader->img.strip_count]; for (u64 i = 0; i < reader->img.strip_count; ++i) { const TiffStrip *strip = &(reader->img.strips[i]); + u64 pixel_count = strip->byte_count / reader->img.sample_count; + args[i] = (StripReaderArgs){ + .fp = fopen(reader->filename, "rb"), + .strip = strip, + .pixel_count = pixel_count, + .samples_per_pixel = reader->img.sample_count, + .main_samples = + reader->img.sample_count - reader->img.extra_samples_count, + .alpha = reader->img.alpha, + .pixel_write_start = &(reader->pixels[position]), + }; - for (u64 j = 0; j < strip->byte_count / reader->img.sample_count; ++j) { - p = &(reader->pixels[position]); - start_offset = strip->offset + j * reader->img.sample_count; - alpha_offset = start_offset + main_samples + alpha.sample_offset; - - fread_with_offset(reader->fp, p, main_samples, start_offset); - - if (alpha.type == ALPHA_TYPE_UNDEFINED) { - p->a = 255; - } else { - fread_with_offset(reader->fp, &(p->a), 1, alpha_offset); - - if (alpha.type == ALPHA_TYPE_UNASSOCIATED) { - f32 a_norm = u8_normalise(p->a); - - p->r = u8_denormalise(u8_normalise(p->r) * a_norm); - p->g = u8_denormalise(u8_normalise(p->g) * a_norm); - p->b = u8_denormalise(u8_normalise(p->b) * a_norm); - } - } - - ++position; + if (!args[i].fp) { + output = false; + goto READ_STRIPS_CLOSE_FILES; } + + position += pixel_count; + ++strips_read; } + + for (u64 i = 0; i < reader->img.strip_count; ++i) { + if (pthread_create(&(threads[i]), NULL, read_strip, (void *)&(args[i])) != + 0) { + break; + } + + ++threads_created; + } + + if (threads_created < reader->img.strip_count) { + for (u64 i = 0; i < strips_read; ++i) { + pthread_cancel(threads[i]); + } + + return false; + } + + for (u64 i = 0; i < reader->img.strip_count; ++i) { + pthread_join(threads[i], NULL); + } + +READ_STRIPS_CLOSE_FILES: + for (u64 i = 0; i < strips_read; ++i) { + fclose(args[i].fp); + } + + return output; +} + +internal void *read_strip(void *arg) { + StripReaderArgs *args = (StripReaderArgs *)arg; + + Pixel *p; + u64 write_offset = 0; + u64 read_offset; + u64 alpha_offset; + + for (u64 j = 0; j < args->pixel_count; ++j) { + p = args->pixel_write_start + write_offset; + read_offset = args->strip->offset + j * args->samples_per_pixel; + alpha_offset = read_offset + args->main_samples + args->alpha.sample_offset; + + fread_with_offset(args->fp, p, args->main_samples, read_offset); + + if (args->alpha.type == ALPHA_TYPE_UNDEFINED) { + p->a = 255; + } else { + fread_with_offset(args->fp, &(p->a), 1, alpha_offset); + + if (args->alpha.type == ALPHA_TYPE_UNASSOCIATED) { + f32 a_norm = u8_normalise(p->a); + + p->r = u8_denormalise(u8_normalise(p->r) * a_norm); + p->g = u8_denormalise(u8_normalise(p->g) * a_norm); + p->b = u8_denormalise(u8_normalise(p->b) * a_norm); + } + } + + ++write_offset; + } + + return NULL; } internal void read_strip_data_field(const TiffReader *reader,