diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/core/slang-memory-arena.cpp | 36 | ||||
| -rw-r--r-- | source/core/slang-memory-arena.h | 3 | ||||
| -rw-r--r-- | source/core/slang-riff.cpp | 102 | ||||
| -rw-r--r-- | source/core/slang-riff.h | 116 | ||||
| -rw-r--r-- | source/slang/slang-ir-serialize.cpp | 78 |
5 files changed, 223 insertions, 112 deletions
diff --git a/source/core/slang-memory-arena.cpp b/source/core/slang-memory-arena.cpp index a9fc1ec19..6fc6c0c3f 100644 --- a/source/core/slang-memory-arena.cpp +++ b/source/core/slang-memory-arena.cpp @@ -258,6 +258,42 @@ MemoryArena::Block* MemoryArena::_newBlock(size_t allocSize, size_t alignment) return block; } +void MemoryArena::addExternalBlock(void* inData, size_t size) +{ + // Allocate block + Block* block = (Block*)m_blockFreeList.allocate(); + if (!block) + { + return; + } + + uint8_t* alloc = (uint8_t*)inData; + + const size_t alignMask = m_blockAlignment - 1; + + // Do the alignment on the allocation + uint8_t* const start = (uint8_t*)((size_t(alloc) + alignMask) & ~alignMask); + + // Setup the block + block->m_alloc = alloc; + block->m_start = start; + block->m_end = alloc + size; + block->m_next = nullptr; + + // We don't want to place at start, if there is any used blocks - as that is the one + // that is being split from and can be rewound. So we place just behind in that case + if (m_usedBlocks) + { + block->m_next = m_usedBlocks->m_next; + m_usedBlocks->m_next = block; + } + else + { + // There aren't any blocks, so just place at the front + m_usedBlocks = block; + } +} + void* MemoryArena::_allocateAlignedFromNewBlockAndZero(size_t sizeInBytes, size_t alignment) { void* mem = _allocateAlignedFromNewBlock(sizeInBytes, alignment); diff --git a/source/core/slang-memory-arena.h b/source/core/slang-memory-arena.h index 75744710f..d346197f0 100644 --- a/source/core/slang-memory-arena.h +++ b/source/core/slang-memory-arena.h @@ -138,6 +138,9 @@ public: /// Rewind (and effectively deallocate) all allocations *after* the cursor void rewindToCursor(const void* cursor); + /// Add a block such that it will be freed when everything else is freed. + void addExternalBlock(void* data, size_t size); + /// Default Ctor MemoryArena(); /// Construct with block size and alignment. Block alignment must be a power of 2. diff --git a/source/core/slang-riff.cpp b/source/core/slang-riff.cpp index 9849cfc26..3a3722bb8 100644 --- a/source/core/slang-riff.cpp +++ b/source/core/slang-riff.cpp @@ -175,7 +175,7 @@ struct DumpVisitor : public RiffContainer::Visitor // If it's the root it's 'riff' _dumpRiffType(list == m_rootChunk ? RiffFourCC::kRiff : RiffFourCC::kList); m_writer.put(" "); - _dumpRiffType(list->m_subType); + _dumpRiffType(list->getSubType()); m_writer.put("\n"); m_indent++; return SLANG_OK; @@ -184,10 +184,9 @@ struct DumpVisitor : public RiffContainer::Visitor { _dumpIndent(); // Write out the name - _dumpRiffType(data->m_type); + _dumpRiffType(data->m_fourCC); m_writer.put(" "); - int hash = data->calcHash(); // We don't know in general what the contents is or means... but we can display a hash @@ -250,7 +249,7 @@ struct DumpVisitor : public RiffContainer::Visitor listHeader.chunk.type = isRoot ? RiffFourCC::kRiff : RiffFourCC::kList; listHeader.chunk.size = uint32_t(list->m_payloadSize); - listHeader.subType = list->m_subType; + listHeader.subType = list->getSubType(); try { @@ -276,7 +275,7 @@ struct DumpVisitor : public RiffContainer::Visitor // Must be a regular chunk with data RiffHeader chunkHeader; - chunkHeader.type = dataChunk->m_type; + chunkHeader.type = dataChunk->m_fourCC; chunkHeader.size = uint32_t(dataChunk->m_payloadSize); stream->write(&chunkHeader, sizeof(chunkHeader)); @@ -386,7 +385,9 @@ struct DumpVisitor : public RiffContainer::Visitor else { ScopeChunk scopeChunk(&outContainer, Chunk::Kind::Data, header.chunk.type); - RiffContainer::Data* data = outContainer.addData(header.chunk.size); + RiffContainer::Data* data = outContainer.addData(); + + outContainer.setPayload(data, nullptr, header.chunk.size); size_t readSize; SLANG_RETURN_ON_FAIL(readPayload(stream, header.chunk.size, data->getPayload(), readSize)); @@ -520,15 +521,12 @@ size_t RiffContainer::ListChunk::calcPayloadSize() return size; } -RiffContainer::Chunk* RiffContainer::ListChunk::findContained(FourCC type) const +RiffContainer::Chunk* RiffContainer::ListChunk::findContained(FourCC fourCC) const { Chunk* chunk = m_containedChunks; while (chunk) { - const FourCC checkType = (chunk->m_kind == Chunk::Kind::Data) ? - static_cast<RiffContainer::DataChunk*>(chunk)->m_type : - static_cast<RiffContainer::ListChunk*>(chunk)->m_subType; - if (checkType == type) + if (chunk->m_fourCC == fourCC) { return chunk; } @@ -568,7 +566,7 @@ static RiffContainer::ListChunk* _findListRec(RiffContainer::ListChunk* list, Fo if (auto childList = as<RiffContainer::ListChunk>(chunk)) { // Test if the child is the subtype, if so we are done - if (childList->m_subType == subType) + if (childList->getSubType() == subType) { return childList; } @@ -585,23 +583,25 @@ static RiffContainer::ListChunk* _findListRec(RiffContainer::ListChunk* list, Fo /* static */RiffContainer::ListChunk* RiffContainer::ListChunk::findListRec(FourCC subType) { - return (m_subType == subType) ? this : _findListRec(this, subType); + return (getSubType() == subType) ? this : _findListRec(this, subType); } // !!!!!!!!!!!!!!!!!!!!!!!!!!! RiffContainer::DataChunk !!!!!!!!!!!!!!!!!!!!!! RiffContainer::Data* RiffContainer::DataChunk::getSingleData() const { - if (m_kind == Kind::Data) + Data* data = m_dataList; + return (data && data->m_next == nullptr) ? data : nullptr; +} + +RiffReadHelper RiffContainer::DataChunk::asReadHelper() const +{ + Data* data = getSingleData(); + if (data) { - auto dataChunk = static_cast<const DataChunk*>(this); - Data* data = dataChunk->m_dataList; - if (data && data->m_next == nullptr) - { - return data; - } + return RiffReadHelper((const uint8_t*)data->getPayload(), data->getSize()); } - return nullptr; + return RiffReadHelper(nullptr, 0); } int RiffContainer::DataChunk::calcHash() const @@ -765,19 +765,67 @@ void RiffContainer::endChunk() SLANG_ASSERT(isChunkOk(chunk)); } -RiffContainer::Data* RiffContainer::addData(size_t size) +void RiffContainer::setPayload(Data* data, const void* payload, size_t size) { - // We must be in a chunk + // We must be in a data chunk SLANG_ASSERT(m_dataChunk); + // The data shouldn't be set up + SLANG_ASSERT(data->m_ownership == Ownership::Uninitialized); // Add current chunks data m_dataChunk->m_payloadSize += size; - Data* data = (Data*)m_arena.allocate(sizeof(Data) + size); + data->m_ownership = Ownership::Arena; + data->m_size = size; + + data->m_payload = m_arena.allocate(size); + + if (payload) + { + ::memcpy(data->m_payload, payload, size); + } +} - data->m_next = nullptr; +void RiffContainer::moveOwned(Data* data, void* payload, size_t size) +{ + // We must be in a data chunk + SLANG_ASSERT(m_dataChunk); + // The data shouldn't be set up + SLANG_ASSERT(data->m_ownership == Ownership::Uninitialized); + + // Add current chunks data + m_dataChunk->m_payloadSize += size; + + data->m_ownership = Ownership::Owned; data->m_size = size; + // The area will manage this block + m_arena.addExternalBlock(payload, size); + data->m_payload = payload; +} + +void RiffContainer::setUnowned(Data* data, void* payload, size_t size) +{ + // We must be in a data chunk + SLANG_ASSERT(m_dataChunk); + // The data shouldn't be set up + SLANG_ASSERT(data->m_ownership == Ownership::Uninitialized); + // Add current chunks data + m_dataChunk->m_payloadSize += size; + + data->m_ownership = Ownership::NotOwned; + data->m_size = size; + data->m_payload = payload; +} + +RiffContainer::Data* RiffContainer::addData() +{ + // We must be in a chunk + SLANG_ASSERT(m_dataChunk); + + Data* data = (Data*)m_arena.allocate(sizeof(Data)); + data->init(); + Data*& next = m_dataChunk->m_endData ? m_dataChunk->m_endData->m_next : m_dataChunk->m_dataList; SLANG_ASSERT(next == nullptr); @@ -790,8 +838,8 @@ RiffContainer::Data* RiffContainer::addData(size_t size) void RiffContainer::write(const void* inData, size_t size) { - auto data = addData(size); - ::memcpy(data->getPayload(), inData, size); + auto data = addData(); + setPayload(data, inData, size); } static SlangResult _isChunkOk(RiffContainer::Chunk* chunk, void* data) diff --git a/source/core/slang-riff.h b/source/core/slang-riff.h index 9dfe655b6..4d23e45c1 100644 --- a/source/core/slang-riff.h +++ b/source/core/slang-riff.h @@ -98,6 +98,42 @@ struct RiffSemanticVersion RawType m_raw; }; +/* A helper class that makes reading data from a data block simpler */ +class RiffReadHelper +{ +public: + template <typename T> + SlangResult read(T& out) + { + if (m_cur + sizeof(T) > m_end) + { + return SLANG_FAIL; + } + // Make sure the alignment is plausible + SLANG_ASSERT((size_t(m_cur) & (SLANG_ALIGN_OF(T) - 1)) == 0); + ::memcpy(&out, m_cur, sizeof(T)); + m_cur += sizeof(T); + return SLANG_OK; + } + + /// Get the data + const uint8_t* getData() const { return m_cur; } + /// Get the remaining size + size_t getRemainingSize() const { return size_t(m_end - m_cur); } + + RiffReadHelper(const uint8_t* data, size_t size): + m_start(data), + m_end(data + size), + m_cur(data) + { + } + +protected: + const uint8_t* m_start; + const uint8_t* m_end; + const uint8_t* m_cur; +}; + /* A container for data in RIFF format. Holds the contents in memory. With the data held in memory allows for adding or removing chunks at will. @@ -112,24 +148,38 @@ class RiffContainer { public: + enum class Ownership + { + Uninitialized, ///< Doesn't contain anything + NotOwned, ///< It's not owned by the container + Arena, ///< It's owned and allocated on the arena + Owned, ///< It's owned, but wasn't allocated on the arena + }; + struct ListChunk; struct DataChunk; struct Data { - /// Get the payload - void* getPayload() { return (void*)(this + 1); } - size_t getSize() { return m_size; } + /// Get the payload + void* getPayload() { return m_payload; } + /// Get the size of the payload + size_t getSize() const { return m_size; } + /// Get the ownership of the data held in the payload + Ownership getOwnership() const { return m_ownership; } void init() { + m_ownership = Ownership::Uninitialized; m_size = 0; m_next = nullptr; + m_payload = nullptr; } - size_t m_size; - Data* m_next; - // Followed by the payload + Ownership m_ownership; ///< Stores the ownership of the payload + size_t m_size; ///< The size of the payload + void* m_payload; ///< The payload + Data* m_next; ///< The next Data block in the list }; struct Chunk; @@ -144,9 +194,10 @@ public: Data, }; - void init(Kind kind) + void init(Kind kind, FourCC fourCC) { m_kind = kind; + m_fourCC = fourCC; m_payloadSize = 0; m_next = nullptr; m_parent = nullptr; @@ -159,19 +210,14 @@ public: /// Returns a single data chunk Data* getSingleData() const; - /// Get the unique type - FourCC getUniqueType() const; - + /// Calculate the payload size size_t calcPayloadSize(); - // TODO(JS): - // We might want to consider moving subType/type to the Chunk, because in practice they typically - // mean the same thing, and as it has been arranged, for list chunk the overall chunk type is implied - // by the kind. - Kind m_kind; ///< Kind of chunk - size_t m_payloadSize; ///< The payload size (ie does NOT include RiffChunk header). - Chunk* m_next; ///< Next chunk in this list - ListChunk* m_parent; ///< The chunk this belongs to + Kind m_kind; ///< Kind of chunk + FourCC m_fourCC; ///< The chunk type for data, or the sub type for a List (riff/list) + size_t m_payloadSize; ///< The payload size (ie does NOT include RiffChunk header). + Chunk* m_next; ///< Next chunk in this list + ListChunk* m_parent; ///< The chunk this belongs to }; struct ListChunk : public Chunk @@ -181,8 +227,7 @@ public: void init(FourCC subType) { - Super::init(Kind::List); - m_subType = subType; + Super::init(Kind::List, subType); m_containedChunks = nullptr; m_endChunk = nullptr; @@ -206,7 +251,9 @@ public: /// NOTE! Assumes all contained chunks have correct payload sizes size_t calcPayloadSize(); - FourCC m_subType; ///< The subtype of this contained + /// Get the sub type + FourCC getSubType() const { return m_fourCC; } + Chunk* m_containedChunks; ///< The contained chunks Chunk* m_endChunk; ///< The last chunk (only set when pushed, and used when popped) }; @@ -224,15 +271,16 @@ public: /// Get single data payload. Data* getSingleData() const; - void init(FourCC type) + /// Return as read helper + RiffReadHelper asReadHelper() const; + + void init(FourCC fourCC) { - Super::init(Kind::Data); - m_type = type; + Super::init(Kind::Data, fourCC); m_dataList = nullptr; m_endData = nullptr; } - FourCC m_type; ///< Type of chunk Data* m_dataList; ///< List of 0 or more data items Data* m_endData; ///< The last data point }; @@ -266,7 +314,16 @@ public: /// Write data into a chunk (can only be inside a Kind::Data) void write(const void* data, size_t size); - Data* addData(size_t size); + + /// Adds an empty data block + Data* addData(); + /// Set the payload on a data. Payload can be passed as nullptr, if it is no memory will be copied. + void setPayload(Data* data, const void* payload, size_t size); + + /// Move ownership to + void moveOwned(Data* data, void* payload, size_t size); + /// Move unowned + void setUnowned(Data* data, void* payload, size_t size); /// End a chunk void endChunk(); @@ -299,15 +356,10 @@ protected: ListChunk* m_listChunk; DataChunk* m_dataChunk; - MemoryArena m_arena; + MemoryArena m_arena; ///< Can be used to use other owned blocks }; // ----------------------------------------------------------------------------- -SLANG_FORCE_INLINE FourCC RiffContainer::Chunk::getUniqueType() const -{ - return (m_kind == Kind::Data) ? static_cast<const DataChunk*>(this)->m_type : static_cast<const ListChunk*>(this)->m_subType; -} -// ----------------------------------------------------------------------------- template <typename T> T* as(RiffContainer::Chunk* chunk) { diff --git a/source/slang/slang-ir-serialize.cpp b/source/slang/slang-ir-serialize.cpp index ebbb792f4..97b070f9c 100644 --- a/source/slang/slang-ir-serialize.cpp +++ b/source/slang/slang-ir-serialize.cpp @@ -827,7 +827,9 @@ static Result _writeArrayChunk(IRSerialBinary::CompressionType compressionType, header.m_numCompressedEntries = uint32_t(numCompressedEntries); container->write(&header, sizeof(header)); - container->write(compressedPayload.begin(), compressedPayload.getCount()); + + const size_t compressedSize = compressedPayload.getCount(); + container->moveOwned(container->addData(), compressedPayload.detachBuffer(), compressedSize); break; } default: @@ -963,7 +965,10 @@ Result _writeInstArrayChunk(IRSerialBinary::CompressionType compressionType, uin header.m_numCompressedEntries = 0; container->write(&header, sizeof(header)); - container->write(compressedPayload.begin(), compressedPayload.getCount()); + + const size_t compressedPayloadSize = compressedPayload.getCount(); + container->moveOwned(container->addData(), compressedPayload.detachBuffer(), compressedPayloadSize); + return SLANG_OK; } default: break; @@ -1050,56 +1055,32 @@ static Result _readArrayChunk(IRSerialBinary::CompressionType compressionType, R { typedef IRSerialBinary Bin; - RiffContainer::Data* data = dataChunk->getSingleData(); - const uint8_t* cur = (const uint8_t*)data->getPayload(); - const uint8_t* end = cur + data->m_size; - + RiffReadHelper read = dataChunk->asReadHelper(); const size_t typeSize = listOut.getTypeSize(); switch (compressionType) { case Bin::CompressionType::VariableByteLite: { - if (cur + sizeof(Bin::CompressedArrayHeader) > end) - { - return SLANG_FAIL; - } + Bin::CompressedArrayHeader header; + SLANG_RETURN_ON_FAIL(read.read(header)); - // We have a compressed header - Bin::CompressedArrayHeader header = *(const Bin::CompressedArrayHeader*)cur; - cur += sizeof(Bin::CompressedArrayHeader); - void* dst = listOut.setSize(header.m_numEntries); - - // Need to read all the compressed data... - size_t payloadSize = size_t(end - cur); - - List<uint8_t> compressedPayload; - compressedPayload.setCount(payloadSize); - SLANG_ASSERT(header.m_numCompressedEntries == uint32_t((header.m_numEntries * typeSize) / sizeof(uint32_t))); // Decode.. - ByteEncodeUtil::decodeLiteUInt32(cur, header.m_numCompressedEntries, (uint32_t*)dst); + ByteEncodeUtil::decodeLiteUInt32(read.getData(), header.m_numCompressedEntries, (uint32_t*)dst); break; } case Bin::CompressionType::None: { // Read uncompressed - if (cur + sizeof(Bin::ArrayHeader) > end) - { - return SLANG_FAIL; - } - - Bin::ArrayHeader header = *(const Bin::ArrayHeader*)cur; - cur += sizeof(Bin::ArrayHeader); - + Bin::ArrayHeader header; + SLANG_RETURN_ON_FAIL(read.read(header)); const size_t payloadSize = header.m_numEntries * typeSize; - - SLANG_ASSERT(payloadSize == size_t(end - cur)); + SLANG_ASSERT(payloadSize == read.getRemainingSize()); void* dst = listOut.setSize(header.m_numEntries); - - ::memcpy(dst, cur, payloadSize); + ::memcpy(dst, read.getData(), payloadSize); break; } } @@ -1113,7 +1094,7 @@ static Result _readArrayChunk(const IRSerialBinary::ModuleHeader* header, RiffCo Bin::CompressionType compressionType = Bin::CompressionType::None; - if (dataChunk->m_type == SLANG_MAKE_COMPRESSED_FOUR_CC(dataChunk->m_type)) + if (dataChunk->m_fourCC == SLANG_MAKE_COMPRESSED_FOUR_CC(dataChunk->m_fourCC)) { // If it has compression, use the compression type set in the header compressionType = Bin::CompressionType(header->m_compressionType); @@ -1125,10 +1106,9 @@ static Result _readArrayChunk(const IRSerialBinary::ModuleHeader* header, RiffCo template <typename T> static Result _readArrayUncompressedChunk(const IRSerialBinary::ModuleHeader* header, RiffContainer::DataChunk* chunk, List<T>& arrayOut) { - typedef IRSerialBinary Bin; SLANG_UNUSED(header); ListResizerForType<T> resizer(arrayOut); - return _readArrayChunk(Bin::CompressionType::None, chunk, resizer); + return _readArrayChunk(IRSerialBinary::CompressionType::None, chunk, resizer); } static Result _decodeInsts(IRSerialBinary::CompressionType compressionType, const uint8_t* encodeCur, size_t encodeInSize, List<IRSerialData::Inst>& instsOut) @@ -1209,7 +1189,7 @@ static Result _readInstArrayChunk(const IRSerialBinary::ModuleHeader* moduleHead typedef IRSerialBinary Bin; Bin::CompressionType compressionType = Bin::CompressionType::None; - if (chunk->m_type == SLANG_MAKE_COMPRESSED_FOUR_CC(chunk->m_type)) + if (chunk->m_fourCC == SLANG_MAKE_COMPRESSED_FOUR_CC(chunk->m_fourCC)) { compressionType = Bin::CompressionType(moduleHeader->m_compressionType); } @@ -1223,22 +1203,14 @@ static Result _readInstArrayChunk(const IRSerialBinary::ModuleHeader* moduleHead } case Bin::CompressionType::VariableByteLite: { - RiffContainer::Data* data = chunk->getSingleData(); - const uint8_t* cur = (const uint8_t*)data->getPayload(); - const uint8_t* end = cur + data->m_size; - if (cur + sizeof(Bin::CompressedArrayHeader) <= end) - { - return SLANG_FAIL; - } - Bin::CompressedArrayHeader header = *(const Bin::CompressedArrayHeader*)cur; - cur += sizeof(Bin::CompressedArrayHeader); - - arrayOut.setCount(header.m_numEntries); + RiffReadHelper read = chunk->asReadHelper(); - // Need to read all the compressed data... - size_t payloadSize = size_t(end - cur); + Bin::CompressedArrayHeader header; + SLANG_RETURN_ON_FAIL(read.read(header)); + + arrayOut.setCount(header.m_numEntries); - SLANG_RETURN_ON_FAIL(_decodeInsts(compressionType, cur, payloadSize, arrayOut)); + SLANG_RETURN_ON_FAIL(_decodeInsts(compressionType, read.getData(), read.getRemainingSize(), arrayOut)); break; } default: @@ -1270,7 +1242,7 @@ static Result _readInstArrayChunk(const IRSerialBinary::ModuleHeader* moduleHead continue; } - switch (dataChunk->m_type) + switch (dataChunk->m_fourCC) { case SLANG_MAKE_COMPRESSED_FOUR_CC(Bin::kInstFourCc): case Bin::kInstFourCc: |
