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

ImageBuf: Only back IB with IC when passed an IC #3986

Merged
merged 2 commits into from
Sep 22, 2023
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
47 changes: 24 additions & 23 deletions src/doc/oiiotool.rst
Original file line number Diff line number Diff line change
Expand Up @@ -916,8 +916,8 @@ output each one to a different file, with names `sub0001.tif`,

.. option:: --cache <size>

Set the underlying ImageCache size (in MB). See Section
:ref:`sec-imagecache-api`.
Causes images to be read through an ImageCache and set the underlying
cache size (in MB). See Section :ref:`sec-imagecache-api`.

.. option:: --oiioattrib <name> <value>

Expand Down Expand Up @@ -1264,29 +1264,30 @@ These are all non-positional flags that affect how all images are read in the

.. option:: --native

Normally, all images read by :program:`oiiotool` are read into an
ImageBuf backed by an underlying ImageCache, and are automatically
Normally, all images read by :program:`oiiotool` are automatically
converted to `float` pixels for internal storage (because any subsequent
image processing is usually much faster and more accurate when done on
floating-point values).

This option causes (1) input images to be stored internally in their
native pixel data type rather than converted to float, and (2) to bypass
the ImageCache (reading directly into an ImageBuf) if the pixel data
type is not one of the types that is supported internally to ImageCache
(`UINT8`, `uint16`, `half`, and `float`).

images whose pixels are comprised of data types that are not natively
representable exactly in the ImageCache to bypass the ImageCache and be
read directly into an ImageBuf.

The typical use case for this is when you know you are dealing with
unusual pixel data types that might lose precision if converted to
`float` (for example, if you have images with `uint32` or `double`
pixels). Another use case is if you are using :program:`oiiotool` merely
for file format or data format conversion, with no actual image
processing math performed on the pixel values -- in that case, you might
save time and memory by bypassing the conversion to `float`.
floating-point values), and also if the `--cache` option is used, the
reading and storage of images will be mediated through an ImageCache.

The `--native` option causes input images to be stored internally in their
native pixel data type of th file rather than converted to float. Also,
even if the `--cache` option is used, reads will bypass the ImageCache
(reading directly into an ImageBuf) if the pixel data type is not one of
the types that is supported internally by ImageCache (`UINT8`, `uint16`,
`half`, and `float`).

There are three uses cases where `--native` might be very helpful: (a) If
you are using :program:`oiiotool` merely for file format or data format
conversion, with no actual image processing math performed on the pixel
values -- in that case, you might save time and memory by avoiding the
conversion to `float`. (b) If you are reading exceptionally large images
that have smaller data types than `float` (for example, `uint8` pixels),
and the only way to make the images fit in memory are to store them as
uint8 rather than converting to float (which takes 4 times as much space
in memory). (c) If you know the file has unusual pixel data types that
might lose precision if converted to `float` (for example, if you have
images with `uint32` or `double` pixels).

.. option:: --autotile <tilesize>

