DD::Image::Row Class Reference

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 ()
 
bool holdsCacheLine () const
 
void setCacheLine (std::unique_ptr< CacheLineUnlockGuard > &&guard)
 
void range (int X, int R)
 
void forceRange (int X, int R)
 
void offset (int delta)
 
void write (Channel, float *)
 
void read (Channel, float *)
 
void setPreallocatedWriteBuffer (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
 
std::ostream & operator<< (std::ostream &, const Row &)
 

Detailed Description

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.

A 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 a 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 a Row and then looking at it is enormously faster than calling Iop::at(). You should do this if at all possible.

Constructor & Destructor Documentation

Row::Row ( int  X,
int  R 
)

Construct a 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.

Row::~Row ( )

The destructor does release() and deletes any buffers allocated by writable().

Member Function Documentation

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.

Referenced by DD::Image::Iop::get().

bool Row::holdsCacheLine ( ) const

Checks whether row has a pointer to an Iop cache.

Referenced by DD::Image::Iop::get().

void Row::setCacheLine ( std::unique_ptr< CacheLineUnlockGuard > &&  guard)

Sets the pointer to an Iop cache. This is for internal use and should not be used.

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(), and MIN().

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);

Referenced by DD::Image::Iop::get().

void Row::write ( Channel  z,
float *  buffer 
)

You can make a 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().

void Row::read ( Channel  z,
float *  buffer 
)

You can make a Row read from 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 at least until the Row is destroyed.

Referenced by DD::Image::Iop::get().

void Row::setPreallocatedWriteBuffer ( Channel  z,
float *  preAllocatedBuffer 
)

You can give this Row a pointer to your own preallocated memory without setting the row as writable. If/when writable() is then called on the row, instead of calling allocate() to create new writable memory, the pointer provided here will be used instead.

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::Material::engine(), DD::Image::Write::engine(), DD::Image::Read::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().

void Row::pre_copy ( Channel  z,
Row source,
Channel  source_channel 
) const

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().

void Row::copy ( Channel  z,
const Row source,
Channel  source_channel,
int  x,
int  r 
)

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

Set things up so a later copy() with the same arguments may run a lot faster.

This is the same as calling pre_copy(z,source,z) for all the given channels.

References setPreallocatedWriteBuffer(), and write().

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(), DD::Image::Material::engine(), and DD::Image::PlanarIop::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.

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.

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().

Friends And Related Function Documentation

std::ostream& operator<< ( std::ostream &  ,
const Row  
)
friend

Not implemented in the library but you can define it.



©2019 The Foundry Visionmongers, Ltd. All Rights Reserved.
www.thefoundry.co.uk