ImageCache vs TextureSystem: Understanding the Distinction for Texture Access in OpenImageIO
ImageCache provides low-level, raw pixel access to image files while TextureSystem adds high-level texture semantics including UV coordinates, filtering, and mip-mapping on top of an underlying ImageCache.
OpenImageIO (OIIO) offers two distinct APIs in the AcademySoftwareFoundation/openimageio repository for accessing image data. Understanding the distinction between ImageCache and TextureSystem for accessing textures is critical for selecting the right approach for rendering pipelines versus raw image processing tools.
What Is ImageCache?
ImageCache (OIIO::ImageCache) serves as the low-level caching layer that opens image files, reads individual tiles or scanlines, and stores decoded pixels in memory. According to the source code in src/include/OpenImageIO/imagecache.h, this class provides a thread-safe API oriented around files and pixel regions, with no concept of texture coordinates, wrap modes, or filtering.
The cache manages file handles, memory limits, and deduplication automatically. Key methods include get_pixels() for reading arbitrary pixel regions and get_tile() for direct tile access, both implemented in src/libtexture/imagecache.cpp.
#include <OpenImageIO/imagecache.h>
using namespace OIIO;
// Create a shared ImageCache instance
std::shared_ptr<ImageCache> ic = ImageCache::create();
// Read raw pixels from a specific region of interest
ROI roi = get_roi_full(); // selects the whole image
std::vector<float> pixels(roi.width() * roi.height() * roi.nchannels());
bool ok = ic->get_pixels("myimage.exr", 0, 0, // filename, subimage, miplevel
roi, TypeFloat,
make_span(pixels));
This API is ideal for utilities like maketx or oiiotool that require direct pixel manipulation without texture sampling semantics.
What Is TextureSystem?
TextureSystem (OIIO::TextureSystem) builds upon an ImageCache to provide high-level texture look-up capabilities. As defined in src/include/OpenImageIO/texture.h and implemented in src/libtexture/texturesys.cpp, it adds UV/UVW coordinate look-ups, wrap mode handling, automatic mip-level selection, anisotropic filtering, and derivative-based antialiasing.
Internally, TextureSystemImpl (declared in src/libtexture/texture_pvt.h) maintains a shared pointer to an ImageCache instance (m_imagecache_sp) and delegates all file I/O to it while applying the texture sampling pipeline.
#include <OpenImageIO/texture.h>
using namespace OIIO;
// Create a TextureSystem (internally creates a shared ImageCache)
std::shared_ptr<TextureSystem> ts = TextureSystem::create();
// Configure texture sampling options
TextureOpt opt;
opt.mipmap = TextureOpt::MipModeTrilinear;
opt.wrap = TextureOpt::WrapClamp;
opt.anisotropic = 16;
// Sample at normalized UV coordinates (0.33, 0.77)
float result[4];
bool ok = ts->texture("mytexture.tx", opt,
0.33f, 0.77f, // s, t
0.0f, 0.0f, // dsdx, dtdx (derivatives)
0.0f, 0.0f, // dsdy, dtdy (derivatives)
4, result); // nchannels, output
Key Architectural Differences
Coordinate System
- ImageCache: Uses integer pixel indices and Regions of Interest (ROI) to access data.
- TextureSystem: Uses normalized floating-point UV/UVW coordinates (ranging from 0.0 to 1.0) with derivative vectors for filtering calculations.
Feature Set
- ImageCache: Provides autotiling, file-handle limits, memory management, and deduplication. It exposes methods like
get_tile()andget_image_info()fromsrc/include/OpenImageIO/imagecache.h. - TextureSystem: Adds wrap modes (clamp, periodic, mirror), trilinear and anisotropic filtering, environment map look-ups (
environment()method), and 3D volume texture support (texture3d()insrc/libtexture/texture3d.cpp).
Memory Management
- ImageCache: Can be created as a standalone instance via
ImageCache::create(bool shared=true)or shared globally. - TextureSystem: Typically constructed via
TextureSystem::create(bool shared, std::shared_ptr<ImageCache> ic), allowing it to use either the global shared cache or a dedicated private cache for isolated memory management.
When to Use Each API
Use ImageCache directly when building image processing utilities that need raw pixel data without filtering. This includes format conversion tools, metadata inspectors, or batch processors that operate on pixel arrays rather than texture samples.
Use TextureSystem when implementing renderers, shading engines, or any application requiring filtered texture sampling. The system handles complex filtering automatically based on screen-space derivatives, producing antialiased results that raw pixel access cannot provide.
You can mix both approaches by creating a private ImageCache and explicitly passing it to a TextureSystem:
// Create a private ImageCache (shared=false)
auto ic = ImageCache::create(false);
// Create a TextureSystem using that specific cache
auto tex = TextureSystem::create(false, ic);
This pattern provides complete isolation of cache memory between different processing contexts.
Summary
- ImageCache manages raw image file I/O, tile caching, and pixel buffers in
src/libtexture/imagecache.cpp, exposing a file-centric API. - TextureSystem in
src/libtexture/texturesys.cppprovides filtered texture look-ups using UV coordinates and sits atop an internal ImageCache instance (m_imagecache_sp). - ImageCache understands pixels and ROIs; TextureSystem understands texture coordinates, mip-mapping, and filtering.
- Rendering code should typically use TextureSystem exclusively, while low-level image utilities should use ImageCache directly.
Frequently Asked Questions
Can TextureSystem function without an ImageCache?
No. According to the implementation in src/libtexture/texture_pvt.h, the TextureSystemImpl class contains a member std::shared_ptr<ImageCache> m_imagecache_sp that provides all underlying file I/O. When you call TextureSystem::create(), it either uses a shared global cache or creates a new one internally, but the architectural dependency is mandatory.
Which API should I use for rendering applications?
Use TextureSystem. It provides the derivative-based filtering, mip-map selection, and wrap-mode handling required for high-quality texture sampling in renderers. The texture() method signature includes dsdx, dtdx, dsdy, and dtdy parameters specifically for antialiasing calculations based on screen-space derivatives.
How do I control memory limits when using both systems?
Configure memory limits on the underlying ImageCache using methods like attribute("max_memory_MB", value) from src/include/OpenImageIO/imagecache.h. If using a shared cache, these limits apply globally. If using a private cache passed to TextureSystem::create(false, ic), the limits apply only to that isolated instance.
Does ImageCache support all the file formats that TextureSystem supports?
Yes. Both APIs leverage the same image format plugins and I/O machinery. TextureSystem simply adds a processing layer on top of the raw data provided by ImageCache. Any file format readable by ImageCache::get_pixels() in src/libtexture/imagecache.cpp is automatically available for texture sampling through TextureSystem::texture().
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →