Performance Tuning for Large Textures in ArmorPaint: 6 Optimization Strategies
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 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, 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 (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 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 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 (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 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:
/* 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:
/* 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.cautomatically reduce undo history when textures exceed 8K to conserve memory. - Render-target pooling via
util_uv.creuses GPU resources unless the resolution changes, preventing fragmentation. - Format selection using
GPU_TEXTURE_FORMAT_R8instead of RGBA32 reduces single-channel texture memory by 75%. - Down-sampled previews in
util_render_layer_preview_sizekeep the UI responsive by avoiding full-size texture reads. - Fast path-tracing mode in
config.creduces per-pixel samples for high-resolution canvases. - Conditional allocation ensures expensive
RGBA128formats 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 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, 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, 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.
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 →