diff --git a/source/blender/draw/engines/image/image_drawing_mode.hh b/source/blender/draw/engines/image/image_drawing_mode.hh index 21dac8009f6..8913b7469ed 100644 --- a/source/blender/draw/engines/image/image_drawing_mode.hh +++ b/source/blender/draw/engines/image/image_drawing_mode.hh @@ -332,6 +332,7 @@ template class ScreenSpaceDrawingMode : public AbstractD offset++; } } + IMB_gpu_clamp_half_float(&extracted_buffer); GPU_texture_update_sub(texture, GPU_DATA_FLOAT, @@ -388,6 +389,7 @@ template 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); } diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 7e652e31506..5c76dfe52df 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -894,6 +894,13 @@ eGPUTextureFormat IMB_gpu_get_texture_format(const struct ImBuf *ibuf, bool high_bitdepth, bool use_grayscale); +/** + * 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(). diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c index 6f1275e1812..dd509677d8d 100644 --- a/source/blender/imbuf/intern/util_gpu.c +++ b/source/blender/imbuf/intern/util_gpu.c @@ -370,3 +370,19 @@ eGPUTextureFormat IMB_gpu_get_texture_format(const ImBuf *ibuf, return gpu_texture_format; } + +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); + } +}