Skip to content

Commit 397eb4f

Browse files
committed
ImageBuf: contiguous_scanline(), fixes to internal span
Add a new ImageBuf method: `contiguous_scanline()`, which reveals if each scanline is contiguous in the ImageBuf's internal memory (no padding or unusual spacing between channels or pixels). It's analogous to the existing `contiguous()`, but the latter also tests contiguity in y and z. Additional internal fixes: * Always and only set m_bufspan via calls to `set_bufspan()`, so it's consistent. In particular, it ensures that we correctly set the channel size, which some call sites previously did not correctly do for untyped "byte" buffers. * Re-evaluate the contiguous flags whenever resetting m_bufspan. * contiguous() calls need to call validate_pixels(). An IB from a file that hasn't been read yet into memory yet isn't considered contiguous. But once it's read, it will be (if it's got the strides right, etc.). So when somebody asks if it's contiguous, what does that mean? They are asking because they are about to do something that requires memory contiguity (meaning, it needs to be IN memory), just like if they call localpixels(). So just like localpixels(), we need to call validate_pixels() to assure that if the pixels are destined for the local buffer, it's done now if not yet. Signed-off-by: Larry Gritz <lg@larrygritz.com>
1 parent 51d60b9 commit 397eb4f

File tree

3 files changed

+44
-26
lines changed

3 files changed

+44
-26
lines changed

src/include/OpenImageIO/imagebuf.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1386,14 +1386,23 @@ class OIIO_API ImageBuf {
13861386
/// Z plane stride within the localpixels memory.
13871387
stride_t z_stride() const;
13881388

1389-
/// Is this an in-memory buffer with the data layout "contiguous", i.e.,
1389+
/// Is this an in-memory buffer with the data layout "fully contiguous",
1390+
/// i.e.,
13901391
/// ```
13911392
/// pixel_stride == nchannels * pixeltype().size()
13921393
/// scanline_stride == pixel_stride * spec().width
13931394
/// z_stride == scanline_stride * spec().height
13941395
/// ```
13951396
bool contiguous() const;
13961397

1398+
/// Is this an in-memory buffer with the data layout "contiguous" for
1399+
/// each scanline (but not considering whether adjacent scanlines or
1400+
/// image planes are fully contiguous), i.e.,
1401+
/// ```
1402+
/// pixel_stride == nchannels * pixeltype().size()
1403+
/// ```
1404+
bool contiguous_scanline() const;
1405+
13971406
/// Are the pixels backed by an ImageCache, rather than the whole
13981407
/// image being in RAM somewhere?
13991408
bool cachedpixels() const;

src/libOpenImageIO/imagebuf.cpp

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ class ImageBufImpl {
155155
m_spec.nchannels, m_spec.width, m_spec.height,
156156
m_spec.depth, formatsize, xstride, ystride,
157157
zstride, formatsize);
158+
eval_contiguous();
158159
}
159160

160161
bool init_spec(string_view filename, int subimage, int miplevel,
@@ -319,10 +320,11 @@ class ImageBufImpl {
319320

320321
void eval_contiguous()
321322
{
322-
m_contiguous = m_bufspan.data() != nullptr
323-
&& (m_storage == ImageBuf::LOCALBUFFER
324-
|| m_storage == ImageBuf::APPBUFFER)
325-
&& m_bufspan.is_contiguous();
323+
bool in_memory = m_bufspan.data() != nullptr
324+
&& (m_storage == ImageBuf::LOCALBUFFER
325+
|| m_storage == ImageBuf::APPBUFFER);
326+
m_contiguous = in_memory && m_bufspan.is_contiguous();
327+
m_contiguous_scanline = in_memory && m_bufspan.is_contiguous_scanline();
326328
}
327329

328330
bool has_thumbnail(DoLock do_lock = DoLock(true)) const;
@@ -353,7 +355,8 @@ class ImageBufImpl {
353355
bool m_readonly = true; // The bufspan is read-only
354356
bool m_badfile = false; // File not found
355357
float m_pixelaspect = 1.0f; // Pixel aspect ratio of the image
356-
bool m_contiguous = false;
358+
bool m_contiguous = false; // Full image is contiguous in memory
359+
bool m_contiguous_scanline = false; // Scanlines are contiguous in memory
357360
std::shared_ptr<ImageCache> m_imagecache; // ImageCache to use
358361
TypeDesc m_cachedpixeltype; // Data type stored in the cache
359362
DeepData m_deepdata; // Deep data
@@ -461,7 +464,6 @@ ImageBufImpl::ImageBufImpl(string_view filename, int subimage, int miplevel,
461464
, m_current_subimage(subimage)
462465
, m_current_miplevel(miplevel)
463466
, m_readonly(readonly)
464-
, m_contiguous(false)
465467
, m_imagecache(imagecache)
466468
{
467469
if (spec) {
@@ -514,6 +516,7 @@ ImageBufImpl::ImageBufImpl(const ImageBufImpl& src)
514516
, m_badfile(src.m_badfile)
515517
, m_pixelaspect(src.m_pixelaspect)
516518
, m_contiguous(src.m_contiguous)
519+
, m_contiguous_scanline(src.m_contiguous_scanline)
517520
, m_imagecache(src.m_imagecache)
518521
, m_cachedpixeltype(src.m_cachedpixeltype)
519522
, m_deepdata(src.m_deepdata)
@@ -774,7 +777,9 @@ ImageBufImpl::free_pixels()
774777
}
775778
m_pixels.reset();
776779
// print("IB Freed pixels of length {}\n", m_bufspan.size());
777-
m_bufspan = {};
780+
m_bufspan = {};
781+
m_contiguous = false;
782+
m_contiguous_scanline = false;
778783
m_deepdata.free();
779784
m_storage = ImageBuf::UNINITIALIZED;
780785
m_blackpixel.clear();
@@ -861,13 +866,14 @@ ImageBufImpl::clear()
861866
m_spec = ImageSpec();
862867
m_nativespec = ImageSpec();
863868
m_pixels.reset();
864-
m_bufspan = {};
865-
m_spec_valid = false;
866-
m_pixels_valid = false;
867-
m_badfile = false;
868-
m_pixels_read = false;
869-
m_pixelaspect = 1;
870-
m_contiguous = false;
869+
m_bufspan = {};
870+
m_spec_valid = false;
871+
m_pixels_valid = false;
872+
m_badfile = false;
873+
m_pixels_read = false;
874+
m_pixelaspect = 1;
875+
m_contiguous = false;
876+
m_contiguous_scanline = false;
871877
m_imagecache.reset();
872878
m_deepdata.free();
873879
m_blackpixel.clear();
@@ -1179,9 +1185,7 @@ ImageBufImpl::init_spec(string_view filename, int subimage, int miplevel,
11791185
return false;
11801186
}
11811187

1182-
m_bufspan = image_span<std::byte>(nullptr, m_spec.nchannels,
1183-
m_spec.width, m_spec.height,
1184-
m_spec.depth, m_spec.format.size());
1188+
set_bufspan(nullptr);
11851189
m_blackpixel.resize(round_to_multiple(m_spec.pixel_bytes(),
11861190
OIIO_SIMD_MAX_SIZE_BYTES),
11871191
0);
@@ -1263,9 +1267,7 @@ ImageBufImpl::init_spec(string_view filename, int subimage, int miplevel,
12631267
m_spec_valid = true;
12641268
m_fileformat = ustring(input->format_name());
12651269
m_nativespec = m_spec;
1266-
m_bufspan = image_span<std::byte>(nullptr, m_spec.nchannels,
1267-
m_spec.width, m_spec.height,
1268-
m_spec.depth, m_spec.format.size());
1270+
set_bufspan(nullptr);
12691271
m_blackpixel.resize(
12701272
round_to_multiple(m_spec.pixel_bytes(), OIIO_SIMD_MAX_SIZE_BYTES));
12711273
// ^^^ NB make it big enough for SIMD
@@ -1381,10 +1383,7 @@ ImageBufImpl::read(int subimage, int miplevel, int chbegin, int chend,
13811383
if (!localpixels() && !force && !use_channel_subset
13821384
&& (convert == m_cachedpixeltype || convert == TypeDesc::UNKNOWN)) {
13831385
m_spec.format = m_cachedpixeltype;
1384-
m_bufspan = image_span<std::byte>(nullptr, m_spec.nchannels,
1385-
m_spec.width, m_spec.height,
1386-
m_spec.depth,
1387-
m_spec.format.size());
1386+
set_bufspan(nullptr);
13881387
m_blackpixel.resize(round_to_multiple(m_spec.pixel_bytes(),
13891388
OIIO_SIMD_MAX_SIZE_BYTES));
13901389
// NB make it big enough for SSE
@@ -2197,11 +2196,21 @@ ImageBuf::z_stride() const
21972196
bool
21982197
ImageBuf::contiguous() const
21992198
{
2199+
m_impl->validate_pixels();
22002200
return m_impl->m_contiguous;
22012201
}
22022202

22032203

22042204

2205+
bool
2206+
ImageBuf::contiguous_scanline() const
2207+
{
2208+
m_impl->validate_pixels();
2209+
return m_impl->m_contiguous_scanline;
2210+
}
2211+
2212+
2213+
22052214
bool
22062215
ImageBuf::cachedpixels() const
22072216
{

src/libOpenImageIO/imagebufalgo_hwy_pvt.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ RoiRowPtr(const HwyLocalPixelsView<ByteT>& v, int y, const ROI& roi) noexcept
9393
/// and the number of channels defaults to the number of channels in the ROI.
9494
template<typename T>
9595
inline bool
96-
HwySupports(const ImageBuf& A, const ROI& roi=ROI(), int nchannels = 0)
96+
HwySupports(const ImageBuf& A, const ROI& roi = ROI(), int nchannels = 0)
9797
{
9898
if (nchannels <= 0)
9999
nchannels = roi.defined() ? roi.nchannels() : A.nchannels();

0 commit comments

Comments
 (0)