Expand Down
39 changes: 17 additions & 22 deletions src/include/OpenImageIO/imagebuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ enum class InitializePixels { No = 0, Yes = 1 };
/// the details of memory layout and data representation (translating
/// to/from float automatically).
///
/// ImageBuf makes an important simplification: all channels are just one
/// ImageBuf makes an important simplification: all channels are the same
/// data type. For example, if an image file on disk has a mix of `half` and
/// `float` channels, the in-memory ImageBuf representation will be entirely
/// `float` (for mixed data types, it will try to pick one that can best
Expand All @@ -76,21 +76,17 @@ enum class InitializePixels { No = 0, Yes = 1 };
/// other than the first subimage of the file, or forcing the read to
/// translate into a different data format than appears in the file).
///
/// ImageBuf data coming from disk files is backed by ImageCache. That is,
/// especially for tiled files, specific regions of the image will only
/// be read if and when they are needed, and if there are many large
/// ImageBuf's, memory holding pixels not recently accesssed will be
/// automatically freed. Thus, performance of ImageBuf on very large images
/// (or if there are many ImageBuf's simultaneously in use) can be sensitive
/// to choices of the ImageCache parameters such as "autotile". It may be
/// wise for maximum performance to explicitly `read()` (with `force=true`)
/// small images into memory rather than using the ImageCache, in cases
/// where your application has no need for the ImageCache features that
/// limit memory footprint (such as if you know for sure that your app will
/// only read a small number of images, of reasonable size, and will need
/// to access all the pixels of all the images it reads).
/// ImageBuf data coming from disk files may optionally be backed by
/// ImageCache, by explicitly passing an `ImageCache*` to the ImageBuf
/// constructor or `reset()` method (pass `ImageCache::create()` to get a
/// pointer to the default global ImageCache), or by having previously set the
/// global OIIO attribute `"imagebuf:use_imagecache"` to a nonzero value. When
/// an ImageBuf is backed by ImageCache in this way, specific regions of the
/// image will only be read if and when they are needed, and if there are many
/// large ImageBuf's, memory holding pixels not recently accessed will be
/// automatically freed if the cache size limit is reached.
///
/// Writeable ImageBufs are always stored entirely in memory, and do not use
/// Writable ImageBufs are always stored entirely in memory, and do not use
/// the ImageCache or any other clever schemes to limit memory. If you have
/// enough simultaneous writeable large ImageBuf's, you can run out of RAM.
/// Note that if an ImageBuf starts as readable (backed by ImageCache), any
Expand Down Expand Up @@ -178,11 +174,8 @@ class OIIO_API ImageBuf {
/// The subimage and MIP level to read (defaults to the
/// first subimage of the file, highest-res MIP level).
/// @param imagecache
/// Optionally, a particular ImageCache to use. If nullptr,
/// the default global/shared image cache will be used. If
/// a custom ImageCache (not the global/shared one), it is
/// important that the IC should not be destroyed while the
/// ImageBuf is still alive.
/// Optionally, an ImageCache to use, if possible, rather
/// than reading the entire image file into memory.
/// @param config
/// Optionally, a pointer to an ImageSpec whose metadata
/// contains configuration hints that set options related
Expand Down Expand Up @@ -393,7 +386,8 @@ class OIIO_API ImageBuf {
/// `LOCALPIXELS` storage buffer). Otherwise, it is up to
/// the implementation whether to immediately read or have
/// the image backed by an ImageCache (storage
/// `IMAGECACHE`.)
/// `IMAGECACHE`, if the ImageBuf was originall constructed
/// or reset with an ImageCache specified).
/// @param convert
/// If set to a specific type (not`UNKNOWN`), the ImageBuf
/// memory will be allocated for that type specifically and
Expand Down Expand Up @@ -1026,7 +1020,8 @@ class OIIO_API ImageBuf {
/// image being in RAM somewhere?
bool cachedpixels() const;

/// A pointer to the underlying ImageCache.
/// A pointer to the underlying ImageCache, or nullptr if this ImageBuf
/// is not backed by an ImageCache.
ImageCache* imagecache() const;

/// Return the address where pixel `(x,y,z)`, channel `ch`, is stored in
Expand Down
20 changes: 20 additions & 0 deletions src/include/OpenImageIO/imageio.h
Original file line number Diff line number Diff line change
Expand Up @@ -2994,6 +2994,11 @@ OIIO_API std::string geterror(bool clear = true);
/// to neither retrieve errors themselves nor have them printed in this
/// manner can disable the behavior by setting this attribute to 0.
///
/// - `imagebuf:use_imagecache` (0)
///
/// If nonzero, an `ImageBuf` that references a file but is not given an
/// ImageCache will read the image through the default ImageCache.
///
OIIO_API bool attribute(string_view name, TypeDesc type, const void* val);

/// Shortcut attribute() for setting a single integer.
Expand Down Expand Up @@ -3059,6 +3064,21 @@ inline bool attribute (string_view name, string_view val) {
/// full paths), and all the directories that OpenImageIO will search for
/// fonts. (Added in OpenImageIO 2.5)
///
/// - int64_t IB_local_mem_current
/// - int64_t IB_local_mem_peak
///
/// Current and peak size (in bytes) of how much memory was consumed by
/// ImageBufs that owned their own allcoated local pixel buffers. (Added in
/// OpenImageIO 2.5.)
///
/// - float IB_total_open_time
/// - float IB_total_image_read_time
///
/// Total amount of time (in seconds) that ImageBufs spent opening
/// (including reading header information) and reading pixel data from files
/// that they opened and read themselves (that is, excluding I/O from IBs
/// that were backed by ImageCach. (Added in OpenImageIO 2.5.)
///
/// - `string opencolorio_version`
///
/// Returns the version (such as "2.2.0") of OpenColorIO that is used by
Expand Down
Loading