Skip to content

Commit

Permalink
checkpoint
Browse files Browse the repository at this point in the history
Signed-off-by: Larry Gritz <lg@larrygritz.com>
  • Loading branch information
lgritz committed Aug 28, 2024
1 parent e88b1de commit 57814de
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 22 deletions.
8 changes: 6 additions & 2 deletions src/include/OpenImageIO/fmath.h
Original file line number Diff line number Diff line change
Expand Up @@ -693,9 +693,13 @@ sincos (double x, double* sine, double* cosine)
}


inline OIIO_HOSTDEVICE float sign (float x)

/// Return -1 if x<0, 0 if x==0, 1 if x>0. For floating point types, this is
/// not friendly to NaN inputs!
template<typename T>
inline OIIO_HOSTDEVICE T sign(T x)
{
return x < 0.0f ? -1.0f : (x==0.0f ? 0.0f : 1.0f);
return x < T(0) ? T(-1) : (x == T(0) ? T(0) : T(1));
}


Expand Down
43 changes: 40 additions & 3 deletions src/include/OpenImageIO/imagebuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,46 @@ class OIIO_API ImageBuf {
set_name(name);
}

/// Destroy any previous contents of the ImageBuf and re-initialize it
/// as if newly constructed with the same arguments, to "wrap" existing
/// pixel memory owned by the calling application.
/// Destroy any previous contents of the ImageBuf and re-initialize it as
/// if newly constructed with the same arguments, to "wrap" existing pixel
/// memory owned by the calling application.
///
/// @param spec
/// An ImageSpec describing the image and its metadata.
/// @param buffer
/// A span delineating the extent of the memory comprising the
/// pixel data.
/// @param buforigin
/// A pointer to the first pixel of the buffer. If null, it
/// will be assumed to be the beginning of the buffer. (This
/// is useful if any negative strides are used to give an
/// unusual layout of pixels within the buffer)
/// @param xstride/ystride/zstride
/// The distance in bytes between successive pixels,
/// scanlines, and image planes in the buffer (or
/// `AutoStride` to indicate "contiguous" data in any of
/// those dimensions).
template<typename T /*, OIIO_ENABLE_IF(!std::same_as_v<T, std::byte>)*/>
void reset(const ImageSpec& spec, span<T> buffer, void* buforigin = nullptr,
stride_t xstride = AutoStride, stride_t ystride = AutoStride,
stride_t zstride = AutoStride)
{
// The general case for non-byte data types just converts to bytes and
// calls the byte version.
reset(spec, as_writable_bytes(buffer), buforigin, xstride, ystride,
zstride);
}
// Special base case for byte spans, this one does the hard work.
template<>
void reset(const ImageSpec& spec, span<std::byte> buffer, void* buforigin,
stride_t xstride, stride_t ystride, stride_t zstride);

