Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

cmake_minimum_required (VERSION 3.18.2...4.0)

set (OpenImageIO_VERSION "3.1.1.0")
set (OpenImageIO_VERSION "3.1.2.0")
set (OpenImageIO_VERSION_OVERRIDE "" CACHE STRING
"Version override (use with caution)!")
mark_as_advanced (OpenImageIO_VERSION_OVERRIDE)
Expand Down
4 changes: 2 additions & 2 deletions src/include/OpenImageIO/image_span.h
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ template<typename T> using image1d_span = image_span<T, 2>;
/// covering the same range of memory.
template<typename T, size_t Rank>
image_span<const std::byte>
as_image_span_bytes(image_span<T, Rank> src) noexcept
as_image_span_bytes(const image_span<T, Rank>& src) noexcept
{
return image_span<const std::byte>(
reinterpret_cast<const std::byte*>(src.data()), src.nchannels(),
Expand All @@ -378,7 +378,7 @@ as_image_span_bytes(image_span<T, Rank> src) noexcept
/// the same range of memory.
template<typename T, size_t Rank>
image_span<std::byte>
as_image_span_writable_bytes(image_span<T, Rank> src) noexcept
as_image_span_writable_bytes(const image_span<T, Rank>& src) noexcept
{
return image_span<std::byte>(reinterpret_cast<std::byte*>(src.data()),
src.nchannels(), src.width(), src.height(),
Expand Down
546 changes: 474 additions & 72 deletions src/include/OpenImageIO/imageio.h

Large diffs are not rendered by default.

15 changes: 14 additions & 1 deletion src/include/OpenImageIO/span.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ OIIO_NAMESPACE_BEGIN
using span_size_t = size_t;
using oiio_span_size_type = OIIO::span_size_t; // back-compat alias

inline constexpr span_size_t dynamic_extent = -1;
inline constexpr span_size_t dynamic_extent
= std::numeric_limits<span_size_t>::max();



Expand Down Expand Up @@ -586,6 +587,18 @@ as_bytes_ref(const T& ref) noexcept



/// Copy the memory contents of `src` to `dst`. They must have the same
/// total size.
template<typename T, typename S>
inline void
spancpy(span<T> dst, span<S> src)
{
OIIO_DASSERT(dst.size_bytes() == src.size_bytes());
memcpy(dst.data(), src.data(), src.size_bytes());
}



/// Try to copy `n` items of type `T` from `src[srcoffset...]` to
/// `dst[dstoffset...]`. Don't read or write outside the respective span
/// boundaries. Return the number of items actually copied, which should be
Expand Down
22 changes: 19 additions & 3 deletions src/include/OpenImageIO/typedesc.h
Original file line number Diff line number Diff line change
Expand Up @@ -394,44 +394,60 @@ inline constexpr TypeDesc TypeUstringhash(TypeDesc::USTRINGHASH);
///
template<typename T> struct BaseTypeFromC {};
template<> struct BaseTypeFromC<unsigned char> { static constexpr TypeDesc::BASETYPE value = TypeDesc::UINT8; };
template<> struct BaseTypeFromC<const unsigned char> { static constexpr TypeDesc::BASETYPE value = TypeDesc::UINT8; };
template<> struct BaseTypeFromC<char> { static constexpr TypeDesc::BASETYPE value = TypeDesc::INT8; };
template<> struct BaseTypeFromC<const char> { static constexpr TypeDesc::BASETYPE value = TypeDesc::INT8; };
template<> struct BaseTypeFromC<uint16_t> { static constexpr TypeDesc::BASETYPE value = TypeDesc::UINT16; };
template<> struct BaseTypeFromC<const uint16_t> { static constexpr TypeDesc::BASETYPE value = TypeDesc::UINT16; };
template<> struct BaseTypeFromC<int16_t> { static constexpr TypeDesc::BASETYPE value = TypeDesc::INT16; };
template<> struct BaseTypeFromC<const int16_t> { static constexpr TypeDesc::BASETYPE value = TypeDesc::INT16; };
template<> struct BaseTypeFromC<uint32_t> { static constexpr TypeDesc::BASETYPE value = TypeDesc::UINT; };
template<> struct BaseTypeFromC<const uint32_t> { static constexpr TypeDesc::BASETYPE value = TypeDesc::UINT; };
template<> struct BaseTypeFromC<int32_t> { static constexpr TypeDesc::BASETYPE value = TypeDesc::INT; };
template<> struct BaseTypeFromC<const int32_t> { static constexpr TypeDesc::BASETYPE value = TypeDesc::INT; };
template<> struct BaseTypeFromC<uint64_t> { static constexpr TypeDesc::BASETYPE value = TypeDesc::UINT64; };
template<> struct BaseTypeFromC<const uint64_t> { static constexpr TypeDesc::BASETYPE value = TypeDesc::UINT64; };
template<> struct BaseTypeFromC<int64_t> { static constexpr TypeDesc::BASETYPE value = TypeDesc::INT64; };
template<> struct BaseTypeFromC<const int64_t> { static constexpr TypeDesc::BASETYPE value = TypeDesc::INT64; };
#if defined(__GNUC__) && __WORDSIZE == 64 && !(defined(__APPLE__) && defined(__MACH__))
// Some platforms consider int64_t and long long to be different types, even
// though they are actually the same size.
static_assert(!std::is_same_v<unsigned long long, uint64_t>);
static_assert(!std::is_same_v<long long, int64_t>);
template<> struct BaseTypeFromC<unsigned long long> { static constexpr TypeDesc::BASETYPE value = TypeDesc::UINT64; };
template<> struct BaseTypeFromC<const unsigned long long> { static constexpr TypeDesc::BASETYPE value = TypeDesc::UINT64; };
template<> struct BaseTypeFromC<long long> { static constexpr TypeDesc::BASETYPE value = TypeDesc::INT64; };
template<> struct BaseTypeFromC<const long long> { static constexpr TypeDesc::BASETYPE value = TypeDesc::INT64; };
#endif
#if defined(_HALF_H_) || defined(IMATH_HALF_H_)
template<> struct BaseTypeFromC<half> { static constexpr TypeDesc::BASETYPE value = TypeDesc::HALF; };
template<> struct BaseTypeFromC<const half> { static constexpr TypeDesc::BASETYPE value = TypeDesc::HALF; };
#endif
template<> struct BaseTypeFromC<float> { static constexpr TypeDesc::BASETYPE value = TypeDesc::FLOAT; };
template<> struct BaseTypeFromC<const float> { static constexpr TypeDesc::BASETYPE value = TypeDesc::FLOAT; };
template<> struct BaseTypeFromC<double> { static constexpr TypeDesc::BASETYPE value = TypeDesc::DOUBLE; };
template<> struct BaseTypeFromC<const char*> { static constexpr TypeDesc::BASETYPE value = TypeDesc::STRING; };
template<> struct BaseTypeFromC<const double> { static constexpr TypeDesc::BASETYPE value = TypeDesc::DOUBLE; };
template<> struct BaseTypeFromC<char*> { static constexpr TypeDesc::BASETYPE value = TypeDesc::STRING; };
template<> struct BaseTypeFromC<const char*> { static constexpr TypeDesc::BASETYPE value = TypeDesc::STRING; };
template<> struct BaseTypeFromC<std::string> { static constexpr TypeDesc::BASETYPE value = TypeDesc::STRING; };
template<> struct BaseTypeFromC<const std::string> { static constexpr TypeDesc::BASETYPE value = TypeDesc::STRING; };
template<> struct BaseTypeFromC<string_view> { static constexpr TypeDesc::BASETYPE value = TypeDesc::STRING; };
template<> struct BaseTypeFromC<const string_view> { static constexpr TypeDesc::BASETYPE value = TypeDesc::STRING; };
class ustring;
template<> struct BaseTypeFromC<ustring> { static constexpr TypeDesc::BASETYPE value = TypeDesc::STRING; };
template<> struct BaseTypeFromC<const ustring> { static constexpr TypeDesc::BASETYPE value = TypeDesc::STRING; };
template<size_t S> struct BaseTypeFromC<char[S]> { static constexpr TypeDesc::BASETYPE value = TypeDesc::STRING; };
template<size_t S> struct BaseTypeFromC<const char[S]> { static constexpr TypeDesc::BASETYPE value = TypeDesc::STRING; };
template<typename P> struct BaseTypeFromC<P*> { static constexpr TypeDesc::BASETYPE value = TypeDesc::PTR; };

/// `BaseTypeFromC_v<T>` is shorthand for `BaseTypeFromC<T>::value()`.
template<typename T>
constexpr TypeDesc::BASETYPE BaseTypeFromC_v = BaseTypeFromC<std::remove_cv_t<T>>::value();
constexpr TypeDesc::BASETYPE BaseTypeFromC_v = BaseTypeFromC<std::remove_cv_t<T>>::value;

/// A template mechanism for getting the TypeDesc from a C type.
/// The default for simple types is just the TypeDesc based on BaseTypeFromC.
/// But we can specialize more complex types.
template<typename T> struct TypeDescFromC { static const constexpr TypeDesc value() { return TypeDesc(BaseTypeFromC<T>::value); } };
template<typename T> struct TypeDescFromC { static const constexpr TypeDesc value() { return TypeDesc(BaseTypeFromC_v<T>); } };
template<> struct TypeDescFromC<int32_t> { static const constexpr TypeDesc value() { return TypeDesc::INT32; } };
template<> struct TypeDescFromC<uint32_t> { static const constexpr TypeDesc value() { return TypeDesc::UINT32; } };
template<> struct TypeDescFromC<int16_t> { static const constexpr TypeDesc value() { return TypeDesc::INT16; } };
Expand Down
2 changes: 1 addition & 1 deletion src/include/imageio_pvt.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ get_default_quantize(TypeDesc format, long long& quant_min,
/// which is either dst or src (if the strides indicated that data were
/// already contiguous).
OIIO_API span<const std::byte>
contiguize(image_span<const std::byte> src, span<std::byte> dst);
contiguize(const image_span<const std::byte>& src, span<std::byte> dst);

/// Turn potentially non-contiguous-stride data (e.g. "RGBxRGBx") into
/// contiguous-stride ("RGBRGB"), for any format or stride values
Expand Down
120 changes: 120 additions & 0 deletions src/libOpenImageIO/image_span_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,124 @@ test_image_span_convert_image()



// Sum all values in an image using a pass-by-value image_span
float
sum_image_span_val(image_span<const float> img)
{
float sum = 0;
for (uint32_t z = 0; z < img.depth(); ++z) {
for (uint32_t y = 0; y < img.height(); ++y) {
for (uint32_t x = 0; x < img.width(); ++x) {
for (uint32_t c = 0; c < img.nchannels(); ++c) {
sum += img.get(c, x, y, z);
}
}
}
}
return sum;
}


// Sum all values in an image using a pass-by-reference image_span
float
sum_image_span_ref(const image_span<const float>& img)
{
float sum = 0;
for (uint32_t z = 0; z < img.depth(); ++z) {
for (uint32_t y = 0; y < img.height(); ++y) {
for (uint32_t x = 0; x < img.width(); ++x) {
for (uint32_t c = 0; c < img.nchannels(); ++c) {
sum += img.get(c, x, y, z);
}
}
}
}
return sum;
}


// Sum all values in an image using raw pointers, sizes, strides
float
sum_image_span_ptr(const float* ptr, uint32_t chans, uint32_t width,
uint32_t height, uint32_t depth, int64_t chstride,
int64_t xstride, int64_t ystride, int64_t zstride)
{
float sum = 0;
for (uint32_t z = 0; z < depth; ++z) {
for (uint32_t y = 0; y < height; ++y) {
for (uint32_t x = 0; x < width; ++x) {
for (uint32_t c = 0; c < chans; ++c) {
const float* p = reinterpret_cast<const float*>(
(const char*)ptr + c * chstride + x * xstride
+ y * ystride + z * zstride);
sum += *p;
}
}
}
}
return sum;
}



void
benchmark_image_span_passing()
{
print("\nbenchmark_image_span_passing\n");
const int xres = 2048, yres = 1536, nchans = 4;
std::vector<float> sbuf(xres * yres * nchans, 1.0f);
image_span<const float> ispan(sbuf.data(), nchans, xres, yres, 1);

Benchmarker bench;
bench.units(Benchmarker::Unit::us);
float sum = 0.0f;

bench(" pass by value (big)",
[=, &sum]() { sum += sum_image_span_val(ispan); });
bench(" pass by value imm (big)", [=, &sum]() {
sum += sum_image_span_val(
image_span<const float>(sbuf.data(), nchans, xres, yres, 1));
});
bench(" pass by ref (big)",
[=, &sum]() { sum += sum_image_span_ref(ispan); });
bench(" pass by ref imm (big)", [=, &sum]() {
sum += sum_image_span_ref(
image_span<const float>(sbuf.data(), nchans, xres, yres, 1));
});
bench(" pass by ptr (big)", [=, &sum]() {
sum += sum_image_span_ptr(sbuf.data(), nchans, xres, yres, 1,
sizeof(float), nchans * sizeof(float),
nchans * sizeof(float) * xres,
nchans * sizeof(float) * xres * yres);
});

// Do it all again for a SMALL image
bench.units(Benchmarker::Unit::ns);
int small = 16;
image_span<const float> smispan(sbuf.data(), nchans, small, small, 1);
bench(" pass by value (small)",
[=, &sum]() { sum += sum_image_span_val(smispan); });
bench(" pass by value imm (small)", [=, &sum]() {
sum += sum_image_span_val(
image_span<const float>(sbuf.data(), nchans, small, small, 1));
});
bench(" pass by ref (small)",
[=, &sum]() { sum += sum_image_span_ref(smispan); });
bench(" pass by ref imm (small)", [=, &sum]() {
sum += sum_image_span_ref(
image_span<const float>(sbuf.data(), nchans, small, small, 1));
});
bench(" pass by ptr (small)", [=, &sum]() {
sum += sum_image_span_ptr(sbuf.data(), nchans, small, small, 1,
sizeof(float), nchans * sizeof(float),
nchans * sizeof(float) * small,
nchans * sizeof(float) * small * small);
});
print(" [sum={}]\n", sum); // seems necessary to not optimize away
}



int
main(int /*argc*/, char* /*argv*/[])
{
Expand Down Expand Up @@ -378,5 +496,7 @@ main(int /*argc*/, char* /*argv*/[])
test_image_span_convert_image<uint16_t, half>();
test_image_span_convert_image<half, uint16_t>();

benchmark_image_span_passing();

return unit_test_failures;
}
8 changes: 5 additions & 3 deletions src/libOpenImageIO/imageio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,7 @@ _contiguize(const T* src, int nchannels, stride_t xstride, stride_t ystride,


span<const std::byte>
pvt::contiguize(image_span<const std::byte> src, span<std::byte> dst)
pvt::contiguize(const image_span<const std::byte>& src, span<std::byte> dst)
{
// Contiguized result must fit in dst
OIIO_DASSERT(src.size_bytes() <= dst.size_bytes());
Expand Down Expand Up @@ -1053,7 +1053,8 @@ copy_image(int nchannels, int width, int height, int depth, const void* src,

template<typename T>
void
aligned_copy_image(image_span<std::byte> dst, image_span<const std::byte> src)
aligned_copy_image(const image_span<std::byte>& dst,
const image_span<const std::byte>& src)
{
size_t systride = src.ystride();
size_t dystride = dst.ystride();
Expand Down Expand Up @@ -1081,7 +1082,8 @@ aligned_copy_image(image_span<std::byte> dst, image_span<const std::byte> src)


bool
copy_image(image_span<std::byte> dst, image_span<const std::byte> src)
copy_image(const image_span<std::byte>& dst,
const image_span<const std::byte>& src)
{
OIIO_DASSERT(src.width() == dst.width() && src.height() == dst.height()
&& src.depth() == dst.depth()
Expand Down
Loading
Loading