ImBuf: do not clear newly allocated image pixels when not needed #118321

Merged
Aras Pranckevicius merged 2 commits from aras_p/blender:imbuf_noclear into main 2024-02-15 14:55:06 +01:00
15 changed files with 83 additions and 45 deletions

View File

@ -113,7 +113,7 @@ ImBuf *make_waveform_view_from_ibuf(const ImBuf *ibuf)
#endif
const int w = ibuf->x;
const int h = 256;
ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect);
ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect | IB_uninitialized_pixels);
uchar *tgt = rval->byte_buffer.data;
uchar wtable[256];
@ -172,7 +172,7 @@ ImBuf *make_sep_waveform_view_from_ibuf(const ImBuf *ibuf)
#endif
int w = ibuf->x;
int h = 256;
ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect);
ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect | IB_uninitialized_pixels);
uchar *tgt = rval->byte_buffer.data;
int sw = ibuf->x / 3;
@ -222,7 +222,7 @@ ImBuf *make_zebra_view_from_ibuf(const ImBuf *ibuf, float perc)
#ifdef DEBUG_TIME
SCOPED_TIMER(__func__);
#endif
ImBuf *res = IMB_allocImBuf(ibuf->x, ibuf->y, 32, IB_rect);
ImBuf *res = IMB_allocImBuf(ibuf->x, ibuf->y, 32, IB_rect | IB_uninitialized_pixels);
threading::parallel_for(IndexRange(ibuf->y), 16, [&](IndexRange y_range) {
if (ibuf->float_buffer.data) {
@ -346,7 +346,7 @@ ImBuf *make_vectorscope_view_from_ibuf(const ImBuf *ibuf)
#endif
const int size = 512;
const float size_mul = size - 1.0f;
ImBuf *rval = IMB_allocImBuf(size, size, 32, IB_rect);
ImBuf *rval = IMB_allocImBuf(size, size, 32, IB_rect | IB_uninitialized_pixels);
uchar *dst = rval->byte_buffer.data;
float rgb[3];

View File

@ -595,15 +595,18 @@ void *imb_alloc_pixels(unsigned int x,
unsigned int y,
unsigned int channels,
size_t typesize,
bool initialize_pixels,
const char *alloc_name);
bool imb_addrectImBuf(ImBuf *ibuf);
bool imb_addrectImBuf(ImBuf *ibuf, bool initialize_pixels = true);
/**
* Any free `ibuf->rect` frees mipmaps to be sure, creation is in render on first request.
*/
void imb_freerectImBuf(ImBuf *ibuf);
bool imb_addrectfloatImBuf(ImBuf *ibuf, const unsigned int channels);
bool imb_addrectfloatImBuf(ImBuf *ibuf,
const unsigned int channels,
bool initialize_pixels = true);
/**
* Any free `ibuf->rect` frees mipmaps to be sure, creation is in render on first request.
*/

View File

@ -106,6 +106,11 @@ enum eImBufFlags {
IB_multilayer = 1 << 7,
IB_metadata = 1 << 8,
IB_animdeinterlace = 1 << 9,
/** Do not clear image pixel buffer to zero. Without this flag, allocating
* a new ImBuf does clear the pixel data to zero (transparent black). If
* whole pixel data is overwritten after allocation, then this flag can be
* faster since it avoids a memory clear. */
IB_uninitialized_pixels = 1 << 10,
/** indicates whether image on disk have premul alpha */
IB_alphamode_premul = 1 << 12,

View File

@ -87,11 +87,15 @@ template<class BufferType> static void imb_free_buffer(BufferType &buffer)
/* Allocate pixel storage of the given buffer. The buffer owns the allocated memory.
* Returns true of allocation succeeded, false otherwise. */
template<class BufferType>
bool imb_alloc_buffer(
BufferType &buffer, const uint x, const uint y, const uint channels, const size_t type_size)
bool imb_alloc_buffer(BufferType &buffer,
const uint x,
const uint y,
const uint channels,
const size_t type_size,
bool initialize_pixels)
{
buffer.data = static_cast<decltype(BufferType::data)>(
imb_alloc_pixels(x, y, channels, type_size, __func__));
imb_alloc_pixels(x, y, channels, type_size, initialize_pixels, __func__));
if (!buffer.data) {
return false;
}
@ -297,7 +301,9 @@ bool imb_addencodedbufferImBuf(ImBuf *ibuf)
ibuf->encoded_size = 0;
if (!imb_alloc_buffer(ibuf->encoded_buffer, ibuf->encoded_buffer_size, 1, 1, sizeof(uint8_t))) {
if (!imb_alloc_buffer(
ibuf->encoded_buffer, ibuf->encoded_buffer_size, 1, 1, sizeof(uint8_t), true))
{
return false;
}
@ -323,7 +329,7 @@ bool imb_enlargeencodedbufferImBuf(ImBuf *ibuf)
}
ImBufByteBuffer new_buffer;
if (!imb_alloc_buffer(new_buffer, newsize, 1, 1, sizeof(uint8_t))) {
if (!imb_alloc_buffer(new_buffer, newsize, 1, 1, sizeof(uint8_t), true)) {
return false;
}
@ -343,7 +349,8 @@ bool imb_enlargeencodedbufferImBuf(ImBuf *ibuf)
return true;
}
void *imb_alloc_pixels(uint x, uint y, uint channels, size_t typesize, const char *alloc_name)
void *imb_alloc_pixels(
uint x, uint y, uint channels, size_t typesize, bool initialize_pixels, const char *alloc_name)
{
/* Protect against buffer overflow vulnerabilities from files specifying
* a width and height that overflow and alloc too little memory. */
@ -352,10 +359,10 @@ void *imb_alloc_pixels(uint x, uint y, uint channels, size_t typesize, const cha
}
size_t size = size_t(x) * size_t(y) * size_t(channels) * typesize;
return MEM_callocN(size, alloc_name);
return initialize_pixels ? MEM_callocN(size, alloc_name) : MEM_mallocN(size, alloc_name);
}
bool imb_addrectfloatImBuf(ImBuf *ibuf, const uint channels)
bool imb_addrectfloatImBuf(ImBuf *ibuf, const uint channels, bool initialize_pixels)
{
if (ibuf == nullptr) {
return false;
@ -368,7 +375,9 @@ bool imb_addrectfloatImBuf(ImBuf *ibuf, const uint channels)
imb_freerectfloatImBuf(ibuf); /* frees mipmap too, hrm */
}
if (!imb_alloc_buffer(ibuf->float_buffer, ibuf->x, ibuf->y, channels, sizeof(float))) {
if (!imb_alloc_buffer(
ibuf->float_buffer, ibuf->x, ibuf->y, channels, sizeof(float), initialize_pixels))
{
return false;
}
@ -378,7 +387,7 @@ bool imb_addrectfloatImBuf(ImBuf *ibuf, const uint channels)
return true;
}
bool imb_addrectImBuf(ImBuf *ibuf)
bool imb_addrectImBuf(ImBuf *ibuf, bool initialize_pixels)
{
/* Question; why also add ZBUF (when `planes > 32`)? */
@ -390,7 +399,9 @@ bool imb_addrectImBuf(ImBuf *ibuf)
* this call is used only too give float buffers display. */
imb_free_buffer(ibuf->byte_buffer);
if (!imb_alloc_buffer(ibuf->byte_buffer, ibuf->x, ibuf->y, 4, sizeof(uint8_t))) {
if (!imb_alloc_buffer(
ibuf->byte_buffer, ibuf->x, ibuf->y, 4, sizeof(uint8_t), initialize_pixels))
{
return false;
}
@ -505,13 +516,13 @@ ImBuf *IMB_allocFromBuffer(
if (float_buffer) {
/* TODO(sergey): The 4 channels is the historical code. Should probably be `channels`, but
* needs a dedicated investigation. */
imb_alloc_buffer(ibuf->float_buffer, w, h, 4, sizeof(float));
imb_alloc_buffer(ibuf->float_buffer, w, h, 4, sizeof(float), false);
memcpy(ibuf->float_buffer.data, float_buffer, sizeof(float[4]) * w * h);
}
if (byte_buffer) {
imb_alloc_buffer(ibuf->byte_buffer, w, h, 4, sizeof(uint8_t));
imb_alloc_buffer(ibuf->byte_buffer, w, h, 4, sizeof(uint8_t), false);
memcpy(ibuf->byte_buffer.data, byte_buffer, sizeof(uint8_t[4]) * w * h);
}
@ -548,14 +559,16 @@ bool IMB_initImBuf(ImBuf *ibuf, uint x, uint y, uchar planes, uint flags)
/* IMB_DPI_DEFAULT -> pixels-per-meter. */
ibuf->ppm[0] = ibuf->ppm[1] = IMB_DPI_DEFAULT / 0.0254;
const bool init_pixels = (flags & IB_uninitialized_pixels) == 0;
if (flags & IB_rect) {
if (imb_addrectImBuf(ibuf) == false) {
if (imb_addrectImBuf(ibuf, init_pixels) == false) {
return false;
}
}
if (flags & IB_rectfloat) {
if (imb_addrectfloatImBuf(ibuf, ibuf->channels) == false) {
if (imb_addrectfloatImBuf(ibuf, ibuf->channels, init_pixels) == false) {
return false;
}
}
@ -569,7 +582,7 @@ bool IMB_initImBuf(ImBuf *ibuf, uint x, uint y, uchar planes, uint flags)
ImBuf *IMB_dupImBuf(const ImBuf *ibuf1)
{
ImBuf *ibuf2, tbuf;
int flags = 0;
int flags = IB_uninitialized_pixels;
int a, x, y;
if (ibuf1 == nullptr) {

View File

@ -413,7 +413,7 @@ static ImBuf *avi_fetchibuf(ImBufAnim *anim, int position)
else
# endif
{
ibuf = IMB_allocImBuf(anim->x, anim->y, 24, IB_rect);
ibuf = IMB_allocImBuf(anim->x, anim->y, 24, IB_rect | IB_uninitialized_pixels);
tmp = static_cast<int *>(AVI_read_frame(
anim->avi, AVI_FORMAT_RGB32, position, AVI_get_stream(anim->avi, AVIST_VIDEO, 0)));

View File

@ -237,7 +237,7 @@ int logImageSetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB
int returnValue;
elementData = (float *)imb_alloc_pixels(
logImage->width, logImage->height, logImage->depth, sizeof(float), __func__);
logImage->width, logImage->height, logImage->depth, sizeof(float), true, __func__);
if (elementData == nullptr) {
return 1;
}
@ -438,8 +438,12 @@ int logImageGetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB
/* descriptor_Depth and descriptor_Composite are not supported */
if (!ELEM(logImage->element[i].descriptor, descriptor_Depth, descriptor_Composite)) {
/* Allocate memory */
elementData[i] = static_cast<float *>(imb_alloc_pixels(
logImage->width, logImage->height, logImage->element[i].depth, sizeof(float), __func__));
elementData[i] = static_cast<float *>(imb_alloc_pixels(logImage->width,
logImage->height,
logImage->element[i].depth,
sizeof(float),
true,
__func__));
if (elementData[i] == nullptr) {
if (verbose) {
printf("DPX/Cineon: Cannot allocate memory for elementData[%d]\n.", i);
@ -624,7 +628,7 @@ int logImageGetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB
}
mergedData = (float *)imb_alloc_pixels(
logImage->width, logImage->height, mergedElement.depth, sizeof(float), __func__);
logImage->width, logImage->height, mergedElement.depth, sizeof(float), true, __func__);
if (mergedData == nullptr) {
if (verbose) {
printf("DPX/Cineon: Cannot allocate mergedData.\n");
@ -1707,7 +1711,7 @@ static int convertRGBAToLogElement(
if (srcIsLinearRGB != 0) {
/* we need to convert src to sRGB */
srgbSrc = (float *)imb_alloc_pixels(
logImage->width, logImage->height, 4, sizeof(float), __func__);
logImage->width, logImage->height, 4, sizeof(float), false, __func__);
if (srgbSrc == nullptr) {
return 1;
}

View File

@ -702,7 +702,7 @@ void IMB_rect_from_float(ImBuf *ibuf)
/* create byte rect if it didn't exist yet */
if (ibuf->byte_buffer.data == nullptr) {
if (imb_addrectImBuf(ibuf) == 0) {
if (imb_addrectImBuf(ibuf, false) == 0) {
return;
}
}

View File

@ -292,7 +292,9 @@ static ImBuf *ibJpegImageFromCinfo(
jpeg_abort_decompress(cinfo);
ibuf = IMB_allocImBuf(x, y, 8 * depth, 0);
}
else if ((ibuf = IMB_allocImBuf(x, y, 8 * depth, IB_rect)) == nullptr) {
else if ((ibuf = IMB_allocImBuf(x, y, 8 * depth, IB_rect | IB_uninitialized_pixels)) ==
nullptr)
{
jpeg_abort_decompress(cinfo);
}
else {

View File

@ -100,7 +100,7 @@ static ImBuf *load_pixels(
{
/* Allocate the ImBuf for the image. */
constexpr bool is_float = sizeof(T) > 1;
const uint format_flag = is_float ? IB_rectfloat : IB_rect;
const uint format_flag = (is_float ? IB_rectfloat : IB_rect) | IB_uninitialized_pixels;
const uint ibuf_flags = (flags & IB_test) ? 0 : format_flag;
const int planes = use_all_planes ? 32 : 8 * channels;
ImBuf *ibuf = IMB_allocImBuf(width, height, planes, ibuf_flags);

View File

@ -369,6 +369,7 @@ void *avi_converter_from_mjpeg(AviMovie *movie, int stream, uchar *buffer, const
movie->header->Width,
3,
sizeof(uchar),
true,
"avi.avi_converter_from_mjpeg 1"));
if (!buf) {
return nullptr;
@ -383,6 +384,7 @@ void *avi_converter_from_mjpeg(AviMovie *movie, int stream, uchar *buffer, const
movie->header->Width,
3,
sizeof(uchar),
true,
"avi.avi_converter_from_mjpeg 2"));
if (buffer) {
interlace(buffer, buf, movie->header->Width, movie->header->Height);
@ -407,6 +409,7 @@ void *avi_converter_to_mjpeg(AviMovie *movie, int stream, uchar *buffer, size_t
movie->header->Width,
3,
sizeof(uchar),
true,
"avi.avi_converter_to_mjpeg 1"));
if (!buf) {
return nullptr;
@ -430,6 +433,7 @@ void *avi_converter_to_mjpeg(AviMovie *movie, int stream, uchar *buffer, size_t
movie->header->Width,
3,
sizeof(uchar),
true,
"avi.avi_converter_to_mjpeg 1"));
if (buf) {

View File

@ -43,7 +43,7 @@ void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, uchar *buffer, con
#endif
buf = static_cast<uchar *>(imb_alloc_pixels(
movie->header->Height, movie->header->Width, 3, sizeof(uchar), "fromavirgbbuf"));
movie->header->Height, movie->header->Width, 3, sizeof(uchar), false, "fromavirgbbuf"));
if (buf) {
size_t y = movie->header->Height;
@ -80,7 +80,7 @@ void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, uchar *buffer, con
}
buf = static_cast<uchar *>(imb_alloc_pixels(
movie->header->Height, movie->header->Width, 3, sizeof(uchar), "fromavirgbbuf"));
movie->header->Height, movie->header->Width, 3, sizeof(uchar), false, "fromavirgbbuf"));
if (buf) {
size_t rowstride = movie->header->Width * 3;

View File

@ -26,7 +26,7 @@ void *avi_converter_from_rgb32(AviMovie *movie, int stream, uchar *buffer, size_
*size = size_t(movie->header->Height) * size_t(movie->header->Width) * 3;
buf = static_cast<uchar *>(imb_alloc_pixels(
movie->header->Height, movie->header->Width, 3, sizeof(uchar), "fromrgb32buf"));
movie->header->Height, movie->header->Width, 3, sizeof(uchar), false, "fromrgb32buf"));
if (!buf) {
return nullptr;
}
@ -56,7 +56,7 @@ void *avi_converter_to_rgb32(AviMovie *movie, int stream, uchar *buffer, size_t
*size = size_t(movie->header->Height) * size_t(movie->header->Width) * 4;
buf = static_cast<uchar *>(imb_alloc_pixels(
movie->header->Height, movie->header->Width, 4, sizeof(uchar), "torgb32buf"));
movie->header->Height, movie->header->Width, 4, sizeof(uchar), false, "torgb32buf"));
if (!buf) {
return nullptr;
}

View File

@ -632,12 +632,14 @@ ImBuf *seq_disk_cache_read_file(SeqDiskCache *disk_cache, SeqCacheKey *key)
if (header.entry[entry_index].size_raw == size_char) {
expected_size = size_char;
ibuf = IMB_allocImBuf(key->context.rectx, key->context.recty, 32, IB_rect);
ibuf = IMB_allocImBuf(
key->context.rectx, key->context.recty, 32, IB_rect | IB_uninitialized_pixels);
IMB_colormanagement_assign_byte_colorspace(ibuf, header.entry[entry_index].colorspace_name);
}
else if (header.entry[entry_index].size_raw == size_float) {
expected_size = size_float;
ibuf = IMB_allocImBuf(key->context.rectx, key->context.recty, 32, IB_rectfloat);
ibuf = IMB_allocImBuf(
key->context.rectx, key->context.recty, 32, IB_rectfloat | IB_uninitialized_pixels);
IMB_colormanagement_assign_float_colorspace(ibuf, header.entry[entry_index].colorspace_name);
}
else {

View File

@ -165,26 +165,28 @@ static void store_opaque_black_pixel(float *dst)
static ImBuf *prepare_effect_imbufs(const SeqRenderData *context,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
ImBuf *ibuf3,
bool uninitialized_pixels = true)
{
ImBuf *out;
Scene *scene = context->scene;
int x = context->rectx;
int y = context->recty;
int base_flags = uninitialized_pixels ? IB_uninitialized_pixels : 0;
if (!ibuf1 && !ibuf2 && !ibuf3) {
/* hmmm, global float option ? */
out = IMB_allocImBuf(x, y, 32, IB_rect);
out = IMB_allocImBuf(x, y, 32, IB_rect | base_flags);
}
else if ((ibuf1 && ibuf1->float_buffer.data) || (ibuf2 && ibuf2->float_buffer.data) ||
(ibuf3 && ibuf3->float_buffer.data))
{
/* if any inputs are rectfloat, output is float too */
out = IMB_allocImBuf(x, y, 32, IB_rectfloat);
out = IMB_allocImBuf(x, y, 32, IB_rectfloat | base_flags);
}
else {
out = IMB_allocImBuf(x, y, 32, IB_rect);
out = IMB_allocImBuf(x, y, 32, IB_rect | base_flags);
}
if (out->float_buffer.data) {
@ -2708,7 +2710,9 @@ static ImBuf *do_text_effect(const SeqRenderData *context,
ImBuf *ibuf2,
ImBuf *ibuf3)
{
ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
/* Note: text rasterization only fills in part of output image,
* need to clear it. */
ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3, false);
TextVars *data = static_cast<TextVars *>(seq->effectdata);
int width = out->x;
int height = out->y;

View File

@ -139,7 +139,7 @@ void seq_imbuf_to_sequencer_space(const Scene *scene, ImBuf *ibuf, bool make_flo
/* We perform conversion to a float buffer so we don't worry about
* precision loss.
*/
imb_addrectfloatImBuf(ibuf, 4);
imb_addrectfloatImBuf(ibuf, 4, false);
IMB_colormanagement_transform_from_byte_threaded(ibuf->float_buffer.data,
ibuf->byte_buffer.data,
ibuf->x,
@ -1342,7 +1342,8 @@ ImBuf *seq_render_mask(const SeqRenderData *context,
const float *fp_src;
float *fp_dst;
ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rectfloat);
ibuf = IMB_allocImBuf(
context->rectx, context->recty, 32, IB_rectfloat | IB_uninitialized_pixels);
fp_src = maskbuf;
fp_dst = ibuf->float_buffer.data;
@ -1360,7 +1361,7 @@ ImBuf *seq_render_mask(const SeqRenderData *context,
const float *fp_src;
uchar *ub_dst;
ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect | IB_uninitialized_pixels);
fp_src = maskbuf;
ub_dst = ibuf->byte_buffer.data;