AcademySoftwareFoundation / AcademySoftwareFoundation/OpenImageIO

[BUG] Unable to sample UDIMs from pre-populated in-memory ImageCache

Open
#4,378 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
2.4k
Forks
698
Avg merge
3d 4h
Merged PRs (30d)
47

Description

**Description**

Note - this is the result of a discussion on the Academy Software Foundation slack.

I wanted to sample a number of in-memory buffers representing tiles using the texturesystem. I thought (based on advice) that I could populate an ImageCache with "fake" images named in the fashion of UDIM tiles such as "`test.1001.null`", "`test.1002.null`", and sample them using the name containing the UDIM pattern (such as `test..null`). This does work for single images but not for UDIM tiles.

**OpenImageIO version and dependencies**

OpenImageIO 2.5.10.0

**To Reproduce**

Steps to reproduce the behavior:
1. Use the test C++ code snippet below in a setup that has OIIO available (sorry I don't have exact steps here).
2. Call `OIIOTest::testBufferUDIMSampling();`
3. The output will be:
```
Checking test.1001.null at st: {0.5,0.5}
No inventory test.1001.null u0 v0
Checking test.1002.null at st: {0.5,0.5}
No inventory test.1002.null u0 v0
Checking test..null at st: {0.5,0.5}
No inventory test..null u0 v0
test..null did not sample correctly.
Incorrect result: {0,0,0,0}
```
4. This indicates that after populating the cache we were able to sample the image `test.1001.null` and `test.1002.null`, and get the expected result, but were unable to sample `test..null`. The inventory of UDIM tiles always gives 0 tiles, in all three cases, which may be a clue.

The code using the `nullImageInputCreator` follows the example found here: https://github.com/AcademySoftwareFoundation/OpenImageIO/blob/64f829febd352686538beaba10e4ca716a9403a1/src/libOpenImageIO/imagecache_test.cpp#L161-L186

Test code snippet:
```cpp
#include
#include
#include

#include
#include

namespace OIIOTest {

using namespace OIIO;

// Simple wrapper to return a raw "null" ImageInput*.
// Taken from OIIO tests
ImageInput* nullImageInputCreator() {
// Original comment:
// Note: we can't create it directly, but we can ask for a managed
// pointer and then release the raw pointer from it.
return ImageInput::create("0.null").release();
}

bool checkSample(ImageCache* imageCache, ustring filename, float s, float t, float* expected) {
std::cerr << "Checking " << filename << " at st: {" << s << "," << t << "}\n";
float r[4] = {-1.f, -1.f, -1.f, -1.f};
TextureOpt opt;
opt.interpmode = TextureOpt::InterpMode::InterpClosest;
bool ok;
{
auto textureSys = TextureSystem::create(false /*Not shared*/, imageCache);

{
std::vector filenames;
int ut, vt;
textureSys->inventory_udim(filename, filenames, ut, vt);
if (filenames.empty())
std::cerr << " No inventory " << filename << " u" << ut << " v" << vt << "\n";
}

ok = textureSys->texture(filename, opt, //
s, t, // float s, t
0.f, 0.f, 0.f, 0.f, // float dsdx, dtdx, dsdy, dtdy,
4, // int nchannels,
r); // float *result
TextureSystem::destroy(textureSys);
}

if (!imageCache->geterror(false).empty() || !ok) {
std::cerr << " " << filename << " gave OIIO error. \n";
std::cerr << " " << imageCache->geterror(true);
return false;
}
if (r[0] != expected[0] || r[1] != expected[1] || r[2] != expected[2] || r[3] != expected[3]) {
std::cerr << " " << filename << " did not sample correctly. \n";
std::cerr << " Incorrect result: {" << r[0] << "," << r[1] << "," << r[2] << "," << r[3]
<< "}\n";
return false;
}
return true;
}

bool testBufferUDIMSampling() {
/*
We create two UDIM tiles, 1001 and 1002.
*/
std::vector pixels1001 = {
1.f, 0.f, 0.f, 1.f, // red
1.f, 0.f, 0.f, 1.f, // red
1.f, 0.f, 0.f, 1.f, // red
1.f, 0.f, 0.f, 1.f, // red
};
std::vector pixels1002 = {
0.f, 1.f, 0.f, 1.f, // green
0.f, 1.f, 0.f, 1.f, // green
0.f, 1.f, 0.f, 1.f, // green
0.f, 1.f, 0.f, 1.f, // green
};

const ustring nameUDIM("test..null");
const ustring name1001("test.1001.null");
const ustring name1002("test.1002.null");

auto imageCache = ImageCache::create(false); // unshared

ImageSpec spec = ImageSpec(2, 2, 4, TypeDesc::FLOAT);
spec.attribute("null:force", 1); // necessary because no .null extension

imageCache->add_file(name1001, nullImageInputCreator, &spec);
imageCache->add_tile(name1001,
0, // subimage
0, // miplevel
0, 0, 0, // origin x, y, z
0, 4, // channel start, end
TypeDesc::FLOAT, // image type
pixels1001.data(), // the buffer
AutoStride, AutoStride, AutoStride, // strides
true // copy
);
imageCache->add_file(name1002, nullImageInputCreator, &spec);
imageCache->add_tile(name1002,
0, // subimage
0, // miplevel
0, 0, 0, // origin x, y, z
0, 4, // channel start, end
TypeDesc::FLOAT, // image type
pixels1002.data(), // the buffer
AutoStride, AutoStride, AutoStride, // strides
true // copy
);

if (!imageCache->geterror(false).empty()) {
std::cerr << imageCache->geterror(true);
return false;
}

float s = 0.5f, t = 0.5f;
float expected1001[4] = {1.f, 0.f, 0.f, 1.f};
float expected1002[4] = {0.f, 1.f, 0.f, 1.f};

// Sampling "test.1001.null" works
if (!checkSample(imageCache, name1001, s, t, expected1001)) return false;

// Sampling "test.1002.null" works as well (no udim tile behavior, just shows this loaded.)
if (!checkSample(imageCache, name1002, s, t, expected1002)) return false;

// Sampling it as "test..null" fails
if (!checkSample(imageCache, nameUDIM, s, t, expected1001)) return false;

// (never reached)
if (!checkSample(imageCache, nameUDIM, s + 1.f, t, expected1002)) return false;

std::cerr << "Success \n";
return true;
}
} // namespace OIIOTest
```

Contributor guide

Open the contributing guide

Research direction

Start by reproducing OIIOTest::testBufferUDIMSampling() with ImageCache::add_file/add_tile and the TextureSystem inventory_udim and texture entry points shown in the report. Compare direct tile sampling with sampling through test..null; done means the in-memory tiles are inventoried and the UDIM pattern returns the expected red and green samples.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
computer-graphics
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.