Repository navigation
fix(ImageBuf): IB::nmiplevels() returns 0 for non-IC ImageBuf - #5437
luna-y-kim wants to merge 1 commit into
Conversation
|
I'm worried that this is quite expensive, since seek_subimage will read/decode all the MIP image metadata. It will make opening a file with an ImageBuf bear the expense of seek_subimage calls even if no mip levels will ever be needed. I'm wondering a few things:
Or, another possibility is that we don't do it as part of the read() at all, but instead use the separate ImageBuf::nmiplevels() method for this. Right now it returns m_nmiplevels, which obviously might not know. But it could instead figure it out by doing the seeks or spec_dimensions or whatever, if it doesn't already set it. In other words, we split the responsibilities to figure this out lazily:
So that would prevent/postpone the expensive kind of search until the occasion that the user actually needs to know the answer, conveyed by calling nmiplevels(). Thoughts? |
|
Oops, it was an oversight. Here are my thoughts after some investigation:
So I think the next steps are:
Am I missing something?..... Or would checking |
9fc4d66 to
ea0183e
Compare
nmiplevels() returned 0 for non-IC ImageBuf|
The test reference |
|
Yeah, this is kind of an icky one-time switch and I'm hoping to get it merged soon. Just want to give people a chance to air any concerns. But inspecting the results, it looks like everything translated just fine, and I challenge anyone to find a visible difference compared to the docs in rst. (Of course, it cheats a little by lapsing into rst for short sections within the md files when it needs to.) |
ea0183e to
602f286
Compare
602f286 to
2229645
Compare
2229645 to
c11c3bf
Compare
|
All conflicts resolved! |
|
Sorry it took me a while to get back to this, busy with releases. I have to say, I'm not crazy about all the ref outputs being cluttered with "oiio:miplevels" set to 1. I'd like to avoid that if possible, so I want to propose a slightly different approach:
I think that this is very close overall to what you have implemented, but has the advantage that most of the reference outputs will not need to change, since the vast majority of cases, the "oiio:miplevels" will not be present, rather than be 1 needlessly. (If it bugs people to have "0" mean "mipmapped, but not known", then we could use -1 there? Then the nonzeroness means "mipmapped" and the negativity means "but we don't know how many levels yet.) |
The ImageBuf constructor path without an ImageCache ends in `init_spec()`. There, the non-IC branch only reset `m_nmiplevels = 0` and never assigned a real value, so `IB::nmiplevels()` always returned 0. Now `IB::nmiplevels()` returns 1 for non-MIP-mapped images, or assigns the number of MIP levels if it can be known up front using the `oiio:miplevels` spec attribute. If an image is MIP-mapped but the count requires walking through the levels, then it is counted by iteration lazily. The iteration calls `spec_dimensions()` repeatedly until it returns an empty ImageSpec, which is less expensive than `seek_subimage()`. A return value of 0 for `IB::nmiplevels()` indicates failures such as a failure in `validate_spec()`, a file open failure, or a `seek_subimage()` failure inside `spec_dimensions()`. This improves ImageInput for EXR and DDS to set the "oiio:miplevels" attribute (Ptex is already setting it), so that `IB::nmiplevels()` can get the attribute's value and save it to `ImageBufImpl::m_nmiplevels`. For TIFF, it only sets the attribute to 0 if the image is MIP-mapped, which triggers the iteration count in `IB::nmiplevels()`. A test for `IB::nmiplevels()` is added to the python-imagebuf testsuite. Documentation for the `oiio:miplevels` attribute is also updated. Fixes AcademySoftwareFoundation#5409 Signed-off-by: Luna Kim <hi@lunakim.ca>
c11c3bf to
d707fe9
Compare
|
That makes sense. Updated. I used the value 0 for |
|
I think we're still not there yet. I definitely don't want the output to say "oiio:miplevels" 0. Output like you'd get from "oiiotool --info" or "iinfo" should not include this, I think it's confusing. But I'm not sure how to fix this yet, let me sleep on it and think about it over the weekend. Remind me -- is TIFF the only format where it might be MIP-mapped, but we can't tell up front how many MIP levels there are? |
Yeah. Currently TIFF is the only format where we can't know the MIP level count up front (among the formats supporting mipmaps). |
|
TIFF is special. It doesn't really support MIP-maps, they are emulated. It only supports subimages, but when the TIFFTAG_PIXAR_TEXTUREFORMAT tag is present in the header, we choose to interpret / pretend that the multiple images in the file are MIP levels, and we also set the "textureformat" attribute in the ImageSpec when that happens. I'm wondering if maybe ImageInput should only set "oiio:miplevels" if it knows the number of levels for sure (i.e., always >= 1 and only set for true MIP mapped files) and not set it for the case where it doesn't know yet. Then ImageBuf can use the combination of the presence of "textureformat" and the absence of "oiio:miplevels" to understand that this is the sole case where it's MIP-mapped but it doesn't know how many levels yet, and that if IB::miplevels() is called, it will have to do the possibly-expensive inventory. |
|
Oh! I used the |
|
Hello, just throwing out another idea while following along this thread: Can we just simply check the So, something like: if (m_emulate_mipmap) {
// treat every directory as a MIP level
int nmiplevels = int(TIFFNumberOfDirectories(m_tif));
if (nmiplevels > 1)
m_spec.attribute("oiio:miplevels", nmiplevels);
} |
|
Ooh, Jinnie FTW! I hadn't thought of that! Verify with a couple MIP-mapped TIFF files, but it sure sounds like it might work. |
The ImageBuf constructor path without an ImageCache ends in
init_spec(). There, the non-IC branch only resetm_nmiplevels = 0and never assigned a real value, soIB::nmiplevels()always returned 0.Now
IB::nmiplevels()returns 1 for non-MIP-mapped images, or the number of MIP levels if it can be known up front using theoiio:miplevelsspec attribute. If an image is MIP-mapped but the count requires walking through the levels, then it is counted by iteration lazily. The iteration callsspec_dimensions()repeatedly until it returns an empty ImageSpec, which is less expensive thanseek_subimage().A return value of 0 for
IB::nmiplevels()indicates failures such as a failure invalidate_spec(), a file open failure, or aseek_subimage()failure insidespec_dimensions().This improves ImageInput for EXR and DDS to set the "oiio:miplevels" attribute (Ptex is already setting it), so that
IB::nmiplevels()can get the attribute's value and save it toImageBufImpl::m_nmiplevels. For TIFF, it only sets the attribute to 0 if the image is MIP-mapped, which triggers the iteration count inIB::nmiplevels().A test for
IB::nmiplevels()is added to the python-imagebuf testsuite.Documentation for the
oiio:miplevelsattribute is also updated.Fixes #5409