Calvin Williamson wrote:
Will there be other kinds of iterators in the future? E.g. will there
be a sliding-neighborhood iterator, or whole tile iterator?
Yes. I think we need all of those you mention.
And if so,
should an ImageOp be allowed to have more than one iterator associated
with it at the same time?
Primarily I think that each ImageData object would deliver back one
type of iterator - say one of the types you mention.
But if different threads (once multi-threading is there) were
filling different areas on an image, then they would each need an
iterator for the portion they are filling in. I think in that case each
thread would be talking to a different ImageData object though.
These different ImageData objects would be pulling data from the
same underlying Image though.
Ok, so here is the big problem I am noticing. If you put an image
iterator object into an image, you end up with circular references.
Because of this, it is unclear to me how to make an ImageData manage an
image iterator with out creating a lot of problems when it comes time to
free up the memory.
One way of dealing with this is to simply unref the image once after
adding the image iterator object. This, however, exposes an
implementation detail of the image iterator that shouldn't be exposed.
It also bugs me to write code like that. It feels fragile and makes me
think there is a better way.
Another way of handling this is to pass the Data objects to process and
let process() choose the best iterator _and_ loop over the data
(including incrementing the iterator). I don't like this option because
it makes it harder to use process() in multiple threads, or a render farm.
We could also pass both the data inputs and the data iterators. I don't
like this because it feels like we are passing pointers and pointers to
the pointers, which is pointless.
Finally, we could generalize data iterators (which is what we need to do
eventually, anyway) so that you can create iterators for other types of
data, even ones that don't necessarly need the concept of iteration
(like scalars). I kinda don't like the idea of faux iterators (cause
they don't do what they should), so this is what I suggest:
Move ImageIterator to a subclass of ImageData. This makes sense,
because an image iterator presents a subset of ImageData (and thus,
valid image data). This also makes sense because an ImageIterator is
just an image, with a smaller rectangle, that also happens to know how
to move the rectangle around the larger image.
Then, after you create the ImageIterator, you can pass it with the rest
of the data objects just like it was an image, and process() and even
cast it as such. Further, process doesn't need to know if it is scan
line processing or not (for point ops anyway). It just processes the
entire subrectangle of the ImageIterator. If you want to process
scanlines, just set the image iterator to have a height of one, but this
is easily changed. It may be benificial here to have the op have a
hinting function that suggests or enforces the best processing size.
I like this last solution the best (as if my verbage bias wasn't enough)
What do you think is the best way to go?
--
Dan