Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

huge images cause bad_array_new_length exception in exrdisplay #610

Closed
claudeha opened this issue Nov 5, 2019 · 15 comments
Closed

huge images cause bad_array_new_length exception in exrdisplay #610

claudeha opened this issue Nov 5, 2019 · 15 comments
Labels
Awaiting Feedback The issue is waiting for someone to respond. Bug A bug in the source code
Milestone

Comments

@claudeha
Copy link

claudeha commented Nov 5, 2019

I have successfully constructed a huge image using the openexr libraries (over 2 gigapixels, about 13GB of image data, about 9GB compressed):

$ exrheader output.exr

file output.exr:

file format version: 2, flags 0x0
channels (type chlist):
    B, 16-bit floating-point, sampling 1 1
    G, 16-bit floating-point, sampling 1 1
    R, 16-bit floating-point, sampling 1 1
compression (type compression): zip, multi-scanline blocks
dataWindow (type box2i): (0 0) - (63999 35999)
displayWindow (type box2i): (0 0) - (63999 35999)
lineOrder (type lineOrder): increasing y
pixelAspectRatio (type float): 1
screenWindowCenter (type v2f): (0 0)
screenWindowWidth (type float): 1
type (type string): "scanlineimage"

$

But I can't display it:

$ exrdisplay output.exr
std::bad_array_new_length
$

I imagine the most likely cause might be a signed 32bit type overflowing to negative?

@lgritz
Copy link
Contributor

lgritz commented Nov 5, 2019

Probably. I just fixed a couple bugs like that (in the deep image handling code). It wouldn't surprise me if there were more lurking. We should probably make sure the unit tests exercise code paths with very large images that are constructed to purposely overflow 32 bit math.

@cary-ilm cary-ilm added the Needs Discussion To be discussed in the technical steering committee label Nov 14, 2019
@cary-ilm
Copy link
Member

Can you share how you generated the image, so we can reproduce it for testing? Is there anything particularly special about it other than the large size?

@claudeha
Copy link
Author

I tried some sed -i s/int/ssize_t/ and after some fixups it compiled and no longer crashed, but it didn't display anything either.

Nothing special apart from large dimensions. File has R, G, B channels with half data.

The large file was created with exrtactile, my program for assembling images from many tiles:
https://code.mathr.co.uk/exrtact/blob/079d1d78a00feee4569004ccd2b39a47b56c829f:/exrtactile.cpp

The tiles were created with kalles-fraktaler-2, a fractal rendering program which I maintain:
https://code.mathr.co.uk/kalles-fraktaler-2/blob/4fd9a283a891fb557461bd28597ba209ec6baa4b:/fraktal_sft/exr.cpp

I gave arguments to exrtactile to keep only the RGB channels, as otherwise the file was too big (50GB+) for my RAM.

@lgritz
Copy link
Contributor

lgritz commented Nov 21, 2019

If you just want a quick way to generate a large test image and have OpenImageIO installed, you can do something like:

oiiotool -pattern checker 64000x36000 3 -d half -o big.exr

(oops, fixed typo)

@peterhillman
Copy link
Contributor

@lgritz, I get a similar error from oiiotool throwing std::bad_alloc from OpenImageIO_v2_2::ImageBufImpl::new_pixels
(using commit 639daadc4fe2e5221dfbde341172be52b4d9a381)
I built an image with the following, but ran out of memory trying to reproduce the issue with exrdisplay.

#include <ImfOutputFile.h>
#include <ImfFrameBuffer.h>
#include <ImfChannelList.h>
#include <vector>

int main(int argc,char*argv[])
{
        int width = 64000;
        int height = 32000;
        Imf::Header h( width ,  height );
        h.channels().insert( "R" , Imf::HALF );
        Imf::OutputFile out( argv[1] , h );
        Imf::FrameBuffer buf;

        std::vector<half> pixels(width);
        buf.insert("R",Imf::Slice( Imf::HALF , (char*) pixels.data() , sizeof(half) , 0 ));
        out.setFrameBuffer(buf);
        for(int i = 0 ; i < height ; ++i )
        {
                std::fill(pixels.begin(),pixels.end(),float(i)/float(height-1));
                out.writePixels(1);
        }
}

@lgritz
Copy link
Contributor

lgritz commented Nov 24, 2019

oops. Interesting!

@lgritz
Copy link
Contributor

lgritz commented Nov 25, 2019

Works for me on my laptop, but the internal allocation for a float image of those dimensions will be around 23GB, so I can see that it might die if you don't have enough system memory.

@peterhillman
Copy link
Contributor

Ah yes, the machine I tried had less that 23GB including swap. I've found a couple of bugs - still working on one of them

@peterhillman
Copy link
Contributor

I'm now in the same position: exrdisplay opens but doesn't draw anything in the image. I suspect my graphics card can't handle rendering images that wide either.

exrdisplay simply isn't intended for displaying large images. It doesn't have a pan/zoom facility, so it tries to open a 64,000 pixel wide window, and loads and renders the entire image, not just a small subsection of it.

Perhaps other viewers would be better suited to this task?

@lgritz
Copy link
Contributor

lgritz commented Nov 25, 2019

@peterhillman You inspired me to make a couple fixes: AcademySoftwareFoundation/OpenImageIO#2414 With this patch, you can generate a big file with only a 6 GB memory footprint:

oiiotool -pattern:type=uint8 checker 64000x36000 3 -d half -o big.exr

Also, OIIO's "iv" viewer -- which honestly I'm not especially proud of in general -- is able to display a 64k x 32k file just fine (though rather slowly to load), even before the patch.

