Read each strip in a separate thread
This commit is contained in:
		| @@ -4,8 +4,10 @@ | ||||
| #include "image.h" | ||||
| #include "mem_arena.h" | ||||
| #include <assert.h> | ||||
| #include <bits/pthreadtypes.h> | ||||
| #include <math.h> | ||||
| #include <netinet/in.h> | ||||
| #include <pthread.h> | ||||
| #include <stdbool.h> | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| @@ -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, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user