Public Types | |
typedef float * | WritablePtr |
typedef const float * | ReadablePtr |
Public Member Functions | |
int | getLeft () const |
int | getRight () const |
Row (int X, int R) | |
~Row () | |
void | release () |
void | range (int X, int R) |
void | offset (int delta) |
void | write (Channel, float *) |
ChannelMask | writable_channels () const |
ReadablePtr | operator[] (Channel z) const |
WritablePtr | writable (Channel z) |
WritablePtr | writableConstant (const float val, Channel z) |
void | pre_copy (Channel z, Row &, Channel source_channel) const |
void | pre_copy (Row &s, Channel z) const |
void | copy (Channel z, const Row &, Channel source_channel, int x, int r) |
void | copy (const Row &s, Channel z, int x, int r) |
void | pre_copy (Row &, ChannelMask) const |
void | copy (const Row &, ChannelMask, int x, int r) |
void | get (Iop &, int y, int x, int r, ChannelMask) |
void | erase (ChannelMask) |
void | erase (Channel) |
bool | is_zero (Channel channel) const |
void | _debug (int x, int r, ChannelMask channels) const |
void | debug (int x, int r, ChannelMask channels) const |
Static Public Member Functions | |
static bool | is_zero (const float *, int X, int R) |
static const float * | zero_buffer (unsigned size) |
static bool | is_zero_buffer (const float *) |
static float * | junk_buffer (unsigned size) |
Friends | |
class | Cache |
class | Iop |
std::ostream & | operator<< (std::ostream &, const Row &) |
Contains a read-write buffer of pixels representing a set of channels for a single horizontal line in an image. This is the standard method of passing image data around in DDImage.
An Row acts like an array of 32 arrays of float pixel values, one for each possible channel. Each of these "buffers" can be indexed by X position. Only the locations greater or equal to a "left" position and less than a "right" position are legal, this range is set by the constructor or by the range() or offset() methods. (the stored pointer is offset from the allocated memory block by -left and the memory block is at least right-left long).
The normal method of putting data into an Row is to call one of the get() functions. You can also call writable() to get a pointer to write to, or use erase() or copy().
A great deal of code is dedicated to allowing the buffers to be shared between Row, Interest, caches, and local arrays, to avoid the expense of allocating them and especially of copying them. Each buffer may either be owned by the Row (in which case it is writable and it is deleted when the Row is destroyed), or it can be a read-only pointer to another piece of memory. Rows and other objects can copy the pointers from each other and can also transfer the "write" ownership of a buffer between them.
Notice that getting your data into an Row and then looking at it is enormously faster than calling Iop::at(). You should do this if at all possible.
Row::Row | ( | int | X, |
int | R | ||
) |
Construct an Row where the legal range of horizontal indexes is x >= X and x < R. No buffers are allocated and attempts to index them without calling writable() first are undefined.
References zero_buffer().
Row::~Row | ( | ) |
The destructor does release() and deletes any buffers allocated by writable().
void Row::release | ( | ) |
Rows may have pointers directly into Iop caches, where they increment a reference count to lock the data into the cache. However this reference count is ignored when caches are cleared or deleted, so it is vital that you get rid of these pointers before this happens (which is when invalidate() is called on an Iop).
This is usually done by the Row destructor but if you want to keep the row around for some reason, you can call this.
References DD::Image::Iop::cache().
Referenced by DD::Image::Iop::get().
void Row::range | ( | int | X, |
int | R | ||
) |
Change the Row to contain at least the horizontal range X..R. The actual range will be the union of the range passed to the constructor, and all calls to range() since then.
This is useful if Iop::engine() would like to write pixels outside the x,r range passed to it. Without this call, writing these pixels could crash because that memory may not be allocated.
An example of such an Iop is file readers which need to decompress starting at pixel zero. It is far easier and faster to write the decompressor so it can store all the pixels as it calculates them, rather than having to test each to see if it is in range. So most such file readers call range(0,width) and then write the entire width.
Because callers typically reuse rows for multiple requests, the reallocated buffers and larger size will likely be preserved for the next call. This means that much less memory allocation and freeing will be done than it looks like this does.
WARNING: this will (possibly) free all buffers. Any pointers returned by [z] or by writable() are no longer valid.
See also the offset() function, which does not free buffers, but can only change the range to a new one of the same length.
References MAX(), MIN(), and zero_buffer().
Referenced by DD::Image::Read::engine(), and DD::Image::Iop::get().
void Row::offset | ( | int | delta | ) |
Move all the data and the left/right range of the row right by delta. This can be used to horizontally shift data without copying it.
If the Row does not belong to you, you must restore the shift by calling this with -delta before returning.
This can be used by an operator that horizontally shifts an image, for instance the Position operator does this (dx and dy contain the translation in pixels):
row.offset(-dx); row.get(input0(), Y-dy, X-dx, R-dx, channels); row.offset(dx);
References DD::Image::incr().
Referenced by DD::Image::Iop::get().
void Row::write | ( | Channel | z, |
float * | buffer | ||
) |
You can make an Row write to your own allocated memory by calling this. The area from buffer[left] to buffer[right-1] (where left and right are the current range of the Row) must exist and it must stay around until after the Row is destroyed.
There is no guarantee that the buffer will be written to, Iops may just change the pointer to caches, zeros, or other data. You should check if row[z]==buffer and if not you want to copy the data from row[z]+x to row[z]+r to buffer+x.
Referenced by pre_copy().
ReadablePtr DD::Image::Row::operator[] | ( | Channel | z | ) | const [inline] |
Return a pointer to the pixel at x == 0 in channel z.
Only the region of this buffer between the X and R passed to the constructor actually exists. Indexing outside that area will produce garbage or a core dump. If this channel has not been requested with get() or writable() the returned value is garbage.
To access an arbitrary pixel at channel z, horizontal position x, call row[z][x]
. For maximum speed it is best to use a local pointer with const float* IN = row[z]+x
and then increment it across the row.
Row::WritablePtr Row::writable | ( | Channel | z | ) |
Return a pointer to pixel at x == 0 in channel z, this pointer points at memory that may be written. If the current buffer is not writable, it is thrown away and a buffer is allocated.
Converting a row to writable does not preserve the contents. However you can assume that multiple calls to writable() will return the same pointer.
You can only write to the region between the X and R passed to the constructor. Writing outside that area is a sure way to get a core dump!
If z is Chan_Black then a pointer is returned to the shared junk_buffer(), where you can safely dispose of your data without having to put a test for Chan_Black into your code. However all operators and threads share this buffer so you cannot rely on the data staying unchanged after you store it, this is a write-only buffer!
Referenced by copy(), DD::Image::Render::draw_primitives(), DD::Image::Write::engine(), DD::Image::Read::engine(), DD::Image::Material::engine(), DD::Image::Iop::get(), DD::Image::ImagePlane::getRow(), and DD::Image::DrawIop::pixel_engine().
Row::WritablePtr Row::writableConstant | ( | const float | val, |
Channel | z | ||
) |
Utility function. Allocate a buffer at channel z where all the values are set to val. Otherwise behaves exactly the same as writable().
Referenced by DD::Image::Read::engine().
Set things up so a later copy() with the same arguments may run a lot faster.
This is done by modifying source to share buffer pointers with this Row. This is a hack: you must not do any calls to this Row other than the matching copy() until source is deleted. Any attempt to use this Row may cause some buffers to be freed and then the source row will be pointing at freed memory.
The arguments are exactly like copy() and you call this method on the destination row, even though it really modifies the source row. This was done so that you can easily duplicate the arguments to copy() when making this function. See copy() for descriptions of the arguments.
Sample usage:
void MyIop::engine(int y, int x, int r, ChannelMask channels, Row& out) { ChannelSet achannels = channels; achannels &= (copied_channels); ChannelSet bchannels = channels; bchannels -= (copied_channels); Row arow(x,r); out.pre_copy(arow, uncooked); arow.get(input1(), y, x, r, achannels); out.get(input0(), y, x, r, bchannels); out.copy(arow, uncooked, x, r); }
References write().
Referenced by DD::Image::Write::engine(), and DD::Image::DrawIop::pixel_engine().
Copy a channel from the source Row to this row.
WARNING: X and R indicate what region you require to be copied, but more than that may be copied! This is not a merge! To merge data, you must copy the pixels yourself.
Calling pre_copy() with the same arguments before filling the source row can greatly speed this up by allowing an already-existing output buffer to be shared. In this case the copy may already be done and this will return immediately.
References erase(), and writable().
Referenced by copy(), DD::Image::Render::draw_primitives(), DD::Image::Write::engine(), and DD::Image::DrawIop::pixel_engine().
void Row::pre_copy | ( | Row & | source, |
ChannelMask | channels | ||
) | const |
void Row::copy | ( | const Row & | source, |
ChannelMask | channels, | ||
int | x, | ||
int | r | ||
) |
Same as "foreach(z,channels) copy(z, source, z, x, r)" but this may be faster.
References copy().
void Row::get | ( | Iop & | iop, |
int | y, | ||
int | x, | ||
int | r, | ||
ChannelMask | channels | ||
) |
For back compatibility only, this is the same as doing iop.get(y, x, r, channels, this);
References DD::Image::Iop::get().
Referenced by DD::Image::Iop::doFetchPlane(), and DD::Image::Material::engine().
const float * Row::zero_buffer | ( | unsigned | size | ) | [static] |
Return an array containing at least size 0.0 values. This can be used as a source of zeros in an algorithim that does not want the overhead of checking whether a pointer is null or not. It is also used by the erase() method and pointers are checked against the return values for the is_zero() method.
References DD::Image::Memory::allocate_void().
bool Row::is_zero_buffer | ( | const float * | array | ) | [static] |
Return true if array is equal to one of the return values from zero_buffer().
Referenced by is_zero().
float * Row::junk_buffer | ( | unsigned | size | ) | [static] |
Return an array containing at least size locations you can write to. This can be used as a "data sink" for algorithims that produce data that might be ignored. A pointer to this is returned when writable(Chan_Black) is called.
References DD::Image::Memory::allocate_void().
void Row::erase | ( | ChannelMask | channels | ) |
Clear the channels to zero. This is done by changing the pointer to point at zero_buffer(). This will make the is_zero() test return true.
Referenced by copy(), DD::Image::Render::draw_primitives(), DD::Image::Write::engine(), DD::Image::Read::engine(), DD::Image::Iop::get(), DD::Image::ImagePlane::getRow(), and DD::Image::DrawIop::pixel_engine().
void Row::erase | ( | Channel | channel | ) |
Clear the entire channel to zero. This is done by changing the pointer to point at zero_buffer(). This makes the is_zero() test return true.
bool Row::is_zero | ( | Channel | channel | ) | const |
Fast test to see if all of the given channel is zero. This will return true if erase() was called, or if other code such as caches has detected that the row is entirely zero.
References is_zero_buffer().
std::ostream& operator<< | ( | std::ostream & | , |
const Row & | |||
) | [friend] |
Not implemented in the library but you can define it.