ImageEngine: Clamp image data to fit half float range.

When image data exceeds half float ranges values are set to +/-
infinity that could lead to artifacts later on in the pipeline.
Color management for example.

This patch adds a utility function `IMB_gpu_clamp_half_float`
that clamps full float values to fit within the range of
half floats.

This fixes T98575 and T101601.
This commit is contained in:
Jeroen Bakker 2022-10-12 08:47:12 +02:00 committed by Philipp Oeser
parent f9c6e0c814
commit 0386737097
Notes: blender-bot 2023-02-13 15:17:42 +01:00
Referenced by issue #100749, Blender LTS: Maintenance Task 3.3
Referenced by issue #101601, Regression: Cryptomatte doesn't show all objects available
Referenced by issue #98575, Issues with HDRIs and render result pixel values that exceed half float limits
3 changed files with 25 additions and 0 deletions

View File

@ -335,6 +335,7 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
offset++;
}
}
IMB_gpu_clamp_half_float(&extracted_buffer);
GPU_texture_update_sub(texture,
GPU_DATA_FLOAT,
@ -391,6 +392,7 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
}
BKE_image_release_ibuf(image, tile_buffer, lock);
}
IMB_gpu_clamp_half_float(&texture_buffer);
GPU_texture_update(info.texture, GPU_DATA_FLOAT, texture_buffer.rect_float);
imb_freerectImbuf_all(&texture_buffer);
}

View File

@ -937,6 +937,13 @@ struct GPUTexture *IMB_create_gpu_texture(const char *name,
struct ImBuf *ibuf,
bool use_high_bitdepth,
bool use_premult);
/**
* Ensures that values stored in the float rect can safely loaded into half float gpu textures.
*
* Does nothing when given image_buffer doesn't contain a float rect.
*/
void IMB_gpu_clamp_half_float(struct ImBuf *image_buffer);
/**
* The `ibuf` is only here to detect the storage type. The produced texture will have undefined
* content. It will need to be populated by using #IMB_update_gpu_texture_sub().

View File

@ -290,3 +290,19 @@ GPUTexture *IMB_create_gpu_texture(const char *name,
return tex;
}
void IMB_gpu_clamp_half_float(ImBuf *image_buffer)
{
const float half_min = -65504;
const float half_max = 65504;
if (!image_buffer->rect_float) {
return;
}
int rect_float_len = image_buffer->x * image_buffer->y *
(image_buffer->channels == 0 ? 4 : image_buffer->channels);
for (int i = 0; i < rect_float_len; i++) {
image_buffer->rect_float[i] = clamp_f(image_buffer->rect_float[i], half_min, half_max);
}
}