@cary-ilm
Copy link
Member

cary-ilm commented Feb 5, 2020

Following up on this, @peterhillman, you mentioned finding a couple bugs, are these covered in your recent commits? If so, @claudeha, can you confirm that it no longer crashes? I'd recommending calling this resolved if the crash is fixed. As @peterhillman says, exrdisplay isn't really suited to displaying huge images.

@cary-ilm cary-ilm closed this as completed Feb 5, 2020
@cary-ilm cary-ilm reopened this Feb 5, 2020
@peterhillman
Copy link
Contributor

Commit bd6ab91 has the "bug fix" which should prevent the bad_array_length exception, but may still run out of main memory or GPU memory when displaying large images. This may itself cause a crash, or might not display the image. You will also get a window that is very large, since there is no zoom facility.

@cary-ilm cary-ilm added Awaiting Feedback The issue is waiting for someone to respond. Bug A bug in the source code and removed Needs Discussion To be discussed in the technical steering committee labels Feb 7, 2020
@cary-ilm cary-ilm added this to the Next Patch Release milestone Feb 7, 2020
@claudeha
Copy link
Author

claudeha commented Feb 8, 2020

There is still a 32bit overflow it seems (somewhere something goes negative, and is sign extended to a huge 64bit value), but I haven't checked if that is before or after the data is passed to OpenGL:

claude@eiskaffee:~/code/github.com/openexr/openexr/build$ ./bin/exrheader ~/tmp/32000x18000.exr

file /home/claude/tmp/32000x18000.exr:

file format version: 2, flags 0x0
channels (type chlist):
    B, 16-bit floating-point, sampling 1 1
    G, 16-bit floating-point, sampling 1 1
    R, 16-bit floating-point, sampling 1 1
compression (type compression): zip, multi-scanline blocks
dataWindow (type box2i): (0 0) - (31999 17999)
displayWindow (type box2i): (0 0) - (31999 17999)
lineOrder (type lineOrder): increasing y
pixelAspectRatio (type float): 1
screenWindowCenter (type v2f): (0 0)
screenWindowWidth (type float): 1
type (type string): "scanlineimage"

claude@eiskaffee:~/code/github.com/openexr/openexr/build$ ./bin/exrdisplay ~/tmp/32000x18000.exr
Warning: Environment variable CTL_DISPLAY_CHROMATICITIES is not set; using default value (chromaticities according to Rec. ITU-R BT.709).
Warning: Environment variable EXR_DISPLAY_VIDEO_GAMMA is not set; using default value (2.2).
amdgpu: Failed to allocate a buffer:
amdgpu:    size      : 18446744071761887232 bytes
amdgpu:    alignment : 32768 bytes
amdgpu:    domains   : 4
(last 4 lines repeated 8 times)

Checking the value:

ghci> showHex 18446744071761887232 ""
ffffffff8be90000

Window is large (as expected), contents of the image region are plain grey (bug):

$ xwininfo 

xwininfo: Please select the window about which you
          would like information by clicking the
          mouse in that window.

xwininfo: Window id: 0x4400002 "/home/claude/tmp/32000x18000.exr"

  Absolute upper-left X:  3
  Absolute upper-left Y:  29
  Relative upper-left X:  0
  Relative upper-left Y:  29
  Width: 32010
  Height: 18160
  Depth: 24
  Visual: 0x21
  Visual Class: TrueColor
  Border width: 0
  Class: InputOutput
  Colormap: 0x20 (not installed)
  Bit Gravity State: ForgetGravity
  Window Gravity State: NorthWestGravity
  Backing Store State: NotUseful
  Save Under State: no
  Map State: IsViewable
  Override Redirect State: no
  Corners:  +3+29  --30093+29  --30093--17109  +3--17109
  -geometry 32010x18160+3+29

It seems exrdisplay uses glDrawPixels() from system memory instead of glTexImage2D() or similar so it doesn't explicitly allocate GPU memory for the image data.

It could be that the overflow is internal to Mesa/amdgpu? I might be able to check on an older NVIDIA system next week, to rule that out, or also try to replicate the issue with a smaller OpenGL program.

@claudeha
Copy link
Author

claudeha commented Feb 8, 2020

With a 64000x32000.exr as generated by the simple code above, exrdisplay opens a very thin window. I guess somewhere the width is 16bit signed, which overflows negative and is clamped below to 1?

$ xwininfo 

xwininfo: Please select the window about which you
          would like information by clicking the
          mouse in that window.

xwininfo: Window id: 0x4400002 "64000x32000.exr"

  Absolute upper-left X:  959
  Absolute upper-left Y:  29
  Relative upper-left X:  3
  Relative upper-left Y:  29
  Width: 1
  Height: 32160
  Depth: 24
  Visual: 0x21
  Visual Class: TrueColor
  Border width: 0
  Class: InputOutput
  Colormap: 0x20 (not installed)
  Bit Gravity State: ForgetGravity
  Window Gravity State: NorthWestGravity
  Backing Store State: NotUseful
  Save Under State: no
  Map State: IsViewable
  Override Redirect State: no
  Corners:  +959+29  -960+29  -960--31109  +959--31109
  -geometry 1x32160+959+29

There are no error reports from amdgpu printed.

@peterhillman
Copy link
Contributor

Although the display issues for large images have not be identified, we're considering this fixed.
Now #660 is merged, exrdisplay will no longer attempt to load huge images. Also, with #676, exrdisplay is no longer compiled by default, and will be removed in future releases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting Feedback The issue is waiting for someone to respond. Bug A bug in the source code
Projects
None yet
Development

No branches or pull requests

4 participants