From 52f13d79b015194b899d17c8b0ddda4b9dd671f7 Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Tue, 13 Aug 2024 21:57:39 -0700 Subject: [PATCH] refactor: de-virtualize IC and TS Background: The ImageCache and TextureSystem had historically been implemented as pure virtual abstract base classe defining an interface, then a hidden concrete subclass. The flexibility this was intended to provide was never really used; instead the imagined main client for the flexibility, OSL, has a different mechanism for customizing the texture system (via their RendererServices class). Meanwhile, this has made the interfaces to IC and TS impossible to change without breaking the ABI. So this PR does the following: * ImageCache and TextureSytem are full de-virtualized, and are now concrete classes, no hidden subclassing, no virtual methods. As such, removing or changing existing methods will be an ABI break, but adding new methods is not. * Each use a PIMPL idiom, where all the data amd internal methods are hidden from the public enterface and do not affect the ABI. * Roughly speaking, we added the PIMPL pointers and made the ImageCacheImpl/TextureSystemImpl -- what used to be the hidden concrete subclasses -- into the hidden PIMPL classes. * Moved a lot of classes that used to be in a "pvt" namespace into the main namespace. If they are opaque types not exposed in public headers or as symbols exported from the library, it doesn't matter, so this just removes some arbitrary clutter. * Had to rearrange some of the recently added heapsize/footprint code, moved some inline functions in the headers into methods of the classes, defined in the cpp files. This itself is a huge ABI change, so will only be merged into master, to become part of the 3.0 release. This is not an API change, though! This is all about the internals, and should not require any client software to change a single line of code. I may do further simplification or refactoring of this code in the future, but that will all be smaller and have no further API/ABI changes that break compatibility. Although the structure of the class hierarchy has changed around, none of the logic about how IC and TS actually *work* has changed, so there should be no change in observable behavior. Signed-off-by: Larry Gritz --- src/include/OpenImageIO/imagebuf.h | 7 +- src/include/OpenImageIO/imagecache.h | 264 ++++++------ src/include/OpenImageIO/texture.h | 366 ++++++++--------- src/libtexture/environment.cpp | 52 ++- src/libtexture/imagecache.cpp | 502 ++++++++++++++++++++++- src/libtexture/imagecache_memory_print.h | 100 +---- src/libtexture/imagecache_memory_pvt.h | 34 +- src/libtexture/imagecache_pvt.h | 186 +++++---- src/libtexture/texture3d.cpp | 51 ++- src/libtexture/texture_pvt.h | 204 ++++----- src/libtexture/texturesys.cpp | 500 ++++++++++++++++++---- 11 files changed, 1534 insertions(+), 732 deletions(-) diff --git a/src/include/OpenImageIO/imagebuf.h b/src/include/OpenImageIO/imagebuf.h index 61946a17a4..c3f4402bc3 100644 --- a/src/include/OpenImageIO/imagebuf.h +++ b/src/include/OpenImageIO/imagebuf.h @@ -25,10 +25,7 @@ OIIO_NAMESPACE_BEGIN class ImageBuf; class ImageBufImpl; // Opaque type for the unique_ptr. class ImageCache; - -namespace pvt { class ImageCacheTile; -}; // namespace pvt @@ -1369,7 +1366,7 @@ class OIIO_API ImageBuf { int m_rng_xbegin, m_rng_xend, m_rng_ybegin, m_rng_yend, m_rng_zbegin, m_rng_zend; int m_x, m_y, m_z; - pvt::ImageCacheTile* m_tile = nullptr; + ImageCacheTile* m_tile = nullptr; int m_tilexbegin, m_tileybegin, m_tilezbegin; int m_tilexend; int m_nchannels; @@ -1638,7 +1635,7 @@ class OIIO_API ImageBuf { // tile for the given pixel, and return the ptr to the actual pixel // within the tile. If any read errors occur, set haderror=true (but // if there are no errors, do not modify haderror). - const void* retile(int x, int y, int z, pvt::ImageCacheTile*& tile, + const void* retile(int x, int y, int z, ImageCacheTile*& tile, int& tilexbegin, int& tileybegin, int& tilezbegin, int& tilexend, bool& haderr, bool exists, WrapMode wrap) const; diff --git a/src/include/OpenImageIO/imagecache.h b/src/include/OpenImageIO/imagecache.h index 63ff62c491..54671c5926 100644 --- a/src/include/OpenImageIO/imagecache.h +++ b/src/include/OpenImageIO/imagecache.h @@ -2,10 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 // https://github.com/AcademySoftwareFoundation/OpenImageIO -// clang-format off - - - #pragma once #include @@ -31,16 +27,13 @@ OIIO_NAMESPACE_BEGIN -// Forward declaration +// Forward declarations class TextureOpt; -namespace pvt { -// Forward declaration -class ImageCacheImpl; +class ImageCachePerThreadInfo; class ImageCacheFile; class ImageCacheTile; -class ImageCachePerThreadInfo; -}; // namespace pvt +class ImageCacheImpl; @@ -89,7 +82,8 @@ class OIIO_API ImageCache { /// nobody else is still holding a reference (otherwise, it will /// leave it intact). This parameter has no effect if `cache` was /// not the single globally shared ImageCache. - static void destroy(std::shared_ptr& cache, bool teardown = false); + static void destroy(std::shared_ptr& cache, + bool teardown = false); /// @} @@ -354,16 +348,30 @@ class OIIO_API ImageCache { /// (including it being an unrecognized attribute or not /// of the correct type). /// - virtual bool attribute (string_view name, TypeDesc type, - const void *val) = 0; + bool attribute(string_view name, TypeDesc type, const void* val); /// Specialized `attribute()` for setting a single `int` value. - virtual bool attribute (string_view name, int val) = 0; + bool attribute(string_view name, int val) + { + return attribute(name, TypeInt, &val); + } /// Specialized `attribute()` for setting a single `float` value. - virtual bool attribute (string_view name, float val) = 0; - virtual bool attribute (string_view name, double val) = 0; + bool attribute(string_view name, float val) + { + return attribute(name, TypeFloat, &val); + } + bool attribute(string_view name, double val) + { + float f = (float)val; + return attribute(name, TypeFloat, &f); + } /// Specialized `attribute()` for setting a single string value. - virtual bool attribute (string_view name, string_view val) = 0; + bool attribute(string_view name, string_view val) + { + std::string valstr(val); + const char* s = valstr.c_str(); + return attribute(name, TypeString, &s); + } /// Get the named attribute, store it in `*val`. All of the attributes /// that may be set with the `attribute() call` may also be queried with @@ -399,26 +407,48 @@ class OIIO_API ImageCache { /// attribute was retrieved, or `false` upon failure /// (including it being an unrecognized attribute or not /// of the correct type). - virtual bool getattribute (string_view name, TypeDesc type, - void *val) const = 0; + bool getattribute(string_view name, TypeDesc type, void* val) const; /// Specialized `attribute()` for retrieving a single `int` value. - virtual bool getattribute (string_view name, int &val) const = 0; + bool getattribute(string_view name, int& val) const + { + return getattribute(name, TypeInt, &val); + } /// Specialized `attribute()` for retrieving a single `float` value. - virtual bool getattribute (string_view name, float &val) const = 0; - virtual bool getattribute (string_view name, double &val) const = 0; + bool getattribute(string_view name, float& val) const + { + return getattribute(name, TypeFloat, &val); + } + bool getattribute(string_view name, double& val) const + { + float f; + bool ok = getattribute(name, TypeFloat, &f); + if (ok) + val = f; + return ok; + } /// Specialized `attribute()` for retrieving a single `string` value /// as a `char*`. - virtual bool getattribute (string_view name, char **val) const = 0; + bool getattribute(string_view name, char** val) const + { + return getattribute(name, TypeString, val); + } /// Specialized `attribute()` for retrieving a single `string` value /// as a `std::string`. - virtual bool getattribute (string_view name, std::string &val) const = 0; + bool getattribute(string_view name, std::string& val) const + { + ustring s; + bool ok = getattribute(name, TypeString, &s); + if (ok) + val = s.string(); + return ok; + } /// If the named attribute is known, return its data type. If no such /// attribute exists, return `TypeUnknown`. /// /// This was added in version 2.5. - virtual TypeDesc getattributetype(string_view name) const = 0; + TypeDesc getattributetype(string_view name) const; /// @} @@ -456,7 +486,7 @@ class OIIO_API ImageCache { /// Define an opaque data type that allows us to have a pointer to /// certain per-thread information that the ImageCache maintains. Any /// given one of these should NEVER be shared between running threads. - typedef pvt::ImageCachePerThreadInfo Perthread; + using Perthread = ImageCachePerThreadInfo; /// Retrieve a Perthread, unique to the calling thread. This is a /// thread-specific pointer that will always return the Perthread for a @@ -469,19 +499,19 @@ class OIIO_API ImageCache { /// thread_info is not NULL, it won't create a new one or retrieve a /// TSP, but it will do other necessary housekeeping on the Perthread /// information. - virtual Perthread* get_perthread_info(Perthread* thread_info = NULL) = 0; + Perthread* get_perthread_info(Perthread* thread_info = NULL); /// Create a new Perthread. It is the caller's responsibility to /// eventually destroy it using `destroy_thread_info()`. - virtual Perthread* create_thread_info() = 0; + Perthread* create_thread_info(); /// Destroy a Perthread that was allocated by `create_thread_info()`. - virtual void destroy_thread_info(Perthread* thread_info) = 0; + void destroy_thread_info(Perthread* thread_info); /// Define an opaque data type that allows us to have a handle to an /// image (already having its name resolved) but without exposing any /// internals. - typedef pvt::ImageCacheFile ImageHandle; + using ImageHandle = ImageCacheFile; /// Retrieve an opaque handle for fast texture lookups, or nullptr upon /// failure. The filename is presumed to be UTF-8 encoded. The `options`, @@ -489,26 +519,27 @@ class OIIO_API ImageCache { /// texture option choices. (Currently unused, but reserved for the future /// or for alternate IC implementations.) The opaque pointer `thread_info` /// is thread-specific information returned by `get_perthread_info()`. - virtual ImageHandle* get_image_handle(ustring filename, - Perthread* thread_info = nullptr, - const TextureOpt* options = nullptr) = 0; + ImageHandle* get_image_handle(ustring filename, + Perthread* thread_info = nullptr, + const TextureOpt* options = nullptr); /// Get an ImageHandle using a UTF-16 encoded wstring filename. ImageHandle* get_image_handle(const std::wstring& filename, - Perthread* thread_info = nullptr, - const TextureOpt* options = nullptr) { + Perthread* thread_info = nullptr, + const TextureOpt* options = nullptr) + { return get_image_handle(ustring(Strutil::utf16_to_utf8(filename)), thread_info, options); } /// Return true if the image handle (previously returned by /// `get_image_handle()`) is a valid image that can be subsequently read. - virtual bool good(ImageHandle* file) = 0; + bool good(ImageHandle* file); /// Given a handle, return the filename for that image. /// /// This method was added in OpenImageIO 2.3. - virtual ustring filename_from_handle(ImageHandle* handle) = 0; + ustring filename_from_handle(ImageHandle* handle); /// @} @@ -519,7 +550,7 @@ class OIIO_API ImageCache { /// Given possibly-relative `filename` (UTF-8 encoded), resolve it and use /// the true path to the file, with searchpath logic applied. - virtual std::string resolve_filename(const std::string& filename) const = 0; + std::string resolve_filename(const std::string& filename) const; /// Get information or metadata about the named image and store it in /// `*data`. @@ -684,14 +715,14 @@ class OIIO_API ImageCache { /// Except for the `"exists"` query, a file that does not /// exist or could not be read properly as an image also /// constitutes a query failure that will return `false`. - virtual bool get_image_info (ustring filename, int subimage, int miplevel, - ustring dataname, TypeDesc datatype, void *data) = 0; + bool get_image_info(ustring filename, int subimage, int miplevel, + ustring dataname, TypeDesc datatype, void* data); /// A more efficient variety of `get_image_info()` for cases where you /// can use an `ImageHandle*` to specify the image and optionally have a /// `Perthread*` for the calling thread. - virtual bool get_image_info (ImageHandle *file, Perthread *thread_info, - int subimage, int miplevel, - ustring dataname, TypeDesc datatype, void *data) = 0; + bool get_image_info(ImageHandle* file, Perthread* thread_info, int subimage, + int miplevel, ustring dataname, TypeDesc datatype, + void* data); /// Copy the ImageSpec associated with the named image (the first /// subimage & miplevel by default, or as set by `subimage` and @@ -716,16 +747,14 @@ class OIIO_API ImageCache { /// as being unable to find, open, or read the file, or if /// it does not contain the designated subimage or MIP /// level). - virtual bool get_imagespec (ustring filename, ImageSpec &spec, - int subimage=0, int miplevel=0, - bool native=false) = 0; + bool get_imagespec(ustring filename, ImageSpec& spec, int subimage = 0, + int miplevel = 0, bool native = false); /// A more efficient variety of `get_imagespec()` for cases where you /// can use an `ImageHandle*` to specify the image and optionally have a /// `Perthread*` for the calling thread. - virtual bool get_imagespec (ImageHandle *file, Perthread *thread_info, - ImageSpec &spec, - int subimage=0, int miplevel=0, - bool native=false) = 0; + bool get_imagespec(ImageHandle* file, Perthread* thread_info, + ImageSpec& spec, int subimage = 0, int miplevel = 0, + bool native = false); /// Return a pointer to an ImageSpec associated with the named image /// (the first subimage & MIP level by default, or as set by `subimage` @@ -754,15 +783,14 @@ class OIIO_API ImageCache { /// A pointer to the spec, if the image is found and able to /// be opened and read by an available image format plugin, /// and the designated subimage and MIP level exists. - virtual const ImageSpec *imagespec (ustring filename, int subimage=0, - int miplevel=0, bool native=false) = 0; + const ImageSpec* imagespec(ustring filename, int subimage = 0, + int miplevel = 0, bool native = false); /// A more efficient variety of `imagespec()` for cases where you can /// use an `ImageHandle*` to specify the image and optionally have a /// `Perthread*` for the calling thread. - virtual const ImageSpec *imagespec (ImageHandle *file, - Perthread *thread_info, - int subimage=0, int miplevel=0, - bool native=false) = 0; + const ImageSpec* imagespec(ImageHandle* file, Perthread* thread_info, + int subimage = 0, int miplevel = 0, + bool native = false); /// Copy into `thumbnail` any associated thumbnail associated with this /// image (for the first subimage by default, or as set by `subimage`). @@ -779,13 +807,12 @@ class OIIO_API ImageCache { /// `true` upon success, `false` upon failure failure (such /// as being unable to find, open, or read the file, or if /// it does not contain a thumbnail). - virtual bool get_thumbnail (ustring filename, ImageBuf& thumbnail, - int subimage=0) = 0; + bool get_thumbnail(ustring filename, ImageBuf& thumbnail, int subimage = 0); /// A more efficient variety of `get_thumbnail()` for cases where you /// can use an `ImageHandle*` to specify the image and optionally have a /// `Perthread*` for the calling thread. - virtual bool get_thumbnail (ImageHandle *file, Perthread *thread_info, - ImageBuf& thumbnail, int subimage=0) = 0; + bool get_thumbnail(ImageHandle* file, Perthread* thread_info, + ImageBuf& thumbnail, int subimage = 0); /// @} /// @{ @@ -835,38 +862,36 @@ class OIIO_API ImageCache { /// /// @returns /// `true` for success, `false` for failure. - virtual bool get_pixels (ustring filename, - int subimage, int miplevel, int xbegin, int xend, - int ybegin, int yend, int zbegin, int zend, - int chbegin, int chend, TypeDesc format, void *result, - stride_t xstride=AutoStride, stride_t ystride=AutoStride, - stride_t zstride=AutoStride, - int cache_chbegin = 0, int cache_chend = -1) = 0; + bool get_pixels(ustring filename, int subimage, int miplevel, int xbegin, + int xend, int ybegin, int yend, int zbegin, int zend, + int chbegin, int chend, TypeDesc format, void* result, + stride_t xstride = AutoStride, + stride_t ystride = AutoStride, + stride_t zstride = AutoStride, int cache_chbegin = 0, + int cache_chend = -1); /// A more efficient variety of `get_pixels()` for cases where you can /// use an `ImageHandle*` to specify the image and optionally have a /// `Perthread*` for the calling thread. - virtual bool get_pixels (ImageHandle *file, Perthread *thread_info, - int subimage, int miplevel, int xbegin, int xend, - int ybegin, int yend, int zbegin, int zend, - int chbegin, int chend, TypeDesc format, void *result, - stride_t xstride=AutoStride, stride_t ystride=AutoStride, - stride_t zstride=AutoStride, - int cache_chbegin = 0, int cache_chend = -1) = 0; + bool get_pixels(ImageHandle* file, Perthread* thread_info, int subimage, + int miplevel, int xbegin, int xend, int ybegin, int yend, + int zbegin, int zend, int chbegin, int chend, + TypeDesc format, void* result, + stride_t xstride = AutoStride, + stride_t ystride = AutoStride, + stride_t zstride = AutoStride, int cache_chbegin = 0, + int cache_chend = -1); /// A simplified `get_pixels()` where all channels are retrieved, /// strides are assumed to be contiguous. - virtual bool get_pixels (ustring filename, int subimage, int miplevel, - int xbegin, int xend, int ybegin, int yend, - int zbegin, int zend, - TypeDesc format, void *result) = 0; + bool get_pixels(ustring filename, int subimage, int miplevel, int xbegin, + int xend, int ybegin, int yend, int zbegin, int zend, + TypeDesc format, void* result); /// A more efficient variety of `get_pixels()` for cases where you can /// use an `ImageHandle*` to specify the image and optionally have a /// `Perthread*` for the calling thread. - virtual bool get_pixels (ImageHandle *file, Perthread *thread_info, - int subimage, int miplevel, - int xbegin, int xend, int ybegin, int yend, - int zbegin, int zend, - TypeDesc format, void *result) = 0; + bool get_pixels(ImageHandle* file, Perthread* thread_info, int subimage, + int miplevel, int xbegin, int xend, int ybegin, int yend, + int zbegin, int zend, TypeDesc format, void* result); /// @} /// @{ @@ -886,11 +911,11 @@ class OIIO_API ImageCache { /// If `force` is true, this invalidation will happen unconditionally; if /// false, the file will only be invalidated if it has been changed since /// it was first opened by the ImageCache. - virtual void invalidate(ustring filename, bool force = true) = 0; + void invalidate(ustring filename, bool force = true); /// A more efficient variety of `invalidate()` for cases where you /// already have an `ImageHandle*` for the file you want to invalidate. - virtual void invalidate(ImageHandle* file, bool force = true) = 0; + void invalidate(ImageHandle* file, bool force = true); /// Invalidate all loaded tiles and close open file handles. This is /// safe to do even if other procedures are currently holding @@ -902,21 +927,21 @@ class OIIO_API ImageCache { /// wasteful it is, but if `force` is false, in actuality files will /// only be invalidated if their modification times have been changed /// since they were first opened. - virtual void invalidate_all(bool force = false) = 0; + void invalidate_all(bool force = false); /// Close any open file handles associated with a named file (UTF-8 /// encoded), but do not invalidate any image spec information or pixels /// associated with the files. A client might do this in order to release /// OS file handle resources, or to make it safe for other processes to /// modify image files on disk. - virtual void close (ustring filename) = 0; + void close(ustring filename); /// `close()` all files known to the cache. - virtual void close_all () = 0; + void close_all(); /// An opaque data type that allows us to have a pointer to a tile but /// without exposing any internals. - typedef pvt::ImageCacheTile Tile; + using Tile = ImageCacheTile; /// Find the tile specified by an image filename (UTF-8 encoded), subimage /// & miplevel, the coordinates of a pixel, and optionally a channel @@ -926,30 +951,28 @@ class OIIO_API ImageCache { /// called on the tile pointer the same number of times that `get_tile()` /// was called (reference counting). This is thread-safe! If `chend < /// chbegin`, it will retrieve a tile containing all channels in the file. - virtual Tile * get_tile (ustring filename, int subimage, int miplevel, - int x, int y, int z, - int chbegin = 0, int chend = -1) = 0; + Tile* get_tile(ustring filename, int subimage, int miplevel, int x, int y, + int z, int chbegin = 0, int chend = -1); /// A slightly more efficient variety of `get_tile()` for cases where /// you can use an `ImageHandle*` to specify the image and optionally /// have a `Perthread*` for the calling thread. /// /// @see `get_pixels()` - virtual Tile * get_tile (ImageHandle *file, Perthread *thread_info, - int subimage, int miplevel, - int x, int y, int z, - int chbegin = 0, int chend = -1) = 0; + Tile* get_tile(ImageHandle* file, Perthread* thread_info, int subimage, + int miplevel, int x, int y, int z, int chbegin = 0, + int chend = -1); /// After finishing with a tile, release_tile will allow it to /// once again be purged from the tile cache if required. - virtual void release_tile(Tile* tile) const = 0; + void release_tile(Tile* tile) const; /// Retrieve the data type of the pixels stored in the tile, which may /// be different than the type of the pixels in the disk file. - virtual TypeDesc tile_format(const Tile* tile) const = 0; + TypeDesc tile_format(const Tile* tile) const; /// Retrieve the ROI describing the pixels and channels stored in the /// tile. - virtual ROI tile_roi(const Tile* tile) const = 0; + ROI tile_roi(const Tile* tile) const; /// For a tile retrieved by `get_tile()`, return a pointer to the pixel /// data itself, and also store in `format` the data type that the @@ -957,7 +980,7 @@ class OIIO_API ImageCache { /// data type of the pixels in the disk file). This method should only /// be called on a tile that has been requested by `get_tile()` but has /// not yet been released with `release_tile()`. - virtual const void* tile_pixels(Tile* tile, TypeDesc& format) const = 0; + const void* tile_pixels(Tile* tile, TypeDesc& format) const; /// The add_file() call causes a file to be opened or added to the /// cache. There is no reason to use this method unless you are @@ -989,9 +1012,8 @@ class OIIO_API ImageCache { /// ImageCache. But if replace is true, any existing entry will be /// invalidated, closed and overwritten. So any subsequent access will /// see the new file. Existing texture handles will still be valid. - virtual bool add_file (ustring filename, ImageInput::Creator creator=nullptr, - const ImageSpec *config=nullptr, - bool replace = false) = 0; + bool add_file(ustring filename, ImageInput::Creator creator = nullptr, + const ImageSpec* config = nullptr, bool replace = false); /// Preemptively add a tile corresponding to the named image, at the /// given subimage, MIP level, and channel range. The tile added is the @@ -1003,11 +1025,11 @@ class OIIO_API ImageCache { /// data is assumed to be in some kind of persistent storage and will /// not be copied, nor will its pixels take up additional memory in the /// cache. - virtual bool add_tile (ustring filename, int subimage, int miplevel, - int x, int y, int z, int chbegin, int chend, - TypeDesc format, const void *buffer, - stride_t xstride=AutoStride, stride_t ystride=AutoStride, - stride_t zstride=AutoStride, bool copy = true) = 0; + bool add_tile(ustring filename, int subimage, int miplevel, int x, int y, + int z, int chbegin, int chend, TypeDesc format, + const void* buffer, stride_t xstride = AutoStride, + stride_t ystride = AutoStride, stride_t zstride = AutoStride, + bool copy = true); /// @} @@ -1015,40 +1037,44 @@ class OIIO_API ImageCache { /// @name Errors and statistics /// Is there a pending error message waiting to be retrieved? - virtual bool has_error() const = 0; + bool has_error() const; /// Return the text of all pending error messages issued against this /// ImageCache, and clear the pending error message unless `clear` is /// false. If no error message is pending, it will return an empty /// string. - virtual std::string geterror(bool clear = true) const = 0; + std::string geterror(bool clear = true) const; /// Returns a big string containing useful statistics about the /// ImageCache operations, suitable for saving to a file or outputting /// to the terminal. The `level` indicates the amount of detail in /// the statistics, with higher numbers (up to a maximum of 5) yielding /// more and more esoteric information. - virtual std::string getstats(int level = 1) const = 0; + std::string getstats(int level = 1) const; /// Reset most statistics to be as they were with a fresh ImageCache. /// Caveat emptor: this does not flush the cache itelf, so the resulting /// statistics from the next set of texture requests will not match the /// number of tile reads, etc., that would have resulted from a new /// ImageCache. - virtual void reset_stats() = 0; + void reset_stats(); /// @} - virtual ~ImageCache() {} + ImageCache(); + ~ImageCache(); + +private: + friend class TextureSystem; + friend class TextureSystemImpl; + + // PIMPL idiom + using Impl = ImageCacheImpl; + static void impl_deleter(Impl*); + std::unique_ptr m_impl; -protected: // User code should never directly construct or destruct an ImageCache. // Always use ImageCache::create() and ImageCache::destroy(). - ImageCache(void) {} -private: - // Make delete private and unimplemented in order to prevent apps - // from calling it. Instead, they should call ImageCache::destroy(). - void operator delete(void* /*todel*/) {} }; diff --git a/src/include/OpenImageIO/texture.h b/src/include/OpenImageIO/texture.h index 43eba9a7f8..e64adaccd2 100644 --- a/src/include/OpenImageIO/texture.h +++ b/src/include/OpenImageIO/texture.h @@ -45,11 +45,11 @@ OIIO_NAMESPACE_BEGIN // Forward declarations class ImageCache; +class TextureSystemImpl; namespace pvt { -class TextureSystemImpl; // Used internally by TextureSystem. Unfortunately, this is the only // clean place to store it. Sorry, users, this isn't really for you. @@ -295,7 +295,7 @@ class OIIO_API TextureOpt { // Options set INTERNALLY by libtexture after the options are passed // by the user. Users should not attempt to alter these! int envlayout; // Layout for environment wrap - friend class pvt::TextureSystemImpl; + friend class TextureSystemImpl; }; @@ -347,10 +347,13 @@ class OIIO_API TextureOptBatch { // by the user. Users should not attempt to alter these! int envlayout = 0; // Layout for environment wrap - friend class pvt::TextureSystemImpl; + friend class TextureSystemImpl; }; +// clang-format on + + /// Define an API to an abstract class that that manages texture files, /// caches of open file handles as well as tiles of texels so that truly @@ -391,8 +394,8 @@ class OIIO_API TextureSystem { /// when the last shared_ptr to it is destroyed. /// /// @see TextureSystem::destroy - static std::shared_ptr create(bool shared=true, - std::shared_ptr imagecache = {}); + static std::shared_ptr + create(bool shared = true, std::shared_ptr imagecache = {}); /// Release the shared_ptr to a TextureSystem, including freeing all /// system resources that it holds if no one else is still using it. This @@ -566,15 +569,30 @@ class OIIO_API TextureSystem { /// (including it being an unrecognized attribute or not /// of the correct type). /// - virtual bool attribute (string_view name, TypeDesc type, const void *val) = 0; + bool attribute(string_view name, TypeDesc type, const void* val); /// Specialized `attribute()` for setting a single `int` value. - virtual bool attribute (string_view name, int val) = 0; + bool attribute(string_view name, int val) + { + return attribute(name, TypeInt, &val); + } /// Specialized `attribute()` for setting a single `float` value. - virtual bool attribute (string_view name, float val) = 0; - virtual bool attribute (string_view name, double val) = 0; + bool attribute(string_view name, float val) + { + return attribute(name, TypeFloat, &val); + } + bool attribute(string_view name, double val) + { + float f = (float)val; + return attribute(name, TypeFloat, &f); + } /// Specialized `attribute()` for setting a single string value. - virtual bool attribute (string_view name, string_view val) = 0; + bool attribute(string_view name, string_view val) + { + std::string valstr(val); + const char* s = valstr.c_str(); + return attribute(name, TypeDesc::STRING, &s); + } /// Get the named attribute of the texture system, store it in `*val`. /// All of the attributes that may be set with the `attribute() call` @@ -610,26 +628,48 @@ class OIIO_API TextureSystem { /// attribute was retrieved, or `false` upon failure /// (including it being an unrecognized attribute or not /// of the correct type). - virtual bool getattribute (string_view name, - TypeDesc type, void *val) const = 0; + bool getattribute(string_view name, TypeDesc type, void* val) const; /// Specialized `attribute()` for retrieving a single `int` value. - virtual bool getattribute(string_view name, int& val) const = 0; + bool getattribute(string_view name, int& val) const + { + return getattribute(name, TypeInt, &val); + } /// Specialized `attribute()` for retrieving a single `float` value. - virtual bool getattribute(string_view name, float& val) const = 0; - virtual bool getattribute(string_view name, double& val) const = 0; + bool getattribute(string_view name, float& val) const + { + return getattribute(name, TypeFloat, &val); + } + bool getattribute(string_view name, double& val) const + { + float f; + bool ok = getattribute(name, TypeFloat, &f); + if (ok) + val = f; + return ok; + } /// Specialized `attribute()` for retrieving a single `string` value /// as a `char*`. - virtual bool getattribute(string_view name, char** val) const = 0; + bool getattribute(string_view name, char** val) const + { + return getattribute(name, TypeString, val); + } /// Specialized `attribute()` for retrieving a single `string` value /// as a `std::string`. - virtual bool getattribute(string_view name, std::string& val) const = 0; + bool getattribute(string_view name, std::string& val) const + { + const char* s; + bool ok = getattribute(name, TypeString, &s); + if (ok) + val = s; + return ok; + } /// If the named attribute is known, return its data type. If no such /// attribute exists, return `TypeUnknown`. /// /// This was added in version 2.5. - virtual TypeDesc getattributetype (string_view name) const = 0; + TypeDesc getattributetype(string_view name) const; /// @} @@ -680,14 +720,14 @@ class OIIO_API TextureSystem { /// thread_info is not nullptr, it won't create a new one or retrieve a /// TSP, but it will do other necessary housekeeping on the Perthread /// information. - virtual Perthread* get_perthread_info(Perthread* thread_info = nullptr) = 0; + Perthread* get_perthread_info(Perthread* thread_info = nullptr); /// Create a new Perthread. It is the caller's responsibility to /// eventually destroy it using `destroy_thread_info()`. - virtual Perthread* create_thread_info() = 0; + Perthread* create_thread_info(); /// Destroy a Perthread that was allocated by `create_thread_info()`. - virtual void destroy_thread_info(Perthread* threadinfo) = 0; + void destroy_thread_info(Perthread* threadinfo); /// Define an opaque data type that allows us to have a handle to a /// texture (already having its name resolved) but without exposing @@ -700,13 +740,14 @@ class OIIO_API TextureSystem { /// (currently: the colorspace). The opaque pointer `thread_info` is /// thread-specific information returned by `get_perthread_info()`. Return /// nullptr if something has gone horribly wrong. - virtual TextureHandle* get_texture_handle(ustring filename, - Perthread* thread_info = nullptr, - const TextureOpt* options = nullptr) = 0; + TextureHandle* get_texture_handle(ustring filename, + Perthread* thread_info = nullptr, + const TextureOpt* options = nullptr); /// Get a TextureHandle using a UTF-16 encoded wstring filename. TextureHandle* get_texture_handle(const std::wstring& filename, - Perthread* thread_info = nullptr, - const TextureOpt* options = nullptr) { + Perthread* thread_info = nullptr, + const TextureOpt* options = nullptr) + { return get_texture_handle(ustring(Strutil::utf16_to_utf8(filename)), thread_info, options); } @@ -714,21 +755,19 @@ class OIIO_API TextureSystem { /// Return true if the texture handle (previously returned by /// `get_image_handle()`) is a valid texture that can be subsequently /// read. - virtual bool good(TextureHandle* texture_handle) = 0; + bool good(TextureHandle* texture_handle); /// Given a handle, return the UTF-8 encoded filename for that texture. /// /// This method was added in OpenImageIO 2.3. - virtual ustring filename_from_handle(TextureHandle* handle) = 0; + ustring filename_from_handle(TextureHandle* handle); /// Retrieve an id for a color transformation by name. This ID can be used /// as the value for TextureOpt::colortransformid. The returned value will /// be -1 if either color space is unknown, and 0 for a null /// transformation. - virtual int get_colortransform_id(ustring fromspace, - ustring tospace) const = 0; - virtual int get_colortransform_id(ustringhash fromspace, - ustringhash tospace) const = 0; + int get_colortransform_id(ustring fromspace, ustring tospace) const; + int get_colortransform_id(ustringhash fromspace, ustringhash tospace) const; /// @} /// @{ @@ -812,20 +851,17 @@ class OIIO_API TextureSystem { /// found or could not be opened by any available ImageIO /// plugin. /// - virtual bool texture (ustring filename, TextureOpt &options, - float s, float t, float dsdx, float dtdx, - float dsdy, float dtdy, - int nchannels, float *result, - float *dresultds=nullptr, float *dresultdt=nullptr) = 0; + bool texture(ustring filename, TextureOpt& options, float s, float t, + float dsdx, float dtdx, float dsdy, float dtdy, int nchannels, + float* result, float* dresultds = nullptr, + float* dresultdt = nullptr); /// Slightly faster version of texture() lookup if the app already has a /// texture handle and per-thread info. - virtual bool texture (TextureHandle *texture_handle, - Perthread *thread_info, TextureOpt &options, - float s, float t, float dsdx, float dtdx, - float dsdy, float dtdy, - int nchannels, float *result, - float *dresultds=nullptr, float *dresultdt=nullptr) = 0; + bool texture(TextureHandle* texture_handle, Perthread* thread_info, + TextureOpt& options, float s, float t, float dsdx, float dtdx, + float dsdy, float dtdy, int nchannels, float* result, + float* dresultds = nullptr, float* dresultdt = nullptr); /// Perform a filtered 3D volumetric texture lookup on a position @@ -907,40 +943,19 @@ class OIIO_API TextureSystem { /// found or could not be opened by any available ImageIO /// plugin. /// - virtual bool texture3d (ustring filename, TextureOpt &options, - V3fParam P, V3fParam dPdx, - V3fParam dPdy, V3fParam dPdz, - int nchannels, float *result, - float *dresultds=nullptr, float *dresultdt=nullptr, - float *dresultdr=nullptr) = 0; + bool texture3d(ustring filename, TextureOpt& options, V3fParam P, + V3fParam dPdx, V3fParam dPdy, V3fParam dPdz, int nchannels, + float* result, float* dresultds = nullptr, + float* dresultdt = nullptr, float* dresultdr = nullptr); /// Slightly faster version of texture3d() lookup if the app already has /// a texture handle and per-thread info. - virtual bool texture3d (TextureHandle *texture_handle, - Perthread *thread_info, TextureOpt &options, - V3fParam P, V3fParam dPdx, - V3fParam dPdy, V3fParam dPdz, - int nchannels, float *result, - float *dresultds=nullptr, float *dresultdt=nullptr, - float *dresultdr=nullptr) = 0; - - - // Retrieve a shadow lookup for a single position P. - // - // Return true if the file is found and could be opened by an - // available ImageIO plugin, otherwise return false. - virtual bool shadow (ustring filename, TextureOpt &options, - V3fParam P, V3fParam dPdx, - V3fParam dPdy, float *result, - float *dresultds=nullptr, float *dresultdt=nullptr) = 0; - - // Slightly faster version of texture3d() lookup if the app already - // has a texture handle and per-thread info. - virtual bool shadow (TextureHandle *texture_handle, Perthread *thread_info, - TextureOpt &options, - V3fParam P, V3fParam dPdx, - V3fParam dPdy, float *result, - float *dresultds=nullptr, float *dresultdt=nullptr) = 0; + bool texture3d(TextureHandle* texture_handle, Perthread* thread_info, + TextureOpt& options, V3fParam P, V3fParam dPdx, + V3fParam dPdy, V3fParam dPdz, int nchannels, float* result, + float* dresultds = nullptr, float* dresultdt = nullptr, + float* dresultdr = nullptr); + /// Perform a filtered directional environment map lookup in the /// direction of vector `R`, from the texture identified by `filename`, @@ -998,18 +1013,16 @@ class OIIO_API TextureSystem { /// `true` upon success, or `false` if the file was not /// found or could not be opened by any available ImageIO /// plugin. - virtual bool environment (ustring filename, TextureOpt &options, - V3fParam R, V3fParam dRdx, - V3fParam dRdy, int nchannels, float *result, - float *dresultds=nullptr, float *dresultdt=nullptr) = 0; + bool environment(ustring filename, TextureOpt& options, V3fParam R, + V3fParam dRdx, V3fParam dRdy, int nchannels, float* result, + float* dresultds = nullptr, float* dresultdt = nullptr); /// Slightly faster version of environment() if the app already has a /// texture handle and per-thread info. - virtual bool environment (TextureHandle *texture_handle, - Perthread *thread_info, TextureOpt &options, - V3fParam R, V3fParam dRdx, - V3fParam dRdy, int nchannels, float *result, - float *dresultds=nullptr, float *dresultdt=nullptr) = 0; + bool environment(TextureHandle* texture_handle, Perthread* thread_info, + TextureOpt& options, V3fParam R, V3fParam dRdx, + V3fParam dRdy, int nchannels, float* result, + float* dresultds = nullptr, float* dresultdt = nullptr); /// @} @@ -1063,23 +1076,19 @@ class OIIO_API TextureSystem { /// found or could not be opened by any available ImageIO /// plugin. /// - virtual bool texture (ustring filename, TextureOptBatch &options, - Tex::RunMask mask, const float *s, const float *t, - const float *dsdx, const float *dtdx, - const float *dsdy, const float *dtdy, - int nchannels, float *result, - float *dresultds=nullptr, - float *dresultdt=nullptr) = 0; + bool texture(ustring filename, TextureOptBatch& options, Tex::RunMask mask, + const float* s, const float* t, const float* dsdx, + const float* dtdx, const float* dsdy, const float* dtdy, + int nchannels, float* result, float* dresultds = nullptr, + float* dresultdt = nullptr); /// Slightly faster version of texture() lookup if the app already has a /// texture handle and per-thread info. - virtual bool texture (TextureHandle *texture_handle, - Perthread *thread_info, TextureOptBatch &options, - Tex::RunMask mask, const float *s, const float *t, - const float *dsdx, const float *dtdx, - const float *dsdy, const float *dtdy, - int nchannels, float *result, - float *dresultds=nullptr, - float *dresultdt=nullptr) = 0; + bool texture(TextureHandle* texture_handle, Perthread* thread_info, + TextureOptBatch& options, Tex::RunMask mask, const float* s, + const float* t, const float* dsdx, const float* dtdx, + const float* dsdy, const float* dtdy, int nchannels, + float* result, float* dresultds = nullptr, + float* dresultdt = nullptr); /// Perform filtered 3D volumetric texture lookups on a batch of /// positions from the same texture, all at once. The "point-like" @@ -1129,23 +1138,18 @@ class OIIO_API TextureSystem { /// found or could not be opened by any available ImageIO /// plugin. /// - virtual bool texture3d (ustring filename, - TextureOptBatch &options, Tex::RunMask mask, - const float *P, const float *dPdx, - const float *dPdy, const float *dPdz, - int nchannels, float *result, - float *dresultds=nullptr, float *dresultdt=nullptr, - float *dresultdr=nullptr) = 0; + bool texture3d(ustring filename, TextureOptBatch& options, + Tex::RunMask mask, const float* P, const float* dPdx, + const float* dPdy, const float* dPdz, int nchannels, + float* result, float* dresultds = nullptr, + float* dresultdt = nullptr, float* dresultdr = nullptr); /// Slightly faster version of texture3d() lookup if the app already /// has a texture handle and per-thread info. - virtual bool texture3d (TextureHandle *texture_handle, - Perthread *thread_info, - TextureOptBatch &options, Tex::RunMask mask, - const float *P, const float *dPdx, - const float *dPdy, const float *dPdz, - int nchannels, float *result, - float *dresultds=nullptr, float *dresultdt=nullptr, - float *dresultdr=nullptr) = 0; + bool texture3d(TextureHandle* texture_handle, Perthread* thread_info, + TextureOptBatch& options, Tex::RunMask mask, const float* P, + const float* dPdx, const float* dPdy, const float* dPdz, + int nchannels, float* result, float* dresultds = nullptr, + float* dresultdt = nullptr, float* dresultdr = nullptr); /// Perform filtered directional environment map lookups on a batch of /// directions from the same texture, all at once. The "point-like" @@ -1195,28 +1199,17 @@ class OIIO_API TextureSystem { /// found or could not be opened by any available ImageIO /// plugin. /// - virtual bool environment (ustring filename, - TextureOptBatch &options, Tex::RunMask mask, - const float *R, const float *dRdx, const float *dRdy, - int nchannels, float *result, - float *dresultds=nullptr, float *dresultdt=nullptr) = 0; + bool environment(ustring filename, TextureOptBatch& options, + Tex::RunMask mask, const float* R, const float* dRdx, + const float* dRdy, int nchannels, float* result, + float* dresultds = nullptr, float* dresultdt = nullptr); /// Slightly faster version of environment() if the app already has a /// texture handle and per-thread info. - virtual bool environment (TextureHandle *texture_handle, Perthread *thread_info, - TextureOptBatch &options, Tex::RunMask mask, - const float *R, const float *dRdx, const float *dRdy, - int nchannels, float *result, - float *dresultds=nullptr, float *dresultdt=nullptr) = 0; - - // Batched shadow lookups - virtual bool shadow (ustring filename, - TextureOptBatch &options, Tex::RunMask mask, - const float *P, const float *dPdx, const float *dPdy, - float *result, float *dresultds=nullptr, float *dresultdt=nullptr) = 0; - virtual bool shadow (TextureHandle *texture_handle, Perthread *thread_info, - TextureOptBatch &options, Tex::RunMask mask, - const float *P, const float *dPdx, const float *dPdy, - float *result, float *dresultds=nullptr, float *dresultdt=nullptr) = 0; + bool environment(TextureHandle* texture_handle, Perthread* thread_info, + TextureOptBatch& options, Tex::RunMask mask, + const float* R, const float* dRdx, const float* dRdy, + int nchannels, float* result, float* dresultds = nullptr, + float* dresultdt = nullptr); /// @} @@ -1227,7 +1220,7 @@ class OIIO_API TextureSystem { /// Given possibly-relative 'filename' (UTF-8 encoded), resolve it using /// the search path rules and return the full resolved filename. - virtual std::string resolve_filename (const std::string &filename) const=0; + std::string resolve_filename(const std::string& filename) const; /// Get information or metadata about the named texture and store it in /// `*data`. @@ -1412,15 +1405,15 @@ class OIIO_API TextureSystem { /// Except for the `"exists"` query, a file that does not /// exist or could not be read properly as an image also /// constitutes a query failure that will return `false`. - virtual bool get_texture_info (ustring filename, int subimage, - ustring dataname, TypeDesc datatype, void *data) = 0; + bool get_texture_info(ustring filename, int subimage, ustring dataname, + TypeDesc datatype, void* data); /// A more efficient variety of `get_texture_info()` for cases where you /// can use a `TextureHandle*` to specify the image and optionally have /// a `Perthread*` for the calling thread. - virtual bool get_texture_info (TextureHandle *texture_handle, - Perthread *thread_info, int subimage, - ustring dataname, TypeDesc datatype, void *data) = 0; + bool get_texture_info(TextureHandle* texture_handle, Perthread* thread_info, + int subimage, ustring dataname, TypeDesc datatype, + void* data); /// Copy the ImageSpec associated with the named texture (the first /// subimage by default, or as set by `subimage`). @@ -1438,14 +1431,12 @@ class OIIO_API TextureSystem { /// as being unable to find, open, or read the file, or if /// it does not contain the designated subimage or MIP /// level). - virtual bool get_imagespec (ustring filename, int subimage, - ImageSpec &spec) = 0; + bool get_imagespec(ustring filename, int subimage, ImageSpec& spec); /// A more efficient variety of `get_imagespec()` for cases where you /// can use a `TextureHandle*` to specify the image and optionally have /// a `Perthread*` for the calling thread. - virtual bool get_imagespec (TextureHandle *texture_handle, - Perthread *thread_info, int subimage, - ImageSpec &spec) = 0; + bool get_imagespec(TextureHandle* texture_handle, Perthread* thread_info, + int subimage, ImageSpec& spec); /// Return a pointer to an ImageSpec associated with the named texture /// if the file is found and is an image format that can be read, @@ -1468,13 +1459,13 @@ class OIIO_API TextureSystem { /// A pointer to the spec, if the image is found and able to /// be opened and read by an available image format plugin, /// and the designated subimage exists. - virtual const ImageSpec *imagespec (ustring filename, int subimage=0) = 0; + const ImageSpec* imagespec(ustring filename, int subimage = 0); /// A more efficient variety of `imagespec()` for cases where you can /// use a `TextureHandle*` to specify the image and optionally have a /// `Perthread*` for the calling thread. - virtual const ImageSpec *imagespec (TextureHandle *texture_handle, - Perthread *thread_info = nullptr, - int subimage=0) = 0; + const ImageSpec* imagespec(TextureHandle* texture_handle, + Perthread* thread_info = nullptr, + int subimage = 0); /// For a texture specified by name, retrieve the rectangle of raw /// unfiltered texels from the subimage specified in `options` and at @@ -1517,20 +1508,17 @@ class OIIO_API TextureSystem { /// /// @returns /// `true` for success, `false` for failure. - virtual bool get_texels (ustring filename, TextureOpt &options, - int miplevel, int xbegin, int xend, - int ybegin, int yend, int zbegin, int zend, - int chbegin, int chend, - TypeDesc format, void *result) = 0; + bool get_texels(ustring filename, TextureOpt& options, int miplevel, + int xbegin, int xend, int ybegin, int yend, int zbegin, + int zend, int chbegin, int chend, TypeDesc format, + void* result); /// A more efficient variety of `get_texels()` for cases where you can /// use a `TextureHandle*` to specify the image and optionally have a /// `Perthread*` for the calling thread. - virtual bool get_texels (TextureHandle *texture_handle, - Perthread *thread_info, TextureOpt &options, - int miplevel, int xbegin, int xend, - int ybegin, int yend, int zbegin, int zend, - int chbegin, int chend, - TypeDesc format, void *result) = 0; + bool get_texels(TextureHandle* texture_handle, Perthread* thread_info, + TextureOpt& options, int miplevel, int xbegin, int xend, + int ybegin, int yend, int zbegin, int zend, int chbegin, + int chend, TypeDesc format, void* result); /// @} @@ -1541,12 +1529,12 @@ class OIIO_API TextureSystem { /// Is the UTF-8 encoded filename a UDIM pattern? /// /// This method was added in OpenImageIO 2.3. - virtual bool is_udim(ustring filename) = 0; + bool is_udim(ustring filename); /// Does the handle refer to a file that's a UDIM pattern? /// /// This method was added in OpenImageIO 2.3. - virtual bool is_udim(TextureHandle* udimfile) = 0; + bool is_udim(TextureHandle* udimfile); /// For a UDIM filename pattern (UTF-8 encoded) and texture coordinates, /// return the TextureHandle pointer for the concrete tile file it refers @@ -1554,17 +1542,15 @@ class OIIO_API TextureSystem { /// allowed to be sparse). /// /// This method was added in OpenImageIO 2.3. - virtual TextureHandle* resolve_udim(ustring udimpattern, - float s, float t) = 0; + TextureHandle* resolve_udim(ustring udimpattern, float s, float t); /// A more efficient variety of `resolve_udim()` for cases where you /// have the `TextureHandle*` that corresponds to the "virtual" UDIM /// file and optionally have a `Perthread*` for the calling thread. /// /// This method was added in OpenImageIO 2.3. - virtual TextureHandle* resolve_udim(TextureHandle* udimfile, - Perthread* thread_info, - float s, float t) = 0; + TextureHandle* resolve_udim(TextureHandle* udimfile, Perthread* thread_info, + float s, float t); /// Produce a full inventory of the set of concrete files comprising the /// UDIM set specified by UTF-8 encoded `udimpattern`. The apparent @@ -1577,19 +1563,17 @@ class OIIO_API TextureSystem { /// `utile + vtile * nvtiles`. /// /// This method was added in OpenImageIO 2.3. - virtual void inventory_udim(ustring udimpattern, - std::vector& filenames, - int& nutiles, int& nvtiles) = 0; + void inventory_udim(ustring udimpattern, std::vector& filenames, + int& nutiles, int& nvtiles); /// A more efficient variety of `inventory_udim()` for cases where you /// have the `TextureHandle*` that corresponds to the "virtual" UDIM /// file and optionally have a `Perthread*` for the calling thread. /// /// This method was added in OpenImageIO 2.3. - virtual void inventory_udim(TextureHandle* udimfile, - Perthread* thread_info, - std::vector& filenames, - int& nutiles, int& nvtiles) = 0; + void inventory_udim(TextureHandle* udimfile, Perthread* thread_info, + std::vector& filenames, int& nutiles, + int& nvtiles); /// @} /// @{ @@ -1600,11 +1584,11 @@ class OIIO_API TextureSystem { /// encoded), including loaded texture tiles from that texture, and close /// any open file handle associated with the file. This calls /// `ImageCache::invalidate(filename,force)` on the underlying ImageCache. - virtual void invalidate (ustring filename, bool force = true) = 0; + void invalidate(ustring filename, bool force = true); /// Invalidate all cached data for all textures. This calls /// `ImageCache::invalidate_all(force)` on the underlying ImageCache. - virtual void invalidate_all (bool force=false) = 0; + void invalidate_all(bool force = false); /// Close any open file handles associated with a UTF-8 encoded filename, /// but do not invalidate any image spec information or pixels associated @@ -1612,10 +1596,10 @@ class OIIO_API TextureSystem { /// handle resources, or to make it safe for other processes to modify /// textures on disk. This calls `ImageCache::close(force)` on the /// underlying ImageCache. - virtual void close (ustring filename) = 0; + void close(ustring filename); /// `close()` all files known to the cache. - virtual void close_all () = 0; + void close_all(); /// @} @@ -1623,13 +1607,13 @@ class OIIO_API TextureSystem { /// @name Errors and statistics /// Is there a pending error message waiting to be retrieved? - virtual bool has_error() const = 0; + bool has_error() const; /// Return the text of all pending error messages issued against this /// TextureSystem, and clear the pending error message unless `clear` is /// false. If no error message is pending, it will return an empty /// string. - virtual std::string geterror(bool clear = true) const = 0; + std::string geterror(bool clear = true) const; /// Returns a big string containing useful statistics about the /// TextureSystem operations, suitable for saving to a file or @@ -1639,34 +1623,36 @@ class OIIO_API TextureSystem { /// the returned string will also contain all the statistics of the /// underlying ImageCache, but if false will only contain /// texture-specific statistics. - virtual std::string getstats (int level=1, bool icstats=true) const = 0; + std::string getstats(int level = 1, bool icstats = true) const; /// Reset most statistics to be as they were with a fresh TextureSystem. /// Caveat emptor: this does not flush the cache itself, so the resulting /// statistics from the next set of texture requests will not match the /// number of tile reads, etc., that would have resulted from a new /// TextureSystem. - virtual void reset_stats () = 0; + void reset_stats(); /// @} /// Return an opaque, non-owning pointer to the underlying ImageCache /// (if there is one). - virtual std::shared_ptr imagecache() const = 0; - - virtual ~TextureSystem () { } + std::shared_ptr imagecache() const; // For testing -- do not use static void unit_test_hash(); -protected: + TextureSystem(std::shared_ptr imagecache); + ~TextureSystem(); + +private: + // PIMPL idiom + using Impl = TextureSystemImpl; + // class Impl; + static void impl_deleter(Impl*); + std::unique_ptr m_impl; + // User code should never directly construct or destruct a TextureSystem. // Always use TextureSystem::create() and TextureSystem::destroy(). - TextureSystem (void) { } -private: - // Make delete private and unimplemented in order to prevent apps - // from calling it. Instead, they should call TextureSystem::destroy(). - void operator delete(void* /*todel*/) {} }; diff --git a/src/libtexture/environment.cpp b/src/libtexture/environment.cpp index 535a89853c..d9ec38bbd9 100644 --- a/src/libtexture/environment.cpp +++ b/src/libtexture/environment.cpp @@ -203,6 +203,54 @@ OIIO_NAMESPACE_BEGIN using namespace pvt; using namespace simd; + +bool +TextureSystem::environment(ustring filename, TextureOpt& options, V3fParam R, + V3fParam dRdx, V3fParam dRdy, int nchannels, + float* result, float* dresultds, float* dresultdt) +{ + return m_impl->environment(filename, options, R, dRdx, dRdy, nchannels, + result, dresultds, dresultdt); +} + + +bool +TextureSystem::environment(TextureHandle* texture_handle, + Perthread* thread_info, TextureOpt& options, + V3fParam R, V3fParam dRdx, V3fParam dRdy, + int nchannels, float* result, float* dresultds, + float* dresultdt) +{ + return m_impl->environment(texture_handle, thread_info, options, R, dRdx, + dRdy, nchannels, result, dresultds, dresultdt); +} + + +bool +TextureSystem::environment(ustring filename, TextureOptBatch& options, + Tex::RunMask mask, const float* R, const float* dRdx, + const float* dRdy, int nchannels, float* result, + float* dresultds, float* dresultdt) +{ + return m_impl->environment(filename, options, mask, R, dRdx, dRdy, + nchannels, result, dresultds, dresultdt); +} + + +bool +TextureSystem::environment(TextureHandle* texture_handle, + Perthread* thread_info, TextureOptBatch& options, + Tex::RunMask mask, const float* R, const float* dRdx, + const float* dRdy, int nchannels, float* result, + float* dresultds, float* dresultdt) +{ + return m_impl->environment(texture_handle, thread_info, options, mask, R, + dRdx, dRdy, nchannels, result, dresultds, + dresultdt); +} + + + namespace pvt { @@ -225,6 +273,8 @@ vector_to_latlong(const Imath::V3f& R, bool y_is_up, float& s, float& t) t = 0.0f; } +} // namespace pvt + bool @@ -594,6 +644,4 @@ TextureSystemImpl::environment(ustring filename, TextureOptBatch& options, } -} // end namespace pvt - OIIO_NAMESPACE_END diff --git a/src/libtexture/imagecache.cpp b/src/libtexture/imagecache.cpp index 9c7c480135..e520aebf90 100644 --- a/src/libtexture/imagecache.cpp +++ b/src/libtexture/imagecache.cpp @@ -39,14 +39,11 @@ OIIO_NAMESPACE_BEGIN using namespace pvt; -namespace pvt { - // The static perthread mutex needs to outlive the shared_image_cache // instance, so must be declared first in this file to avoid static // initialization order problems. spin_mutex ImageCacheImpl::m_perthread_info_mutex; -} // namespace pvt namespace { // anonymous @@ -122,9 +119,6 @@ redundantbytes_compare(const ImageCacheFileRef& a, const ImageCacheFileRef& b) }; // end anonymous namespace -namespace pvt { // namespace pvt - - void ImageCacheStatistics::init() @@ -1242,6 +1236,19 @@ ImageCacheFile::mark_broken(string_view error) +size_t +ImageCacheFile::heapsize() const +{ + size_t size = pvt::heapsize(m_subimages); + size += pvt::heapsize(m_configspec); + size += pvt::heapsize(m_input); + size += pvt::heapsize(m_mipreadcount); + size += pvt::heapsize(m_udim_lookup); + return size; +} + + + ImageCacheFile* ImageCacheImpl::find_file(ustring filename, ImageCachePerThreadInfo* thread_info, @@ -2468,7 +2475,7 @@ ImageCacheImpl::getattribute(string_view name, TypeDesc type, void* val) const if (Strutil::starts_with(name, "stat:")) { // Stats we can just grab - ATTR_DECODE("stat:cache_footprint", long long, footprint(*this)); + ATTR_DECODE("stat:cache_footprint", long long, pvt::footprint(*this)); ATTR_DECODE("stat:cache_memory_used", long long, m_mem_used); ATTR_DECODE("stat:tiles_created", int, m_stat_tiles_created); ATTR_DECODE("stat:tiles_current", int, m_stat_tiles_current); @@ -3930,7 +3937,139 @@ ImageCacheImpl::append_error(string_view message) const -} // end namespace pvt +size_t +ImageCacheImpl::heapsize() const +{ + using OIIO::pvt::footprint; + using OIIO::pvt::heapsize; + + size_t size = 0; + // strings + size += heapsize(m_searchpath) + heapsize(m_plugin_searchpath) + + heapsize(m_searchdirs); + // thread info + size += heapsize(m_all_perthread_info); + // tile cache + for (TileCache::iterator t = m_tilecache.begin(), e = m_tilecache.end(); + t != e; ++t) + size += footprint(t->first) + footprint(t->second); + // files + for (FilenameMap::iterator t = m_files.begin(), e = m_files.end(); t != e; + ++t) + size += footprint(t->first) + footprint(t->second); + // finger prints; we only account for references, this map does not own the files. + constexpr size_t sizeofFingerprintPair = sizeof(ustring) + + sizeof(ImageCacheFileRef); + size += m_fingerprints.size() * sizeofFingerprintPair; + return size; +} + + + +size_t +ImageCacheImpl::footprint(ImageCacheFootprint& output) const +{ + using OIIO::pvt::footprint; + using OIIO::pvt::heapsize; + + // strings + output.ic_str_count = m_searchdirs.size() + 2; + output.ic_str_mem = heapsize(m_searchdirs) + heapsize(m_searchpath) + + heapsize(m_plugin_searchpath); + + // thread info + output.ic_thdi_count = m_all_perthread_info.size(); + output.ic_thdi_mem = heapsize(m_all_perthread_info); + + // tile cache + output.ic_tile_count = m_tilecache.size(); + for (TileCache::iterator t = m_tilecache.begin(), e = m_tilecache.end(); + t != e; ++t) + output.ic_tile_mem += footprint(t->first) + footprint(t->second); + + // finger prints; we only account for references, this map does not own the files. + constexpr size_t sizeofFingerprintPair = sizeof(ustring) + + sizeof(ImageCacheFileRef); + output.ic_fgpt_count = m_fingerprints.size(); + output.ic_fgpt_mem = output.ic_fgpt_count * sizeofFingerprintPair; + + // files; count the footprint of files, subimages, level infos, image inputs, image specs + for (FilenameMap::iterator t = m_files.begin(), e = m_files.end(); t != e; + ++t) { + // get file format ustring; files with empty file format are simply constant valued. + const ImageCacheFile& file(*t->second); + const ustring& format = !file.fileformat().empty() + ? file.fileformat() + : ImageCacheFootprint::uconstant; + + const size_t fileftp = footprint(t->first) + footprint(t->second); + output.add(fileftp, format); + + const size_t specftp = footprint(file.m_configspec); + output.add(specftp, format); + + const size_t inputftp = footprint(file.m_input); + output.add(inputftp, format); + + // subimages + for (int s = 0, send = file.subimages(); s < send; ++s) { + const ImageCacheFile::SubimageInfo& sub(file.subimageinfo(s)); + const size_t subftp = footprint(sub); + output.add(subftp, format); + + // level infos + for (const auto& level : sub.levels) { + const size_t lvlftp = footprint(level); + output.add(lvlftp, format); + + // extra infos; there are two ImageSpec structures stored in each LevelInfos, + // and they turn out to be memory heavy, so we further break that down next. + const size_t lvlspecftp = footprint(level.m_spec) + + footprint(level.nativespec); + const size_t lvlattrftp + = (level.m_spec ? footprint(level.m_spec->extra_attribs) + : 0) + + footprint(level.nativespec.extra_attribs); + const size_t lvlchanftp + = (level.m_spec ? footprint(level.m_spec->channelnames) : 0) + + footprint(level.nativespec.channelnames); + output.add(lvlspecftp, format); + output.add(2 * sizeof(ImageSpec), + format); + output.add(lvlattrftp, format); + output.add(lvlchanftp, format); + } + } + } + + // update total memory + output.ic_mem += output.ic_str_mem; + output.ic_mem += output.ic_tile_mem; + output.ic_mem += output.ic_thdi_mem; + output.ic_mem += output.fmap.find(ImageCacheFootprint::utotal)->second[kMem]; + output.ic_mem += output.ic_fgpt_mem; + + return output.ic_mem; +} + + + +void +ImageCache::impl_deleter(ImageCacheImpl* todel) +{ + delete todel; +} + + + +ImageCache::ImageCache() + : m_impl(new ImageCacheImpl, &impl_deleter) +{ +} + + + +ImageCache::~ImageCache() {} @@ -3942,12 +4081,12 @@ ImageCache::create(bool shared) // exists, just return it, otherwise record the new cache. spin_lock guard(shared_image_cache_mutex); if (!shared_image_cache) - shared_image_cache = std::make_shared(); + shared_image_cache = std::make_shared(); return shared_image_cache; } // Doesn't need a shared cache - return std::make_shared(); + return std::make_shared(); } @@ -3972,4 +4111,347 @@ ImageCache::destroy(std::shared_ptr& cache, bool teardown) } + +bool +ImageCache::attribute(string_view name, TypeDesc type, const void* val) +{ + return m_impl->attribute(name, type, val); +} + + + +bool +ImageCache::getattribute(string_view name, TypeDesc type, void* val) const +{ + return m_impl->getattribute(name, type, val); +} + + +TypeDesc +ImageCache::getattributetype(string_view name) const +{ + return m_impl->getattributetype(name); +} + + + +ImageCache::Perthread* +ImageCache::get_perthread_info(Perthread* thread_info) +{ + return m_impl->get_perthread_info(thread_info); +} + + + +ImageCache::Perthread* +ImageCache::create_thread_info() +{ + return m_impl->create_thread_info(); +} + + + +void +ImageCache::destroy_thread_info(Perthread* thread_info) +{ + m_impl->destroy_thread_info(thread_info); +} + + + +ImageCache::ImageHandle* +ImageCache::get_image_handle(ustring filename, Perthread* thread_info, + const TextureOpt* options) +{ + return m_impl->get_image_handle(filename, thread_info, options); +} + + + +bool +ImageCache::good(ImageHandle* file) +{ + return m_impl->good(file); +} + + + +ustring +ImageCache::filename_from_handle(ImageHandle* handle) +{ + return m_impl->filename_from_handle(handle); +} + + + +std::string +ImageCache::resolve_filename(const std::string& filename) const +{ + return m_impl->resolve_filename(filename); +} + + + +bool +ImageCache::get_image_info(ustring filename, int subimage, int miplevel, + ustring dataname, TypeDesc datatype, void* data) +{ + return m_impl->get_image_info(filename, subimage, miplevel, dataname, + datatype, data); +} + + + +bool +ImageCache::get_image_info(ImageHandle* file, Perthread* thread_info, + int subimage, int miplevel, ustring dataname, + TypeDesc datatype, void* data) +{ + return m_impl->get_image_info(file, thread_info, subimage, miplevel, + dataname, datatype, data); +} + + + +bool +ImageCache::get_imagespec(ustring filename, ImageSpec& spec, int subimage, + int miplevel, bool native) +{ + return m_impl->get_imagespec(filename, spec, subimage, miplevel, native); +} + + +bool +ImageCache::get_imagespec(ImageHandle* file, Perthread* thread_info, + ImageSpec& spec, int subimage, int miplevel, + bool native) +{ + return m_impl->get_imagespec(file, thread_info, spec, subimage, miplevel, + native); +} + + + +const ImageSpec* +ImageCache::imagespec(ustring filename, int subimage, int miplevel, bool native) +{ + return m_impl->imagespec(filename, subimage, miplevel, native); +} + + +const ImageSpec* +ImageCache::imagespec(ImageHandle* file, Perthread* thread_info, int subimage, + int miplevel, bool native) +{ + return m_impl->imagespec(file, thread_info, subimage, miplevel, native); +} + + + +bool +ImageCache::get_thumbnail(ustring filename, ImageBuf& thumbnail, int subimage) +{ + return m_impl->get_thumbnail(filename, thumbnail, subimage); +} + + +bool +ImageCache::get_thumbnail(ImageHandle* file, Perthread* thread_info, + ImageBuf& thumbnail, int subimage) +{ + return m_impl->get_thumbnail(file, thread_info, thumbnail, subimage); +} + + + +bool +ImageCache::get_pixels(ustring filename, int subimage, int miplevel, int xbegin, + int xend, int ybegin, int yend, int zbegin, int zend, + int chbegin, int chend, TypeDesc format, void* result, + stride_t xstride, stride_t ystride, stride_t zstride, + int cache_chbegin, int cache_chend) +{ + return m_impl->get_pixels(filename, subimage, miplevel, xbegin, xend, + ybegin, yend, zbegin, zend, chbegin, chend, + format, result, xstride, ystride, zstride, + cache_chbegin, cache_chend); +} + + +bool +ImageCache::get_pixels(ImageHandle* file, Perthread* thread_info, int subimage, + int miplevel, int xbegin, int xend, int ybegin, int yend, + int zbegin, int zend, int chbegin, int chend, + TypeDesc format, void* result, stride_t xstride, + stride_t ystride, stride_t zstride, int cache_chbegin, + int cache_chend) +{ + return m_impl->get_pixels(file, thread_info, subimage, miplevel, xbegin, + xend, ybegin, yend, zbegin, zend, chbegin, chend, + format, result, xstride, ystride, zstride, + cache_chbegin, cache_chend); +} + + + +bool +ImageCache::get_pixels(ustring filename, int subimage, int miplevel, int xbegin, + int xend, int ybegin, int yend, int zbegin, int zend, + TypeDesc format, void* result) +{ + return m_impl->get_pixels(filename, subimage, miplevel, xbegin, xend, + ybegin, yend, zbegin, zend, format, result); +} + + +bool +ImageCache::get_pixels(ImageHandle* file, Perthread* thread_info, int subimage, + int miplevel, int xbegin, int xend, int ybegin, int yend, + int zbegin, int zend, TypeDesc format, void* result) +{ + return m_impl->get_pixels(file, thread_info, subimage, miplevel, xbegin, + xend, ybegin, yend, zbegin, zend, format, result); +} + + + +void +ImageCache::invalidate(ustring filename, bool force) +{ + m_impl->invalidate(filename, force); +} + + +void +ImageCache::invalidate(ImageHandle* file, bool force) +{ + m_impl->invalidate(file, force); +} + + +void +ImageCache::invalidate_all(bool force) +{ + m_impl->invalidate_all(force); +} + + +void +ImageCache::close(ustring filename) +{ + m_impl->close(filename); +} + + +void +ImageCache::close_all() +{ + m_impl->close_all(); +} + + +ImageCache::Tile* +ImageCache::get_tile(ustring filename, int subimage, int miplevel, int x, int y, + int z, int chbegin, int chend) +{ + return m_impl->get_tile(filename, subimage, miplevel, x, y, z, chbegin, + chend); +} + + +ImageCache::Tile* +ImageCache::get_tile(ImageHandle* file, Perthread* thread_info, int subimage, + int miplevel, int x, int y, int z, int chbegin, int chend) +{ + return m_impl->get_tile(file, thread_info, subimage, miplevel, x, y, z, + chbegin, chend); +} + + + +void +ImageCache::release_tile(Tile* tile) const +{ + m_impl->release_tile(tile); +} + + + +TypeDesc +ImageCache::tile_format(const Tile* tile) const +{ + return m_impl->tile_format(tile); +} + + + +ROI +ImageCache::tile_roi(const Tile* tile) const +{ + return m_impl->tile_roi(tile); +} + + + +const void* +ImageCache::tile_pixels(Tile* tile, TypeDesc& format) const +{ + return m_impl->tile_pixels(tile, format); +} + + + +bool +ImageCache::add_file(ustring filename, ImageInput::Creator creator, + const ImageSpec* config, bool replace) +{ + return m_impl->add_file(filename, creator, config, replace); +} + + + +bool +ImageCache::add_tile(ustring filename, int subimage, int miplevel, int x, int y, + int z, int chbegin, int chend, TypeDesc format, + const void* buffer, stride_t xstride, stride_t ystride, + stride_t zstride, bool copy) +{ + return m_impl->add_tile(filename, subimage, miplevel, x, y, z, chbegin, + chend, format, buffer, xstride, ystride, zstride, + copy); +} + + + +bool +ImageCache::has_error() const +{ + return m_impl->has_error(); +} + + + +std::string +ImageCache::geterror(bool clear) const +{ + return m_impl->geterror(clear); +} + + + +std::string +ImageCache::getstats(int level) const +{ + return m_impl->getstats(level); +} + + + +void +ImageCache::reset_stats() +{ + m_impl->reset_stats(); +} + + OIIO_NAMESPACE_END diff --git a/src/libtexture/imagecache_memory_print.h b/src/libtexture/imagecache_memory_print.h index 1c8cdeff17..369dc52ffe 100644 --- a/src/libtexture/imagecache_memory_print.h +++ b/src/libtexture/imagecache_memory_print.h @@ -16,8 +16,6 @@ OIIO_NAMESPACE_BEGIN -namespace pvt { - //// Memory tracking helper to get ImageCacheImpl statistics //! recorded entries per file format @@ -39,9 +37,12 @@ enum FileFootprintEnty : uint8_t { kFootprintEntrySize }; + typedef std::array FileFootprint; typedef tsl::robin_map FileFootprintMap; + + struct ImageCacheFootprint { static const ustring utotal; static const ustring uconstant; @@ -83,97 +84,22 @@ struct ImageCacheFootprint { const ustring ImageCacheFootprint::utotal = ustring("total"); const ustring ImageCacheFootprint::uconstant = ustring("constant"); + + /// Fills the parameter with a memory breakdown of the ImageCache. inline size_t footprint(const ImageCacheImpl& ic, ImageCacheFootprint& output) { - // strings - output.ic_str_count = ic.m_searchdirs.size() + 2; - output.ic_str_mem = heapsize(ic.m_searchdirs) + heapsize(ic.m_searchpath) - + heapsize(ic.m_plugin_searchpath); - - // thread info - output.ic_thdi_count = ic.m_all_perthread_info.size(); - output.ic_thdi_mem = heapsize(ic.m_all_perthread_info); - - // tile cache - output.ic_tile_count = ic.m_tilecache.size(); - for (TileCache::iterator t = ic.m_tilecache.begin(), - e = ic.m_tilecache.end(); - t != e; ++t) - output.ic_tile_mem += footprint(t->first) + footprint(t->second); - - // finger prints; we only account for references, this map does not own the files. - constexpr size_t sizeofFingerprintPair = sizeof(ustring) - + sizeof(ImageCacheFileRef); - output.ic_fgpt_count = ic.m_fingerprints.size(); - output.ic_fgpt_mem = output.ic_fgpt_count * sizeofFingerprintPair; - - // files; count the footprint of files, subimages, level infos, image inputs, image specs - for (FilenameMap::iterator t = ic.m_files.begin(), e = ic.m_files.end(); - t != e; ++t) { - // get file format ustring; files with empty file format are simply constant valued. - const ImageCacheFile& file(*t->second); - const ustring& format = !file.fileformat().empty() - ? file.fileformat() - : ImageCacheFootprint::uconstant; - - const size_t fileftp = footprint(t->first) + footprint(t->second); - output.add(fileftp, format); - - const size_t specftp = footprint(file.m_configspec); - output.add(specftp, format); - - const size_t inputftp = footprint(file.m_input); - output.add(inputftp, format); - - // subimages - for (int s = 0, send = file.subimages(); s < send; ++s) { - const ImageCacheFile::SubimageInfo& sub(file.subimageinfo(s)); - const size_t subftp = footprint(sub); - output.add(subftp, format); - - // level infos - for (const auto& level : sub.levels) { - const size_t lvlftp = footprint(level); - output.add(lvlftp, format); - - // extra infos; there are two ImageSpec structures stored in each LevelInfos, - // and they turn out to be memory heavy, so we further break that down next. - const size_t lvlspecftp = footprint(level.m_spec) - + footprint(level.nativespec); - const size_t lvlattrftp - = (level.m_spec ? footprint(level.m_spec->extra_attribs) - : 0) - + footprint(level.nativespec.extra_attribs); - const size_t lvlchanftp - = (level.m_spec ? footprint(level.m_spec->channelnames) : 0) - + footprint(level.nativespec.channelnames); - output.add(lvlspecftp, format); - output.add(2 * sizeof(ImageSpec), - format); - output.add(lvlattrftp, format); - output.add(lvlchanftp, format); - } - } - } - - // update total memory - output.ic_mem += output.ic_str_mem; - output.ic_mem += output.ic_tile_mem; - output.ic_mem += output.ic_thdi_mem; - output.ic_mem += output.fmap.find(ImageCacheFootprint::utotal)->second[kMem]; - output.ic_mem += output.ic_fgpt_mem; - - return output.ic_mem; + return ic.footprint(output); } + inline void printImageCacheMemory(std::ostream& out, const ImageCacheImpl& ic) { // get memory data - pvt::ImageCacheFootprint data; - pvt::footprint(ic, data); + ImageCacheFootprint data; + footprint(ic, data); // print image cache memory usage print(out, " Cache : {}\n", Strutil::memformat(data.ic_mem)); @@ -190,8 +116,8 @@ printImageCacheMemory(std::ostream& out, const ImageCacheImpl& ic) data.fmap[ImageCacheFootprint::utotal][kCount]); // print file formats memory usage - for (pvt::FileFootprintMap::const_iterator t = data.fmap.begin(), - e = data.fmap.end(); + for (FileFootprintMap::const_iterator t = data.fmap.begin(), + e = data.fmap.end(); t != e; ++t) { if (t.key() == ImageCacheFootprint::utotal) continue; @@ -229,6 +155,4 @@ printImageCacheMemory(std::ostream& out, const ImageCacheImpl& ic) } } -} // namespace pvt - -OIIO_NAMESPACE_END \ No newline at end of file +OIIO_NAMESPACE_END diff --git a/src/libtexture/imagecache_memory_pvt.h b/src/libtexture/imagecache_memory_pvt.h index 10ee4ee8b9..debd22b8be 100644 --- a/src/libtexture/imagecache_memory_pvt.h +++ b/src/libtexture/imagecache_memory_pvt.h @@ -51,12 +51,7 @@ template<> inline size_t heapsize(const ImageCacheFile& file) { - size_t size = heapsize(file.m_subimages); - size += heapsize(file.m_configspec); - size += heapsize(file.m_input); - size += heapsize(file.m_mipreadcount); - size += heapsize(file.m_udim_lookup); - return size; + return file.heapsize(); } // heapsize specialization for ImageCacheTile @@ -72,9 +67,7 @@ template<> inline size_t heapsize(const ImageCachePerThreadInfo& info) { - /// TODO: this should take into account the two last tiles, if their refcount is zero. - constexpr size_t sizeofPair = sizeof(ustring) + sizeof(ImageCacheFile*); - return info.m_thread_files.size() * sizeofPair; + return info.heapsize(); } // heapsize specialization for ImageCacheImpl @@ -82,28 +75,9 @@ template<> inline size_t heapsize(const ImageCacheImpl& ic) { - size_t size = 0; - // strings - size += heapsize(ic.m_searchpath) + heapsize(ic.m_plugin_searchpath) - + heapsize(ic.m_searchdirs); - // thread info - size += heapsize(ic.m_all_perthread_info); - // tile cache - for (TileCache::iterator t = ic.m_tilecache.begin(), - e = ic.m_tilecache.end(); - t != e; ++t) - size += footprint(t->first) + footprint(t->second); - // files - for (FilenameMap::iterator t = ic.m_files.begin(), e = ic.m_files.end(); - t != e; ++t) - size += footprint(t->first) + footprint(t->second); - // finger prints; we only account for references, this map does not own the files. - constexpr size_t sizeofFingerprintPair = sizeof(ustring) - + sizeof(ImageCacheFileRef); - size += ic.m_fingerprints.size() * sizeofFingerprintPair; - return size; + return ic.heapsize(); } } // namespace pvt -OIIO_NAMESPACE_END \ No newline at end of file +OIIO_NAMESPACE_END diff --git a/src/libtexture/imagecache_pvt.h b/src/libtexture/imagecache_pvt.h index 262ee99ca1..f8f8b33284 100644 --- a/src/libtexture/imagecache_pvt.h +++ b/src/libtexture/imagecache_pvt.h @@ -4,7 +4,7 @@ /// \file -/// Non-public classes used internally by ImgeCacheImpl. +/// Non-public classes used internally by ImageCacheImpl. #ifndef OPENIMAGEIO_IMAGECACHE_PVT_H @@ -25,7 +25,6 @@ OIIO_NAMESPACE_BEGIN -namespace pvt { #ifndef NDEBUG # define IMAGECACHE_TIME_STATS 1 @@ -40,16 +39,21 @@ namespace pvt { #define FILE_CACHE_SHARDS 64 #define TILE_CACHE_SHARDS 128 + + struct TileID; class ImageCacheImpl; -class ImageCachePerThreadInfo; struct ImageCacheFootprint; +namespace pvt { + const char* texture_format_name(TexFormat f); const char* texture_type_name(TexFormat f); +} // namespace pvt + /// Structure to hold IC and TS statistics. We combine into a single @@ -107,6 +111,9 @@ struct ImageCacheStatistics { +namespace pvt { + + struct UdimInfo { ustring filename; std::atomic icfile { nullptr }; @@ -137,6 +144,8 @@ struct UdimInfo { } }; +} // namespace pvt + /// Unique in-memory record for each image file on disk. Note that @@ -150,6 +159,10 @@ struct UdimInfo { /// thread-specific IC data including microcache and statistics. /// class OIIO_API ImageCacheFile final : public RefCnt { + using TexFormat = pvt::TexFormat; + using EnvLayout = pvt::EnvLayout; + using UdimInfo = pvt::UdimInfo; + public: ImageCacheFile(ImageCacheImpl& imagecache, ImageCachePerThreadInfo* thread_info, ustring filename, @@ -367,6 +380,8 @@ class OIIO_API ImageCacheFile final : public RefCnt { // Return the regex wildcard matching pattern for a udim spec. static std::string udim_to_wildcard(string_view udimpattern); + size_t heapsize() const; + private: ustring m_filename_original; ///< original filename before search path ustring m_filename; ///< Filename @@ -468,12 +483,6 @@ class OIIO_API ImageCacheFile final : public RefCnt { friend class ImageCacheImpl; friend class TextureSystemImpl; friend struct SubimageInfo; - - /// Memory tracking. Specializes the base memory tracking functions from memory.h. - /// declare a friend heapsize definition - template friend inline size_t heapsize(const T&); - /// declare a friend image cache footprint definition - friend inline size_t footprint(const ImageCacheImpl&, ImageCacheFootprint&); }; @@ -732,10 +741,8 @@ class ImageCacheTile final : public RefCnt { int m_tile_width { 0 }; ///< Tile width bool m_valid { false }; ///< Valid pixels bool m_nofree { false }; ///< We do NOT own the pixels, do not free! - volatile bool m_pixels_ready { - false - }; ///< The pixels have been read from disk - atomic_int m_used { 1 }; ///< Used recently + volatile bool m_pixels_ready { false }; // Pixels have been read from disk + atomic_int m_used { 1 }; ///< Used recently }; @@ -754,6 +761,7 @@ typedef unordered_map_concurrent< TileCache; + /// A very small amount of per-thread data that saves us from locking /// the mutex quite as often. We store things here used by both /// ImageCache and TextureSystem, so they don't each need a costly @@ -796,6 +804,13 @@ class ImageCachePerThreadInfo { auto f = m_thread_files.find(n); return f == m_thread_files.end() ? nullptr : f->second; } + + size_t heapsize() const + { + /// TODO: this should take into account the two last tiles, if their refcount is zero. + constexpr size_t sizeofPair = sizeof(ustring) + sizeof(ImageCacheFile*); + return m_thread_files.size() * sizeofPair; + } }; @@ -805,60 +820,65 @@ class ImageCachePerThreadInfo { /// Some of the methods require a pointer to the thread-specific IC data /// including microcache and statistics. /// -class ImageCacheImpl final : public ImageCache { +class ImageCacheImpl { public: + using Perthread = ImageCachePerThreadInfo; + using ImageHandle = ImageCacheFile; + using Tile = ImageCacheTile; + friend class TextureSystem; + friend class TextureSystemImpl; + ImageCacheImpl(); - ~ImageCacheImpl() override; + ~ImageCacheImpl(); - bool attribute(string_view name, TypeDesc type, const void* val) override; - bool attribute(string_view name, int val) override + bool attribute(string_view name, TypeDesc type, const void* val); + bool attribute(string_view name, int val) { - return attribute(name, TypeDesc::INT, &val); + return attribute(name, TypeInt, &val); } - bool attribute(string_view name, float val) override + bool attribute(string_view name, float val) { - return attribute(name, TypeDesc::FLOAT, &val); + return attribute(name, TypeFloat, &val); } - bool attribute(string_view name, double val) override + bool attribute(string_view name, double val) { float f = (float)val; - return attribute(name, TypeDesc::FLOAT, &f); + return attribute(name, TypeFloat, &f); } - bool attribute(string_view name, string_view val) override + bool attribute(string_view name, string_view val) { std::string valstr(val); const char* s = valstr.c_str(); - return attribute(name, TypeDesc::STRING, &s); + return attribute(name, TypeString, &s); } - TypeDesc getattributetype(string_view name) const override; + TypeDesc getattributetype(string_view name) const; - bool getattribute(string_view name, TypeDesc type, - void* val) const override; - bool getattribute(string_view name, int& val) const override + bool getattribute(string_view name, TypeDesc type, void* val) const; + bool getattribute(string_view name, int& val) const { - return getattribute(name, TypeDesc::INT, &val); + return getattribute(name, TypeInt, &val); } - bool getattribute(string_view name, float& val) const override + bool getattribute(string_view name, float& val) const { - return getattribute(name, TypeDesc::FLOAT, &val); + return getattribute(name, TypeFloat, &val); } - bool getattribute(string_view name, double& val) const override + bool getattribute(string_view name, double& val) const { float f; - bool ok = getattribute(name, TypeDesc::FLOAT, &f); + bool ok = getattribute(name, TypeFloat, &f); if (ok) val = f; return ok; } - bool getattribute(string_view name, char** val) const override + bool getattribute(string_view name, char** val) const { - return getattribute(name, TypeDesc::STRING, val); + return getattribute(name, TypeString, val); } - bool getattribute(string_view name, std::string& val) const override + bool getattribute(string_view name, std::string& val) const { ustring s; - bool ok = getattribute(name, TypeDesc::STRING, &s); + bool ok = getattribute(name, TypeString, &s); if (ok) val = s.string(); return ok; @@ -882,7 +902,7 @@ class ImageCacheImpl final : public ImageCache { void get_commontoworld(Imath::M44f& result) const { result = m_Mc2w; } int max_errors_per_file() const { return m_max_errors_per_file; } - std::string resolve_filename(const std::string& filename) const override; + std::string resolve_filename(const std::string& filename) const; // Set m_max_open_files, with logic to try to clamp reasonably. void set_max_open_files(int m); @@ -890,12 +910,11 @@ class ImageCacheImpl final : public ImageCache { /// Get information about the given image. /// bool get_image_info(ustring filename, int subimage, int miplevel, - ustring dataname, TypeDesc datatype, - void* data) override; + ustring dataname, TypeDesc datatype, void* data); bool get_image_info(ImageCacheFile* file, ImageCachePerThreadInfo* thread_info, int subimage, int miplevel, ustring dataname, TypeDesc datatype, - void* data) override; + void* data); /// Get the ImageSpec associated with the named image. If the file /// is found and is an image format that can be read, store a copy @@ -903,18 +922,17 @@ class ImageCacheImpl final : public ImageCache { /// the file was not found or could not be opened as an image file /// by any available ImageIO plugin. bool get_imagespec(ustring filename, ImageSpec& spec, int subimage = 0, - int miplevel = 0, bool native = false) override; + int miplevel = 0, bool native = false); bool get_imagespec(ImageCacheFile* file, ImageCachePerThreadInfo* thread_info, ImageSpec& spec, - int subimage = 0, int miplevel = 0, - bool native = false) override; + int subimage = 0, int miplevel = 0, bool native = false); const ImageSpec* imagespec(ustring filename, int subimage = 0, - int miplevel = 0, bool native = false) override; + int miplevel = 0, bool native = false); const ImageSpec* imagespec(ImageCacheFile* file, ImageCachePerThreadInfo* thread_info = NULL, int subimage = 0, int miplevel = 0, - bool native = false) override; + bool native = false); ImageCacheFile* resolve_udim(ImageCacheFile* udimfile, Perthread* thread_info, int utile, int vtile); @@ -922,26 +940,25 @@ class ImageCacheImpl final : public ImageCache { std::vector& filenames, int& nutiles, int& nvtiles); - bool get_thumbnail(ustring filename, ImageBuf& thumbnail, - int subimage = 0) override; + bool get_thumbnail(ustring filename, ImageBuf& thumbnail, int subimage = 0); bool get_thumbnail(ImageHandle* file, Perthread* thread_info, - ImageBuf& thumbnail, int subimage = 0) override; + ImageBuf& thumbnail, int subimage = 0); // Retrieve a rectangle of raw unfiltered pixels. bool get_pixels(ustring filename, int subimage, int miplevel, int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, - TypeDesc format, void* result) override; + TypeDesc format, void* result); bool get_pixels(ImageCacheFile* file, ImageCachePerThreadInfo* thread_info, int subimage, int miplevel, int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, TypeDesc format, - void* result) override; + void* result); bool get_pixels(ustring filename, int subimage, int miplevel, int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, int chbegin, int chend, TypeDesc format, void* result, stride_t xstride = AutoStride, stride_t ystride = AutoStride, stride_t zstride = AutoStride, int cache_chbegin = 0, - int cache_chend = -1) override; + int cache_chend = -1); bool get_pixels(ImageCacheFile* file, ImageCachePerThreadInfo* thread_info, int subimage, int miplevel, int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, int chbegin, @@ -949,7 +966,7 @@ class ImageCacheImpl final : public ImageCache { stride_t xstride = AutoStride, stride_t ystride = AutoStride, stride_t zstride = AutoStride, int cache_chbegin = 0, - int cache_chend = -1) override; + int cache_chend = -1); // Find the ImageCacheFile record for the named image, adding an entry // if it is not already in the cache. This returns a plain old pointer, @@ -976,7 +993,7 @@ class ImageCacheImpl final : public ImageCache { ImageCacheFile* get_image_handle(ustring filename, ImageCachePerThreadInfo* thread_info, - const TextureOpt* options) override + const TextureOpt* options) { if (!thread_info) thread_info = get_perthread_info(); @@ -984,12 +1001,9 @@ class ImageCacheImpl final : public ImageCache { return verify_file(file, thread_info); } - bool good(ImageCacheFile* handle) override - { - return handle && !handle->broken(); - } + bool good(ImageCacheFile* handle) { return handle && !handle->broken(); } - ustring filename_from_handle(ImageCacheFile* handle) override + ustring filename_from_handle(ImageCacheFile* handle) { return handle ? handle->filename() : ustring(); } @@ -1040,41 +1054,40 @@ class ImageCacheImpl final : public ImageCache { } Tile* get_tile(ustring filename, int subimage, int miplevel, int x, int y, - int z, int chbegin, int chend) override; + int z, int chbegin, int chend); Tile* get_tile(ImageHandle* file, Perthread* thread_info, int subimage, - int miplevel, int x, int y, int z, int chbegin, - int chend) override; - void release_tile(Tile* tile) const override; - TypeDesc tile_format(const Tile* tile) const override; - ROI tile_roi(const Tile* tile) const override; - const void* tile_pixels(Tile* tile, TypeDesc& format) const override; + int miplevel, int x, int y, int z, int chbegin, int chend); + void release_tile(Tile* tile) const; + TypeDesc tile_format(const Tile* tile) const; + ROI tile_roi(const Tile* tile) const; + const void* tile_pixels(Tile* tile, TypeDesc& format) const; bool add_file(ustring filename, ImageInput::Creator creator, - const ImageSpec* config, bool replace) override; + const ImageSpec* config, bool replace); bool add_tile(ustring filename, int subimage, int miplevel, int x, int y, int z, int chbegin, int chend, TypeDesc format, const void* buffer, stride_t xstride, stride_t ystride, - stride_t zstride, bool copy) override; + stride_t zstride, bool copy); /// Return the numerical subimage index for the given subimage name, /// as stored in the "oiio:subimagename" metadata. Return -1 if no /// subimage matches its name. int subimage_from_name(ImageCacheFile* file, ustring subimagename); - bool has_error() const override; - std::string geterror(bool clear = true) const override; - std::string getstats(int level = 1) const override; - void reset_stats() override; - void invalidate(ustring filename, bool force) override; - void invalidate(ImageHandle* file, bool force) override; - void invalidate_all(bool force = false) override; - void close(ustring filename) override; - void close_all() override; + bool has_error() const; + std::string geterror(bool clear = true) const; + std::string getstats(int level = 1) const; + void reset_stats(); + void invalidate(ustring filename, bool force); + void invalidate(ImageHandle* file, bool force); + void invalidate_all(bool force = false); + void close(ustring filename); + void close_all(); /// Merge all the per-thread statistics into one set of stats. /// void mergestats(ImageCacheStatistics& merged) const; - void operator delete(void* todel) { ::delete ((char*)todel); } + // void operator delete(void* todel) { ::delete ((char*)todel); } /// Called when a new file is opened, so that the system can track /// the number of simultaneously-opened files. @@ -1121,9 +1134,9 @@ class ImageCacheImpl final : public ImageCache { /// Append a string to the current error message void append_error(string_view message) const; - Perthread* get_perthread_info(Perthread* thread_info = NULL) override; - Perthread* create_thread_info() override; - void destroy_thread_info(Perthread* thread_info) override; + Perthread* get_perthread_info(Perthread* thread_info = NULL); + Perthread* create_thread_info(); + void destroy_thread_info(Perthread* thread_info); /// Ensure that the max_memory_bytes is at least newsize bytes. /// Override the previous value if necessary, with thread-safety. @@ -1136,6 +1149,9 @@ class ImageCacheImpl final : public ImageCache { ustring colorspace() const noexcept { return m_colorspace; } + size_t heapsize() const; + size_t footprint(ImageCacheFootprint& output) const; + private: void init(); @@ -1246,17 +1262,9 @@ class ImageCacheImpl final : public ImageCache { // done it with nobody else interfering. } while (llstat->compare_exchange_strong(*llnewval, *lloldval)); } - - /// declare a friend heapsize definition - template friend inline size_t heapsize(const T&); - /// declare a friend image cache footprint definition - friend inline size_t footprint(const ImageCacheImpl&, ImageCacheFootprint&); }; - -} // end namespace pvt - OIIO_NAMESPACE_END diff --git a/src/libtexture/texture3d.cpp b/src/libtexture/texture3d.cpp index f55c37d389..51fd2d6c1b 100644 --- a/src/libtexture/texture3d.cpp +++ b/src/libtexture/texture3d.cpp @@ -47,7 +47,54 @@ float2float(float val) } // end anonymous namespace -namespace pvt { // namespace pvt +bool +TextureSystem::texture3d(ustring filename, TextureOpt& options, V3fParam P, + V3fParam dPdx, V3fParam dPdy, V3fParam dPdz, + int nchannels, float* result, float* dresultds, + float* dresultdt, float* dresultdr) +{ + return m_impl->texture3d(filename, options, P, dPdx, dPdy, dPdz, nchannels, + result, dresultds, dresultdt, dresultdr); +} + + +bool +TextureSystem::texture3d(TextureHandle* texture_handle, Perthread* thread_info, + TextureOpt& options, V3fParam P, V3fParam dPdx, + V3fParam dPdy, V3fParam dPdz, int nchannels, + float* result, float* dresultds, float* dresultdt, + float* dresultdr) +{ + return m_impl->texture3d(texture_handle, thread_info, options, P, dPdx, + dPdy, dPdz, nchannels, result, dresultds, + dresultdt, dresultdr); +} + + +bool +TextureSystem::texture3d(ustring filename, TextureOptBatch& options, + Tex::RunMask mask, const float* P, const float* dPdx, + const float* dPdy, const float* dPdz, int nchannels, + float* result, float* dresultds, float* dresultdt, + float* dresultdr) +{ + return m_impl->texture3d(filename, options, mask, P, dPdx, dPdy, dPdz, + nchannels, result, dresultds, dresultdt, + dresultdr); +} + + +bool +TextureSystem::texture3d(TextureHandle* texture_handle, Perthread* thread_info, + TextureOptBatch& options, Tex::RunMask mask, + const float* P, const float* dPdx, const float* dPdy, + const float* dPdz, int nchannels, float* result, + float* dresultds, float* dresultdt, float* dresultdr) +{ + return m_impl->texture3d(texture_handle, thread_info, options, mask, P, + dPdx, dPdy, dPdz, nchannels, result, dresultds, + dresultdt, dresultdr); +} @@ -714,6 +761,4 @@ TextureSystemImpl::texture3d(ustring filename, TextureOptBatch& options, } -} // end namespace pvt - OIIO_NAMESPACE_END diff --git a/src/libtexture/texture_pvt.h b/src/libtexture/texture_pvt.h index b7d231c35c..66c47dc0bf 100644 --- a/src/libtexture/texture_pvt.h +++ b/src/libtexture/texture_pvt.h @@ -16,107 +16,103 @@ OIIO_NAMESPACE_BEGIN class ImageCache; -class Filter1D; - -namespace pvt { - class TextureSystemImpl; +class Filter1D; #ifndef OPENIMAGEIO_IMAGECACHE_PVT_H -class ImageCacheImpl; class ImageCacheFile; class ImageCacheTile; class ImageCacheTileRef; +class ImageCacheTileID; +class ImageCacheImpl; #endif /// Working implementation of the abstract TextureSystem class. -/// -class TextureSystemImpl final : public TextureSystem { +class TextureSystemImpl { public: - typedef ImageCacheFile TextureFile; + using TextureHandle = TextureSystem::TextureHandle; + using Perthread = TextureSystem::Perthread; + using TextureFile = ImageCacheFile; - TextureSystemImpl(std::shared_ptr imagecache); - ~TextureSystemImpl() override; + TextureSystemImpl(std::shared_ptr imagecache = {}); + ~TextureSystemImpl(); - bool attribute(string_view name, TypeDesc type, const void* val) override; - bool attribute(string_view name, int val) override + bool attribute(string_view name, TypeDesc type, const void* val); + bool attribute(string_view name, int val) { - return attribute(name, TypeDesc::INT, &val); + return attribute(name, TypeInt, &val); } - bool attribute(string_view name, float val) override + bool attribute(string_view name, float val) { - return attribute(name, TypeDesc::FLOAT, &val); + return attribute(name, TypeFloat, &val); } - bool attribute(string_view name, double val) override + bool attribute(string_view name, double val) { float f = (float)val; - return attribute(name, TypeDesc::FLOAT, &f); + return attribute(name, TypeFloat, &f); } - bool attribute(string_view name, string_view val) override + bool attribute(string_view name, string_view val) { std::string valstr(val); const char* s = valstr.c_str(); - return attribute(name, TypeDesc::STRING, &s); + return attribute(name, TypeString, &s); } - TypeDesc getattributetype(string_view name) const override; + TypeDesc getattributetype(string_view name) const; - bool getattribute(string_view name, TypeDesc type, - void* val) const override; - bool getattribute(string_view name, int& val) const override + bool getattribute(string_view name, TypeDesc type, void* val) const; + bool getattribute(string_view name, int& val) const { - return getattribute(name, TypeDesc::INT, &val); + return getattribute(name, TypeInt, &val); } - bool getattribute(string_view name, float& val) const override + bool getattribute(string_view name, float& val) const { - return getattribute(name, TypeDesc::FLOAT, &val); + return getattribute(name, TypeFloat, &val); } - bool getattribute(string_view name, double& val) const override + bool getattribute(string_view name, double& val) const { float f; - bool ok = getattribute(name, TypeDesc::FLOAT, &f); + bool ok = getattribute(name, TypeFloat, &f); if (ok) val = f; return ok; } - bool getattribute(string_view name, char** val) const override + bool getattribute(string_view name, char** val) const { - return getattribute(name, TypeDesc::STRING, val); + return getattribute(name, TypeString, val); } - bool getattribute(string_view name, std::string& val) const override + bool getattribute(string_view name, std::string& val) const { const char* s; - bool ok = getattribute(name, TypeDesc::STRING, &s); + bool ok = getattribute(name, TypeString, &s); if (ok) val = s; return ok; } - // Retrieve options void get_commontoworld(Imath::M44f& result) const { result = m_Mc2w; } - Perthread* get_perthread_info(Perthread* thread_info = NULL) override + Perthread* get_perthread_info(Perthread* thread_info = NULL) { return (Perthread*)m_imagecache->get_perthread_info( (ImageCachePerThreadInfo*)thread_info); } - Perthread* create_thread_info() override + Perthread* create_thread_info() { OIIO_ASSERT(m_imagecache); return (Perthread*)m_imagecache->create_thread_info(); } - void destroy_thread_info(Perthread* threadinfo) override + void destroy_thread_info(Perthread* threadinfo) { OIIO_ASSERT(m_imagecache); m_imagecache->destroy_thread_info((ImageCachePerThreadInfo*)threadinfo); } - TextureHandle* - get_texture_handle(ustring filename, Perthread* thread, - const TextureOpt* options = nullptr) override + TextureHandle* get_texture_handle(ustring filename, Perthread* thread, + const TextureOpt* options = nullptr) { PerThreadInfo* thread_info = thread ? ((PerThreadInfo*)thread) @@ -124,173 +120,134 @@ class TextureSystemImpl final : public TextureSystem { return (TextureHandle*)find_texturefile(filename, thread_info, options); } - bool good(TextureHandle* texture_handle) override + bool good(TextureHandle* texture_handle) { return texture_handle && !((TextureFile*)texture_handle)->broken(); } - ustring filename_from_handle(TextureHandle* handle) override + ustring filename_from_handle(TextureHandle* handle) { return handle ? ((ImageCache::ImageHandle*)handle)->filename() : ustring(); } - int get_colortransform_id(ustring fromspace, - ustring tospace) const override; - int get_colortransform_id(ustringhash fromspace, - ustringhash tospace) const override; + int get_colortransform_id(ustring fromspace, ustring tospace) const; + int get_colortransform_id(ustringhash fromspace, ustringhash tospace) const; bool texture(ustring filename, TextureOpt& options, float s, float t, float dsdx, float dtdx, float dsdy, float dtdy, int nchannels, float* result, float* dresultds = NULL, - float* dresultdt = NULL) override; + float* dresultdt = NULL); bool texture(TextureHandle* texture_handle, Perthread* thread_info, TextureOpt& options, float s, float t, float dsdx, float dtdx, float dsdy, float dtdy, int nchannels, float* result, - float* dresultds = NULL, float* dresultdt = NULL) override; + float* dresultds = NULL, float* dresultdt = NULL); bool texture(ustring filename, TextureOptBatch& options, Tex::RunMask mask, const float* s, const float* t, const float* dsdx, const float* dtdx, const float* dsdy, const float* dtdy, int nchannels, float* result, float* dresultds = nullptr, - float* dresultdt = nullptr) override; + float* dresultdt = nullptr); bool texture(TextureHandle* texture_handle, Perthread* thread_info, TextureOptBatch& options, Tex::RunMask mask, const float* s, const float* t, const float* dsdx, const float* dtdx, const float* dsdy, const float* dtdy, int nchannels, float* result, float* dresultds = nullptr, - float* dresultdt = nullptr) override; + float* dresultdt = nullptr); bool texture3d(ustring filename, TextureOpt& options, V3fParam P, V3fParam dPdx, V3fParam dPdy, V3fParam dPdz, int nchannels, float* result, float* dresultds = NULL, - float* dresultdt = NULL, float* dresultdr = NULL) override; + float* dresultdt = NULL, float* dresultdr = NULL); bool texture3d(TextureHandle* texture_handle, Perthread* thread_info, TextureOpt& options, V3fParam P, V3fParam dPdx, V3fParam dPdy, V3fParam dPdz, int nchannels, float* result, float* dresultds = NULL, float* dresultdt = NULL, - float* dresultdr = NULL) override; + float* dresultdr = NULL); bool texture3d(ustring filename, TextureOptBatch& options, Tex::RunMask mask, const float* P, const float* dPdx, const float* dPdy, const float* dPdz, int nchannels, float* result, float* dresultds = nullptr, - float* dresultdt = nullptr, - float* dresultdr = nullptr) override; + float* dresultdt = nullptr, float* dresultdr = nullptr); bool texture3d(TextureHandle* texture_handle, Perthread* thread_info, TextureOptBatch& options, Tex::RunMask mask, const float* P, const float* dPdx, const float* dPdy, const float* dPdz, int nchannels, float* result, float* dresultds = nullptr, - float* dresultdt = nullptr, - float* dresultdr = nullptr) override; - - bool shadow(ustring /*filename*/, TextureOpt& /*options*/, V3fParam /*P*/, - V3fParam /*dPdx*/, V3fParam /*dPdy*/, float* /*result*/, - float* /*dresultds*/, float* /*dresultdt*/) override - { - return false; - } - bool shadow(TextureHandle* /*texture_handle*/, Perthread* /*thread_info*/, - TextureOpt& /*options*/, V3fParam /*P*/, V3fParam /*dPdx*/, - V3fParam /*dPdy*/, float* /*result*/, float* /*dresultds*/, - float* /*dresultdt*/) override - { - return false; - } - bool shadow(ustring /*filename*/, TextureOptBatch& /*options*/, - Tex::RunMask /*mask*/, const float* /*P*/, - const float* /*dPdx*/, const float* /*dPdy*/, float* /*result*/, - float* /*dresultds*/, float* /*dresultdt*/) override - { - return false; - } - bool shadow(TextureHandle* /*texture_handle*/, Perthread* /*thread_info*/, - TextureOptBatch& /*options*/, Tex::RunMask /*mask*/, - const float* /*P*/, const float* /*dPdx*/, - const float* /*dPdy*/, float* /*result*/, float* /*dresultds*/, - float* /*dresultdt*/) override - { - return false; - } + float* dresultdt = nullptr, float* dresultdr = nullptr); bool environment(ustring filename, TextureOpt& options, V3fParam R, V3fParam dRdx, V3fParam dRdy, int nchannels, float* result, - float* dresultds = NULL, float* dresultdt = NULL) override; + float* dresultds = NULL, float* dresultdt = NULL); bool environment(TextureHandle* texture_handle, Perthread* thread_info, TextureOpt& options, V3fParam R, V3fParam dRdx, V3fParam dRdy, int nchannels, float* result, - float* dresultds = NULL, float* dresultdt = NULL) override; + float* dresultds = NULL, float* dresultdt = NULL); bool environment(ustring filename, TextureOptBatch& options, Tex::RunMask mask, const float* R, const float* dRdx, const float* dRdy, int nchannels, float* result, - float* dresultds = nullptr, - float* dresultdt = nullptr) override; + float* dresultds = nullptr, float* dresultdt = nullptr); bool environment(TextureHandle* texture_handle, Perthread* thread_info, TextureOptBatch& options, Tex::RunMask mask, const float* R, const float* dRdx, const float* dRdy, int nchannels, float* result, float* dresultds = nullptr, - float* dresultdt = nullptr) override; + float* dresultdt = nullptr); - std::string resolve_filename(const std::string& filename) const override; + std::string resolve_filename(const std::string& filename) const; bool get_texture_info(ustring filename, int subimage, ustring dataname, - TypeDesc datatype, void* data) override; + TypeDesc datatype, void* data); bool get_texture_info(TextureHandle* texture_handle, Perthread* thread_info, int subimage, ustring dataname, TypeDesc datatype, - void* data) override; + void* data); - bool get_imagespec(ustring filename, int subimage, - ImageSpec& spec) override; + bool get_imagespec(ustring filename, int subimage, ImageSpec& spec); bool get_imagespec(TextureHandle* texture_handle, Perthread* thread_info, - int subimage, ImageSpec& spec) override; + int subimage, ImageSpec& spec); - const ImageSpec* imagespec(ustring filename, int subimage = 0) override; + const ImageSpec* imagespec(ustring filename, int subimage = 0); const ImageSpec* imagespec(TextureHandle* texture_handle, - Perthread* thread_info = NULL, - int subimage = 0) override; + Perthread* thread_info = NULL, int subimage = 0); bool get_texels(ustring filename, TextureOpt& options, int miplevel, int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, int chbegin, int chend, TypeDesc format, - void* result) override; + void* result); bool get_texels(TextureHandle* texture_handle, Perthread* thread_info, TextureOpt& options, int miplevel, int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, int chbegin, - int chend, TypeDesc format, void* result) override; + int chend, TypeDesc format, void* result); - bool is_udim(ustring filename) override; - bool is_udim(TextureHandle* udimfile) override; - TextureHandle* resolve_udim(ustring filename, float s, float t) override; + bool is_udim(ustring filename); + bool is_udim(TextureHandle* udimfile); + TextureHandle* resolve_udim(ustring filename, float s, float t); TextureHandle* resolve_udim(TextureHandle* udimfile, Perthread* thread_info, - float s, float t) override; + float s, float t); void inventory_udim(ustring udimpattern, std::vector& filenames, - int& nutiles, int& nvtiles) override; + int& nutiles, int& nvtiles); void inventory_udim(TextureHandle* udimfile, Perthread* thread_info, std::vector& filenames, int& nutiles, - int& nvtiles) override; + int& nvtiles); - bool has_error() const override; - std::string geterror(bool clear = true) const override; - std::string getstats(int level = 1, bool icstats = true) const override; - void reset_stats() override; + bool has_error() const; + std::string geterror(bool clear = true) const; + std::string getstats(int level = 1, bool icstats = true) const; + void reset_stats(); - void invalidate(ustring filename, bool force) override; - void invalidate_all(bool force = false) override; - void close(ustring filename) override; - void close_all() override; + void invalidate(ustring filename, bool force); + void invalidate_all(bool force = false); + void close(ustring filename); + void close_all(); - void operator delete(void* todel) { ::delete ((char*)todel); } + // void operator delete(void* todel) { ::delete ((char*)todel); } typedef bool (*wrap_impl)(int& coord, int origin, int width); /// Return an opaque, non-owning pointer to the underlying ImageCache /// (if there is one). - std::shared_ptr imagecache() const override - { - return m_imagecache_sp; - } + std::shared_ptr imagecache() const { return m_imagecache_sp; } -private: - typedef ImageCacheTileRef TileRef; - typedef ImageCachePerThreadInfo PerThreadInfo; + // private: + using TileRef = ImageCacheTileRef; + using PerThreadInfo = ImageCachePerThreadInfo; void init(); @@ -594,9 +551,6 @@ TextureSystemImpl::st_to_texel(float s, float t, TextureFile& texturefile, } - -} // end namespace pvt - OIIO_NAMESPACE_END #endif // OPENIMAGEIO_TEXTURE_PVT_H diff --git a/src/libtexture/texturesys.cpp b/src/libtexture/texturesys.cpp index 8d5400ce6b..9770b6a95e 100644 --- a/src/libtexture/texturesys.cpp +++ b/src/libtexture/texturesys.cpp @@ -81,6 +81,26 @@ static const OIIO_SIMD4_ALIGN vbool4 channel_masks[5] = { } // end anonymous namespace + +void +TextureSystem::impl_deleter(TextureSystemImpl* todel) +{ + delete todel; +} + + + +TextureSystem::TextureSystem(std::shared_ptr imagecache) + : m_impl(new TextureSystemImpl(imagecache), &impl_deleter) +{ +} + + + +TextureSystem::~TextureSystem() {} + + + std::shared_ptr TextureSystem::create(bool shared, std::shared_ptr imagecache) { @@ -96,7 +116,7 @@ TextureSystem::create(bool shared, std::shared_ptr imagecache) // as the shared one. spin_lock guard(shared_texturesys_mutex); if (!shared_texturesys) - shared_texturesys = std::make_shared( + shared_texturesys = std::make_shared( ImageCache::create(true)); return shared_texturesys; } @@ -107,8 +127,8 @@ TextureSystem::create(bool shared, std::shared_ptr imagecache) imagecache = ImageCache::create(false); own_ic = true; } - auto ts = std::make_shared(imagecache); - ts->m_imagecache_owner = own_ic; + auto ts = std::make_shared(imagecache); + ts->m_impl->m_imagecache_owner = own_ic; OIIO_PRAGMA_WARNING_POP return ts; } @@ -121,8 +141,8 @@ TextureSystem::destroy(std::shared_ptr& ts, { if (!ts) return; - TextureSystemImpl* impl = (TextureSystemImpl*)ts.get(); if (teardown_imagecache) { + TextureSystemImpl* impl = ts->m_impl.get(); if (impl->m_imagecache_owner) ImageCache::destroy(impl->m_imagecache_sp, true); impl->m_imagecache = nullptr; @@ -134,7 +154,346 @@ TextureSystem::destroy(std::shared_ptr& ts, -namespace pvt { // namespace pvt +TextureSystem::Perthread* +TextureSystem::get_perthread_info(Perthread* thread_info) +{ + return m_impl->get_perthread_info( + (TextureSystemImpl::Perthread*)thread_info); +} + + + +TextureSystem::Perthread* +TextureSystem::create_thread_info() +{ + return m_impl->create_thread_info(); +} + + + +void +TextureSystem::destroy_thread_info(Perthread* threadinfo) +{ + m_impl->destroy_thread_info((TextureSystemImpl::Perthread*)threadinfo); +} + + + +bool +TextureSystem::attribute(string_view name, TypeDesc type, const void* val) +{ + return m_impl->attribute(name, type, val); +} + + + +TypeDesc +TextureSystem::getattributetype(string_view name) const +{ + return m_impl->getattributetype(name); +} + + + +bool +TextureSystem::getattribute(string_view name, TypeDesc type, void* val) const +{ + return m_impl->getattribute(name, type, val); +} + + + +TextureSystem::TextureHandle* +TextureSystem::get_texture_handle(ustring filename, Perthread* thread_info, + const TextureOpt* options) +{ + return m_impl->get_texture_handle( + filename, (TextureSystemImpl::Perthread*)thread_info, options); +} + + + +bool +TextureSystem::good(TextureHandle* texture_handle) +{ + return m_impl->good(texture_handle); +} + + + +ustring +TextureSystem::filename_from_handle(TextureHandle* handle) +{ + return m_impl->filename_from_handle(handle); +} + + + +int +TextureSystem::get_colortransform_id(ustring fromspace, ustring tospace) const +{ + return m_impl->get_colortransform_id(fromspace, tospace); +} + + +int +TextureSystem::get_colortransform_id(ustringhash fromspace, + ustringhash tospace) const +{ + return m_impl->get_colortransform_id(fromspace, tospace); +} + + + +bool +TextureSystem::texture(ustring filename, TextureOpt& options, float s, float t, + float dsdx, float dtdx, float dsdy, float dtdy, + int nchannels, float* result, float* dresultds, + float* dresultdt) +{ + return m_impl->texture(filename, options, s, t, dsdx, dtdx, dsdy, dtdy, + nchannels, result, dresultds, dresultdt); +} + + +bool +TextureSystem::texture(TextureHandle* texture_handle, Perthread* thread_info, + TextureOpt& options, float s, float t, float dsdx, + float dtdx, float dsdy, float dtdy, int nchannels, + float* result, float* dresultds, float* dresultdt) +{ + return m_impl->texture(texture_handle, thread_info, options, s, t, dsdx, + dtdx, dsdy, dtdy, nchannels, result, dresultds, + dresultdt); +} + + +bool +TextureSystem::texture(ustring filename, TextureOptBatch& options, + Tex::RunMask mask, const float* s, const float* t, + const float* dsdx, const float* dtdx, const float* dsdy, + const float* dtdy, int nchannels, float* result, + float* dresultds, float* dresultdt) +{ + return m_impl->texture(filename, options, mask, s, t, dsdx, dtdx, dsdy, + dtdy, nchannels, result, dresultds, dresultdt); +} + + +bool +TextureSystem::texture(TextureHandle* texture_handle, Perthread* thread_info, + TextureOptBatch& options, Tex::RunMask mask, + const float* s, const float* t, const float* dsdx, + const float* dtdx, const float* dsdy, const float* dtdy, + int nchannels, float* result, float* dresultds, + float* dresultdt) +{ + return m_impl->texture(texture_handle, thread_info, options, mask, s, t, + dsdx, dtdx, dsdy, dtdy, nchannels, result, dresultds, + dresultdt); +} + + + +std::string +TextureSystem::resolve_filename(const std::string& filename) const +{ + return m_impl->resolve_filename(filename); +} + + + +bool +TextureSystem::get_texture_info(ustring filename, int subimage, + ustring dataname, TypeDesc datatype, void* data) +{ + return m_impl->get_texture_info(filename, subimage, dataname, datatype, + data); +} + + +bool +TextureSystem::get_texture_info(TextureHandle* texture_handle, + Perthread* thread_info, int subimage, + ustring dataname, TypeDesc datatype, void* data) +{ + return m_impl->get_texture_info(texture_handle, thread_info, subimage, + dataname, datatype, data); +} + + +bool +TextureSystem::get_imagespec(ustring filename, int subimage, ImageSpec& spec) +{ + return m_impl->get_imagespec(filename, subimage, spec); +} + + +bool +TextureSystem::get_imagespec(TextureHandle* texture_handle, + Perthread* thread_info, int subimage, + ImageSpec& spec) +{ + return m_impl->get_imagespec(texture_handle, thread_info, subimage, spec); +} + + +const ImageSpec* +TextureSystem::imagespec(ustring filename, int subimage) +{ + return m_impl->imagespec(filename, subimage); +} + + +const ImageSpec* +TextureSystem::imagespec(TextureHandle* texture_handle, Perthread* thread_info, + int subimage) +{ + return m_impl->imagespec(texture_handle, thread_info, subimage); +} + + +bool +TextureSystem::get_texels(ustring filename, TextureOpt& options, int miplevel, + int xbegin, int xend, int ybegin, int yend, + int zbegin, int zend, int chbegin, int chend, + TypeDesc format, void* result) +{ + return m_impl->get_texels(filename, options, miplevel, xbegin, xend, ybegin, + yend, zbegin, zend, chbegin, chend, format, + result); +} + + +bool +TextureSystem::get_texels(TextureHandle* texture_handle, Perthread* thread_info, + TextureOpt& options, int miplevel, int xbegin, + int xend, int ybegin, int yend, int zbegin, int zend, + int chbegin, int chend, TypeDesc format, void* result) +{ + return m_impl->get_texels(texture_handle, thread_info, options, miplevel, + xbegin, xend, ybegin, yend, zbegin, zend, chbegin, + chend, format, result); +} + + + +bool +TextureSystem::is_udim(ustring filename) +{ + return m_impl->is_udim(filename); +} + + +bool +TextureSystem::is_udim(TextureHandle* udimfile) +{ + return m_impl->is_udim(udimfile); +} + + + +TextureSystem::TextureHandle* +TextureSystem::resolve_udim(ustring udimpattern, float s, float t) +{ + return m_impl->resolve_udim(udimpattern, s, t); +} + + +TextureSystem::TextureHandle* +TextureSystem::resolve_udim(TextureHandle* udimfile, Perthread* thread_info, + float s, float t) +{ + return m_impl->resolve_udim(udimfile, thread_info, s, t); +} + + + +void +TextureSystem::inventory_udim(ustring udimpattern, + std::vector& filenames, int& nutiles, + int& nvtiles) +{ + m_impl->inventory_udim(udimpattern, filenames, nutiles, nvtiles); +} + + +void +TextureSystem::inventory_udim(TextureHandle* udimfile, Perthread* thread_info, + std::vector& filenames, int& nutiles, + int& nvtiles) +{ + m_impl->inventory_udim(udimfile, thread_info, filenames, nutiles, nvtiles); +} + + + +void +TextureSystem::invalidate(ustring filename, bool force) +{ + m_impl->invalidate(filename, force); +} + + +void +TextureSystem::invalidate_all(bool force) +{ + m_impl->invalidate_all(force); +} + + + +void +TextureSystem::close(ustring filename) +{ + m_impl->close(filename); +} + + +void +TextureSystem::close_all() +{ + m_impl->close_all(); +} + + + +bool +TextureSystem::has_error() const +{ + return m_impl->has_error(); +} + + +std::string +TextureSystem::geterror(bool clear) const +{ + return m_impl->geterror(clear); +} + + + +std::string +TextureSystem::getstats(int level, bool icstats) const +{ + return m_impl->getstats(level, icstats); +} + + +void +TextureSystem::reset_stats() +{ + m_impl->reset_stats(); +} + + + +std::shared_ptr +TextureSystem::imagecache() const +{ + return m_impl->m_imagecache_sp; +} + EightBitConverter TextureSystemImpl::uchar2float; @@ -145,7 +504,6 @@ EightBitConverter TextureSystemImpl::uchar2float; // result is a valid pixel coordinate, false if black should be used // instead. - bool TextureSystemImpl::wrap_periodic_sharedborder(int& coord, int origin, int width) { @@ -174,6 +532,7 @@ const TextureSystemImpl::wrap_impl TextureSystemImpl::wrap_functions[] = { }; +namespace pvt { simd::vbool4 wrap_black_simd(simd::vint4& coord_, const simd::vint4& origin, @@ -312,12 +671,15 @@ texture_type_name(TexFormat f) } +} // namespace pvt + + TextureSystemImpl::TextureSystemImpl(std::shared_ptr imagecache) : m_id(++txsys_next_id) { - m_imagecache_sp = imagecache; - m_imagecache = (ImageCacheImpl*)m_imagecache_sp.get(); + m_imagecache_sp = std::move(imagecache); + m_imagecache = (ImageCacheImpl*)m_imagecache_sp->m_impl.get(); init(); } @@ -337,7 +699,7 @@ TextureSystemImpl::init() // Allow environment variable to override default options const char* options = getenv("OPENIMAGEIO_TEXTURE_OPTIONS"); if (options) - attribute("options", options); + attribute("options", TypeString, &options); if (do_unit_test_texture) unit_test_texture(); @@ -2449,33 +2811,33 @@ TextureSystemImpl::sample_bilinear( namespace { - // Evaluate Bspline weights for both value and derivatives (if dw is not - // NULL) into w[0..3] and dw[0..3]. This is the canonical version for - // reference, but we don't actually call it, instead favoring the much - // harder to read SIMD versions below. - template - inline void evalBSplineWeights_and_derivs(T* w, T fraction, T* dw = NULL) - { - T one_frac = 1.0 - fraction; - w[0] = T(1.0 / 6.0) * one_frac * one_frac * one_frac; - w[1] = T(2.0 / 3.0) - - T(0.5) * fraction * fraction * (T(2.0) - fraction); - w[2] = T(2.0 / 3.0) - - T(0.5) * one_frac * one_frac * (T(2.0) - one_frac); - w[3] = T(1.0 / 6.0) * fraction * fraction * fraction; - if (dw) { - dw[0] = T(-0.5) * one_frac * one_frac; - dw[1] = T(0.5) * fraction * (T(3.0) * fraction - T(4.0)); - dw[2] = T(-0.5) * one_frac * (T(3.0) * one_frac - T(4.0)); - dw[3] = T(0.5) * fraction * fraction; - } +// Evaluate Bspline weights for both value and derivatives (if dw is not +// NULL) into w[0..3] and dw[0..3]. This is the canonical version for +// reference, but we don't actually call it, instead favoring the much +// harder to read SIMD versions below. +template +inline void +evalBSplineWeights_and_derivs(T* w, T fraction, T* dw = NULL) +{ + T one_frac = 1.0 - fraction; + w[0] = T(1.0 / 6.0) * one_frac * one_frac * one_frac; + w[1] = T(2.0 / 3.0) - T(0.5) * fraction * fraction * (T(2.0) - fraction); + w[2] = T(2.0 / 3.0) - T(0.5) * one_frac * one_frac * (T(2.0) - one_frac); + w[3] = T(1.0 / 6.0) * fraction * fraction * fraction; + if (dw) { + dw[0] = T(-0.5) * one_frac * one_frac; + dw[1] = T(0.5) * fraction * (T(3.0) * fraction - T(4.0)); + dw[2] = T(-0.5) * one_frac * (T(3.0) * one_frac - T(4.0)); + dw[3] = T(0.5) * fraction * fraction; } +} - // Evaluate the 4 Bspline weights (no derivs), returning them as a vfloat4. - // The fraction also comes in as a vfloat4 (assuming the same value in all 4 - // slots). - inline vfloat4 evalBSplineWeights(const vfloat4& fraction) - { +// Evaluate the 4 Bspline weights (no derivs), returning them as a vfloat4. +// The fraction also comes in as a vfloat4 (assuming the same value in all 4 +// slots). +inline vfloat4 +evalBSplineWeights(const vfloat4& fraction) +{ #if 0 // Version that's easy to read and understand: float one_frac = 1.0f - fraction; @@ -2486,24 +2848,25 @@ namespace { w[3] = 0.0f + (1.0f / 6.0f) * fraction * fraction * fraction; return w; #else - // Not as clear, but fastest version I've been able to achieve: - OIIO_SIMD_FLOAT4_CONST4(A, 0.0f, 2.0f / 3.0f, 2.0f / 3.0f, 0.0f); - OIIO_SIMD_FLOAT4_CONST4(B, 1.0f / 6.0f, -0.5f, -0.5f, 1.0f / 6.0f); - OIIO_SIMD_FLOAT4_CONST4(om1m1o, 1.0f, -1.0f, -1.0f, 1.0f); - OIIO_SIMD_FLOAT4_CONST4(z22z, 0.0f, 2.0f, 2.0f, 0.0f); - simd::vfloat4 one_frac = vfloat4::One() - fraction; - simd::vfloat4 ofof = AxBxAyBy(one_frac, - fraction); // 1-frac, frac, 1-frac, frac - simd::vfloat4 C = (*(vfloat4*)&om1m1o) * ofof + (*(vfloat4*)&z22z); - return (*(vfloat4*)&A) + (*(vfloat4*)&B) * ofof * ofof * C; + // Not as clear, but fastest version I've been able to achieve: + OIIO_SIMD_FLOAT4_CONST4(A, 0.0f, 2.0f / 3.0f, 2.0f / 3.0f, 0.0f); + OIIO_SIMD_FLOAT4_CONST4(B, 1.0f / 6.0f, -0.5f, -0.5f, 1.0f / 6.0f); + OIIO_SIMD_FLOAT4_CONST4(om1m1o, 1.0f, -1.0f, -1.0f, 1.0f); + OIIO_SIMD_FLOAT4_CONST4(z22z, 0.0f, 2.0f, 2.0f, 0.0f); + simd::vfloat4 one_frac = vfloat4::One() - fraction; + simd::vfloat4 ofof = AxBxAyBy(one_frac, + fraction); // 1-frac, frac, 1-frac, frac + simd::vfloat4 C = (*(vfloat4*)&om1m1o) * ofof + (*(vfloat4*)&z22z); + return (*(vfloat4*)&A) + (*(vfloat4*)&B) * ofof * ofof * C; #endif - } +} - // Evaluate Bspline weights for both value and derivatives (if dw is not - // NULL), returning the 4 coefficients for each as vfloat4's. - inline void evalBSplineWeights_and_derivs(simd::vfloat4* w, float fraction, - simd::vfloat4* dw = NULL) - { +// Evaluate Bspline weights for both value and derivatives (if dw is not +// NULL), returning the 4 coefficients for each as vfloat4's. +inline void +evalBSplineWeights_and_derivs(simd::vfloat4* w, float fraction, + simd::vfloat4* dw = NULL) +{ #if 0 // Version that's easy to read and understand: float one_frac = 1.0f - fraction; @@ -2518,21 +2881,21 @@ namespace { (*dw)[3] = 0.5f * fraction * (1.0f * fraction - 0.0f); } #else - // Not as clear, but fastest version I've been able to achieve: - OIIO_SIMD_FLOAT4_CONST4(A, 0.0f, 2.0f / 3.0f, 2.0f / 3.0f, 0.0f); - OIIO_SIMD_FLOAT4_CONST4(B, 1.0f / 6.0f, -0.5f, -0.5f, 1.0f / 6.0f); - float one_frac = 1.0f - fraction; - simd::vfloat4 ofof(one_frac, fraction, one_frac, fraction); - simd::vfloat4 C(one_frac, 2.0f - fraction, 2.0f - one_frac, fraction); - *w = (*(vfloat4*)&A) + (*(vfloat4*)&B) * ofof * ofof * C; - if (dw) { - const simd::vfloat4 D(-0.5f, 0.5f, -0.5f, 0.5f); - const simd::vfloat4 E(1.0f, 3.0f, 3.0f, 1.0f); - const simd::vfloat4 F(0.0f, 4.0f, 4.0f, 0.0f); - *dw = D * ofof * (E * ofof - F); - } -#endif + // Not as clear, but fastest version I've been able to achieve: + OIIO_SIMD_FLOAT4_CONST4(A, 0.0f, 2.0f / 3.0f, 2.0f / 3.0f, 0.0f); + OIIO_SIMD_FLOAT4_CONST4(B, 1.0f / 6.0f, -0.5f, -0.5f, 1.0f / 6.0f); + float one_frac = 1.0f - fraction; + simd::vfloat4 ofof(one_frac, fraction, one_frac, fraction); + simd::vfloat4 C(one_frac, 2.0f - fraction, 2.0f - one_frac, fraction); + *w = (*(vfloat4*)&A) + (*(vfloat4*)&B) * ofof * ofof * C; + if (dw) { + const simd::vfloat4 D(-0.5f, 0.5f, -0.5f, 0.5f); + const simd::vfloat4 E(1.0f, 3.0f, 3.0f, 1.0f); + const simd::vfloat4 F(0.0f, 4.0f, 4.0f, 0.0f); + *dw = D * ofof * (E * ofof - F); } +#endif +} } // anonymous namespace @@ -3090,8 +3453,6 @@ TextureSystemImpl::unit_test_texture() } } -} // end namespace pvt - void @@ -3113,9 +3474,6 @@ TextureSystem::unit_test_hash() auto imagecache = ImageCache::create(); // Set up the ImageCacheFiles outside of the timing loop - using OIIO::pvt::ImageCacheFile; - using OIIO::pvt::ImageCacheFileRef; - using OIIO::pvt::ImageCacheImpl; std::vector icf; for (int f = 0; f < nfiles; ++f) { ustring filename = ustring::fmtformat("{:06}.tif", f); @@ -3129,7 +3487,7 @@ TextureSystem::unit_test_hash() for (int f = 0; f < nfiles; ++f) { for (int y = 0; y < res; y += tilesize) { for (int x = 0; x < res; x += tilesize, ++i) { - OIIO::pvt::TileID id(*icf[f], 0, 0, x, y, 0, 0, 1); + TileID id(*icf[f], 0, 0, x, y, 0, 0, 1); size_t h = id.hash(); hh += h; } @@ -3147,7 +3505,7 @@ TextureSystem::unit_test_hash() for (int f = 0; f < nfiles; ++f) { for (int y = 0; y < res; y += tilesize) { for (int x = 0; x < res; x += tilesize, ++i) { - OIIO::pvt::TileID id(*icf[f], 0, 0, x, y, 0, 0, 1); + TileID id(*icf[f], 0, 0, x, y, 0, 0, 1); size_t h = id.hash(); ++fourbits[h & 0xf]; ++eightbits[h & 0xff];