# How maketx Generates Efficient MIP-Mapped Textures for Renderers

> Discover how maketx generates efficient MIP-mapped textures for renderers using parallel filtering, smart memory, and atomic file writes. Learn about OpenImageIO's ImageBufAlgo::make_texture function.

- Repository: [Academy Software Foundation/openimageio](https://github.com/academysoftwarefoundation/openimageio)
- Tags: how-to-guide
- Published: 2026-02-23

---

**The maketx tool generates efficient MIP-mapped textures by converting source images into tiled, multi-resolution pyramid files using parallelized filtering, intelligent memory management, and atomic file writes, all orchestrated through the `ImageBufAlgo::make_texture` function in OpenImageIO.**

The maketx command-line utility is the standard tool in the OpenImageIO (OIIO) ecosystem for preparing production-ready texture assets. It transforms arbitrary image formats into the `.tx` format—tiled, MIP-mapped textures optimized for renderer consumption. At its core, the tool delegates all texture generation logic to `ImageBufAlgo::make_texture`, implemented in [`src/libOpenImageIO/maketexture.cpp`](https://github.com/academysoftwarefoundation/openimageio/blob/main/src/libOpenImageIO/maketexture.cpp).

## Architecture of the maketx Pipeline

### Command-Line Interface and Configuration

The entry point resides in [`src/maketx/maketx.cpp`](https://github.com/academysoftwarefoundation/openimageio/blob/main/src/maketx/maketx.cpp), where the `getargs` function parses command-line flags into an `ImageSpec` object. This specification carries critical parameters including tile dimensions, filter kernels, sharpening values, and threading counts.

### Core Texture Generation Engine

The actual processing happens in `ImageBufAlgo::make_texture` within [`src/libOpenImageIO/maketexture.cpp`](https://github.com/academysoftwarefoundation/openimageio/blob/main/src/libOpenImageIO/maketexture.cpp). This function implements an eight-stage pipeline that handles everything from memory allocation to final file output.

## The MIP-Map Generation Process

### Input Reading and Memory Strategy

When processing begins, maketx creates an `ImageBuf` from the source. If the image is smaller than the **1 GB read-local threshold**, it loads entirely into RAM; otherwise, it streams data on demand via `ImageCache`. This logic appears in [`maketexture.cpp`](https://github.com/academysoftwarefoundation/openimageio/blob/main/maketexture.cpp) around lines 37-41, allowing the tool to handle both small assets and massive production plates without exhausting system memory.

### Preprocessing Optimizations

Before MIP generation, the tool applies several data-reduction strategies to minimize final file size. These include light-probe conversion, bump-map to slope-map transformation, Gaussian CDF table generation, constant-color detection, alpha-channel dropping, and channel renaming. These steps, located in the pre-process block of [`maketexture.cpp`](https://github.com/academysoftwarefoundation/openimageio/blob/main/maketexture.cpp) (lines 58-124), can dramatically reduce data volume before the computationally expensive filtering operations begin.

### Tiled Layout and MIP Chain Construction

The output `ImageSpec` is forced to a **tiled layout** with default dimensions of 64×64 pixels, though users can specify alternatives via `--tile`. Tiling is mandatory for efficient random-access sampling by renderers. The MIP chain is constructed by repeatedly down-sampling each level using the selected filter—options include **box**, **lanczos**, **mitchell**, and others—with optional sharpening (`--sharpen`) applied during reduction to preserve detail.

### Parallel Execution

All computationally intensive loops leverage `OIIO::parallel_image` and `ImageBufAlgo::parallel_image`, respecting the user-specified thread count via `-t` or `--threads`. This parallel dispatch, visible in [`maketexture.cpp`](https://github.com/academysoftwarefoundation/openimageio/blob/main/maketexture.cpp) around lines 124-132, ensures multi-core CPUs are fully utilized during filtering, statistical analysis, and histogram generation.

### Atomic File Output

To prevent renderers from encountering partially-written textures, maketx writes to a uniquely-named **temporary file** in the target directory. Only upon successful completion does it rename the file to the final `.tx` extension. This safety mechanism appears in [`maketexture.cpp`](https://github.com/academysoftwarefoundation/openimageio/blob/main/maketexture.cpp) lines 56-63, ensuring that a renderer never reads a corrupted texture missing MIP levels.

### Metadata Embedding

The final output includes comprehensive metadata: all processing options, the original command line (stored in the `Software` attribute), and any generated lookup tables such as Gaussian CDF data. Renderers retrieve these attributes for correct texture reconstruction and to verify processing parameters.

## Practical Usage Examples

### Command-Line Usage

The most common workflow uses the `maketx` binary with explicit control over threading, tile size, and filter quality:

```bash

# Generate a tiled, MIP-mapped texture with 128-pixel tiles,

# Lanczos filtering, sharpening, and 8 threads

maketx -t 8 --tile 128 128 --filter lanczos3 \
       --sharpen 0.5 -v input.exr -o output.tx

```

* `-t 8` utilizes eight threads for parallel processing.
* `--tile 128 128` increases tile dimensions for better cache locality in specific renderers.
* `--filter lanczos3` selects a higher-quality reconstruction filter for the MIP chain.

### C++ API Integration

For pipeline integration, invoke the same functionality programmatically via `ImageBufAlgo::make_texture`:

```cpp
#include <OpenImageIO/imagebufalgo.h>
using namespace OIIO;

// Configure texture generation parameters
ImageSpec config;
config.attribute("maketx:threads", 8);
config.attribute("maketx:tile_width", 128);
config.attribute("maketx:tile_height", 128);
config.attribute("maketx:filtername", "lanczos3");
config.attribute("maketx:sharpen", 0.5f);

// Execute texture creation
bool ok = ImageBufAlgo::make_texture(
            ImageBufAlgo::MakeTxTexture,  // Standard texture mode
            "input.exr",                  // Source image path
            "output.tx",                  // Destination path
            config,                       // Configuration spec
            &std::cout);                  // Optional progress output

```

The `maketx:*` attributes mirror the command-line flags, allowing complete control over the MIP-generation pipeline from within custom applications.

## Summary

- **maketx** converts arbitrary images into tiled, MIP-mapped textures via `ImageBufAlgo::make_texture` in [`src/libOpenImageIO/maketexture.cpp`](https://github.com/academysoftwarefoundation/openimageio/blob/main/src/libOpenImageIO/maketexture.cpp).
- The tool employs intelligent memory management using a **1 GB threshold** to choose between full RAM loading and streaming via `ImageCache`.
- **Parallel filtering** using `OIIO::parallel_image` maximizes CPU utilization during MIP generation.
- **Atomic file writes** (temporary file then rename) ensure renderers never encounter partially written textures.
- Default **64×64 tiling** and configurable filters (**box**, **lanczos**, **mitchell**) optimize for renderer random-access patterns.

## Frequently Asked Questions

### What is the default tile size for maketx textures?

The default tile size is **64×64 pixels**, which provides an optimal balance between I/O efficiency and memory locality for most renderers. You can override this using the `--tile` flag or the `maketx:tile_width` and `maketx:tile_height` attributes when using the C++ API. Larger tiles (e.g., 128×128) may improve cache performance for specific rendering engines.

### Which filters does maketx support for MIP-map generation?

maketx supports multiple reconstruction filters for down-sampling, including **box**, **lanczos**, **mitchell**, **triangle**, and **catmull-rom**. The default filter is **box** for maximum speed, but **lanczos** or **mitchell** provide higher quality for production assets. You can specify the filter using `--filter` or `maketx:filtername`, and apply sharpening with `--sharpen` to preserve detail during reduction.

### How does maketx handle large images that exceed available RAM?

When processing images larger than the **1 GB read-local threshold**, maketx switches from loading the entire image into RAM to streaming data on demand via the `ImageCache` subsystem. This threshold check occurs in [`src/libOpenImageIO/maketexture.cpp`](https://github.com/academysoftwarefoundation/openimageio/blob/main/src/libOpenImageIO/maketexture.cpp) (lines 37-41). This streaming approach allows maketx to process arbitrarily large production plates without exhausting system memory, though it may trade some speed for memory efficiency.

### Why does maketx write to a temporary file before renaming?

To prevent renderers from reading corrupted or incomplete textures, maketx implements an **atomic write strategy**. It first writes the entire texture—including all MIP levels and metadata—to a uniquely-named temporary file in the destination directory. Only after the write completes successfully does it rename the file to the final `.tx` extension. This logic in [`src/libOpenImageIO/maketexture.cpp`](https://github.com/academysoftwarefoundation/openimageio/blob/main/src/libOpenImageIO/maketexture.cpp) (lines 56-63) ensures that a renderer never encounters a partially written MIP level, which could cause crashes or rendering artifacts.