Texture Access: TextureSystem

Texture System Introduction and Theory of Operation

Coming soon. FIXME

Helper Classes

Imath

The texture functinality of OpenImageIO uses the excellent open source Ilmbase package’s Imath types when it requires 3D vectors and transformation matrixes. Specifically, we use Imath::V3f for 3D positions and directions, and Imath::M44f for 4x4 transformation matrices. To use these yourself, we recommend that you:

#include <OpenEXR/ImathVec.h>
#include <OpenEXR/ImathMatrix.h>

Please refer to the Ilmbase and OpenEXR documentation and header files for more complete information about use of these types in your own application. However, note that you are not strictly required to use these classes in your application — Imath::V3f has a memory layout identical to float[3] and Imath::M44f has a memory layout identical to float[16], so as long as your own internal vectors and matrices have the same memory layout, it’s ok to just cast pointers to them when passing as arguments to TextureSystem methods.

TextureOpt

TextureOpt is a structure that holds many options controlling single-point texture lookups. Because each texture lookup API call takes a reference to a TextureOpt, the call signatures remain uncluttered rather than having an ever-growing list of parameters, most of which will never vary from their defaults. Here is a brief description of the data members of a TextureOpt structure:

  • int firstchannel : The beginning channel for the lookup. For example, to retrieve just the blue channel, you should have firstchannel = 2 while passing nchannels = 1 to the appropriate texture function.

  • int subimage, ustring subimagename : Specifies the subimage or face within the file to use for the texture lookup. If subimagename is set (it defaults to the empty string), it will try to use the subimage that had a matching metadata "oiio:subimagename", otherwise the integer subimage will be used (which defaults to 0, i.e., the first/default subimage). Nonzero subimage indices only make sense for a texture file that supports subimages (like TIFF or multi-part OpenEXR) or separate images per face (such as Ptex). This will be ignored if the file does not have multiple subimages or separate per-face textures.

  • Wrap swrap, twrap : Specify the wrap mode for 2D texture lookups (and 3D volume texture lookups, using the additional rwrap field). These fields are ignored for shadow and environment lookups. These specify what happens when texture coordinates are found to be outside the usual [0,1] range over which the texture is defined. Wrap is an enumerated type that may take on any of the following values:

    • WrapBlack : The texture is black outside the [0,1] range.

    • WrapClamp : The texture coordinates will be clamped to [0,1], i.e., the value outside [0,1] will be the same as the color at the nearest point on the border.

    • WrapPeriodic : The texture is periodic, i.e., wraps back to 0 after going past 1.

    • WrapMirror : The texture presents a mirror image at the edges, i.e., the coordinates go from 0 to 1, then back down to 0, then back up to 1, etc.

    • WrapDefault : Use whatever wrap might be specified in the texture file itself, or some other suitable default (caveat emptor).

    The wrap mode does not need to be identical in the s and t directions.

  • float swidth, twidth : For each direction, gives a multiplier for the derivatives. Note that a width of 0 indicates a point sampled lookup (assuming that blur is also zero). The default width is 1, indicating that the derivatives should guide the amount of blur applied to the texture filtering (not counting any additional blur specified).

  • float sblur, tblur : For each direction, specifies an additional amount of pre-blur to apply to the texture (after derivatives are taken into account), expressed as a portion of the width of the texture. In other words, blur = 0.1 means that the texture lookup should act as if the texture was pre-blurred with a filter kernel with a width 1/10 the size of the full image. The default blur amount is 0, indicating a sharp texture lookup.

  • float fill : Specifies the value that will be used for any color channels that are requested but not found in the file. For example, if you perform a 4-channel lookup on a 3-channel texture, the last channel will get the fill value. (Note: this behavior is affected by the "gray_to_rgb" attribute described in the Section about TextureSystem attributes.

  • const float* missingcolor : If not NULL, indicates that a missing or broken texture should not be treated as an error, but rather will simply return the supplied color as the texture lookup color and texture() will return true. If the missingcolor field is left at its default (a NULL pointer), a missing or broken texture will be treated as an error and texture() will return false. Note: When not NULL, the data must point to nchannels contiguous floats.

  • float bias : For shadow map lookups only, this gives the “shadow bias” amount.

  • int samples : For shadow map lookups only, the number of samples to use for the lookup.

  • Wrap rwrap, float rblur, rwidth : Specifies wrap, blur, and width for the third component of 3D volume texture lookups. These are not used for 2D texture or environment lookups.

TextureSystem API

class TextureSystem

Define an API to an abstract class that that manages texture files, caches of open file handles as well as tiles of texels so that truly huge amounts of texture may be accessed by an application with low memory footprint, and ways to perform antialiased texture, shadow map, and environment map lookups.

Creating and destroying a texture system

TextureSystem is an abstract API described as a pure virtual class. The actual internal implementation is not exposed through the external API of OpenImageIO. Because of this, you cannot construct or destroy the concrete implementation, so two static methods of TextureSystem are provided:

static TextureSystem *create(bool shared = true, ImageCache *imagecache = nullptr)

Create a TextureSystem and return a pointer to it. This should only be freed by passing it to TextureSystem::destroy()!

Return

A raw pointer to a TextureSystem, which can only be freed with TextureSystem::destroy().

See

TextureSystem::destroy

Parameters
  • shared: If shared is true, the pointer returned will be a shared TextureSystem, (so that multiple parts of an application that request a TextureSystem will all end up with the same one, and the same underlying ImageCache). If shared is false, a completely unique TextureCache will be created and returned.

  • imagecache: If shared is false and imagecache is not nullptr, the TextureSystem will use this as its underlying ImageCache. In that case, it is the caller who is responsible for eventually freeing the ImageCache after the TextureSystem is destroyed. If shared is false and imagecache is nullptr, then a custom ImageCache will be created, owned by the TextureSystem, and automatically freed when the TS destroys.

static void destroy(TextureSystem *ts, bool teardown_imagecache = false)

Destroy an allocated TextureSystem, including freeing all system resources that it holds.

It is safe to destroy even a shared TextureSystem, as the implementation of destroy() will recognize a shared one and only truly release its resources if it has been requested to be destroyed as many times as shared TextureSystem’s were created.

Parameters
  • ts: Raw pointer to the TextureSystem to destroy.

  • teardown_imagecache: For a shared TextureSystem, if the teardown_imagecache parameter is true, it will try to truly destroy the shared cache if nobody else is still holding a reference (otherwise, it will leave it intact). This parameter has no effect if ts was not the single globally shared TextureSystem.

Setting options and limits for the texture system

These are the list of attributes that can bet set or queried by attribute/getattribute:

All attributes ordinarily recognized by ImageCache are accepted and passed through to the underlying ImageCache. These include:

  • int max_open_files : Maximum number of file handles held open.

  • float max_memory_MB : Maximum tile cache size, in MB.

  • string searchpath : Colon-separated search path for texture files.

  • string plugin_searchpath : Colon-separated search path for plugins.

  • int autotile : If >0, tile size to emulate for non-tiled images.

  • int autoscanline : If nonzero, autotile using full width tiles.

  • int automip : If nonzero, emulate mipmap on the fly.

  • int accept_untiled : If nonzero, accept untiled images.

  • int accept_unmipped : If nonzero, accept unmipped images.

  • int failure_retries : How many times to retry a read failure.

  • int deduplicate : If nonzero, detect duplicate textures (default=1).

  • string substitute_image : If supplied, an image to substatute for all texture references.

  • int max_errors_per_file : Limits how many errors to issue for each file. (default: 100)

Texture-specific settings:

  • matrix44 worldtocommon / matrix44 commontoworld : The 4x4 matrices that provide the spatial transformation from “world” to a “common” coordinate system and back. This is mainly used for shadow map lookups, in which the shadow map itself encodes the world coordinate system, but positions passed to shadow() are expressed in “common” coordinates. You do not need to set commontoworld and worldtocommon separately; just setting either one will implicitly set the other, since each is the inverse of the other.

  • int gray_to_rgb : If set to nonzero, texture lookups of single-channel (grayscale) images will replicate the sole channel’s values into the next two channels, making it behave like an RGB image that happens to have all three channels with identical pixel values. (Channels beyond the third will get the “fill” value.) The default value of zero means that all missing channels will get the “fill” color.

  • int max_tile_channels : The maximum number of color channels in a texture file for which all channels will be loaded as a single cached tile. Files with more than this number of color channels will have only the requested subset loaded, in order to save cache space (but at the possible wasted expense of separate tiles that overlap their channel ranges). The default is 5.

  • int max_mip_res : NEW 2.1 Sets the maximum MIP-map resolution for filtered texture lookups. The MIP levels used will be clamped to those having fewer than this number of pixels in each dimension. This can be helpful as a way to limit disk I/O when doing fast preview renders (with the tradeoff that you may see some texture more blurry than they would ideally be). The default is 1 << 30, a value so large that no such clamping will be performed.

  • string latlong_up : The default “up” direction for latlong environment maps (only applies if the map itself doesn’t specify a format or is in a format that explicitly requires a particular orientation). The default is "y". (Currently any other value will result in z being “up.”)

  • int flip_t : If nonzero, t coordinates will be flipped 1-t for all texture lookups. The default is 0.

  • string options This catch-all is simply a comma-separated list of name=value settings of named options, which will be parsed and individually set.

    ic->attribute ("options", "max_memory_MB=512.0,autotile=1");
    

    Note that if an option takes a string value that must itself contain a comma, it is permissible to enclose the value in either single \' or double " quotes.

Read-only attributes

Additionally, there are some read-only attributes that can be queried with getattribute() even though they cannot be set via attribute():

The following member functions of TextureSystem allow you to set (and in some cases retrieve) options that control the overall behavior of the texture system:

virtual bool attribute(string_view name, TypeDesc type, const void *val) = 0

Set a named attribute (i.e., a property or option) of the TextureSystem.

Example:

TextureSystem *ts;
...
int maxfiles = 50;
ts->attribute ("max_open_files", TypeDesc::INT, &maxfiles);

const char *path = "/my/path";
ts->attribute ("searchpath", TypeDesc::STRING, &path);

// There are specialized versions for retrieving a single int,
// float, or string without needing types or pointers:
ts->getattribute ("max_open_files", 50);
ic->attribute ("max_memory_MB", 4000.0f);
ic->attribute ("searchpath", "/my/path");

Note: When passing a string, you need to pass a pointer to the char*, not a pointer to the first character. (Rationale: for an int attribute, you pass the address of the int. So for a string, which is a char*, you need to pass the address of the string, i.e., a char**).

Return

true if the name and type were recognized and the attribute was set, or false upon failure (including it being an unrecognized attribute or not of the correct type).

Parameters
  • name: Name of the attribute to set.

  • type: TypeDesc describing the type of the attribute.

  • val: Pointer to the value data.

virtual bool attribute(string_view name, int val) = 0

Specialized attribute() for setting a single int value.

virtual bool attribute(string_view name, float val) = 0

Specialized attribute() for setting a single float value.

virtual bool attribute(string_view name, string_view val) = 0

Specialized attribute() for setting a single string value.

virtual bool getattribute(string_view name, TypeDesc type, void *val) const = 0

Get the named attribute of the texture system, store it in *val. All of the attributes that may be set with the attribute() call may also be queried with getattribute().

Examples:

TextureSystem *ic;
...
int maxfiles;
ts->getattribute ("max_open_files", TypeDesc::INT, &maxfiles);

const char *path;
ts->getattribute ("searchpath", TypeDesc::STRING, &path);

// There are specialized versions for retrieving a single int,
// float, or string without needing types or pointers:
int maxfiles;
ts->getattribute ("max_open_files", maxfiles);
const char *path;
ts->getattribute ("searchpath", &path);

Note: When retrieving a string, you need to pass a pointer to the char*, not a pointer to the first character. Also, the char* will end up pointing to characters owned by the ImageCache; the caller does not need to ever free the memory that contains the characters.

Return

true if the name and type were recognized and the attribute was retrieved, or false upon failure (including it being an unrecognized attribute or not of the correct type).

Parameters
  • name: Name of the attribute to retrieve.

  • type: TypeDesc describing the type of the attribute.

  • val: Pointer where the attribute value should be stored.

virtual bool getattribute(string_view name, int &val) const = 0

Specialized attribute() for retrieving a single int value.

virtual bool getattribute(string_view name, float &val) const = 0

Specialized attribute() for retrieving a single float value.

virtual bool getattribute(string_view name, char **val) const = 0

Specialized attribute() for retrieving a single string value as a char*.

virtual bool getattribute(string_view name, std::string &val) const = 0

Specialized attribute() for retrieving a single string value as a std::string.

Opaque data for performance lookups

The TextureSystem implementation needs to maintain certain per-thread state, and some methods take an opaque Perthread pointer to this record. There are three options for how to deal with it:

  1. Don’t worry about it at all: don’t use the methods that want Perthread pointers, or always pass nullptr for any `Perthread*1 arguments, and ImageCache will do thread-specific-pointer retrieval as necessary (though at some small cost).

  2. If your app already stores per-thread information of its own, you may call get_perthread_info(nullptr) to retrieve it for that thread, and then pass it into the functions that allow it (thus sparing them the need and expense of retrieving the thread-specific pointer). However, it is crucial that this pointer not be shared between multiple threads. In this case, the ImageCache manages the storage, which will automatically be released when the thread terminates.

  3. If your app also wants to manage the storage of the Perthread, it can explicitly create one with create_perthread_info(), pass it around, and eventually be responsible for destroying it with destroy_perthread_info(). When managing the storage, the app may reuse the Perthread for another thread after the first is terminated, but still may not use the same Perthread for two threads running concurrently.

virtual Perthread *get_perthread_info(Perthread *thread_info = nullptr) = 0

Retrieve a Perthread, unique to the calling thread. This is a thread-specific pointer that will always return the Perthread for a thread, which will also be automatically destroyed when the thread terminates.

Applications that want to manage their own Perthread pointers (with create_thread_info and destroy_thread_info) should still call this, but passing in their managed pointer. If the passed-in thread_info is not nullptr, it won’t create a new one or retrieve a TSP, but it will do other necessary housekeeping on the Perthread information.

virtual Perthread *create_thread_info() = 0

Create a new Perthread. It is the caller’s responsibility to eventually destroy it using destroy_thread_info().

virtual void destroy_thread_info(Perthread *threadinfo) = 0

Destroy a Perthread that was allocated by create_thread_info().

virtual TextureHandle *get_texture_handle(ustring filename, Perthread *thread_info = nullptr) = 0

Retrieve an opaque handle for fast texture lookups. The opaque pointer thread_info is thread-specific information returned by get_perthread_info(). Return nullptr if something has gone horribly wrong.

virtual bool good(TextureHandle *texture_handle) = 0

Return true if the texture handle (previously returned by get_image_handle()) is a valid texture that can be subsequently read.

Texture lookups

virtual bool texture(ustring filename, TextureOpt &options, float s, float t, float dsdx, float dtdx, float dsdy, float dtdy, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr) = 0

Perform a filtered 2D texture lookup on a position centered at 2D coordinates (s, t) from the texture identified by filename, and using relevant texture options. The nchannels parameter determines the number of channels to retrieve (e.g., 1 for a single value, 3 for an RGB triple, etc.). The filtered results will be stored in result[0..nchannels-1].

We assume that this lookup will be part of an image that has pixel coordinates x and y. By knowing how s and t change from pixel to pixel in the final image, we can properly filter or antialias the texture lookups. This information is given via derivatives dsdx and dtdx that define the change in s and t per unit of x, and dsdy and dtdy that define the change in s and t per unit of y. If it is impossible to know the derivatives, you may pass 0 for them, but in that case you will not receive an antialiased texture lookup.

Return

true upon success, or false if the file was not found or could not be opened by any available ImageIO plugin.

Parameters
  • filename: The name of the texture.

  • options: Fields within options that are honored for 2D texture lookups include the following:

    • int firstchannel : The index of the first channel to look up from the texture.

    • int subimage / ustring subimagename : The subimage or face within the file, specified by either by name (if non-empty) or index. This will be ignored if the file does not have multiple subimages or separate per-face textures.

    • Wrap swrap, twrap : Specify the wrap mode for each direction, one of: WrapBlack, WrapClamp, WrapPeriodic, WrapMirror, or WrapDefault.

    • float swidth, twidth : For each direction, gives a multiplier for the derivatives.

    • float sblur, tblur : For each direction, specifies an additional amount of pre-blur to apply to the texture (after derivatives are taken into account), expressed as a portion of the width of the texture.

    • float fill : Specifies the value that will be used for any color channels that are requested but not found in the file. For example, if you perform a 4-channel lookup on a 3-channel texture, the last channel will get the fill value. (Note: this behavior is affected by the "gray_to_rgb" TextureSystem attribute.

    • const float *missingcolor : If not nullptr, specifies the color that will be returned for missing or broken textures (rather than being an error).

  • s/t: The 2D texture coordinates.

  • dsdxdtdxdsdydtdy: The differentials of s and t relative to canonical directions x and y. The choice of x and y are not important to the implementation; it can be any imposed 2D coordinates, such as pixels in screen space, adjacent samples in parameter space on a surface, etc. The st derivatives determine the size and shape of the ellipsoid over which the texture lookup is filtered.

  • nchannels: The number of channels of data to retrieve into result (e.g., 1 for a single value, 3 for an RGB triple, etc.).

  • result[]: The result of the filtered texture lookup will be placed into result[0..nchannels-1].

  • dresultds/dresultdt: If non-null, these designate storage locations for the derivatives of result, i.e., the rate of change per unit s and t, respectively, of the filtered texture. If supplied, they must allow for nchannels of storage.

virtual bool texture(TextureHandle *texture_handle, Perthread *thread_info, TextureOpt &options, float s, float t, float dsdx, float dtdx, float dsdy, float dtdy, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr) = 0

Slightly faster version of texture() lookup if the app already has a texture handle and per-thread info.

virtual bool texture3d(ustring filename, TextureOpt &options, const Imath::V3f &P, const Imath::V3f &dPdx, const Imath::V3f &dPdy, const Imath::V3f &dPdz, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr, float *dresultdr = nullptr) = 0

Perform a filtered 3D volumetric texture lookup on a position centered at 3D position P (with given differentials) from the texture identified by filename, and using relevant texture options. The filtered results will be stored in result[0..nchannels-1].

The P coordinate and dPdx, dPdy, and dPdz derivatives are assumed to be in some kind of common global coordinate system (usually “world” space) and will be automatically transformed into volume local coordinates, if such a transformation is specified in the volume file itself.

Return

true upon success, or false if the file was not found or could not be opened by any available ImageIO plugin.

Parameters
  • filename: The name of the texture.

  • options: Fields within options that are honored for 3D texture lookups include the following:

    • int firstchannel : The index of the first channel to look up from the texture.

    • int subimage / ustring subimagename : The subimage or field within the volume, specified by either by name (if non-empty) or index. This will be ignored if the file does not have multiple subimages or separate per-face textures.

    • Wrap swrap, twrap, rwrap : Specify the wrap mode for each direction, one of: WrapBlack, WrapClamp, WrapPeriodic, WrapMirror, or WrapDefault.

    • float swidth, twidth, rwidth : For each direction, gives a multiplier for the derivatives.

    • float sblur, tblur, rblur : For each direction, specifies an additional amount of pre-blur to apply to the texture (after derivatives are taken into account), expressed as a portion of the width of the texture.

    • float fill : Specifies the value that will be used for any color channels that are requested but not found in the file. For example, if you perform a 4-channel lookup on a 3-channel texture, the last channel will get the fill value. (Note: this behavior is affected by the "gray_to_rgb" TextureSystem attribute.

    • const float *missingcolor : If not nullptr, specifies the color that will be returned for missing or broken textures (rather than being an error).

    • float time : A time value to use if the volume texture specifies a time-varying local transformation (default: 0).

  • P: The 2D texture coordinates.

  • dPdx/dPdy/dPdz: The differentials of P. We assume that this lookup will be part of an image that has pixel coordinates x and y and depth z. By knowing how P changes from pixel to pixel in the final image, and as we step in z depth, we can properly filter or antialias the texture lookups. This information is given via derivatives dPdx, dPdy, and dPdz that define the changes in P per unit of x, y, and z, respectively. If it is impossible to know the derivatives, you may pass 0 for them, but in that case you will not receive an antialiased texture lookup.

  • nchannels: The number of channels of data to retrieve into result (e.g., 1 for a single value, 3 for an RGB triple, etc.).

  • result[]: The result of the filtered texture lookup will be placed into result[0..nchannels-1].

  • dresultds/dresultdt/dresultdr: If non-null, these designate storage locations for the derivatives of result, i.e., the rate of change per unit s, t, and r, respectively, of the filtered texture. If supplied, they must allow for nchannels of storage.

virtual bool texture3d(TextureHandle *texture_handle, Perthread *thread_info, TextureOpt &options, const Imath::V3f &P, const Imath::V3f &dPdx, const Imath::V3f &dPdy, const Imath::V3f &dPdz, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr, float *dresultdr = nullptr) = 0

Slightly faster version of texture3d() lookup if the app already has a texture handle and per-thread info.

virtual bool environment(ustring filename, TextureOpt &options, const Imath::V3f &R, const Imath::V3f &dRdx, const Imath::V3f &dRdy, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr) = 0

Perform a filtered directional environment map lookup in the direction of vector R, from the texture identified by filename, and using relevant texture options. The filtered results will be stored in result[].

Return

true upon success, or false if the file was not found or could not be opened by any available ImageIO plugin.

Parameters
  • filename: The name of the texture.

  • options: Fields within options that are honored for environment lookups include the following:

    • int firstchannel : The index of the first channel to look up from the texture.

    • int subimage / ustring subimagename : The subimage or face within the file, specified by either by name (if non-empty) or index. This will be ignored if the file does not have multiple subimages or separate per-face textures.

    • float swidth, twidth : For each direction, gives a multiplier for the derivatives.

    • float sblur, tblur : For each direction, specifies an additional amount of pre-blur to apply to the texture (after derivatives are taken into account), expressed as a portion of the width of the texture.

    • float fill : Specifies the value that will be used for any color channels that are requested but not found in the file. For example, if you perform a 4-channel lookup on a 3-channel texture, the last channel will get the fill value. (Note: this behavior is affected by the "gray_to_rgb" TextureSystem attribute.

    • const float *missingcolor : If not nullptr, specifies the color that will be returned for missing or broken textures (rather than being an error).

  • R: The direction vector to look up.

  • dRdx/dRdy: The differentials of R with respect to image coordinates x and y.

  • nchannels: The number of channels of data to retrieve into result (e.g., 1 for a single value, 3 for an RGB triple, etc.).

  • result[]: The result of the filtered texture lookup will be placed into result[0..nchannels-1].

  • dresultds/dresultdt: If non-null, these designate storage locations for the derivatives of result, i.e., the rate of change per unit s and t, respectively, of the filtered texture. If supplied, they must allow for nchannels of storage.

virtual bool environment(TextureHandle *texture_handle, Perthread *thread_info, TextureOpt &options, const Imath::V3f &R, const Imath::V3f &dRdx, const Imath::V3f &dRdy, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr) = 0

Slightly faster version of environment() if the app already has a texture handle and per-thread info.

Batched texture lookups

virtual bool texture(ustring filename, TextureOptBatch &options, Tex::RunMask mask, const float *s, const float *t, const float *dsdx, const float *dtdx, const float *dsdy, const float *dtdy, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr) = 0

Perform filtered 2D texture lookups on a batch of positions from the same texture, all at once. The parameters s, t, dsdx, dtdx, and dsdy, dtdy are each a pointer to [BatchWidth] values. The mask determines which of those array elements to actually compute.

The float* results act like float[nchannels][BatchWidth], so that effectively result[0..BatchWidth-1] are the “red” result for each lane, result[BatchWidth..2*BatchWidth-1] are the “green” results, etc. The dresultds and dresultdt should either both be provided, or else both be nullptr (meaning no derivative results are required).

Return

true upon success, or false if the file was not found or could not be opened by any available ImageIO plugin.

Parameters
  • filename: The name of the texture.

  • options: A TextureOptBatch containing texture lookup options. This is conceptually the same as a TextureOpt, but the following fields are arrays of [BatchWidth] elements: sblur, tblur, swidth, twidth. The other fields are, as with TextureOpt, ordinary scalar values.

  • mask: A bit-field designating which “lanes” should be computed: if mask & (1<<i) is nonzero, then results should be computed and stored for result[...][i].

  • s/t: Pointers to the 2D texture coordinates, each as a float[BatchWidth].

  • dsdx/dtdx/dsdy/dtdy: The differentials of s and t relative to canonical directions x and y, each as a float[BatchWidth].

  • nchannels: The number of channels of data to retrieve into result (e.g., 1 for a single value, 3 for an RGB triple, etc.).

  • result[]: The result of the filtered texture lookup will be placed here, as float [nchannels][BatchWidth]. (Note the “SOA” data layout.)

  • dresultds/dresultdt: If non-null, these designate storage locations for the derivatives of result, and like result are in SOA layout: float [nchannels][BatchWidth]

virtual bool texture(TextureHandle *texture_handle, Perthread *thread_info, TextureOptBatch &options, Tex::RunMask mask, const float *s, const float *t, const float *dsdx, const float *dtdx, const float *dsdy, const float *dtdy, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr) = 0

Slightly faster version of texture() lookup if the app already has a texture handle and per-thread info.

virtual bool texture3d(ustring filename, TextureOptBatch &options, Tex::RunMask mask, const float *P, const float *dPdx, const float *dPdy, const float *dPdz, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr, float *dresultdr = nullptr) = 0

Perform filtered 3D volumetric texture lookups on a batch of positions from the same texture, all at once. The “point-like” parameters P, dPdx, dPdy, and dPdz are each a pointers to arrays of float value[3][BatchWidth] (or alternately like Imath::Vec3<FloatWide>). That is, each one points to all the x values for the batch, immediately followed by all the y values, followed by the z values. The mask determines which of those array elements to actually compute.

The various results arrays are also arranged as arrays that behave as if they were declared float result[channels][BatchWidth], where all the batch values for channel 0 are adjacent, followed by all the batch values for channel 1, etc.

Return

true upon success, or false if the file was not found or could not be opened by any available ImageIO plugin.

Parameters
  • filename: The name of the texture.

  • options: A TextureOptBatch containing texture lookup options. This is conceptually the same as a TextureOpt, but the following fields are arrays of [BatchWidth] elements: sblur, tblur, swidth, twidth. The other fields are, as with TextureOpt, ordinary scalar values.

  • mask: A bit-field designating which “lanes” should be computed: if mask & (1<<i) is nonzero, then results should be computed and stored for result[...][i].

  • P: Pointers to the 3D texture coordinates, each as a float[3][BatchWidth].

  • dPdx/dPdy/dPdz: The differentials of P relative to canonical directions x, y, and z, each as a float[3][BatchWidth].

  • nchannels: The number of channels of data to retrieve into result (e.g., 1 for a single value, 3 for an RGB triple, etc.).

  • result[]: The result of the filtered texture lookup will be placed here, as float [nchannels][BatchWidth]. (Note the “SOA” data layout.)

  • dresultds/dresultdt/dresultdr: If non-null, these designate storage locations for the derivatives of result, and like result are in SOA layout: float [nchannels][BatchWidth]

virtual bool texture3d(TextureHandle *texture_handle, Perthread *thread_info, TextureOptBatch &options, Tex::RunMask mask, const float *P, const float *dPdx, const float *dPdy, const float *dPdz, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr, float *dresultdr = nullptr) = 0

Slightly faster version of texture3d() lookup if the app already has a texture handle and per-thread info.

virtual bool environment(ustring filename, TextureOptBatch &options, Tex::RunMask mask, const float *R, const float *dRdx, const float *dRdy, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr) = 0

Perform filtered directional environment map lookups on a batch of directions from the same texture, all at once. The “point-like” parameters R, dRdx, and dRdy are each a pointers to arrays of float value[3][BatchWidth] (or alternately like Imath::Vec3<FloatWide>). That is, each one points to all the x values for the batch, immediately followed by all the y values, followed by the z values. The mask determines which of those array elements to actually compute.

The various results arrays are also arranged as arrays that behave as if they were declared float result[channels][BatchWidth], where all the batch values for channel 0 are adjacent, followed by all the batch values for channel 1, etc.

Return

true upon success, or false if the file was not found or could not be opened by any available ImageIO plugin.

Parameters
  • filename: The name of the texture.

  • options: A TextureOptBatch containing texture lookup options. This is conceptually the same as a TextureOpt, but the following fields are arrays of [BatchWidth] elements: sblur, tblur, swidth, twidth. The other fields are, as with TextureOpt, ordinary scalar values.

  • mask: A bit-field designating which “lanes” should be computed: if mask & (1<<i) is nonzero, then results should be computed and stored for result[...][i].

  • R: Pointers to the 3D texture coordinates, each as a float[3][BatchWidth].

  • dRdx/dRdy: The differentials of R relative to canonical directions x and y, each as a float[3][BatchWidth].

  • nchannels: The number of channels of data to retrieve into result (e.g., 1 for a single value, 3 for an RGB triple, etc.).

  • result[]: The result of the filtered texture lookup will be placed here, as float [nchannels][BatchWidth]. (Note the “SOA” data layout.)

  • dresultds/dresultdt: If non-null, these designate storage locations for the derivatives of result, and like result are in SOA layout: float [nchannels][BatchWidth]

virtual bool environment(TextureHandle *texture_handle, Perthread *thread_info, TextureOptBatch &options, Tex::RunMask mask, const float *R, const float *dRdx, const float *dRdy, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr) = 0

Slightly faster version of environment() if the app already has a texture handle and per-thread info.

Texture metadata and raw texels

virtual std::string resolve_filename(const std::string &filename) const = 0

Given possibly-relative ‘filename’, resolve it using the search path rules and return the full resolved filename.

virtual bool get_texture_info(ustring filename, int subimage, ustring dataname, TypeDesc datatype, void *data) = 0

Get information or metadata about the named texture and store it in *data.

Data names may include any of the following:

  • exists (int): Stores the value 1 if the file exists and is an image format that OpenImageIO can read, or 0 if the file does not exist, or could not be properly read as a texture. Note that unlike all other queries, this query will “succeed” (return true) even if the file does not exist.

  • udim (int) : Stores the value 1 if the file is a “virtual UDIM” or texture atlas file (as described in Section :ref:sec-texturesys-udim) or 0 otherwise.

  • subimages (int) : The number of subimages/faces in the file, as an integer.

  • resolution (int[2] or int[3]): The resolution of the texture file, if an array of 2 integers (described as TypeDesc(INT,2)), or the 3D resolution of the texture file, which is an array of 3 integers (described as TypeDesc(INT,3)) The third value will be 1 unless it’s a volumetric (3D) image.

  • miplevels (int) : The number of MIPmap levels for the specified subimage (an integer).

  • texturetype (string) : A string describing the type of texture of the given file, which describes how the texture may be used (also which texture API call is probably the right one for it). This currently may return one of: “unknown”, “Plain Texture”, “Volume Texture”, “Shadow”, or “Environment”.

  • textureformat

    (string) : A string describing the format of the given file, which describes the kind of texture stored in the file. This currently may return one of: “unknown”, “Plain Texture”, “Volume Texture”, “Shadow”, “CubeFace Shadow”, “Volume

    Shadow”, “LatLong Environment”, or “CubeFace Environment”. Note that there are several kinds of shadows and environment maps, all accessible through the same API calls.

  • channels (int) : The number of color channels in the file.

  • format (int) : The native data format of the pixels in the file (an integer, giving the TypeDesc::BASETYPE of the data). Note that this is not necessarily the same as the data format stored in the image cache.

  • cachedformat (int) : The native data format of the pixels as stored in the image cache (an integer, giving the TypeDesc::BASETYPE of the data). Note that this is not necessarily the same as the native data format of the file.

  • datawindow (int[4] or int[6]): Returns the pixel data window of the image, which is either an array of 4 integers (returning xmin, ymin, xmax, ymax) or an array of 6 integers (returning xmin, ymin, zmin, xmax, ymax, zmax). The z values may be useful for 3D/volumetric images; for 2D images they will be 0).

  • displaywindow (matrix) : Returns the display (a.k.a. full) window of the image, which is either an array of 4 integers (returning xmin, ymin, xmax, ymax) or an array of 6 integers (returning xmin, ymin, zmin, xmax, ymax, zmax). The z values may be useful for 3D/volumetric images; for 2D images they will be 0).

  • worldtocamera (matrix) : The viewing matrix, which is a 4x4 matrix (an Imath::M44f, described as TypeMatrix44) giving the world-to-camera 3D transformation matrix that was used when the image was created. Generally, only rendered images will have this.

  • worldtoscreen (matrix) : The projection matrix, which is a 4x4 matrix (an Imath::M44f, described as TypeMatrix44) giving the matrix that projected points from world space into a 2D screen coordinate system where x and y range from -1 to +1. Generally, only rendered images will have this.

  • worldtoNDC (matrix) : The projection matrix, which is a 4x4 matrix (an Imath::M44f, described as TypeMatrix44) giving the matrix that projected points from world space into a 2D screen coordinate system where x and y range from 0 to +1. Generally, only rendered images will have this.

  • averagecolor (float[nchannels]) : If available in the metadata (generally only for files that have been processed by maketx), this will return the average color of the texture (into an array of floats).

  • averagealpha (float) : If available in the metadata (generally only for files that have been processed by maketx), this will return the average alpha value of the texture (into a float).

  • constantcolor (float[nchannels]) : If the metadata (generally only for files that have been processed by maketx) indicates that the texture has the same values for all pixels in the texture, this will retrieve the constant color of the texture (into an array of floats). A non-constant image (or one that does not have the special metadata tag identifying it as a constant texture) will fail this query (return false).

  • constantalpha (float) : If the metadata indicates that the texture has the same values for all pixels in the texture, this will retrieve the constant alpha value of the texture. A non-constant image (or one that does not have the special metadata tag identifying it as a constant texture) will fail this query (return false).

  • stat:tilesread (int64) : Number of tiles read from this file.

  • stat:bytesread (int64) : Number of bytes of uncompressed pixel data read

  • stat:redundant_tiles (int64) : Number of times a tile was read, where the same tile had been rad before.

  • stat:redundant_bytesread (int64) : Number of bytes (of uncompressed pixel data) in tiles that were read redundantly.

  • stat:redundant_bytesread (int) : Number of tiles read from this file.

  • stat:timesopened (int) : Number of times this file was opened.

  • stat:iotime (float) : Time (in seconds) spent on all I/O for this file.

  • stat:mipsused (int) : Stores 1 if any MIP levels beyond the highest resolution were accessed, otherwise 0.

  • stat:is_duplicate (int) : Stores 1 if this file was a duplicate of another image, otherwise 0.

  • Anything else : For all other data names, the the metadata of the image file will be searched for an item that matches both the name and data type.

Return

true if get_textureinfo() is able to find the requested dataname for the texture and it matched the requested datatype. If the requested data was not found or was not of the right data type, return false. Except for the "exists" query, a file that does not exist or could not be read properly as an image also constitutes a query failure that will return false.

Parameters
  • filename: The name of the texture.

  • subimage: The subimage to query. (The metadata retrieved is for the highest-resolution MIP level of that subimage.)

  • dataname: The name of the metadata to retrieve.

  • datatype: TypeDesc describing the data type.

  • data: Pointer to the caller-owned memory where the values should be stored. It is the caller’s responsibility to ensure that data points to a large enough storage area to accommodate the datatype requested.

virtual bool get_texture_info(TextureHandle *texture_handle, Perthread *thread_info, int subimage, ustring dataname, TypeDesc datatype, void *data) = 0

A more efficient variety of get_texture_info() for cases where you can use a TextureHandle* to specify the image and optionally have a Perthread* for the calling thread.

virtual bool get_imagespec(ustring filename, int subimage, ImageSpec &spec) = 0

Copy the ImageSpec associated with the named texture (the first subimage by default, or as set by subimage).

Return

true upon success, false upon failure failure (such as being unable to find, open, or read the file, or if it does not contain the designated subimage or MIP level).

Parameters
  • filename: The name of the image.

  • subimage: The subimage to query. (The spec retrieved is for the highest-resolution MIP level of that subimage.)

  • spec: ImageSpec into which will be copied the spec for the requested image.

virtual bool get_imagespec(TextureHandle *texture_handle, Perthread *thread_info, int subimage, ImageSpec &spec) = 0

A more efficient variety of get_imagespec() for cases where you can use a TextureHandle* to specify the image and optionally have a Perthread* for the calling thread.

virtual const ImageSpec *imagespec(ustring filename, int subimage = 0) = 0

Return a pointer to an ImageSpec associated with the named texture if the file is found and is an image format that can be read, otherwise return nullptr.

This method is much more efficient than get_imagespec(), since it just returns a pointer to the spec held internally by the TextureSystem (rather than copying the spec to the user’s memory). However, the caller must beware that the pointer is only valid as long as nobody (even other threads) calls invalidate() on the file, or invalidate_all(), or destroys the TextureSystem and its underlying ImageCache.

Return

A pointer to the spec, if the image is found and able to be opened and read by an available image format plugin, and the designated subimage exists.

Parameters
  • filename: The name of the image.

  • subimage: The subimage to query. (The spec retrieved is for the highest-resolution MIP level of that subimage.)

virtual const ImageSpec *imagespec(TextureHandle *texture_handle, Perthread *thread_info = nullptr, int subimage = 0) = 0

A more efficient variety of imagespec() for cases where you can use a TextureHandle* to specify the image and optionally have a Perthread* for the calling thread.

virtual bool get_texels(ustring filename, TextureOpt &options, int miplevel, int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, int chbegin, int chend, TypeDesc format, void *result) = 0

For a texture specified by name, retrieve the rectangle of raw unfiltered texels from the subimage specified in options and at the designated miplevel, storing the pixel values beginning at the address specified by result. The pixel values will be converted to the data type specified by format. The rectangular region to be retrieved includes begin but does not include end (much like STL begin/end usage). Requested pixels that are not part of the valid pixel data region of the image file will be filled with zero values. Channels requested but not present in the file will get the options.fill value.

Return

true for success, false for failure.

Parameters
  • filename: The name of the image.

  • options: A TextureOpt describing access options, including wrap modes, fill value, and subimage, that will be used when retrieving pixels.

  • miplevel: The MIP level to retrieve pixels from (0 is the highest resolution level).

  • xbegin/xend/ybegin/yend/zbegin/zend: The range of pixels to retrieve. The pixels retrieved include the begin value but not the end value (much like STL begin/end usage).

  • chbegin/chend: Channel range to retrieve. To retrieve all channels, use chbegin = 0, chend = nchannels.

  • format: TypeDesc describing the data type of the values you want to retrieve into result. The pixel values will be converted to this type regardless of how they were stored in the file or in the cache.

  • result: Pointer to the memory where the pixel values should be stored. It is up to the caller to ensure that result points to an area of memory big enough to accommodate the requested rectangle (taking into consideration its dimensions, number of channels, and data format).

virtual bool get_texels(TextureHandle *texture_handle, Perthread *thread_info, TextureOpt &options, int miplevel, int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, int chbegin, int chend, TypeDesc format, void *result) = 0

A more efficient variety of get_texels() for cases where you can use a TextureHandle* to specify the image and optionally have a Perthread* for the calling thread.

Controlling the cache

virtual void invalidate(ustring filename, bool force = true) = 0

Invalidate any cached information about the named file, including loaded texture tiles from that texture, and close any open file handle associated with the file. This calls ImageCache::invalidate(filename,force) on the underlying ImageCache.

virtual void invalidate_all(bool force = false) = 0

Invalidate all cached data for all textures. This calls ImageCache::invalidate_all(force) on the underlying ImageCache.

virtual void close(ustring filename) = 0

Close any open file handles associated with a named file, but do not invalidate any image spec information or pixels associated with the files. A client might do this in order to release OS file handle resources, or to make it safe for other processes to modify textures on disk. This calls ImageCache::close(force) on the underlying ImageCache.

virtual void close_all() = 0

close() all files known to the cache.

Errors and statistics

virtual std::string geterror() const = 0

If any of the API routines returned false indicating an error, this routine will return the error string (and clear any error flags). If no error has occurred since the last time geterror() was called, it will return an empty string.

virtual std::string getstats(int level = 1, bool icstats = true) const = 0

Returns a big string containing useful statistics about the TextureSystem operations, suitable for saving to a file or outputting to the terminal. The level indicates the amount of detail in the statistics, with higher numbers (up to a maximum of 5) yielding more and more esoteric information. If icstats is true, the returned string will also contain all the statistics of the underlying ImageCache, but if false will only contain texture-specific statistics.

virtual void reset_stats() = 0

Reset most statistics to be as they were with a fresh TextureSystem. Caveat emptor: this does not flush the cache itself, so the resulting statistics from the next set of texture requests will not match the number of tile reads, etc., that would have resulted from a new TextureSystem.

Public Functions

virtual ImageCache *imagecache() const = 0

Return an opaque, non-owning pointer to the underlying ImageCache (if there is one).

Batched Texture Lookups

On CPU architectures with SIMD processing, texturing entire batches of samples at once may provide a large speedup compared to texturing each sample point individually. The batch size is fixed (for any build of OpenImageIO) and may be accessed with the following constant:

constexpr int OIIO::Tex::BatchWidth = OIIO_TEXTURE_SIMD_BATCH_WIDTH

The SIMD width for batched texturing operations. This is fixed within any release of OpenImageIO, but may change from release to release and also may be overridden at build time. A typical batch size is 16.

typedef simd::VecType<float, OIIO_TEXTURE_SIMD_BATCH_WIDTH>::type OIIO::Tex::FloatWide

A type alias for a SIMD vector of floats with the batch width.

typedef simd::VecType<int, OIIO_TEXTURE_SIMD_BATCH_WIDTH>::type OIIO::Tex::IntWide

A type alias for a SIMD vector of ints with the batch width.

All of the batched calls take a run mask, which describes which subset of “lanes” should be computed by the batched lookup:

typedef uint64_t OIIO::Tex::RunMask

RunMask is defined to be an integer large enough to hold at least BatchWidth bits. The least significant bit corresponds to the first (i.e., [0]) position of all batch arrays. For each position i in the batch, the bit identified by (1 << i) controls whether that position will be computed.

enumerator RunMaskOn

The defined constant RunMaskOn contains the value with all bits 0..BatchWidth-1 set to 1.

Batched Options

TextureOptBatch is a structure that holds the options for doing an entire batch of lookups from the same texture at once. The members of TextureOptBatch correspond to the similarly named members of the single-point TextureOpt, so we refer you to Section TextureOpt for detailed explanations, and this section will only explain the differences between batched and single-point options.

int firstchannel
int subimage
ustring subimagename
Tex::Wrap swrap, twrap, rwrap
Tex::MipMode mipmode
Tex::InterpMode interpmode
int anisotropic
bool conservative_filter
float fill
const float *missingcolor

These fields are all scalars — a single value for each TextureOptBatch — which means that the value of these options must be the same for every texture sample point within a batch. If you have a number of texture lookups to perform for the same texture, but they have (for example) differing wrap modes or subimages from point to point, then you must split them into separate batch calls.

float sblur[Tex::BatchWidth]
float tblur[Tex::BatchWidth]
float rblur[Tex::BatchWidth]

These arrays hold the s, and t blur amounts, for each sample in the batch, respectively. (And the r blur amount, used only for volumetric texture3d() lookups.)

float swidth[Tex::BatchWidth]
float twidth[Tex::BatchWidth]
float rwidth[Tex::BatchWidth]

These arrays hold the s, and t filtering width multiplier for derivatives, for each sample in the batch, respectively. (And the r multiplier, used only for volumetric texture3d() lookups.)

Batched Texture Lookup Calls

bool TextureSystem::texture(ustring filename, TextureOptBatch &options, Tex::RunMask mask, const float *s, const float *t, const float *dsdx, const float *dtdx, const float *dsdy, const float *dtdy, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr)
bool TextureSystem::texture(TextureHandle *texture_handle, Perthread *thread_info, TextureOptBatch &options, Tex::RunMask mask, const float *s, const float *t, const float *dsdx, const float *dtdx, const float *dsdy, const float *dtdy, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr)

Perform filtered 2D texture lookups on a batch of positions from the same texture, all at once. The parameters s, t, dsdx, dtdx, and dsdy, dtdy are each a pointer to [BatchWidth] values. The mask determines which of those array elements to actually compute.

The various results are arranged as arrays that behave as if they were declared:

float result[channels][BatchWidth]

In other words, all the batch values for channel 0 are adjacent, followed by all the batch values for channel 1, etc. (This is “SOA” order.)

This function returns true upon success, or false if the file was not found or could not be opened by any available ImageIO plugin.

bool texture3d(ustring filename, TextureOptBatch &options, Tex::RunMask mask, const float *P, const float *dPdx, const float *dPdy, const float *dPdz, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr, float *dresultdr = nullptr)
bool texture3d(TextureHandle *texture_handle, Perthread *thread_info, TextureOptBatch &options, Tex::RunMask mask, const float *P, const float *dPdx, const float *dPdy, const float *dPdz, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr, float *dresultdr = nullptr)

Perform filtered 3D volumetric texture lookups on a batch of positions from the same texture, all at once. The “point-like” parameters P, dPdx, dPdy, and dPdz are each a pointers to arrays of float value[3][BatchWidth]. That is, each one points to all the x values for the batch, immediately followed by all the y values, followed by the z values.

The various results arrays are also arranged as arrays that behave as if they were declared float result[channels][BatchWidth], where all the batch values for channel 0 are adjacent, followed by all the batch values for channel 1, etc.

This function returns true upon success, or false if the file was not found or could not be opened by any available ImageIO plugin.

bool environment(ustring filename, TextureOptBatch &options, Tex::RunMask mask, const float *R, const float *dRdx, const float *dRdy, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr)
bool environment(TextureHandle *texture_handle, Perthread *thread_info, TextureOptBatch &options, Tex::RunMask mask, const float *R, const float *dRdx, const float *dRdy, int nchannels, float *result, float *dresultds = nullptr, float *dresultdt = nullptr)

Perform filtered directional environment map lookups on a batch of positions from the same texture, all at once. The “point-like” parameters R, dRdx, and dRdy are each a pointers to arrays of float value[3][BatchWidth]. That is, each one points to all the x values for the batch, immediately followed by all the y values, followed by the z values.

Perform filtered directional environment map lookups on a collection of directions all at once, which may be much more efficient than repeatedly calling the single-point version of environment(). The parameters R, dRdx, and dRdy are now VaryingRef’s that may refer to either a single or an array of values, as are many the fields in the options.

The various results arrays are also arranged as arrays that behave as if they were declared float result[channels][BatchWidth], where all the batch values for channel 0 are adjacent, followed by all the batch values for channel 1, etc.

This function returns true upon success, or false if the file was not found or could not be opened by any available ImageIO plugin.

UDIM and texture atlases

Texture lookups

The texture() call supports virtual filenames that expand per lookup for UDIM and other tiled texture atlas techniques. The substitutions will occur if the texture filename initially passed to texture() does not exist as a concrete file and contains one or more of the following substrings:

<UDIM>

1001 + utile + vtile*10

<u>

utile

<v>

vtile

<U>

utile + 1

<V>

vtile + 1

where the tile numbers are derived from the input u,v texture coordinates as follows:

// Each unit square of texture is a different tile
utile = max (0, int(u));
vtile = max (0, int(v));
// Re-adjust the texture coordinates to the offsets within the tile
u = u - utile;
v = v - vtile;

Example:

ustring filename ("paint.<UDIM>.tif");
float s = 1.4, t = 3.8;
texsys->texture (filename, s, t, ...);

will retrieve from file paint.1032.tif at coordinates (0.4,0.8).

Retrieving metadata

Calls to get_texture_info() on UDIM files will retrieve the metadata of the first file it finds matching the name template. The call will fail (return nullptr and not retrieve data) if no concrete texture file can be found that matches the udim naming template.

Handles of udim files

Calls to get_texture_handle() will always succeed. Withing knowing a specific u and v, it has no way to know that the concrete file you will eventually ask for would not succeed.