home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / pixel_processor.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-22  |  8.9 KB  |  385 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * pixel_processor.c: Copyright (C) 1999 Jay Cox <jaycox@earthlink.net>
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19.  */
  20.  
  21. #include "config.h"
  22.  
  23. #include "pixel_processor.h"
  24. #include "pixel_region.h"
  25. #include "pixel_regionP.h"
  26. #include "gimprc.h"
  27. #include <stdarg.h>
  28. #include <stdio.h>
  29. #include <string.h>
  30.  
  31. #ifdef ENABLE_MP
  32.  
  33. #include <pthread.h>
  34.  
  35. #define IF_THREAD(statement) statement
  36.  
  37. #else /* !ENABLE_MP */
  38.  
  39. #define IF_THREAD(statement)
  40.  
  41. #endif /* ENABLE_MP */
  42.  
  43.  
  44.  
  45. typedef void (*p1_func)(void *, PixelRegion *);
  46. typedef void (*p2_func)(void *, PixelRegion * ,PixelRegion *);
  47. typedef void (*p3_func)(void *, PixelRegion * ,PixelRegion *, PixelRegion *);
  48. typedef void (*p4_func)(void *, PixelRegion * ,PixelRegion *, PixelRegion *,
  49.             PixelRegion *);
  50.  
  51. struct _PixelProcessor
  52. {
  53.   void *data;
  54.   p_func f;
  55.   PixelRegionIterator *PRI;
  56.   IF_THREAD(pthread_mutex_t mutex;)
  57.   int nthreads;
  58.   int n_regions;
  59.   PixelRegion *r[4];
  60.  
  61.   void *progress_report_data;
  62.   ProgressReportFunc progress_report_func;
  63. };
  64.  
  65. IF_THREAD(
  66. static void *
  67. do_parallel_regions (PixelProcessor  *p_s)
  68. {
  69.   PixelRegion tr[4];
  70.   int ntiles = 0;
  71.   int i;
  72.   int cont = 1;
  73.  
  74.   pthread_mutex_lock(&p_s->mutex);
  75.  
  76.   if (p_s->nthreads != 0 && p_s->PRI)
  77.     p_s->PRI =  (PixelRegionIterator*)pixel_regions_process(p_s->PRI);
  78.  
  79.   if (p_s->PRI == NULL)
  80.     {
  81.       pthread_mutex_unlock(&p_s->mutex);
  82.       return NULL;
  83.     }
  84.  
  85.   p_s->nthreads++;
  86.  
  87.   do
  88.     {
  89.       for (i = 0; i < p_s->n_regions; i++)
  90.     if (p_s->r[i])
  91.       {
  92.         memcpy(&tr[i], p_s->r[i], sizeof(PixelRegion));
  93.         if (tr[i].tiles)
  94.           tile_lock(tr[i].curtile);
  95.       }
  96.  
  97.       pthread_mutex_unlock(&p_s->mutex);
  98.       ntiles++;
  99.  
  100.       switch(p_s->n_regions)
  101.     {
  102.     case 1:
  103.       ((p1_func)p_s->f)(p_s->data,
  104.                 p_s->r[0] ? &tr[0] : NULL);
  105.       break;
  106.  
  107.     case 2:
  108.       ((p2_func)p_s->f)(p_s->data,
  109.                 p_s->r[0] ? &tr[0] : NULL,
  110.                 p_s->r[1] ? &tr[1] : NULL);
  111.       break;
  112.  
  113.     case 3:
  114.       ((p3_func)p_s->f)(p_s->data,
  115.                 p_s->r[0] ? &tr[0] : NULL,
  116.                 p_s->r[1] ? &tr[1] : NULL,
  117.                 p_s->r[2] ? &tr[2] : NULL);
  118.       break;
  119.  
  120.     case 4:
  121.       ((p4_func)p_s->f)(p_s->data,
  122.                 p_s->r[0] ? &tr[0] : NULL,
  123.                 p_s->r[1] ? &tr[1] : NULL,
  124.                 p_s->r[2] ? &tr[2] : NULL,
  125.                 p_s->r[3] ? &tr[3] : NULL);
  126.       break;
  127.  
  128.     default:
  129.       g_message("do_parallel_regions: Bad number of regions %d\n",
  130.             p_s->n_regions);
  131.     }
  132.  
  133.     pthread_mutex_lock(&p_s->mutex);
  134.  
  135.     for (i = 0; i < p_s->n_regions; i++)
  136.       if (p_s->r[i])
  137.     {
  138.       if (tr[i].tiles)
  139.         tile_release(tr[i].curtile, tr[i].dirty);
  140.     }
  141.  
  142.     if (p_s->progress_report_func && 
  143.     !p_s->progress_report_func(p_s->progress_report_data,
  144.                    p_s->r[0]->x, p_s->r[0]->y, 
  145.                    p_s->r[0]->w, p_s->r[0]->h))
  146.       cont = 0;
  147.  
  148.     } 
  149.   while (cont && p_s->PRI &&
  150.      (p_s->PRI = (PixelRegionIterator*)pixel_regions_process(p_s->PRI)));
  151.  
  152.   p_s->nthreads--;
  153.   /*  fprintf(stderr, "processed %d tiles\n", ntiles); */
  154.   pthread_mutex_unlock(&p_s->mutex);
  155.  
  156.   return NULL;
  157. }
  158. )
  159.  
  160. /*  do_parallel_regions_single is just like do_parallel_regions 
  161.  *   except that all the mutex and tile locks have been removed
  162.  *
  163.  * If we are processing with only a single thread we don't need to do the
  164.  * mutex locks etc. and aditional tile locks even if we were
  165.  * configured --with-mp
  166.  */
  167.  
  168. static void *
  169. do_parallel_regions_single(PixelProcessor  *p_s)
  170. {
  171.   int cont = 1;
  172.  
  173.   do
  174.   {
  175.     switch(p_s->n_regions)
  176.     {
  177.      case 1:
  178.        ((p1_func)p_s->f)(p_s->data,
  179.              p_s->r[0]);
  180.        break;
  181.      case 2:
  182.        ((p2_func)p_s->f)(p_s->data,
  183.              p_s->r[0],
  184.              p_s->r[1]);
  185.        break;
  186.      case 3:
  187.        ((p3_func)p_s->f)(p_s->data,
  188.              p_s->r[0],
  189.              p_s->r[1],
  190.              p_s->r[2]);
  191.        break;
  192.      case 4:
  193.        ((p4_func)p_s->f)(p_s->data,
  194.              p_s->r[0],
  195.              p_s->r[1],
  196.              p_s->r[2],
  197.              p_s->r[3]);
  198.        break;
  199.      default:
  200.        g_message("do_parallel_regions_single: Bad number of regions %d\n",
  201.          p_s->n_regions);
  202.     }
  203.     if (p_s->progress_report_func)
  204.       if (!p_s->progress_report_func(p_s->progress_report_data,
  205.                      p_s->r[0]->x, p_s->r[0]->y, 
  206.                      p_s->r[0]->w, p_s->r[0]->h))
  207.     cont = 0;
  208.   } while (cont && p_s->PRI &&
  209.        (p_s->PRI = (PixelRegionIterator*)pixel_regions_process(p_s->PRI)));
  210.   return NULL;
  211. }
  212.  
  213. #define MAX_THREADS 30
  214.  
  215. static void
  216. pixel_regions_do_parallel(PixelProcessor *p_s)
  217. {
  218.     IF_THREAD(
  219.     int nthreads;
  220.     nthreads = MIN(num_processors, MAX_THREADS);
  221.  
  222.     /* make sure we have at least one tile per thread */
  223.     nthreads = MIN(nthreads,
  224.            (p_s->PRI->region_width * p_s->PRI->region_height)
  225.            /(TILE_WIDTH*TILE_HEIGHT));
  226.  
  227.     if (nthreads > 1)
  228.     {
  229.       int i;
  230.       pthread_t threads[MAX_THREADS];
  231.       pthread_attr_t pthread_attr;
  232.       pthread_attr_init (&pthread_attr);
  233.       for (i = 0; i < nthreads; i++)
  234.       {
  235.     pthread_create (&threads[i], &pthread_attr,
  236.             (void *(*)(void *)) do_parallel_regions,
  237.             p_s);
  238.       }
  239.       for (i = 0; i < nthreads; i++)
  240.       {
  241.     int ret;
  242.     if ((ret = pthread_join(threads[i], NULL)))
  243.       {
  244.         fprintf(stderr, "pixel_regions_do_parallel:: pthread_join returned: %d\n", ret);
  245.       }
  246.       }
  247.       if (p_s->nthreads != 0)
  248.     fprintf(stderr, "pixel_regions_do_prarallel: we lost a thread\n");
  249.     }
  250.     else
  251.     )
  252.     do_parallel_regions_single(p_s);
  253. }
  254.  
  255. static PixelProcessor *
  256. pixel_regions_real_process_parallel(p_func f, void *data,
  257.                     ProgressReportFunc report_func,
  258.                     void *report_data,
  259.                     int num_regions, va_list ap)
  260. {
  261.   int i;
  262.   PixelProcessor *p_s;
  263.  
  264.  
  265.   p_s = g_new(PixelProcessor, 1);
  266.  
  267.  
  268.   for (i = 0; i < num_regions; i++)
  269.     p_s->r[i] = va_arg (ap, PixelRegion *);
  270.  
  271.   switch(num_regions)
  272.   {
  273.    case 1:
  274.     p_s->PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
  275.                                   p_s->r[0]);
  276.     break;
  277.    case 2:
  278.      p_s->PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
  279.                                    p_s->r[0],
  280.                                    p_s->r[1]);
  281.      break;
  282.    case 3:
  283.      p_s->PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
  284.                                    p_s->r[0],
  285.                                    p_s->r[1],
  286.                                    p_s->r[2]);
  287.      break;
  288.    case 4:
  289.      p_s->PRI = (PixelRegionIterator *) pixel_regions_register(num_regions,
  290.                                    p_s->r[0],
  291.                                    p_s->r[1],
  292.                                    p_s->r[2],
  293.                                    p_s->r[3]);
  294.     break;
  295.    default:
  296.      g_message("pixel_regions_real_process_parallel: Bad number of regions %d\n",
  297.            p_s->n_regions);
  298.   }
  299.   if (!p_s->PRI)
  300.   {
  301.     pixel_processor_free(p_s);
  302.     return NULL;
  303.   }
  304.   /* Why would we wan't to set dirty_tiles to 0 here? */
  305.   /*  IF_THREAD(p_s->PRI->dirty_tiles = 0;) */
  306.   p_s->f = f;
  307.   p_s->data = data;
  308.   p_s->n_regions = num_regions;
  309.  IF_THREAD(pthread_mutex_init(&(p_s->mutex), NULL);)
  310.   p_s->nthreads = 0;
  311.  
  312.   p_s->progress_report_data = report_data;
  313.   p_s->progress_report_func = report_func;
  314.  
  315.  
  316.   pixel_regions_do_parallel(p_s);
  317.  
  318.   if (p_s->PRI)
  319.     return p_s;
  320.   pixel_processor_free (p_s);
  321.   return NULL;
  322. }
  323.  
  324. void
  325. pixel_regions_process_parallel(p_func f, void *data, int num_regions, ...)
  326. {
  327.   va_list va;
  328.   va_start (va, num_regions);
  329.  
  330.   pixel_regions_real_process_parallel(f, data, NULL, NULL, num_regions, va);
  331.  
  332.   va_end (va);
  333. }
  334.  
  335. PixelProcessor *
  336. pixel_regions_process_parallel_progress(p_func f, void *data,
  337.                     ProgressReportFunc progress_func,
  338.                     void *progress_data, int num_regions,
  339.                     ...)
  340. {
  341.   PixelProcessor *ret;
  342.   va_list va;
  343.   va_start (va, num_regions);
  344.  
  345.   ret = pixel_regions_real_process_parallel(f, data,
  346.                         progress_func, progress_data,
  347.                         num_regions, va);
  348.  
  349.   va_end (va);
  350.   return ret;
  351. }
  352.  
  353. void
  354. pixel_processor_stop(PixelProcessor *pp)
  355. {
  356.   if (!pp)
  357.     return;
  358.   if (pp->PRI)
  359.   {
  360.     pixel_regions_process_stop (pp->PRI);
  361.     pp->PRI = NULL;
  362.   }
  363.   pixel_processor_free(pp);
  364. }
  365.  
  366. PixelProcessor *
  367. pixel_processor_cont(PixelProcessor *pp)
  368. {
  369.   pixel_regions_do_parallel(pp);
  370.   if (pp->PRI)
  371.     return pp;
  372.   pixel_processor_free (pp);
  373.   return NULL;
  374. }
  375.  
  376. void 
  377. pixel_processor_free (PixelProcessor *pp)
  378. {
  379.   if (pp->PRI)
  380.     pixel_processor_stop(pp);
  381.   else
  382.     g_free(pp);
  383. }
  384.  
  385.