/// Unsafe reset of a "wrapped" buffer, mostly for backward compatibility.
/// This version does not pass a span that explicitly delineates the
/// memory bounds, but only passes a raw pointer and assumes that the
/// caller has ensured that the buffer pointed to is big enough to
/// accommodate accessing any valid pixel as describes by the spec and the
/// strides. Use with caution!
void reset(const ImageSpec& spec, void* buffer,
stride_t xstride = AutoStride, stride_t ystride = AutoStride,
stride_t zstride = AutoStride);
Expand Down
105 changes: 88 additions & 17 deletions src/libOpenImageIO/imagebuf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ class ImageBufImpl {
public:
ImageBufImpl(string_view filename, int subimage, int miplevel,
std::shared_ptr<ImageCache> imagecache = {},
const ImageSpec* spec = nullptr, void* buffer = nullptr,
const ImageSpec* config = nullptr,
const ImageSpec* spec = nullptr, span<std::byte> bufspan = {},
void* buforigin = nullptr, const ImageSpec* config = nullptr,
Filesystem::IOProxy* ioproxy = nullptr,
stride_t xstride = AutoStride, stride_t ystride = AutoStride,
stride_t zstride = AutoStride);
Expand All @@ -106,7 +106,8 @@ class ImageBufImpl {
// supplied, use it for the "native" spec, otherwise make the nativespec
// just copy the regular spec.
void reset(string_view name, const ImageSpec& spec,
const ImageSpec* nativespec = nullptr, void* buffer = nullptr,
const ImageSpec* nativespec = nullptr,
span<std::byte> bufspan = {}, void* buforigin = nullptr,
stride_t xstride = AutoStride, stride_t ystride = AutoStride,
stride_t zstride = AutoStride);
void alloc(const ImageSpec& spec, const ImageSpec* nativespec = nullptr);
Expand All @@ -120,6 +121,10 @@ class ImageBufImpl {
DoLock do_lock = DoLock(true));
void copy_metadata(const ImageBufImpl& src);

// At least one of bufspan or buforigin is supplied. Set this->m_bufspan
// and this->m_localpixels appropriately.
void set_bufspan_localpixels(span<std::byte> bufspan, void* buforigin);

// Note: Uses std::format syntax
template<typename... Args>
void error(const char* fmt, const Args&... args) const
Expand Down Expand Up @@ -286,6 +291,7 @@ class ImageBufImpl {
ImageSpec m_nativespec; ///< Describes the true native image
std::unique_ptr<char[]> m_pixels; ///< Pixel data, if local and we own it
char* m_localpixels; ///< Pointer to local pixels
span<std::byte> m_bufspan; ///< Bounded buffer for local pixels
typedef std::recursive_mutex mutex_t;
typedef std::unique_lock<mutex_t> lock_t;
mutable mutex_t m_mutex; ///< Thread safety for this ImageBuf
Expand Down Expand Up @@ -349,8 +355,8 @@ ImageBuf::impl_deleter(ImageBufImpl* todel)

ImageBufImpl::ImageBufImpl(string_view filename, int subimage, int miplevel,
std::shared_ptr<ImageCache> imagecache,
const ImageSpec* spec, void* buffer,
const ImageSpec* config,
const ImageSpec* spec, span<std::byte> bufspan,
void* buforigin, const ImageSpec* config,
Filesystem::IOProxy* ioproxy, stride_t xstride,
stride_t ystride, stride_t zstride)
: m_storage(ImageBuf::UNINITIALIZED)
Expand Down Expand Up @@ -391,8 +397,8 @@ ImageBufImpl::ImageBufImpl(string_view filename, int subimage, int miplevel,
OIIO_SIMD_MAX_SIZE_BYTES),
0);
// NB make it big enough for SSE
if (buffer) {
m_localpixels = (char*)buffer;
if (buforigin || bufspan.size()) {
set_bufspan_localpixels(bufspan, buforigin);
m_storage = ImageBuf::APPBUFFER;
m_pixels_valid = true;
} else {
Expand All @@ -401,11 +407,13 @@ ImageBufImpl::ImageBufImpl(string_view filename, int subimage, int miplevel,
m_spec_valid = true;
} else if (filename.length() > 0) {
// filename being nonempty means this ImageBuf refers to a file.
OIIO_DASSERT(buffer == nullptr);
OIIO_DASSERT(buforigin == nullptr);
OIIO_DASSERT(bufspan.empty());
reset(filename, subimage, miplevel, std::move(imagecache), config,
ioproxy);
} else {
OIIO_DASSERT(buffer == nullptr);
OIIO_DASSERT(buforigin == nullptr);
OIIO_DASSERT(bufspan.empty());
}
eval_contiguous();
}
Expand Down Expand Up @@ -449,14 +457,17 @@ ImageBufImpl::ImageBufImpl(const ImageBufImpl& src)
if (m_storage == ImageBuf::APPBUFFER) {
// Source just wrapped the client app's pixels, we do the same
m_localpixels = src.m_localpixels;
m_bufspan = src.m_bufspan;
} else {
// We own our pixels -- copy from source
new_pixels(src.m_spec.image_bytes(), src.m_pixels.get());
// N.B. new_pixels will set m_bufspan
}
} else {
// Source was cache-based or deep
// nothing else to do
m_localpixels = nullptr;
m_bufspan = span<std::byte>();
}
if (m_localpixels || m_spec.deep) {
// A copied ImageBuf is no longer a direct file reference, so clear
Expand Down Expand Up @@ -509,7 +520,8 @@ ImageBuf::ImageBuf(string_view filename, int subimage, int miplevel,
const ImageSpec* config, Filesystem::IOProxy* ioproxy)
: m_impl(new ImageBufImpl(filename, subimage, miplevel,
std::move(imagecache), nullptr /*spec*/,
nullptr /*buffer*/, config, ioproxy),
{} /*bufspan*/, nullptr /*buforigin*/, config,
ioproxy),
&impl_deleter)
{
}
Expand All @@ -520,6 +532,7 @@ ImageBuf::ImageBuf(const ImageSpec& spec, InitializePixels zero)
: m_impl(new ImageBufImpl("", 0, 0, NULL, &spec), &impl_deleter)
{
m_impl->alloc(spec);
// N.B. alloc will set m_bufspan
if (zero == InitializePixels::Yes && !deep())
ImageBufAlgo::zero(*this);
}
Expand All @@ -528,8 +541,9 @@ ImageBuf::ImageBuf(const ImageSpec& spec, InitializePixels zero)

ImageBuf::ImageBuf(const ImageSpec& spec, void* buffer, stride_t xstride,
stride_t ystride, stride_t zstride)
: m_impl(new ImageBufImpl("", 0, 0, NULL, &spec, buffer, nullptr, nullptr,
xstride, ystride, zstride),
: m_impl(new ImageBufImpl("", 0, 0, NULL, &spec, {} /*bufspan*/,
buffer /*buforigin*/, nullptr /*config*/,
nullptr /*ioproxy*/, xstride, ystride, zstride),
&impl_deleter)
{
}
Expand Down Expand Up @@ -579,6 +593,8 @@ ImageBufImpl::new_pixels(size_t size, const void* data)
free_pixels();
try {
m_pixels.reset(size ? new char[size] : nullptr);
// Set bufspan to the allocated memory
m_bufspan = { reinterpret_cast<std::byte*>(m_pixels.get()), size };
} catch (const std::exception& e) {
// Could not allocate enough memory. So don't allocate anything,
// consider this an uninitialized ImageBuf, issue an error, and hope
Expand All @@ -588,6 +604,7 @@ ImageBufImpl::new_pixels(size_t size, const void* data)
e.what());
error("ImageBuf unable to allocate {} bytes ({})\n", size, e.what());
size = 0;
m_bufspan = {};
}
m_allocated_size = size;
pvt::IB_local_mem_current += m_allocated_size;
Expand Down Expand Up @@ -757,7 +774,7 @@ ImageBufImpl::reset(string_view filename, int subimage, int miplevel,
add_configspec();
m_configspec->attribute("oiio:ioproxy", TypeDesc::PTR, &m_rioproxy);
}

m_bufspan = {};
if (m_name.length() > 0) {
// filename non-empty means this ImageBuf refers to a file.
read(subimage, miplevel);
Expand All @@ -779,9 +796,48 @@ ImageBuf::reset(string_view filename, int subimage, int miplevel,



void
ImageBufImpl::set_bufspan_localpixels(span<std::byte> bufspan, void* buforigin)
{
if (bufspan.size() && !buforigin) {
buforigin = bufspan.data();
} else if (buforigin && (!bufspan.data() || bufspan.empty())) {
// Need to figure out the span based on the origin and strides.
// Start with the span range of one pixel.
std::byte* bufstart = (std::byte*)buforigin;
std::byte* bufend = bufstart + m_spec.format.size();
// Expand to the span range for one row. Remember negative strides!
if (m_xstride >= 0) {
bufend += m_xstride * (m_spec.width - 1);
} else {
bufstart -= m_xstride * (m_spec.width - 1);
}
// Expand to the span range for a whole image plane.
if (m_ystride >= 0) {
bufend += m_ystride * (m_spec.height - 1);
} else {
bufstart -= m_ystride * (m_spec.height - 1);
}
// Expand to the span range for a whole volume.
if (m_spec.depth > 1 && m_zstride != 0) {
if (m_zstride >= 0) {
bufend += m_zstride * (m_spec.depth - 1);
} else {
bufstart -= m_zstride * (m_spec.depth - 1);
}
}
bufspan = span{ bufstart, size_t(bufend - bufstart) };
}
m_bufspan = bufspan;
m_localpixels = (char*)buforigin;
}



void
ImageBufImpl::reset(string_view filename, const ImageSpec& spec,
const ImageSpec* nativespec, void* buffer, stride_t xstride,
const ImageSpec* nativespec, span<std::byte> bufspan,
void* buforigin, stride_t xstride,
stride_t ystride, stride_t zstride)
{
clear();
Expand All @@ -794,7 +850,7 @@ ImageBufImpl::reset(string_view filename, const ImageSpec& spec,
m_name = ustring(filename);
m_current_subimage = 0;
m_current_miplevel = 0;
if (buffer) {
if (buforigin || bufspan.size()) {
m_spec = spec;
m_nativespec = nativespec ? *nativespec : spec;
m_channel_stride = stride_t(spec.format.size());
Expand All @@ -806,12 +862,13 @@ ImageBufImpl::reset(string_view filename, const ImageSpec& spec,
m_blackpixel.resize(round_to_multiple(spec.pixel_bytes(),
OIIO_SIMD_MAX_SIZE_BYTES),
0);
m_localpixels = (char*)buffer;
set_bufspan_localpixels(bufspan, buforigin);
m_storage = ImageBuf::APPBUFFER;
m_pixels_valid = true;
} else {
m_storage = ImageBuf::LOCALBUFFER;
alloc(spec);
// N.B. alloc sets m_bufspan
}
if (nativespec)
m_nativespec = *nativespec;
Expand All @@ -833,7 +890,18 @@ void
ImageBuf::reset(const ImageSpec& spec, void* buffer, stride_t xstride,
stride_t ystride, stride_t zstride)
{
m_impl->reset("", spec, nullptr, buffer, xstride, ystride, zstride);
m_impl->reset("", spec, nullptr, {}, buffer, xstride, ystride, zstride);
}



template<>
void
ImageBuf::reset(const ImageSpec& spec, span<std::byte> buffer, void* buforigin,
stride_t xstride, stride_t ystride, stride_t zstride)
{
m_impl->reset("", spec, nullptr, buffer, buforigin, xstride, ystride,
zstride);
}


Expand All @@ -842,6 +910,7 @@ void
ImageBufImpl::realloc()
{
new_pixels(m_spec.deep ? size_t(0) : m_spec.image_bytes());
// N.B. new_pixels will set m_bufspan
m_channel_stride = m_spec.format.size();
m_xstride = AutoStride;
m_ystride = AutoStride;
Expand Down Expand Up @@ -880,6 +949,7 @@ ImageBufImpl::alloc(const ImageSpec& spec, const ImageSpec* nativespec)

m_nativespec = nativespec ? *nativespec : spec;
realloc();
// N.B. realloc sets m_bufspan
m_spec_valid = true;
}

Expand Down Expand Up @@ -1152,6 +1222,7 @@ ImageBufImpl::read(int subimage, int miplevel, int chbegin, int chend,
else
m_spec.format = m_nativespec.format;
realloc();
// N.B. realloc sets m_bufspan

// If forcing a full read, make sure the spec reflects the nativespec's
// tile sizes, rather than that imposed by the ImageCache.
Expand Down

0 comments on commit 57814de

Please sign in to comment.