Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start adding stateless api #1842

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 56 additions & 5 deletions src/lib/OpenEXR/ImfContextInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,18 @@ struct istream_holder
};

static int64_t
istream_read (
istream_size (
exr_const_context_t ctxt,
void* userdata)
{
istream_holder* ih = static_cast<istream_holder*> (userdata);
IStream* s = ih->_stream;

return s->size ();
}

static int64_t
istream_threadsafe_read (
exr_const_context_t ctxt,
void* userdata,
void* buffer,
Expand All @@ -36,6 +47,45 @@ istream_read (
{
istream_holder* ih = static_cast<istream_holder*> (userdata);
IStream* s = ih->_stream;
int64_t nread = -1;

try
{
nread = s->read (buffer, sz, offset);
}
catch (std::exception &e)
{
error_cb (
ctxt,
EXR_ERR_READ_IO,
"Unable to seek to desired offset %" PRIu64 ": %s",
offset,
e.what());
nread = -1;
}
catch (...)
{
error_cb (
ctxt,
EXR_ERR_READ_IO,
"Unable to seek to desired offset %" PRIu64 ": Unknown error",
offset);
nread = -1;
}
return nread;
}

static int64_t
istream_nonparallel_read (
exr_const_context_t ctxt,
void* userdata,
void* buffer,
uint64_t sz,
uint64_t offset,
exr_stream_error_func_ptr_t error_cb)
{
istream_holder* ih = static_cast<istream_holder*> (userdata);
IStream* s = ih->_stream;

if (sz > INT_MAX)
{
Expand Down Expand Up @@ -121,10 +171,11 @@ ContextInitializer&
ContextInitializer::setInputStream (IStream* istr)
{
_initializer.user_data = new istream_holder{istr};
_initializer.read_fn = istream_read;
// TODO: add query to io streams to ask size if possible (such
// that ifstream can return size, others can return -1)
_initializer.size_fn = nullptr; //istream_guess_size;
if (istr->isStatelessRead ())
_initializer.read_fn = istream_threadsafe_read;
else
_initializer.read_fn = istream_nonparallel_read;
_initializer.size_fn = istream_size;
_initializer.write_fn = nullptr;
_initializer.destroy_fn = istream_destroy;
_ctxt_type = ContextFileType::READ;
Expand Down
19 changes: 19 additions & 0 deletions src/lib/OpenEXR/ImfIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,25 @@ IStream::fileName () const
return _fileName.c_str ();
}

int64_t
IStream::size ()
{
return -1;
}

bool
IStream::isStatelessRead () const
{
return false;
}

int64_t
IStream::read (void *, uint64_t, uint64_t)
{
throw IEX_NAMESPACE::InputExc ("Attempt to perform a stateless read "
"on a stream without support.");
}

OStream::OStream (const char fileName[]) : _fileName (fileName)
{
// empty
Expand Down
48 changes: 48 additions & 0 deletions src/lib/OpenEXR/ImfIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,54 @@ class IMF_EXPORT_TYPE IStream

IMF_EXPORT const char* fileName () const;

//------------------------------------------------------
// Get the size of the file (or buffer) associated with
// this stream.
//
// by default, this will return -1. That value will skip a few
// safety checks. However, if you provide the size, it will apply
// a number of file consistency checks as the file is read.
// ------------------------------------------------------

IMF_EXPORT virtual int64_t size ();

//-------------------------------------------------
// Does this input stream support stateless reading?
//
// Stateless reading allows multiple threads to
// read from the stream concurrently from different
// locations in the file
//-------------------------------------------------

IMF_EXPORT virtual bool isStatelessRead () const;

//------------------------------------------------------
// Read from the stream with an offset:
//
// read(b,s,o) should read up to sz bytes from the
// stream using something like pread or ReadFileEx with
// overlapped data at the provided offset in the stream.
//
// for this function, the buffer size requested may be
// either larger than the file or request a read past
// the end of the file. This should NOT be treated as
// an error - the library will handle whether that is
// an error (if the offset is past the end, it should
// read 0)
//
// If there is an error, it should either return -1
// or throw an exception (an exception could provide
// a message).
//
// This will only be used if isStatelessRead returns true.
//
// NB: It is expected that this is thread safe such
// that multiple threads can be reading from the stream
// at the same time
//------------------------------------------------------

IMF_EXPORT virtual int64_t read (void *buf, uint64_t sz, uint64_t offset);

protected:
IMF_EXPORT IStream (const char fileName[]);

Expand Down
40 changes: 40 additions & 0 deletions src/lib/OpenEXR/ImfInputFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,14 @@ struct InputFile::Data
}

void setFrameBuffer (const FrameBuffer& frameBuffer);
void lockedSetFrameBuffer (const FrameBuffer& frameBuffer);

void readPixels (int scanline1, int scanline2);
void bufferedReadPixels (int scanline1, int scanline2);

void readPixels (
const FrameBuffer& frameBuffer, int scanline1, int scanline2);

void deleteCachedBuffer (void);
void copyCachedBuffer (FrameBuffer::ConstIterator to,
FrameBuffer::ConstIterator from,
Expand Down Expand Up @@ -224,6 +228,13 @@ InputFile::readPixels (int scanLine)
_data->readPixels (scanLine, scanLine);
}

void
InputFile::readPixels (
const FrameBuffer& frameBuffer, int scanLine1, int scanLine2)
{
_data->readPixels (frameBuffer, scanLine1, scanLine2);
}

void
InputFile::rawPixelData (
int firstScanLine, const char*& pixelData, int& pixelDataSize)
Expand Down Expand Up @@ -317,7 +328,12 @@ InputFile::Data::setFrameBuffer (const FrameBuffer& frameBuffer)
#if ILMTHREAD_THREADING_ENABLED
std::lock_guard<std::mutex> lk (_mx);
#endif
lockedSetFrameBuffer (frameBuffer);
}

void
InputFile::Data::lockedSetFrameBuffer (const FrameBuffer& frameBuffer)
{
if (_storage == EXR_STORAGE_TILED)
{
//
Expand Down Expand Up @@ -430,6 +446,30 @@ InputFile::Data::readPixels (int scanLine1, int scanLine2)
else { _sFile->readPixels (scanLine1, scanLine2); }
}

void
InputFile::Data::readPixels (
const FrameBuffer& frameBuffer, int scanLine1, int scanLine2)
{
if (_compositor)
{
#if ILMTHREAD_THREADING_ENABLED
std::lock_guard<std::mutex> lock (_mx);
#endif
_compositor->setFrameBuffer (frameBuffer);
_compositor->readPixels (scanLine1, scanLine2);
}
else if (_storage == EXR_STORAGE_TILED)
{
#if ILMTHREAD_THREADING_ENABLED
std::lock_guard<std::mutex> lock (_mx);
#endif

lockedSetFrameBuffer (frameBuffer);
bufferedReadPixels (scanLine1, scanLine2);
}
else { _sFile->readPixels (frameBuffer, scanLine1, scanLine2); }
}

void
InputFile::Data::bufferedReadPixels (int scanLine1, int scanLine2)
{
Expand Down
21 changes: 21 additions & 0 deletions src/lib/OpenEXR/ImfInputFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,27 @@ class IMF_EXPORT_TYPE InputFile
IMF_EXPORT
void readPixels (int scanLine);

//----------------------------------------------
// Combines the setFrameBuffer and readPixels into a singular
// call. This does more than that in that it can, with the right
// conditions, not require a lock on the file, such that multiple
// (external to OpenEXR) threads can read at the same time on
// different framebuffers
//
// NB: if the underlying file is deep or tiled, that requires
// translation, so will not do the pass through, but will behave
// in a threadsafe manner (where the only way that was possible
// before was to have a larger framebuffer, set the framebuffer
// once, then call readPixels by the external threads, although
// that occured with a mutex and so the reads were serialized.
// There are reasons why that might still be serialized, such as a
// non-threadable stream.
//----------------------------------------------

IMF_EXPORT
void readPixels (
const FrameBuffer& frameBuffer, int scanLine1, int scanLine2);

//----------------------------------------------
// Read a block of raw pixel data from the file,
// without uncompressing it (this function is
Expand Down
7 changes: 7 additions & 0 deletions src/lib/OpenEXR/ImfInputPart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ InputPart::readPixels (int scanLine)
file->readPixels (scanLine);
}

void
InputPart::readPixels (
const FrameBuffer& frameBuffer, int scanLine1, int scanLine2)
{
file->readPixels (frameBuffer, scanLine1, scanLine2);
}

void
InputPart::rawPixelData (
int firstScanLine, const char*& pixelData, int& pixelDataSize)
Expand Down
3 changes: 3 additions & 0 deletions src/lib/OpenEXR/ImfInputPart.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ class IMF_EXPORT_TYPE InputPart
IMF_EXPORT
void readPixels (int scanLine);
IMF_EXPORT
void readPixels (
const FrameBuffer& frameBuffer, int scanLine1, int scanLine2);
IMF_EXPORT
void rawPixelData (
int firstScanLine, const char*& pixelData, int& pixelDataSize);

Expand Down
2 changes: 1 addition & 1 deletion src/lib/OpenEXR/ImfMultiPartInputFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class IMF_EXPORT_TYPE MultiPartInputFile
//
// used internally by 'Part' types to access individual parts of the multipart file
//
// TODO: change these to value / reference semantics
// TODO: change these to value / reference semantics (smart ptr)
template <class T> IMF_HIDDEN T* getInputPart (int partNumber);
IMF_HIDDEN InputPartData* getPart (int) const;

Expand Down
7 changes: 7 additions & 0 deletions src/lib/OpenEXR/ImfScanLineInputFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,13 @@ ScanLineInputFile::readPixels (int scanLine1, int scanLine2)
_data->readPixels (frameBuffer (), scanLine1, scanLine2);
}

void
ScanLineInputFile::readPixels (
const FrameBuffer& frame, int scanLine1, int scanLine2)
{
_data->readPixels (frame, scanLine1, scanLine2);
}

////////////////////////////////////////

void
Expand Down
12 changes: 12 additions & 0 deletions src/lib/OpenEXR/ImfScanLineInputFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,18 @@ class IMF_EXPORT_TYPE ScanLineInputFile
IMF_EXPORT
void readPixels (int scanLine);

//----------------------------------------------
// Combines the setFrameBuffer and readPixels into a singular
// call. This does more than that in that it can, with the right
// conditions, not require a lock on the file, such that multiple
// (external to OpenEXR) threads can read at the same time on
// different framebuffers
//----------------------------------------------

IMF_EXPORT
void readPixels (
const FrameBuffer& frame, int scanLine1, int scanLine2);

//----------------------------------------------
// Read a block of raw pixel data from the file,
// without uncompressing it (this function is
Expand Down
Loading