From 7c3c0635e5c520ba4ff840753b7c9d5ead1355db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 24 Oct 2021 19:35:37 +0200 Subject: [PATCH] Trade: add ImporterFlag::ZeroCopy. It's great to see how the design nicely fermented over the three and half (!!) years. This is a completely opt-in feature for all plugins involved, so if the plugin decides to not do anything about it, it doesn't have to. The actual enforcements will come later. --- src/Magnum/Trade/AbstractImporter.cpp | 4 ++- src/Magnum/Trade/AbstractImporter.h | 25 ++++++++++++++++++- .../Trade/Test/AbstractImporterTest.cpp | 11 ++++---- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/Magnum/Trade/AbstractImporter.cpp b/src/Magnum/Trade/AbstractImporter.cpp index fb6a96c08..0a3fd2d05 100644 --- a/src/Magnum/Trade/AbstractImporter.cpp +++ b/src/Magnum/Trade/AbstractImporter.cpp @@ -1176,6 +1176,7 @@ Debug& operator<<(Debug& debug, const ImporterFlag value) { /* LCOV_EXCL_START */ #define _c(v) case ImporterFlag::v: return debug << "::" #v; _c(Verbose) + _c(ZeroCopy) #undef _c /* LCOV_EXCL_STOP */ } @@ -1185,7 +1186,8 @@ Debug& operator<<(Debug& debug, const ImporterFlag value) { Debug& operator<<(Debug& debug, const ImporterFlags value) { return Containers::enumSetDebugOutput(debug, value, "Trade::ImporterFlags{}", { - ImporterFlag::Verbose}); + ImporterFlag::Verbose, + ImporterFlag::ZeroCopy}); } }} diff --git a/src/Magnum/Trade/AbstractImporter.h b/src/Magnum/Trade/AbstractImporter.h index 409bf8103..9625d511d 100644 --- a/src/Magnum/Trade/AbstractImporter.h +++ b/src/Magnum/Trade/AbstractImporter.h @@ -113,6 +113,28 @@ enum class ImporterFlag: UnsignedByte { */ Verbose = 1 << 0, + /** + * Opt-in to zero-copy import, if possible. When this flag is set and + * @ref AbstractImporter::openMemory() is used, returned @ref AnimationData, + * @ref ImageData, @ref MaterialData, @ref MeshData and @ref SkinData + * instances may be views on memory passed to + * @relativeref{AbstractImporter,openMemory()} instead of allocated copies, + * indicated with @ref DataFlag::ExternallyOwned. + * + * Since it's not always possible to directly reference the input memory + * (for example because the input data may need to be parsed from text, + * gathered from an incompatible data layout or patched in some way), this + * flag doesn't put any requirement on the importer --- plugins that don't + * support zero-copy import will behave the same as if this flag was not + * set. + * + * Setting this flag however means you're responsible to keep the memory + * passed to @relativeref{AbstractImporter,openMemory()} in scope for as + * long as any `*Data` instances referencing it are alive. + * @m_since_latest + */ + ZeroCopy = 1 << 1, + /** @todo ~~Y flip~~ Y up for images, "I want to import just once, don't copy" ... */ }; @@ -654,7 +676,8 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi * scope until the importer is destructed, @ref close() is called or * another file is opened. This allows the implementation to directly * operate on the provided memory, without having to allocate a local - * copy to extend its lifetime. + * copy to extend its lifetime. See also @ref ImporterFlag::ZeroCopy + * for a possibility of further optimizations. * @see @ref features(), @ref openFile(), @ref openState() */ bool openMemory(Containers::ArrayView memory); diff --git a/src/Magnum/Trade/Test/AbstractImporterTest.cpp b/src/Magnum/Trade/Test/AbstractImporterTest.cpp index 55fd40800..17da10077 100644 --- a/src/Magnum/Trade/Test/AbstractImporterTest.cpp +++ b/src/Magnum/Trade/Test/AbstractImporterTest.cpp @@ -586,14 +586,13 @@ void AbstractImporterTest::setFlags() { CORRADE_COMPARE(importer.flags(), ImporterFlag::Verbose); CORRADE_COMPARE(importer._flags, ImporterFlag::Verbose); - /** @todo use a real flag when we have more than one */ - importer.addFlags(ImporterFlag(4)); - CORRADE_COMPARE(importer.flags(), ImporterFlag::Verbose|ImporterFlag(4)); - CORRADE_COMPARE(importer._flags, ImporterFlag::Verbose|ImporterFlag(4)); + importer.addFlags(ImporterFlag::ZeroCopy); + CORRADE_COMPARE(importer.flags(), ImporterFlag::Verbose|ImporterFlag::ZeroCopy); + CORRADE_COMPARE(importer._flags, ImporterFlag::Verbose|ImporterFlag::ZeroCopy); importer.clearFlags(ImporterFlag::Verbose); - CORRADE_COMPARE(importer.flags(), ImporterFlag(4)); - CORRADE_COMPARE(importer._flags, ImporterFlag(4)); + CORRADE_COMPARE(importer.flags(), ImporterFlag::ZeroCopy); + CORRADE_COMPARE(importer._flags, ImporterFlag::ZeroCopy); } void AbstractImporterTest::setFlagsFileOpened() {