# Performance Tuning for Large Textures in ArmorPaint: 6 Optimization Strategies

> Optimize large 8K+ textures in ArmorPaint with 6 strategies. Learn how dynamic resolution, render-target pooling, and format selection prevent VRAM exhaustion and GPU stalls.

- Repository: [Armory 3D/armorpaint](https://github.com/armory3d/armorpaint)
- Tags: performance
- Published: 2026-09-11

---

**ArmorPaint uses dynamic resolution caps, render-target pooling, and format selection to prevent 8K+ textures from exhausting VRAM or causing GPU stalls.**

ArmorPaint (armory3d/armorpaint) stores every paint layer and auxiliary map as GPU textures sized by the global texture resolution setting. When working with 8K×8K textures or higher, memory footprint and GPU operations increase exponentially, causing VRAM pressure and frame rate drops. Understanding the engine's built-in optimization mechanisms—implemented across [`paint/sources/config.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/config.c) and the utility layers—allows you to maintain responsive performance without sacrificing visual quality.

## 1. Dynamic Resolution Caps for Memory Management

When texture dimensions exceed 8192×8192, ArmorPaint automatically reduces auxiliary memory allocations to prevent overflow. In [`paint/sources/util/util_layer.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/util/util_layer.c), the engine checks `config_get_texture_res_x() >= 8192` at lines 71-73 to conditionally limit the number of undo steps stored for layer history. This ensures that high-resolution painting remains responsive by trading history depth for memory headroom rather than compromising the active canvas resolution.

## 2. Render-Target Pooling and Reuse

Instead of recreating GPU resources for every operation, ArmorPaint reuses pooled render targets and only reallocates when the resolution changes. The UV-map utilities in [`paint/sources/util/util_uv.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/util/util_uv.c) (lines 8-10) demonstrate this pattern: functions like `util_uv_uvmap` and `util_uv_trianglemap` compare the current target dimensions against `config_get_texture_res_x()` and `config_get_texture_res_y()` before calling `gpu_create_render_target`. This prevents costly GPU memory fragmentation during iterative texture operations.

## 3. Lightweight Texture Formats for Single-Channel Data

High-resolution textures that require only a single channel are allocated with `GPU_TEXTURE_FORMAT_R8` (1 byte per pixel) instead of the standard RGBA32 (4 bytes per pixel). According to [`paint/sources/util/util_layer.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/util/util_layer.c) at lines 94-102, temporary masks and blend layers use this lightweight format to cut memory usage by 75% when full color data is unnecessary. This optimization is critical when stacking multiple 8K auxiliary layers that would otherwise consume gigabytes of VRAM.

## 4. Down-Sampled Previews for UI Efficiency

The renderer generates lower-resolution previews for UI panels to avoid reading full-size textures when not necessary. As implemented in [`paint/sources/util/util_layer.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/util/util_layer.c) at lines 1292-1294, the `util_render_layer_preview_size` function creates reduced-size thumbnails for layer previews and brush stamps. This prevents the interface from stalling when the underlying texture data exceeds 8K resolution.

## 5. Path-Tracing Optimization Modes

When ray-tracing is enabled, ArmorPaint can switch to a "fast" mode that reduces samples per pixel—an essential optimization for large textures where each sample operation is computationally expensive. The configuration logic in [`paint/sources/config.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/config.c) (lines 98-104) selects `PATHTRACE_MODE_FAST` by default when working at high resolutions, significantly lowering per-pixel work without disabling the feature entirely.

## 6. Conditional Format Allocation in Sculpting

The sculpting pipeline creates `RGBA128` textures (16 bytes per pixel) only when the user works at maximum resolution; otherwise, it falls back to lighter formats. This conditional allocation, found in [`paint/sources/util/util_layer.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/util/util_layer.c) at lines 122-132, prevents the sculpting system from reserving excessive memory for intermediate displacement and normal maps unless the project specifically requires 16-bit-per-channel precision at 8K+ scales.

## Implementing Performance Optimizations in Code

To manually leverage these mechanisms in custom plugins or scripts, check the global resolution before allocating resources and select appropriate formats:

```c
/* Example: Reduce memory usage for a custom plugin that only needs a greyscale mask */
gpu_texture_t *mask = NULL;
if (!mask || mask->width != config_get_texture_res_x() ||
            mask->height != config_get_texture_res_y()) {
    if (mask) gpu_delete_texture(mask);
    // Use the 1-byte format instead of full RGBA
    mask = gpu_create_render_target(config_get_texture_res_x(),
                                    config_get_texture_res_y(),
                                    GPU_TEXTURE_FORMAT_R8);
}

```

For path-tracing workloads, explicitly enable fast mode when detecting large textures:

```c
/* Example: Switch to fast ray-trace mode for large textures */
if (config_get_texture_res_x() >= 8192) {
    g_config->pathtrace_mode = PATHTRACE_MODE_FAST;
    config_apply_raytrace_multi();   // Re-apply the setting
}

```

## Summary

- **Dynamic caps** in [`util_layer.c`](https://github.com/armory3d/armorpaint/blob/main/util_layer.c) automatically reduce undo history when textures exceed 8K to conserve memory.
- **Render-target pooling** via [`util_uv.c`](https://github.com/armory3d/armorpaint/blob/main/util_uv.c) reuses GPU resources unless the resolution changes, preventing fragmentation.
- **Format selection** using `GPU_TEXTURE_FORMAT_R8` instead of RGBA32 reduces single-channel texture memory by 75%.
- **Down-sampled previews** in `util_render_layer_preview_size` keep the UI responsive by avoiding full-size texture reads.
- **Fast path-tracing mode** in [`config.c`](https://github.com/armory3d/armorpaint/blob/main/config.c) reduces per-pixel samples for high-resolution canvases.
- **Conditional allocation** ensures expensive `RGBA128` formats are only used when necessary.

## Frequently Asked Questions

### What is the maximum texture size supported by ArmorPaint?

ArmorPaint supports 8K×8K textures and higher, though performance tuning becomes essential at these resolutions. The engine uses conditional checks against `config_get_texture_res_x()` to trigger memory-saving optimizations when dimensions exceed 8192 pixels.

### How does render-target pooling reduce VRAM usage?

Rather than allocating new GPU memory for every brush stroke or UV operation, functions like `util_uv_uvmap` in [`paint/sources/util/util_uv.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/util/util_uv.c) retain existing render targets and only call `gpu_create_render_target` when the configuration resolution changes. This eliminates allocation overhead and prevents memory fragmentation during intensive painting sessions.

### When should I use the fast path-tracing mode?

Enable fast mode when working with textures at or above 8K resolution or when VRAM is constrained. According to [`paint/sources/config.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/config.c), this mode reduces samples per pixel via `PATHTRACE_MODE_FAST`, making ray-traced bakes feasible on large textures that would otherwise cause GPU timeouts.

### Which file contains the global texture resolution settings?

The central configuration API resides in [`paint/sources/config.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/config.c), which exposes `config_get_texture_res_x()`, `config_get_texture_res_y()`, and `config_set_texture_res()`. These functions drive all resolution-dependent optimizations throughout the codebase, from layer management to render-target allocation.