1 /*****************************************************************************/
2 // Copyright 2006-2019 Adobe Systems Incorporated
3 // All Rights Reserved.
4 //
5 // NOTICE:  Adobe permits you to use, modify, and distribute this file in
6 // accordance with the terms of the Adobe license agreement accompanying it.
7 /*****************************************************************************/
8 
9 /** \file
10  * Class to handle partitioning a rectangular image processing operation taking
11  * into account multiple processing resources and memory constraints.
12  */
13 
14 /*****************************************************************************/
15 
16 #ifndef __dng_area_task__
17 #define __dng_area_task__
18 
19 /*****************************************************************************/
20 
21 #include "dng_classes.h"
22 #include "dng_point.h"
23 #include "dng_string.h"
24 #include "dng_types.h"
25 #include "dng_uncopyable.h"
26 
27 /*****************************************************************************/
28 
29 class dng_area_task_progress: private dng_uncopyable
30     {
31 
32     public:
33 
~dng_area_task_progress()34         virtual ~dng_area_task_progress ()
35             {
36             }
37 
38         virtual void FinishedTile (const dng_rect & /* tile */) = 0;
39 
40     };
41 
42 /*****************************************************************************/
43 
44 /// \brief Abstract class for rectangular processing operations with support
45 /// for partitioning across multiple processing resources and observing memory
46 /// constraints.
47 
48 class dng_area_task
49 	{
50 
51 	protected:
52 
53 		uint32 fMaxThreads;
54 
55 		uint32 fMinTaskArea;
56 
57 		dng_point fUnitCell;
58 
59 		dng_point fMaxTileSize;
60 
61 		dng_string fName;
62 
63 	public:
64 
65 		explicit dng_area_task (const char *name = "unnamed dng_area_task");
66 
67 		virtual ~dng_area_task ();
68 
Name()69 		const char * Name () const
70 			{
71 			return fName.Get ();
72 			}
73 
74 		/// Getter for the maximum number of threads (resources) that can be
75 		/// used for processing
76 		///
77 		/// \retval Number of threads, minimum of 1, that can be used for this task.
78 
MaxThreads()79 		virtual uint32 MaxThreads () const
80 			{
81 			return fMaxThreads;
82 			}
83 
84 		/// Getter for minimum area of a partitioned rectangle.
85 		/// Often it is not profitable to use more resources if it requires
86 		/// partitioning the input into chunks that are too small, as the
87 		/// overhead increases more than the speedup. This method can be
88 		/// ovreridden for a specific task to indicate the smallest area for
89 		/// partitioning. Default is 256x256 pixels.
90 		///
91 		/// \retval Minimum area for a partitoned tile in order to give performant
92         /// operation. (Partitions can be smaller due to small inputs and edge cases.)
93 
MinTaskArea()94 		virtual uint32 MinTaskArea () const
95 			{
96 			return fMinTaskArea;
97 			}
98 
99 		/// Getter for dimensions of which partitioned tiles should be a multiple.
100 		/// Various methods of processing prefer certain alignments. The
101 		/// partitioning attempts to construct tiles such that the sizes are a
102 		/// multiple of the dimensions of this point.
103 		///
104 		/// \retval a point giving preferred alignment in x and y
105 
UnitCell()106 		virtual dng_point UnitCell () const
107 			{
108 			return fUnitCell;
109 			}
110 
111 		/// Getter for maximum size of a tile for processing.
112 		/// Often processing will need to allocate temporary buffers or use
113 		/// other resources that are either fixed or in limited supply. The
114 		/// maximum tile size forces further partitioning if the tile is bigger
115 		/// than this size.
116 		///
117 		/// \retval Maximum tile size allowed for this area task.
118 
MaxTileSize()119 		virtual dng_point MaxTileSize () const
120 			{
121 			return fMaxTileSize;
122 			}
123 
124 		/// Getter for RepeatingTile1.
125 		/// RepeatingTile1, RepeatingTile2, and RepeatingTile3 are used to
126 		/// establish a set of 0 to 3 tile patterns for which the resulting
127 		/// partitions that the final Process method is called on will not cross
128 		/// tile boundaries in any of the tile patterns. This can be used for a
129 		/// processing routine that needs to read from two tiles and write to a
130 		/// third such that all the tiles are aligned and sized in a certain
131 		/// way. A RepeatingTile value is valid if it is non-empty. Higher
132 		/// numbered RepeatingTile patterns are only used if all lower ones are
133 		/// non-empty. A RepeatingTile pattern must be a multiple of UnitCell in
134 		/// size for all constraints of the partitionerr to be met.
135 
136 		virtual dng_rect RepeatingTile1 () const;
137 
138 		/// Getter for RepeatingTile2.
139 		/// RepeatingTile1, RepeatingTile2, and RepeatingTile3 are used to
140 		/// establish a set of 0 to 3 tile patterns for which the resulting
141 		/// partitions that the final Process method is called on will not cross
142 		/// tile boundaries in any of the tile patterns. This can be used for a
143 		/// processing routine that needs to read from two tiles and write to a
144 		/// third such that all the tiles are aligned and sized in a certain
145 		/// way. A RepeatingTile value is valid if it is non-empty. Higher
146 		/// numbered RepeatingTile patterns are only used if all lower ones are
147 		/// non-empty. A RepeatingTile pattern must be a multiple of UnitCell in
148 		/// size for all constraints of the partitionerr to be met.
149 
150 		virtual dng_rect RepeatingTile2 () const;
151 
152 		/// Getter for RepeatingTile3.
153 		/// RepeatingTile1, RepeatingTile2, and RepeatingTile3 are used to
154 		/// establish a set of 0 to 3 tile patterns for which the resulting
155 		/// partitions that the final Process method is called on will not cross
156 		/// tile boundaries in any of the tile patterns. This can be used for a
157 		/// processing routine that needs to read from two tiles and write to a
158 		/// third such that all the tiles are aligned and sized in a certain
159 		/// way. A RepeatingTile value is valid if it is non-empty. Higher
160 		/// numbered RepeatingTile patterns are only used if all lower ones are
161 		/// non-empty. A RepeatingTile pattern must be a multiple of UnitCell in
162 		/// size for all constraints of the partitionerr to be met.
163 
164 		virtual dng_rect RepeatingTile3 () const;
165 
166 		/// Task startup method called before any processing is done on partitions.
167 		/// The Start method is called before any processing is done and can be
168 		/// overridden to allocate temporary buffers, etc.
169 		///
170 		/// \param threadCount Total number of threads that will be used for processing.
171         /// Less than or equal to MaxThreads.
172 		/// \param dstArea Area to be processed in the current run of the task.
173 		/// \param tileSize Size of source tiles which will be processed.
174         /// (Not all tiles will be this size due to edge conditions.)
175 		/// \param allocator dng_memory_allocator to use for allocating temporary buffers, etc.
176 		/// \param sniffer Sniffer to test for user cancellation and to set up progress.
177 
178 		virtual void Start (uint32 threadCount,
179 							const dng_rect &dstArea,
180 							const dng_point &tileSize,
181 							dng_memory_allocator *allocator,
182 							dng_abort_sniffer *sniffer);
183 
184 		/// Process one tile or fully partitioned area. This method is
185 		/// overridden by derived classes to implement the actual image
186 		/// processing. Note that the sniffer can be ignored if it is certain
187 		/// that a processing task will complete very quickly. This method
188 		/// should never be called directly but rather accessed via Process.
189 		/// There is no allocator parameter as all allocation should be done in
190 		/// Start.
191 		///
192 		/// \param threadIndex 0 to threadCount - 1 index indicating which thread this is.
193         /// (Can be used to get a thread-specific buffer allocated in the Start method.)
194 		/// \param tile Area to process.
195 		/// \param sniffer dng_abort_sniffer to use to check for user cancellation
196         /// and progress updates.
197 
198 		virtual void Process (uint32 threadIndex,
199 							  const dng_rect &tile,
200 							  dng_abort_sniffer *sniffer) = 0;
201 
202 		/// Task computation finalization and teardown method. Called after all
203 		/// resources have completed processing. Can be overridden to accumulate
204 		/// results and free resources allocated in Start.
205 		///
206 		/// \param threadCount Number of threads used for processing. Same as value passed to Start.
207 
208 		virtual void Finish (uint32 threadCount);
209 
210 		/// Find tile size taking into account repeating tiles, unit cell, and maximum tile size.
211 		/// \param area Computation area for which to find tile size.
212 		/// \retval Tile size as height and width in point.
213 
214 		dng_point FindTileSize (const dng_rect &area) const;
215 
216 		/// Handle one resource's worth of partitioned tiles. Called after
217 		/// thread partitioning has already been done. Area may be further
218 		/// subdivided to handle maximum tile size, etc. It will be rare to
219 		/// override this method.
220 		///
221 		/// \param threadIndex 0 to threadCount - 1 index indicating which thread this is.
222 		/// \param area Tile area partitioned to this resource.
223 		/// \param tileSize size of tiles to use for processing.
224 		/// \param sniffer dng_abort_sniffer to use to check for user cancellation and progress updates.
225 		/// \param progress optional pointer to progress reporting object.
226 
227 		void ProcessOnThread (uint32 threadIndex,
228 							  const dng_rect &area,
229 							  const dng_point &tileSize,
230 							  dng_abort_sniffer *sniffer,
231                               dng_area_task_progress *progress);
232 
233 		/// Factory method to make a tile iterator. This iterator will be used
234 		/// by a thread to process tiles in an area in a specific order. The
235 		/// default implementation uses a forward iterator that visits tiles
236 		/// from left to right (inner), top down (outer). Subclasses can
237 		/// override this method to produce tile iterators that visit tiles in
238 		/// different orders.
239 		///
240 		/// \param threadIndex 0 to threadCount - 1 index indicating which thread this is.
241 		/// \param tile The tile to be traversed within the tile area.
242 		/// \param area Tile area partitioned to this resource.
243 
244 		virtual dng_base_tile_iterator * MakeTileIterator (uint32 threadIndex,
245 														   const dng_rect &tile,
246 														   const dng_rect &area) const;
247 
248 		/// Factory method to make a tile iterator. This iterator will be used
249 		/// by a thread to process tiles in an area in a specific order. The
250 		/// default implementation uses a forward iterator that visits tiles
251 		/// from left to right (inner), top down (outer). Subclasses can
252 		/// override this method to produce tile iterators that visit tiles in
253 		/// different orders.
254 		///
255 		/// \param threadIndex 0 to threadCount - 1 index indicating which thread this is.
256 		/// \param tileSize The tile size to be traversed within the tile area.
257 		/// \param area Tile area partitioned to this resource.
258 
259 		virtual dng_base_tile_iterator * MakeTileIterator (uint32 threadIndex,
260 														   const dng_point &tileSize,
261 														   const dng_rect &area) const;
262 
263 		/// Default resource partitioner that assumes a single resource to be
264 		/// used for processing. Implementations that are aware of multiple
265 		/// processing resources should override (replace) this method. This is
266 		/// usually done in dng_host::PerformAreaTask.
267 		///
268 		/// \param task The task to perform.
269 		/// \param area The area on which mage processing should be performed.
270 		/// \param allocator dng_memory_allocator to use for allocating temporary buffers, etc.
271 		/// \param sniffer dng_abort_sniffer to use to check for user cancellation and progress updates.
272 		/// \param progress optional pointer to progress reporting object.
273 
274 		static void Perform (dng_area_task &task,
275 				  			 const dng_rect &area,
276 				  			 dng_memory_allocator *allocator,
277 				  			 dng_abort_sniffer *sniffer,
278                              dng_area_task_progress *progress);
279 
280 	};
281 
282 /*****************************************************************************/
283 
284 #endif
285 
286 /*****************************************************************************/
287