Skip to content

Commit

Permalink
api: TextureOpt refactor (#4485)
Browse files Browse the repository at this point in the history
* Version the class for easier future expansion! Let's call it
`TextureOpt_v2` and we make a `using` alias so that the name
`TextureOpt` means this. We can then revise the struct in the future by
not losing link compatibility.

* The macro OIIO_TEXTUREOPT_VERSION (now 2) can be used to test which is
the current version.

* Get rid of TextureOpt-local enums by finally switching to the
freestanding ones in the Tex namespace. (We've wanted to do this for a
long time, but couldn't break compatibility.) Preserve API compatibility
for now with clever use of `static constexpr` and `using`.

* Make more efficient use of space in the TextureOpt by: field order
rearrangement to eliminate empty space, switching a couple of the enums
that needed only a few values to be `class enum xxx : uint8_t` so they
take only 1 byte instead of 4, switch `anisotropic` to be 16 bits (do we
really need an anisotropic ratio > 65535?), elimiate the time and
samples fields which have never been used (they were reserved for shadow
maps, which we never implemented).

I think this set of changes is minimally onerous to downstream projects
for the 3.0 release, while laying a path forward (via the versioning) to
allow future changes to the struct to happen with a lower pain
threshold.

I don't claim that this perfectly preserves downstream source
compatibility, but the fact that outside of these changes to
delcarations in texture.h, only 8 lines in the entire rest of the OIIO
codebase needed to change to accommodate them. So I think that the
impact downstream will be minimal. (OSL might be the exception, since
its LLVM code generation is exquisitely sensitive to the exact layout of
the TextureOpt struct, but I'm working on those changes, too.)

---------

Signed-off-by: Larry Gritz <[email protected]>
  • Loading branch information
lgritz authored Oct 12, 2024
1 parent bb4f20a commit 5b962b6
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 115 deletions.
51 changes: 23 additions & 28 deletions src/doc/texturesys.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,28 +81,28 @@ structure:
This will be ignored if the file does not have multiple subimages or
separate per-face textures.

- `Wrap swrap, twrap` :
- `Tex::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.
- `Wrap::Black` : The texture is black outside the [0,1] range.

- `WrapClamp` : The texture coordinates will be clamped to [0,1], i.e.,
- `Wrap::Clamp` : 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
- `Wrap::Periodic` : 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.,
- `Wrap::Mirror` : 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
- `Wrap::Default` : 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`
Expand Down Expand Up @@ -140,50 +140,45 @@ structure:
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` :
- `Tex::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.

- `MipMode mipmode` :
Determines if/how MIP-maps are used:
- `Tex::MipMode mipmode` :
Determines if/how MIP-maps are used. The enum value are:

- `MipModeDefault` : The default high-quality lookup (same as Aniso).
- `MipMode::Default` : The default high-quality lookup (same as Aniso).

- `MipModeNoMIP` : Just use highest-res image, no MIP mapping
- `MipMode::NoMIP` : Just use highest-res image, no MIP mapping

- `MipModeOneLevel` : Use just one mipmap level
- `MipMode::OneLevel` : Use just one mipmap level

- `MipModeTrilinear` : Use two MIPmap levels (trilinear)
- `MipMode::Trilinear` : Use two MIPmap levels (trilinear)

- `MipModeAniso` : Use two MIPmap levels w/ anisotropic
- `MipMode::Aniso` : Use two MIPmap levels w/ anisotropic

- `InterpMode interpmode` :
- `Tex::InterpMode interpmode` :
Determines how we sample within a mipmap level:

- `InterpClosest` : Force closest texel.
- `InterpMode::Closest` : Force closest texel.

- `InterpBilinear` : Force bilinear lookup within a mip level.
- `InterpMode::Bilinear` : Force bilinear lookup within a mip level.

- `InterpBicubic` : Force cubic lookup within a mip level.
- `InterpMode::Bicubic` : Force cubic lookup within a mip level.

- `InterpSmartBicubic` : Bicubic when maxifying, else bilinear (default).
- `InterpMode::SmartBicubic` : Bicubic when maxifying, else bilinear (default).

- `int anisotropic` :
- `uint16_t anisotropic` :
Maximum anisotropic ratio (default: 32).

- `bool conservative_filter` :
When true (the default), filters conservatively in a way that chooses to
sometimes over-blur rather than alias.

- `int colortransformid` :
If non-zero, specifies a color transformation to apply to the texels, a
handle to a transform retrerieved `TextureSystem::get_colortransform_id()`.



Expand Down
10 changes: 5 additions & 5 deletions src/include/OpenImageIO/imagecache.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
OIIO_NAMESPACE_BEGIN

// Forward declarations
class TextureOpt;
class TextureOpt_v2;

class ImageCachePerThreadInfo;
class ImageCacheFile;
Expand Down Expand Up @@ -520,13 +520,13 @@ class OIIO_API ImageCache {
/// or for alternate IC implementations.) The opaque pointer `thread_info`
/// is thread-specific information returned by `get_perthread_info()`.
ImageHandle* get_image_handle(ustring filename,
Perthread* thread_info = nullptr,
const TextureOpt* options = nullptr);
Perthread* thread_info = nullptr,
const TextureOpt_v2* options = nullptr);

/// Get an ImageHandle using a UTF-16 encoded wstring filename.
ImageHandle* get_image_handle(const std::wstring& filename,
Perthread* thread_info = nullptr,
const TextureOpt* options = nullptr)
Perthread* thread_info = nullptr,
const TextureOpt_v2* options = nullptr)
{
return get_image_handle(ustring(Strutil::utf16_to_utf8(filename)),
thread_info, options);
Expand Down
139 changes: 61 additions & 78 deletions src/include/OpenImageIO/texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
// Does TextureSystem::create() return a shared pointer?
#define OIIO_TEXTURESYSTEM_CREATE_SHARED 1

// Revision of the TextureOpt class
#define OIIO_TEXTUREOPT_VERSION 2


#ifndef INCLUDED_IMATHVEC_H
// Placeholder declaration for Imath::V3f if no Imath headers have been
// included.
Expand Down Expand Up @@ -81,7 +85,7 @@ namespace Tex {

/// Wrap mode describes what happens when texture coordinates describe
/// a value outside the usual [0,1] range where a texture is defined.
enum class Wrap {
enum class Wrap : uint8_t {
Default, ///< Use the default found in the file
Black, ///< Black outside [0..1]
Clamp, ///< Clamp to [0..1]
Expand All @@ -107,7 +111,7 @@ OIIO_API void parse_wrapmodes (const char *wrapmodes,

/// Mip mode determines if/how we use mipmaps
///
enum class MipMode {
enum class MipMode : uint8_t {
Default, ///< Default high-quality lookup
NoMIP, ///< Just use highest-res image, no MIP mapping
OneLevel, ///< Use just one mipmap level
Expand All @@ -117,7 +121,7 @@ enum class MipMode {

/// Interp mode determines how we sample within a mipmap level
///
enum class InterpMode {
enum class InterpMode : uint8_t {
Closest, ///< Force closest texel
Bilinear, ///< Force bilinear lookup within a mip level
Bicubic, ///< Force cubic lookup within a mip level
Expand Down Expand Up @@ -187,83 +191,61 @@ class TextureOptions; // forward declaration
/// 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.
class OIIO_API TextureOpt {
///
/// Users should use `TextureOpt`, which will always be an alias to the latest
/// version of this class. But the "real name" is versioned to allow future
/// compatibility changes.
class OIIO_API TextureOpt_v2 {
public:
/// Wrap mode describes what happens when texture coordinates describe
/// a value outside the usual [0,1] range where a texture is defined.
enum Wrap {
WrapDefault, ///< Use the default found in the file
WrapBlack, ///< Black outside [0..1]
WrapClamp, ///< Clamp to [0..1]
WrapPeriodic, ///< Periodic mod 1
WrapMirror, ///< Mirror the image
WrapPeriodicPow2, // Periodic, but only for powers of 2!!!
WrapPeriodicSharedBorder, // Periodic with shared border (env)
WrapLast // Mark the end -- don't use this!
};

/// Mip mode determines if/how we use mipmaps
///
enum MipMode {
MipModeDefault, ///< Default high-quality lookup
MipModeNoMIP, ///< Just use highest-res image, no MIP mapping
MipModeOneLevel, ///< Use just one mipmap level
MipModeTrilinear, ///< Use two MIPmap levels (trilinear)
MipModeAniso, ///< Use two MIPmap levels w/ anisotropic
};

/// Interp mode determines how we sample within a mipmap level
///
enum InterpMode {
InterpClosest, ///< Force closest texel
InterpBilinear, ///< Force bilinear lookup within a mip level
InterpBicubic, ///< Force cubic lookup within a mip level
InterpSmartBicubic ///< Bicubic when magnifying, else bilinear
};
// Definitions for preserving back compatibility.
// These aliases will eventually be deprecated.
using Wrap = Tex::Wrap;
using MipMode = Tex::MipMode;
using InterpMode = Tex::InterpMode;
static constexpr Tex::Wrap WrapDefault = Tex::Wrap::Default;
static constexpr Tex::Wrap WrapBlack = Tex::Wrap::Black;
static constexpr Tex::Wrap WrapClamp = Tex::Wrap::Clamp;
static constexpr Tex::Wrap WrapPeriodic = Tex::Wrap::Periodic;
static constexpr Tex::Wrap WrapMirror = Tex::Wrap::Mirror;
static constexpr Tex::Wrap WrapPeriodicPow2 = Tex::Wrap::PeriodicPow2;
static constexpr Tex::Wrap WrapPeriodicSharedBorder = Tex::Wrap::PeriodicSharedBorder;
static constexpr Tex::Wrap WrapLast = Tex::Wrap::Last;
static constexpr Tex::MipMode MipModeDefault = MipMode::Default;
static constexpr Tex::MipMode MipModeNoMIP = MipMode::NoMIP;
static constexpr Tex::MipMode MipModeOneLevel = MipMode::OneLevel;
static constexpr Tex::MipMode MipModeTrilinear = MipMode::Trilinear;
static constexpr Tex::MipMode MipModeAniso = MipMode::Aniso;
static constexpr Tex::InterpMode InterpClosest = Tex::InterpMode::Closest;
static constexpr Tex::InterpMode InterpBilinear = Tex::InterpMode::Bilinear;
static constexpr Tex::InterpMode InterpBicubic = Tex::InterpMode::Bicubic;
static constexpr Tex::InterpMode InterpSmartBicubic = Tex::InterpMode::SmartBicubic;


/// Create a TextureOpt with all fields initialized to reasonable
/// defaults.
TextureOpt ()
: firstchannel(0), subimage(0),
swrap(WrapDefault), twrap(WrapDefault),
mipmode(MipModeDefault), interpmode(InterpSmartBicubic),
anisotropic(32), conservative_filter(true),
sblur(0.0f), tblur(0.0f), swidth(1.0f), twidth(1.0f),
fill(0.0f), missingcolor(nullptr),
time(0.0f), rnd(-1.0f), samples(1),
rwrap(WrapDefault), rblur(0.0f), rwidth(1.0f),
colortransformid(0),
envlayout(0)
{ }
OIIO_HOSTDEVICE TextureOpt_v2() { }

/// Convert a TextureOptions for one index into a TextureOpt.
///
TextureOpt(const TextureOptions& opt, int index);

int firstchannel; ///< First channel of the lookup
int subimage; ///< Subimage or face ID
ustring subimagename; ///< Subimage name
Wrap swrap; ///< Wrap mode in the s direction
Wrap twrap; ///< Wrap mode in the t direction
MipMode mipmode; ///< Mip mode
InterpMode interpmode; ///< Interpolation mode
int anisotropic; ///< Maximum anisotropic ratio
bool conservative_filter; ///< True == over-blur rather than alias
float sblur, tblur; ///< Blur amount
float swidth, twidth; ///< Multiplier for derivatives
float fill; ///< Fill value for missing channels
const float* missingcolor; ///< Color for missing texture
float time; ///< Time (for time-dependent texture lookups)
float rnd; ///< Stratified sample value
int samples; ///< Number of samples for shadows

// For 3D volume texture lookups only:
Wrap rwrap; ///< Wrap mode in the r direction
float rblur; ///< Blur amount in the r direction
float rwidth; ///< Multiplier for derivatives in r direction

int colortransformid; ///< Color space id of the texture
TextureOpt_v2(const TextureOptions& opt, int index);

int firstchannel = 0; ///< First channel of the lookup
int subimage = 0; ///< Subimage or face ID
ustring subimagename; ///< Subimage name
Wrap swrap = Wrap::Default; ///< Wrap mode in the s direction
Wrap twrap = Wrap::Default; ///< Wrap mode in the t direction
Wrap rwrap = Wrap::Default; ///< Wrap mode in the r direction (volume)
MipMode mipmode = MipMode::Default; ///< Mip mode
InterpMode interpmode = InterpMode::SmartBicubic; ///< Interpolation mode
bool conservative_filter = true; ///< True == over-blur rather than alias
uint16_t anisotropic = 32; ///< Maximum anisotropic ratio
float sblur = 0, tblur = 0, rblur = 0; ///< Blur amount
float swidth = 1, twidth = 1; ///< Multiplier for derivatives
float rwidth = 1; ///< Multiplier for derivs in r direction
float fill = 0; ///< Fill value for missing channels
const float* missingcolor = nullptr; ///< Color for missing texture
float rnd = -1; ///< Stratified sample value
int colortransformid = 0; ///< Color space id of the texture

/// Utility: Return the Wrap enum corresponding to a wrap name:
/// "default", "black", "clamp", "periodic", "mirror".
Expand All @@ -283,22 +265,23 @@ class OIIO_API TextureOpt {
/// Utility: Parse a single wrap mode (e.g., "periodic") or a
/// comma-separated wrap modes string (e.g., "black,clamp") into
/// separate Wrap enums for s and t.
static void parse_wrapmodes(const char* wrapmodes,
TextureOpt::Wrap& swrapcode,
TextureOpt::Wrap& twrapcode)
static void parse_wrapmodes(const char* wrapmodes, Wrap& swrapcode,
Wrap& twrapcode)
{
Tex::parse_wrapmodes(wrapmodes, *(Tex::Wrap*)&swrapcode,
*(Tex::Wrap*)&twrapcode);
Tex::parse_wrapmodes(wrapmodes, swrapcode, twrapcode);
}

private:
// Options set INTERNALLY by libtexture after the options are passed
// by the user. Users should not attempt to alter these!
int envlayout; // Layout for environment wrap
int envlayout = 0; // Layout for environment wrap
friend class TextureSystemImpl;
};


using TextureOpt = TextureOpt_v2;



/// Texture options for a batch of Tex::BatchWidth points and run mask.
class OIIO_API TextureOptBatch {
Expand Down
2 changes: 0 additions & 2 deletions src/python/py_texturesys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,7 @@ declare_textureopt(py::module& m)
.def_readwrite("fill", &TextureOptWrap::fill)
.def_property("missingcolor", &TextureOptWrap::get_missingcolor,
&TextureOptWrap::set_missingcolor)
.def_readwrite("time", &TextureOptWrap::time)
.def_readwrite("rnd", &TextureOptWrap::rnd)
.def_readwrite("samples", &TextureOptWrap::samples)
.def_property(
"rwrap",
[](const TextureOptWrap& texopt) { return (Tex::Wrap)texopt.rwrap; },
Expand Down
4 changes: 2 additions & 2 deletions src/testtex/testtex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ static bool use_handle = false;
static bool use_bluenoise = false;
static float cachesize = -1;
static int maxfiles = -1;
static int mipmode = TextureOpt::MipModeDefault;
static int interpmode = TextureOpt::InterpSmartBicubic;
static int mipmode = int(TextureOpt::MipModeDefault);
static int interpmode = int(TextureOpt::InterpSmartBicubic);
static int stochastic = 0;
static float missing[4] = { -1, 0, 0, 1 };
static float fill = -1; // -1 signifies unset
Expand Down

0 comments on commit 5b962b6

Please sign in to comment.