summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/core/slang-memory-arena.cpp36
-rw-r--r--source/core/slang-memory-arena.h3
-rw-r--r--source/core/slang-riff.cpp102
-rw-r--r--source/core/slang-riff.h116
-rw-r--r--source/slang/slang-ir-serialize.cpp78
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: