An ExtSerialization manager is created using the global function NvBlastExtSerializationCreate:
(From now on we'll assume we are using the Nv::Blast namespace.)
ExtSerialization* ser = NvBlastExtSerializationCreate();
ExtSerialization is capable of loading sets of serializers for different data types and encodings. The NvBlastExtSerialization extension comes with a set of low-level data serializers, with types enumerated in the header NvBlastExtLlSerialization.h.
The low-level serializers are automatically loaded into an ExtSerialization when it is created.
To load serializers for Tk and ExtPhysX assets, you must also load the extensions BlastTk Serialization (NvBlastExtTkSerialization) and ExtPhysX Serialization (NvBlastExtPxSerialization), respectively. See the documentation for those modules.
Each serializer is capable of reading (and writing, if it is not read-only) a single data type in a single encoding (format). Some serializers are read-only, in order to read legacy formats.
The encodings available are enumerated in ExtSerialization::EncodingID. They are currently:
Each serialization module defines the object types it can serialize. ExtSerialization defines the low-level types in NvBlastExtLlSerialization.h:
To serialize an object, for example an NvBlastAsset, use ExtSerialization::serializeIntoBuffer as follows:
const NvBlastAsset* asset = ... // Given pointer to an NvBlastAsset void* buffer; uint64_t size = ser->serializeIntoBuffer(buffer, asset, LlObjectTypeID::Asset);
If successful, the data is written into a buffer allocated using the NvBlastGlobals allocator, written to the "buffer" parameter, and the size of the buffer written is the return value of the function. If the function returns 0, then serialization was unsuccessful. Notice that the second function parameter is actually a void*, so it requires the last parameter to tell it what object it is serializing. A utility wrapper function is given in NvBlastExtLlSerialization.h which performs the same operation with an NvBlastAsset, so one could equivalently use
void* buffer; uint64_t size = NvBlastExtSerializationSerializeAssetIntoBuffer(buffer, *ser, asset);
A corresponding function also exists for NvBlastFamily, as well as other data types supported by other serialization extensions.
This buffer may be written to disk, memory, networked, etc. Since the memory for the buffer is allocated using the allocator in NvBlastGlobals, it may be freed using the same allocator:
NVBLAST_FREE(buffer)
For example:
std::vector<char> growableBuffer; class MyBufferProvider : public Nv::Blast::ExtSerialization::BufferProvider { public: MyBufferProvider(std::vector<char>& growableBuffer) : m_growableBuffer(growableBuffer) {} virtual void* requestBuffer(size_t size) override { if (m_growableBuffer.size() < size) { m_growableBuffer.resize(size); } return m_growableBuffer.data(); } private: std::vector<char>& m_growableBuffer; } myBufferProvider(growableBuffer); ser->setBufferProvider(&myBufferProvider);
Passing NULL to setBufferProvider returns the serialization to its default behavior of using the NvBlastGlobals allocator.
const void* buffer = ... // A given buffer, may be read from disk, memory, etc. const uint64_t size = ... // The buffer's size in bytes NvBlastAsset* asset = static_cast<NvBlastAsset*>(ser->deserializeFromBuffer(buffer, size));
This returns a valid pointer if deserialization was successful, or NULL otherwise. If no serializer is loaded which can handle the object type in the stream in its given encoding, it will fail and return NULL.
Again, the memory for the asset is allocated using NvBlastGlobals, so that the asset may be released using
NVBLAST_FREE(asset);
uint32_t objTypeID; void* obj = ser->deserializeFromBuffer(buffer, size, &objTypeID); NVBLAST_CHECK_ERROR(obj != nullptr, "Object could not be read from buffer.", return); switch (objTypeID) { case LlObjectTypeID::Asset: handleAssetLoad(static_cast<NvBlastAsset*>(obj)); break; case LlObjectTypeID::Family: handleFamilyLoad(static_cast<NvBlastFamily*>(obj)); break; default: NVBLAST_LOG_ERROR("Unknown object type "); }
const void* buffer = ... // The input buffer uint64_t size = ... // The input buffer size while (size) { uint64_t objTypeID; if (!ser->peekHeader(&objTypeID, NULL, NULL, buffer, size)) // Only reading the object type ID; may pass in NULL for the other header value pointers { break; // Read error, stop } if (objectShouldBeLoaded(objTypeID)) // Some function to determine whether or not we want this object { void* obj = ser->deserializeFromBuffer(buffer, size); // Handle loaded object ... } // Jump to next object: buffer = ser->skipObject(size, buffer); // Updates size as well }
ser->release();