From 9c2d1766ea33101b551ac521ddc39516b98b6641 Mon Sep 17 00:00:00 2001 From: jsmall-nvidia Date: Wed, 23 Oct 2019 09:28:58 -0400 Subject: Expose more repro in API, support output params. (#1087) * Added spEnableReproCapture to the API. * Added MemoryStreamBase - which can be used to read from without copyin the data. Added the missing Repro API functions - spEnableReproCapture and spExtractRepro. Added support for serializing output filenames. * Improved naming around Stream. Brought Stream and sub types closer to code conventions. * Renamed content -> contents in Stream. --- source/core/slang-io.cpp | 4 +- source/core/slang-riff.cpp | 14 +- source/core/slang-stream.cpp | 478 +++++++++++++++++---------------- source/core/slang-stream.h | 255 +++++++++++------- source/core/slang-text-io.cpp | 14 +- source/core/slang-text-io.h | 6 +- source/slang/slang-compiler.h | 13 +- source/slang/slang-file-system.cpp | 2 +- source/slang/slang-ir-serialize.cpp | 42 +-- source/slang/slang-options.cpp | 2 +- source/slang/slang-state-serialize.cpp | 102 +++++-- source/slang/slang-state-serialize.h | 8 + source/slang/slang.cpp | 65 +++-- 13 files changed, 591 insertions(+), 414 deletions(-) (limited to 'source') diff --git a/source/core/slang-io.cpp b/source/core/slang-io.cpp index caa45c8f4..6cff8e1c9 100644 --- a/source/core/slang-io.cpp +++ b/source/core/slang-io.cpp @@ -660,10 +660,10 @@ namespace Slang { RefPtr fs = new FileStream(fileName, FileMode::Open, FileAccess::Read, FileShare::ReadWrite); List buffer; - while (!fs->IsEnd()) + while (!fs->isEnd()) { unsigned char ch; - int read = (int)fs->Read(&ch, 1); + int read = (int)fs->read(&ch, 1); if (read) buffer.add(ch); else diff --git a/source/core/slang-riff.cpp b/source/core/slang-riff.cpp index df2076013..ce8b7129b 100644 --- a/source/core/slang-riff.cpp +++ b/source/core/slang-riff.cpp @@ -20,7 +20,7 @@ namespace Slang } // Skip the payload (we don't need to skip the Chunk because that was already read - stream->Seek(SeekOrigin::Current, chunkSize - sizeof(RiffChunk)); + stream->seek(SeekOrigin::Current, chunkSize - sizeof(RiffChunk)); return SLANG_OK; } @@ -29,7 +29,7 @@ namespace Slang { try { - stream->Read(&outChunk, sizeof(RiffChunk)); + stream->read(&outChunk, sizeof(RiffChunk)); } catch (IOException&) { @@ -53,13 +53,13 @@ namespace Slang try { - out->Write(&chunk, sizeof(chunk)); - out->Write(data, size); + out->write(&chunk, sizeof(chunk)); + out->write(data, size); size_t remaining = size & 3; if (remaining) { uint8_t end[4] = { 0, 0, 0, 0}; - out->Write(end, 4 - remaining); + out->write(end, 4 - remaining); } } catch (IOException&) @@ -79,13 +79,13 @@ namespace Slang try { - stream->Read(data.getBuffer(), outChunk.m_size); + stream->read(data.getBuffer(), outChunk.m_size); // Skip to the alignment uint32_t remaining = outChunk.m_size & 3; if (remaining) { - stream->Seek(SeekOrigin::Current, 4 - remaining); + stream->seek(SeekOrigin::Current, 4 - remaining); } } catch (IOException&) diff --git a/source/core/slang-stream.cpp b/source/core/slang-stream.cpp index ee194c451..b5eef1d9b 100644 --- a/source/core/slang-stream.cpp +++ b/source/core/slang-stream.cpp @@ -6,289 +6,301 @@ namespace Slang { - FileStream::FileStream(const Slang::String & fileName, FileMode fileMode) - { - Init(fileName, fileMode, fileMode==FileMode::Open?FileAccess::Read:FileAccess::Write, FileShare::None); - } - FileStream::FileStream(const Slang::String & fileName, FileMode fileMode, FileAccess access, FileShare share) - { - Init(fileName, fileMode, access, share); - } - void FileStream::Init(const Slang::String & fileName, FileMode fileMode, FileAccess access, FileShare share) + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! FileStream !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +FileStream::FileStream(const String& fileName, FileMode fileMode) +{ + _init(fileName, fileMode, fileMode==FileMode::Open?FileAccess::Read:FileAccess::Write, FileShare::None); +} + +FileStream::FileStream(const String& fileName, FileMode fileMode, FileAccess access, FileShare share) +{ + _init(fileName, fileMode, access, share); +} + +void FileStream::_init(const String& fileName, FileMode fileMode, FileAccess access, FileShare share) +{ + const wchar_t * mode = L"rt"; + const char* modeMBCS = "rt"; + switch (fileMode) { - const wchar_t * mode = L"rt"; - const char* modeMBCS = "rt"; - switch (fileMode) + case FileMode::Create: + if (access == FileAccess::Read) + throw ArgumentException("Read-only access is incompatible with Create mode."); + else if (access == FileAccess::ReadWrite) { - case Slang::FileMode::Create: - if (access == FileAccess::Read) - throw ArgumentException("Read-only access is incompatible with Create mode."); - else if (access == FileAccess::ReadWrite) - { - mode = L"w+b"; - modeMBCS = "w+b"; - this->fileAccess = FileAccess::ReadWrite; - } - else - { - mode = L"wb"; - modeMBCS = "wb"; - this->fileAccess = FileAccess::Write; - } - break; - case Slang::FileMode::Open: - if (access == FileAccess::Read) - { - mode = L"rb"; - modeMBCS = "rb"; - this->fileAccess = FileAccess::Read; - } - else if (access == FileAccess::ReadWrite) - { - mode = L"r+b"; - modeMBCS = "r+b"; - this->fileAccess = FileAccess::ReadWrite; - } - else - { - mode = L"wb"; - modeMBCS = "wb"; - this->fileAccess = FileAccess::Write; - } - break; - case Slang::FileMode::CreateNew: - if (File::exists(fileName)) - { - throw IOException("Failed opening '" + fileName + "', file already exists."); - } - if (access == FileAccess::Read) - throw ArgumentException("Read-only access is incompatible with Create mode."); - else if (access == FileAccess::ReadWrite) - { - mode = L"w+b"; - this->fileAccess = FileAccess::ReadWrite; - } - else - { - mode = L"wb"; - this->fileAccess = FileAccess::Write; - } - break; - case Slang::FileMode::Append: - if (access == FileAccess::Read) - throw ArgumentException("Read-only access is incompatible with Append mode."); - else if (access == FileAccess::ReadWrite) - { - mode = L"a+b"; - this->fileAccess = FileAccess::ReadWrite; - } - else - { - mode = L"ab"; - this->fileAccess = FileAccess::Write; - } - break; - default: - break; + mode = L"w+b"; + modeMBCS = "w+b"; + this->m_fileAccess = FileAccess::ReadWrite; } -#ifdef _WIN32 - int shFlag = _SH_DENYRW; - switch (share) + else { - case Slang::FileShare::None: - shFlag = _SH_DENYRW; - break; - case Slang::FileShare::ReadOnly: - shFlag = _SH_DENYWR; - break; - case Slang::FileShare::WriteOnly: - shFlag = _SH_DENYRD; - break; - case Slang::FileShare::ReadWrite: - shFlag = _SH_DENYNO; - break; - default: - throw ArgumentException("Invalid file share mode."); - break; + mode = L"wb"; + modeMBCS = "wb"; + this->m_fileAccess = FileAccess::Write; } - if (share == Slang::FileShare::None) -#pragma warning(suppress:4996) - handle = _wfopen(fileName.toWString(), mode); - else - handle = _wfsopen(fileName.toWString(), mode, shFlag); -#else - handle = fopen(fileName.getBuffer(), modeMBCS); -#endif - if (!handle) + break; + case FileMode::Open: + if (access == FileAccess::Read) + { + mode = L"rb"; + modeMBCS = "rb"; + this->m_fileAccess = FileAccess::Read; + } + else if (access == FileAccess::ReadWrite) + { + mode = L"r+b"; + modeMBCS = "r+b"; + this->m_fileAccess = FileAccess::ReadWrite; + } + else { - throw IOException("Cannot open file '" + fileName + "'"); + mode = L"wb"; + modeMBCS = "wb"; + this->m_fileAccess = FileAccess::Write; } + break; + case FileMode::CreateNew: + if (File::exists(fileName)) + { + throw IOException("Failed opening '" + fileName + "', file already exists."); + } + if (access == FileAccess::Read) + throw ArgumentException("Read-only access is incompatible with Create mode."); + else if (access == FileAccess::ReadWrite) + { + mode = L"w+b"; + this->m_fileAccess = FileAccess::ReadWrite; + } + else + { + mode = L"wb"; + this->m_fileAccess = FileAccess::Write; + } + break; + case FileMode::Append: + if (access == FileAccess::Read) + throw ArgumentException("Read-only access is incompatible with Append mode."); + else if (access == FileAccess::ReadWrite) + { + mode = L"a+b"; + this->m_fileAccess = FileAccess::ReadWrite; + } + else + { + mode = L"ab"; + this->m_fileAccess = FileAccess::Write; + } + break; + default: + break; } - FileStream::~FileStream() +#ifdef _WIN32 + int shFlag = _SH_DENYRW; + switch (share) { - Close(); + case FileShare::None: + shFlag = _SH_DENYRW; + break; + case FileShare::ReadOnly: + shFlag = _SH_DENYWR; + break; + case FileShare::WriteOnly: + shFlag = _SH_DENYRD; + break; + case FileShare::ReadWrite: + shFlag = _SH_DENYNO; + break; + default: + throw ArgumentException("Invalid file share mode."); + break; } - Int64 FileStream::GetPosition() + if (share == FileShare::None) +#pragma warning(suppress:4996) + m_handle = _wfopen(fileName.toWString(), mode); + else + m_handle = _wfsopen(fileName.toWString(), mode, shFlag); +#else + m_handle = fopen(fileName.getBuffer(), modeMBCS); +#endif + if (!m_handle) { + throw IOException("Cannot open file '" + fileName + "'"); + } +} + +FileStream::~FileStream() +{ + close(); +} + +Int64 FileStream::getPosition() +{ #if defined(_WIN32) || defined(__CYGWIN__) - fpos_t pos; - fgetpos(handle, &pos); - return pos; + fpos_t pos; + fgetpos(m_handle, &pos); + return pos; #elif defined(__APPLE__) - return ftell(handle); + return ftell(m_handle); #else - fpos64_t pos; - fgetpos64(handle, &pos); - return *(Int64*)(&pos); + fpos64_t pos; + fgetpos64(m_handle, &pos); + return *(Int64*)(&pos); #endif - } - void FileStream::Seek(SeekOrigin origin, Int64 offset) +} +void FileStream::seek(SeekOrigin origin, Int64 offset) +{ + int _origin; + switch (origin) { - int _origin; - switch (origin) - { - case Slang::SeekOrigin::Start: - _origin = SEEK_SET; - endReached = false; - break; - case Slang::SeekOrigin::End: - _origin = SEEK_END; - // JS TODO: This doesn't seem right, the offset can mean it's not at the end - endReached = true; - break; - case Slang::SeekOrigin::Current: - _origin = SEEK_CUR; - endReached = false; - break; - default: - throw NotSupportedException("Unsupported seek origin."); - break; - } + case SeekOrigin::Start: + _origin = SEEK_SET; + m_endReached = false; + break; + case SeekOrigin::End: + _origin = SEEK_END; + // JS TODO: This doesn't seem right, the offset can mean it's not at the end + m_endReached = true; + break; + case SeekOrigin::Current: + _origin = SEEK_CUR; + m_endReached = false; + break; + default: + throw NotSupportedException("Unsupported seek origin."); + break; + } #ifdef _WIN32 - int rs = _fseeki64(handle, offset, _origin); + int rs = _fseeki64(m_handle, offset, _origin); #else - int rs = fseek(handle, (int)offset, _origin); + int rs = fseek(m_handle, (int)offset, _origin); #endif - if (rs != 0) - { - throw IOException("FileStream seek failed."); - } - } - Int64 FileStream::Read(void * buffer, Int64 length) - { - auto bytes = fread_s(buffer, (size_t)length, 1, (size_t)length, handle); - if (bytes == 0 && length > 0) - { - if (!feof(handle)) - throw IOException("FileStream read failed."); - else if (endReached) - throw EndOfStreamException("End of file is reached."); - endReached = true; - } - return (int)bytes; - } - Int64 FileStream::Write(const void * buffer, Int64 length) - { - auto bytes = (Int64)fwrite(buffer, 1, (size_t)length, handle); - if (bytes < length) - { - throw IOException("FileStream write failed."); - } - return bytes; - } - bool FileStream::CanRead() + if (rs != 0) { - return ((int)fileAccess & (int)FileAccess::Read) != 0; + throw IOException("FileStream seek failed."); } - bool FileStream::CanWrite() +} +Int64 FileStream::read(void* buffer, Int64 length) +{ + auto bytes = fread_s(buffer, (size_t)length, 1, (size_t)length, m_handle); + if (bytes == 0 && length > 0) { - return ((int)fileAccess & (int)FileAccess::Write) != 0; + if (!feof(m_handle)) + throw IOException("FileStream read failed."); + else if (m_endReached) + throw EndOfStreamException("End of file is reached."); + m_endReached = true; } - void FileStream::Close() + return (int)bytes; +} +Int64 FileStream::write(const void* buffer, Int64 length) +{ + auto bytes = (Int64)fwrite(buffer, 1, (size_t)length, m_handle); + if (bytes < length) { - if (handle) - { - fclose(handle); - handle = 0; - } + throw IOException("FileStream write failed."); } - bool FileStream::IsEnd() + return bytes; +} +bool FileStream::canRead() +{ + return ((int)m_fileAccess & (int)FileAccess::Read) != 0; +} +bool FileStream::canWrite() +{ + return ((int)m_fileAccess & (int)FileAccess::Write) != 0; +} +void FileStream::close() +{ + if (m_handle) { - return endReached; + fclose(m_handle); + m_handle = 0; } +} +bool FileStream::isEnd() +{ + return m_endReached; +} - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MemoryStream !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MemoryStreamBase !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - void MemoryStream::Seek(SeekOrigin origin, Int64 offset) +void MemoryStreamBase::seek(SeekOrigin origin, Int64 offset) +{ + Int64 pos = 0; + switch (origin) { - Int64 pos = 0; - switch (origin) - { - case Slang::SeekOrigin::Start: + case SeekOrigin::Start: pos = offset; break; - case Slang::SeekOrigin::End: - pos = Int64(m_contents.getCount()) + offset; + case SeekOrigin::End: + pos = Int64(m_contentsSize) + offset; break; - case Slang::SeekOrigin::Current: + case SeekOrigin::Current: pos = Int64(m_position) + offset; break; default: throw NotSupportedException("Unsupported seek origin."); break; - } + } - m_atEnd = false; + m_atEnd = false; - // Clamp to the valid range - pos = (pos < 0) ? 0 : pos; - pos = (pos > Int64(m_contents.getCount())) ? Int64(m_contents.getCount()) : pos; + // Clamp to the valid range + pos = (pos < 0) ? 0 : pos; + pos = (pos > Int64(m_contentsSize)) ? Int64(m_contentsSize) : pos; - m_position = UInt(pos); + m_position = UInt(pos); +} + +Int64 MemoryStreamBase::read(void* buffer, Int64 length) +{ + if (!canRead()) + { + throw IOException("Cannot read this stream."); } - Int64 MemoryStream::Read(void * buffer, Int64 length) + const Int64 maxRead = Int64(m_contentsSize - m_position); + + if (maxRead == 0 && length > 0) { - if (!CanRead()) - { - throw IOException("Cannot read this stream."); - } + m_atEnd = true; + throw EndOfStreamException("End of file is reached."); + } - const Int64 maxRead = Int64(m_contents.getCount() - m_position); - - if (maxRead == 0 && length > 0) - { - m_atEnd = true; - throw EndOfStreamException("End of file is reached."); - } + length = length > maxRead ? maxRead : length; - length = length > maxRead ? maxRead : length; + ::memcpy(buffer, m_contents + m_position, size_t(length)); + m_position += UInt(length); + return maxRead; +} - ::memcpy(buffer, m_contents.begin() + m_position, size_t(length)); - m_position += UInt(length); - return maxRead; - } - - Int64 MemoryStream::Write(const void * buffer, Int64 length) +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! OwnedMemoryStream !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +Int64 OwnedMemoryStream::write(const void * buffer, Int64 length) +{ + if (!canWrite()) { - if (!CanWrite()) - { - throw IOException("Cannot write this stream."); - } + throw IOException("Cannot write this stream."); + } - if (m_position == m_contents.getCount()) - { - m_contents.addRange((const uint8_t*)buffer, UInt(length)); - } - else - { - m_contents.insertRange(m_position, (const uint8_t*)buffer, UInt(length)); - } + if (m_position == m_ownedContents.getCount()) + { + m_ownedContents.addRange((const uint8_t*)buffer, UInt(length)); + } + else + { + m_ownedContents.insertRange(m_position, (const uint8_t*)buffer, UInt(length)); + } - m_atEnd = false; + m_contents = m_ownedContents.getBuffer(); + m_contentsSize = ptrdiff_t(m_ownedContents.getCount()); - m_position += UInt(length); - return length; - } + m_atEnd = false; + m_position += ptrdiff_t(length); + return length; } + +} // namespace Slang diff --git a/source/core/slang-stream.h b/source/core/slang-stream.h index 67e04fa6a..8b8a6decf 100644 --- a/source/core/slang-stream.h +++ b/source/core/slang-stream.h @@ -5,109 +5,170 @@ namespace Slang { - class IOException : public Exception - { - public: - IOException() - {} - IOException(const String & message) - : Slang::Exception(message) - { - } - }; - - class EndOfStreamException : public IOException - { - public: - EndOfStreamException() - {} - EndOfStreamException(const String & message) - : IOException(message) - { - } - }; - - enum class SeekOrigin - { - Start, End, Current - }; - class Stream : public RefObject - { - public: - virtual ~Stream() {} - virtual Int64 GetPosition()=0; - virtual void Seek(SeekOrigin origin, Int64 offset)=0; - virtual Int64 Read(void * buffer, Int64 length) = 0; - virtual Int64 Write(const void * buffer, Int64 length) = 0; - virtual bool IsEnd() = 0; - virtual bool CanRead() = 0; - virtual bool CanWrite() = 0; - virtual void Close() = 0; - }; - - enum class FileMode +class IOException : public Exception +{ +public: + IOException() + {} + IOException(const String & message) + : Slang::Exception(message) { - Create, Open, CreateNew, Append - }; + } +}; - enum class FileAccess +class EndOfStreamException : public IOException +{ +public: + EndOfStreamException() + {} + EndOfStreamException(const String & message) + : IOException(message) { - None = 0, Read = 1, Write = 2, ReadWrite = 3 - }; + } +}; - enum class FileShare - { - None, ReadOnly, WriteOnly, ReadWrite - }; +enum class SeekOrigin +{ + Start, End, Current +}; + +class Stream : public RefObject +{ +public: + virtual ~Stream() {} + virtual Int64 getPosition()=0; + virtual void seek(SeekOrigin origin, Int64 offset)=0; + virtual Int64 read(void * buffer, Int64 length) = 0; + virtual Int64 write(const void * buffer, Int64 length) = 0; + virtual bool isEnd() = 0; + virtual bool canRead() = 0; + virtual bool canWrite() = 0; + virtual void close() = 0; +}; + +enum class FileMode +{ + Create, Open, CreateNew, Append +}; + +enum class FileAccess +{ + None = 0, Read = 1, Write = 2, ReadWrite = 3 +}; - class MemoryStream : public Stream +enum class FileShare +{ + None, ReadOnly, WriteOnly, ReadWrite +}; + +/// Base class for memory streams. Only supports reading and does NOT own contained data. +class MemoryStreamBase : public Stream +{ +public: + typedef Stream Super; + + virtual Int64 getPosition() SLANG_OVERRIDE { return m_position; } + virtual void seek(SeekOrigin origin, Int64 offset) SLANG_OVERRIDE; + virtual Int64 read(void * buffer, Int64 length) SLANG_OVERRIDE; + virtual Int64 write(const void * buffer, Int64 length) SLANG_OVERRIDE { SLANG_UNUSED(buffer); SLANG_UNUSED(length); return 0; } + virtual bool isEnd() SLANG_OVERRIDE { return m_atEnd; } + virtual bool canRead() SLANG_OVERRIDE { return (int(m_access) & int(FileAccess::Read)) != 0; } + virtual bool canWrite() SLANG_OVERRIDE { return (int(m_access) & int(FileAccess::Write)) != 0; } + virtual void close() SLANG_OVERRIDE { m_access = FileAccess::None; } + + MemoryStreamBase(FileAccess access = FileAccess::Read, const void* contents = nullptr, size_t contentsSize = 0): + m_access(access) { - public: - virtual Int64 GetPosition() SLANG_OVERRIDE { return m_position; } - virtual void Seek(SeekOrigin origin, Int64 offset) SLANG_OVERRIDE; - virtual Int64 Read(void * buffer, Int64 length) SLANG_OVERRIDE; - virtual Int64 Write(const void * buffer, Int64 length) SLANG_OVERRIDE; - virtual bool IsEnd() SLANG_OVERRIDE { return m_atEnd; } - virtual bool CanRead() SLANG_OVERRIDE { return (int(m_access) & int(FileAccess::Read)) != 0; } - virtual bool CanWrite() SLANG_OVERRIDE { return (int(m_access) & int(FileAccess::Write)) != 0; } - virtual void Close() SLANG_OVERRIDE { m_access = FileAccess::None; } - - MemoryStream(FileAccess access) : - m_access(access), - m_position(0), - m_atEnd(false) - {} - - Index m_position; - - bool m_atEnd; ///< Happens when a read is done and nothing can be returned because already at end - - FileAccess m_access; - List m_contents; - }; - - class FileStream : public Stream - { - private: - FILE * handle; - FileAccess fileAccess; - bool endReached = false; - void Init(const Slang::String & fileName, FileMode fileMode, FileAccess access, FileShare share); - public: - FileStream(const Slang::String & fileName, FileMode fileMode = FileMode::Open); - FileStream(const Slang::String & fileName, FileMode fileMode, FileAccess access, FileShare share); - ~FileStream(); - public: - virtual Int64 GetPosition(); - virtual void Seek(SeekOrigin origin, Int64 offset); - virtual Int64 Read(void * buffer, Int64 length); - virtual Int64 Write(const void * buffer, Int64 length); - virtual bool CanRead(); - virtual bool CanWrite(); - virtual void Close(); - virtual bool IsEnd(); - }; -} + _setContents(contents, contentsSize); + } + +protected: + /// Set to replace wholly current content with specified content + void _setContents(const void* contents, size_t contentsSize) + { + m_contents = (const uint8_t*)contents; + m_contentsSize = ptrdiff_t(contentsSize); + m_position = 0; + m_atEnd = false; + } + /// Update means that the content has changed, but position should be maintained + void _updateContents(const void* contents, size_t contentsSize) + { + const ptrdiff_t newPosition = (m_position > ptrdiff_t(contentsSize)) ? ptrdiff_t(contentsSize) : m_position; + _setContents(contents, contentsSize); + m_position = newPosition; + } + + const uint8_t* m_contents; ///< The content held in the stream + + // Using ptrdiff_t (as opposed to size_t) as makes maths simpler + ptrdiff_t m_contentsSize; ///< Total size of the content in bytes + ptrdiff_t m_position; ///< The current position within content (valid values can only be between 0 and m_contentSize) + + bool m_atEnd; ///< Happens when a read is done and nothing can be returned because already at end + + FileAccess m_access; +}; + +/// Memory stream that owns it's contents +class OwnedMemoryStream : public MemoryStreamBase +{ +public: + typedef MemoryStreamBase Super; + + virtual Int64 write(const void* buffer, Int64 length) SLANG_OVERRIDE; + + /// Set the contents + void setContent(const void* contents, size_t contentsSize) + { + m_ownedContents.setCount(contentsSize); + ::memcpy(m_ownedContents.getBuffer(), contents, contentsSize); + _setContents(m_ownedContents.getBuffer(), m_ownedContents.getCount()); + } + + void swapContents(List& rhs) + { + rhs.swapWith(m_ownedContents); + _setContents(m_ownedContents.getBuffer(), m_ownedContents.getCount()); + } + + OwnedMemoryStream(FileAccess access) : + Super(access) + {} + +protected: + + List m_ownedContents; +}; + +class FileStream : public Stream +{ +public: + typedef Stream Super; + + // Stream interface + virtual Int64 getPosition(); + virtual void seek(SeekOrigin origin, Int64 offset); + virtual Int64 read(void* buffer, Int64 length); + virtual Int64 write(const void* buffer, Int64 length); + virtual bool canRead(); + virtual bool canWrite(); + virtual void close(); + virtual bool isEnd(); + + FileStream(const String& fileName, FileMode fileMode = FileMode::Open); + FileStream(const String& fileName, FileMode fileMode, FileAccess access, FileShare share); + ~FileStream(); + +private: + void _init(const String& fileName, FileMode fileMode, FileAccess access, FileShare share); + + FILE* m_handle; + FileAccess m_fileAccess; + bool m_endReached = false; +}; + +} // namespace Slang #endif diff --git a/source/core/slang-text-io.cpp b/source/core/slang-text-io.cpp index 18039e41b..4e989b627 100644 --- a/source/core/slang-text-io.cpp +++ b/source/core/slang-text-io.cpp @@ -126,11 +126,11 @@ namespace Slang this->encoding = encoding; if (encoding == Encoding::UTF16) { - this->stream->Write(&Utf16Header, 2); + this->stream->write(&Utf16Header, 2); } else if (encoding == Encoding::UTF16Reversed) { - this->stream->Write(&Utf16ReversedHeader, 2); + this->stream->write(&Utf16ReversedHeader, 2); } } StreamWriter::StreamWriter(RefPtr stream, Encoding * encoding) @@ -139,11 +139,11 @@ namespace Slang this->encoding = encoding; if (encoding == Encoding::UTF16) { - this->stream->Write(&Utf16Header, 2); + this->stream->write(&Utf16Header, 2); } else if (encoding == Encoding::UTF16Reversed) { - this->stream->Write(&Utf16ReversedHeader, 2); + this->stream->write(&Utf16ReversedHeader, 2); } } void StreamWriter::Write(const String & str) @@ -169,7 +169,7 @@ namespace Slang sb << str[i]; } encoding->GetBytes(encodingBuffer, sb.ProduceString()); - stream->Write(encodingBuffer.getBuffer(), encodingBuffer.getCount()); + stream->write(encodingBuffer.getBuffer(), encodingBuffer.getCount()); } void StreamWriter::Write(const char * str) { @@ -237,7 +237,7 @@ namespace Slang { buffer.setCount(4096); memset(buffer.getBuffer(), 0, buffer.getCount() * sizeof(buffer[0])); - auto len = stream->Read(buffer.getBuffer(), buffer.getCount()); + auto len = stream->read(buffer.getBuffer(), buffer.getCount()); buffer.setCount((int)len); ptr = 0; } @@ -248,7 +248,7 @@ namespace Slang { return buffer[ptr++]; } - if (!stream->IsEnd()) + if (!stream->isEnd()) ReadBuffer(); if (ptrClose(); + stream->close(); } void ReleaseStream() { @@ -300,11 +300,11 @@ namespace Slang virtual String ReadToEnd(); virtual bool IsEnd() { - return ptr == buffer.getCount() && stream->IsEnd(); + return ptr == buffer.getCount() && stream->isEnd(); } virtual void Close() { - stream->Close(); + stream->close(); } void ReleaseStream() { diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index 9b361064d..1e1f166de 100644 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -1172,17 +1172,19 @@ namespace Slang /// If this member is `null`, a default implementation that tries /// to use the native OS filesystem will be used instead. /// - ComPtr fileSystem; + ComPtr m_fileSystem; /// The extended file system implementation. Will be set to a default implementation /// if fileSystem is nullptr. Otherwise it will either be fileSystem's interface, /// or a wrapped impl that makes fileSystem operate as fileSystemExt - ComPtr fileSystemExt; + ComPtr m_fileSystemExt; + /// Set if fileSystemExt is a cache file system - RefPtr cacheFileSystem; + RefPtr m_cacheFileSystem; - ISlangFileSystemExt* getFileSystemExt() { return fileSystemExt; } + ISlangFileSystemExt* getFileSystemExt() { return m_fileSystemExt; } + CacheFileSystem* getCacheFileSystem() const { return m_cacheFileSystem; } /// Load a file into memory using the configured file system. /// @@ -1192,7 +1194,6 @@ namespace Slang /// SlangResult loadFile(String const& path, PathInfo& outPathInfo, ISlangBlob** outBlob); - RefPtr parseTypeString(String typeStr, RefPtr scope); Type* specializeType( @@ -1230,7 +1231,7 @@ namespace Slang return m_sourceManager; } - /// Override the source manager for the linakge. + /// Override the source manager for the linkage. /// /// This is only used to install a temporary override when /// parsing stuff from strings (where we don't want to retain diff --git a/source/slang/slang-file-system.cpp b/source/slang/slang-file-system.cpp index 4ee961df5..7d6d6df66 100644 --- a/source/slang/slang-file-system.cpp +++ b/source/slang/slang-file-system.cpp @@ -138,7 +138,7 @@ SLANG_NO_THROW SlangResult SLANG_MCALL OSFileSystemExt::saveFile(const char* pat { FileStream stream(pathIn, FileMode::Create, FileAccess::Write, FileShare::ReadWrite); - int64_t numWritten = stream.Write(data, size); + int64_t numWritten = stream.write(data, size); if (numWritten != int64_t(size)) { diff --git a/source/slang/slang-ir-serialize.cpp b/source/slang/slang-ir-serialize.cpp index 02ed3142d..c82592527 100644 --- a/source/slang/slang-ir-serialize.cpp +++ b/source/slang/slang-ir-serialize.cpp @@ -847,9 +847,9 @@ static Result _writeArrayChunk(IRSerialBinary::CompressionType compressionType, header.m_chunk.m_size = uint32_t(payloadSize); header.m_numEntries = uint32_t(numEntries); - stream->Write(&header, sizeof(header)); + stream->write(&header, sizeof(header)); - stream->Write(data, typeSize * numEntries); + stream->write(data, typeSize * numEntries); break; } case Bin::CompressionType::VariableByteLite: @@ -868,9 +868,9 @@ static Result _writeArrayChunk(IRSerialBinary::CompressionType compressionType, header.m_numEntries = uint32_t(numEntries); header.m_numCompressedEntries = uint32_t(numCompressedEntries); - stream->Write(&header, sizeof(header)); + stream->write(&header, sizeof(header)); - stream->Write(compressedPayload.begin(), compressedPayload.getCount()); + stream->write(compressedPayload.begin(), compressedPayload.getCount()); break; } default: @@ -884,7 +884,7 @@ static Result _writeArrayChunk(IRSerialBinary::CompressionType compressionType, const uint8_t pad[4] = { 0, 0, 0, 0 }; // Pad outs int padSize = 4 - (payloadSize & 3); - stream->Write(pad, padSize); + stream->write(pad, padSize); } return SLANG_OK; @@ -1013,8 +1013,8 @@ Result _writeInstArrayChunk(IRSerialBinary::CompressionType compressionType, uin header.m_numEntries = uint32_t(array.getCount()); header.m_numCompressedEntries = 0; - stream->Write(&header, sizeof(header)); - stream->Write(compressedPayload.begin(), compressedPayload.getCount()); + stream->write(&header, sizeof(header)); + stream->write(compressedPayload.begin(), compressedPayload.getCount()); // All chunks have sizes rounded to dword size if (payloadSize & 3) @@ -1022,7 +1022,7 @@ Result _writeInstArrayChunk(IRSerialBinary::CompressionType compressionType, uin const uint8_t pad[4] = { 0, 0, 0, 0 }; // Pad outs int padSize = 4 - (payloadSize & 3); - stream->Write(pad, padSize); + stream->write(pad, padSize); } return SLANG_OK; } @@ -1128,7 +1128,7 @@ static size_t _calcInstChunkSize(IRSerialBinary::CompressionType compressionType riffHeader.m_type = Bin::kRiffFourCc; riffHeader.m_size = uint32_t(totalSize); - stream->Write(&riffHeader, sizeof(riffHeader)); + stream->write(&riffHeader, sizeof(riffHeader)); } { Bin::SlangHeader slangHeader; @@ -1136,7 +1136,7 @@ static size_t _calcInstChunkSize(IRSerialBinary::CompressionType compressionType slangHeader.m_chunk.m_size = uint32_t(sizeof(slangHeader) - sizeof(RiffChunk)); slangHeader.m_compressionType = uint32_t(Bin::CompressionType::VariableByteLite); - stream->Write(&slangHeader, sizeof(slangHeader)); + stream->write(&slangHeader, sizeof(slangHeader)); } SLANG_RETURN_ON_FAIL(_writeInstArrayChunk(compressionType, Bin::kInstFourCc, data.m_insts, stream)); @@ -1206,7 +1206,7 @@ static Result _readArrayChunk(IRSerialBinary::CompressionType compressionType, c Bin::CompressedArrayHeader header; header.m_chunk = chunk; - stream->Read(&header.m_chunk + 1, sizeof(header) - sizeof(RiffChunk)); + stream->read(&header.m_chunk + 1, sizeof(header) - sizeof(RiffChunk)); *numReadInOut += sizeof(header) - sizeof(RiffChunk); void* data = listOut.setSize(header.m_numEntries); @@ -1217,7 +1217,7 @@ static Result _readArrayChunk(IRSerialBinary::CompressionType compressionType, c List compressedPayload; compressedPayload.setCount(payloadSize); - stream->Read(compressedPayload.begin(), payloadSize); + stream->read(compressedPayload.begin(), payloadSize); *numReadInOut += payloadSize; SLANG_ASSERT(header.m_numCompressedEntries == uint32_t((header.m_numEntries * typeSize) / sizeof(uint32_t))); @@ -1232,14 +1232,14 @@ static Result _readArrayChunk(IRSerialBinary::CompressionType compressionType, c Bin::ArrayHeader header; header.m_chunk = chunk; - stream->Read(&header.m_chunk + 1, sizeof(header) - sizeof(RiffChunk)); + stream->read(&header.m_chunk + 1, sizeof(header) - sizeof(RiffChunk)); *numReadInOut += sizeof(header) - sizeof(RiffChunk); const size_t payloadSize = header.m_numEntries * typeSize; void* data = listOut.setSize(header.m_numEntries); - stream->Read(data, payloadSize); + stream->read(data, payloadSize); *numReadInOut += payloadSize; break; } @@ -1251,7 +1251,7 @@ static Result _readArrayChunk(IRSerialBinary::CompressionType compressionType, c const uint8_t pad[4] = { 0, 0, 0, 0 }; // Pad outs int padSize = 4 - int(*numReadInOut & 3); - stream->Seek(SeekOrigin::Current, padSize); + stream->seek(SeekOrigin::Current, padSize); *numReadInOut += padSize; } @@ -1374,7 +1374,7 @@ static Result _readInstArrayChunk(const IRSerialBinary::SlangHeader& slangHeader Bin::CompressedArrayHeader header; header.m_chunk = chunk; - stream->Read(&header.m_chunk + 1, sizeof(header) - sizeof(RiffChunk)); + stream->read(&header.m_chunk + 1, sizeof(header) - sizeof(RiffChunk)); *numReadInOut += sizeof(header) - sizeof(RiffChunk); // Need to read all the compressed data... @@ -1383,7 +1383,7 @@ static Result _readInstArrayChunk(const IRSerialBinary::SlangHeader& slangHeader List compressedPayload; compressedPayload.setCount(payloadSize); - stream->Read(compressedPayload.begin(), payloadSize); + stream->read(compressedPayload.begin(), payloadSize); *numReadInOut += payloadSize; arrayOut.setCount(header.m_numEntries); @@ -1402,7 +1402,7 @@ static Result _readInstArrayChunk(const IRSerialBinary::SlangHeader& slangHeader { // Pad outs int padSize = 4 - int(*numReadInOut & 3); - stream->Seek(SeekOrigin::Current, padSize); + stream->seek(SeekOrigin::Current, padSize); *numReadInOut += padSize; } @@ -1449,7 +1449,7 @@ static Result _readInstArrayChunk(const IRSerialBinary::SlangHeader& slangHeader // NOTE! Really we should only read what we know the size to be... // and skip if it's larger - stream->Read(&slangHeader.m_chunk + 1, sizeof(slangHeader) - sizeof(chunk)); + stream->read(&slangHeader.m_chunk + 1, sizeof(slangHeader) - sizeof(chunk)); remainingBytes -= RiffUtil::calcChunkTotalSize(chunk); break; @@ -1964,11 +1964,11 @@ static int _calcFixSourceLoc(const IRSerialData::DebugSourceInfo& info, SourceVi } // Write the data out to stream - MemoryStream memoryStream(FileAccess::ReadWrite); + OwnedMemoryStream memoryStream(FileAccess::ReadWrite); SLANG_RETURN_ON_FAIL(IRSerialWriter::writeStream(serialData, compressionType, &memoryStream)); // Reset stream - memoryStream.Seek(SeekOrigin::Start, 0); + memoryStream.seek(SeekOrigin::Start, 0); IRSerialData readData; diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp index 2e1b625d9..6b09179db 100644 --- a/source/slang/slang-options.cpp +++ b/source/slang/slang-options.cpp @@ -496,7 +496,7 @@ struct OptionsParser else if (argStr == "-dump-repro") { SLANG_RETURN_ON_FAIL(tryReadCommandLineArgument(sink, arg, &argCursor, argEnd, requestImpl->dumpRepro)); - requestImpl->getLinkage()->setRequireCacheFileSystem(true); + spEnableReproCapture(asExternal(requestImpl)); } else if (argStr == "-extract-repro") { diff --git a/source/slang/slang-state-serialize.cpp b/source/slang/slang-state-serialize.cpp index b37529121..110ea52b2 100644 --- a/source/slang/slang-state-serialize.cpp +++ b/source/slang/slang-state-serialize.cpp @@ -318,15 +318,49 @@ static bool _isStorable(const PathInfo::Type type) for (Index i = 0; i < linkage->targets.getCount(); ++i) { - auto& dst = dstTargets[i]; - TargetRequest* targetRequest = linkage->targets[i]; + TargetRequest* srcTargetRequest = linkage->targets[i]; - dst.target = targetRequest->getTarget(); - dst.profile = targetRequest->getTargetProfile(); - dst.targetFlags = targetRequest->targetFlags; - dst.floatingPointMode = targetRequest->floatingPointMode; - } + // Copy the simple stuff + { + auto& dst = dstTargets[i]; + dst.target = srcTargetRequest->getTarget(); + dst.profile = srcTargetRequest->getTargetProfile(); + dst.targetFlags = srcTargetRequest->targetFlags; + dst.floatingPointMode = srcTargetRequest->floatingPointMode; + } + + // Copy the entry point/target output names + { + const auto& srcTargetInfos = request->targetInfos; + + if (RefPtr* infosPtr = srcTargetInfos.TryGetValue(srcTargetRequest)) + { + EndToEndCompileRequest::TargetInfo* infos = *infosPtr; + + const auto& entryPointOutputPaths = infos->entryPointOutputPaths; + + Safe32Array dstOutputStates; + dstOutputStates = inOutContainer.allocateArray(entryPointOutputPaths.Count()); + Index index = 0; + for (const auto& pair : entryPointOutputPaths) + { + Safe32Ptr outputPath = inOutContainer.newString(pair.Value.getUnownedSlice()); + + auto& dstOutputState = dstOutputStates[index]; + + dstOutputState.entryPointIndex = int32_t(pair.Key); + dstOutputState.outputPath = outputPath; + + index++; + } + + dstTargets[i].outputStates = dstOutputStates; + } + } + } + + // Save the result requestState->targetRequests = dstTargets; } @@ -383,7 +417,12 @@ static bool _isStorable(const PathInfo::Type type) // Find files from the file system, and mapping paths to files { - CacheFileSystem* cacheFileSystem = linkage->cacheFileSystem; + CacheFileSystem* cacheFileSystem = linkage->getCacheFileSystem(); + if (!cacheFileSystem) + { + return SLANG_FAIL; + } + // Traverse the references (in process we will construct the map from PathInfo) { const auto& srcFiles = cacheFileSystem->getPathMap(); @@ -651,8 +690,17 @@ static void _loadDefines(const Relative32Array& { auto externalRequest = asExternal(request); + auto linkage = request->getLinkage(); + // TODO(JS): Really should be more exhaustive here, and set up to initial state ideally + // Reset state + { + request->targetInfos.Clear(); + // Remove any requests + linkage->targets.clear(); + } + LoadContext context(linkage->getSourceManager(), fileSystem); // Try to set state through API - as doing so means if state stored in multiple places it will be ok @@ -671,20 +719,41 @@ static void _loadDefines(const Relative32Array& linkage->setMatrixLayoutMode(requestState->defaultMatrixLayoutMode); } + + // Add the target requests { for (Index i = 0; i < requestState->targetRequests.getCount(); ++i) { TargetRequestState& src = requestState->targetRequests[i]; int index = spAddCodeGenTarget(externalRequest, SlangCompileTarget(src.target)); - SLANG_UNUSED(index); SLANG_ASSERT(index == i); - auto dstTarget = linkage->targets[i]; + auto dstTarget = linkage->targets[index]; SLANG_ASSERT(dstTarget->getTarget() == src.target); dstTarget->targetProfile = src.profile; dstTarget->targetFlags = src.targetFlags; dstTarget->floatingPointMode = src.floatingPointMode; + + // If there is output state (like output filenames) add here + if (src.outputStates.getCount()) + { + RefPtr dstTargetInfo(new EndToEndCompileRequest::TargetInfo); + request->targetInfos[dstTarget] = dstTargetInfo; + + for (const auto& srcOutputState : src.outputStates) + { + SLANG_ASSERT(srcOutputState.entryPointIndex < requestState->entryPoints.getCount()); + + String entryPointPath; + if (srcOutputState.outputPath) + { + entryPointPath = srcOutputState.outputPath->getSlice(); + } + + dstTargetInfo->entryPointOutputPaths.Add(srcOutputState.entryPointIndex, entryPointPath); + } + } } } @@ -744,6 +813,9 @@ static void _loadDefines(const Relative32Array& // Entry points { + // Check there aren't any set entry point + SLANG_ASSERT(request->getFrontEndReq()->m_entryPointReqs.getCount() == 0); + for (const auto& srcEntryPoint : requestState->entryPoints) { const char* name = srcEntryPoint.name ? srcEntryPoint.name->getCstr() : nullptr; @@ -782,8 +854,8 @@ static void _loadDefines(const Relative32Array& // This is a bit of a hack, we are going to replace the file system, with our one which is filled in // with what was read from the file. - linkage->fileSystemExt = cacheFileSystem; - linkage->cacheFileSystem = cacheFileSystem; + linkage->m_fileSystemExt = cacheFileSystem; + linkage->m_cacheFileSystem = cacheFileSystem; } return SLANG_OK; @@ -834,11 +906,7 @@ static void _loadDefines(const Relative32Array& /* static */SlangResult StateSerializeUtil::loadState(const uint8_t* data, size_t size, List& outBuffer) { - MemoryStream stream(FileAccess::Read); - - stream.m_contents.setCount(size); - ::memcpy(stream.m_contents.getBuffer(), data, size); - + MemoryStreamBase stream(FileAccess::Read, data, size); return loadState(&stream, outBuffer); } diff --git a/source/slang/slang-state-serialize.h b/source/slang/slang-state-serialize.h index f43cc8d45..dbd1e3992 100644 --- a/source/slang/slang-state-serialize.h +++ b/source/slang/slang-state-serialize.h @@ -52,6 +52,12 @@ struct StateSerializeUtil Relative32Ptr pathInfo; }; + struct OutputState + { + int32_t entryPointIndex; + Relative32Ptr outputPath; + }; + // spSetCodeGenTarget/spAddCodeGenTarget // spSetTargetProfile // spSetTargetFlags @@ -63,6 +69,8 @@ struct StateSerializeUtil CodeGenTarget target; SlangTargetFlags targetFlags; FloatingPointMode floatingPointMode; + + Relative32Array outputStates; }; struct FileReference diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 19ac6ea1f..8479d3202 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -800,11 +800,11 @@ SlangResult Linkage::loadFile(String const& path, PathInfo& outPathInfo, ISlangB { outPathInfo.type = PathInfo::Type::Unknown; - SLANG_RETURN_ON_FAIL(fileSystemExt->loadFile(path.getBuffer(), outBlob)); + SLANG_RETURN_ON_FAIL(m_fileSystemExt->loadFile(path.getBuffer(), outBlob)); ComPtr uniqueIdentity; // Get the unique identity - SLANG_RETURN_ON_FAIL(fileSystemExt->getFileUniqueIdentity(path.getBuffer(), uniqueIdentity.writeRef())); + SLANG_RETURN_ON_FAIL(m_fileSystemExt->getFileUniqueIdentity(path.getBuffer(), uniqueIdentity.writeRef())); outPathInfo.foundPath = path; outPathInfo.type = PathInfo::Type::FoundPath; @@ -2489,17 +2489,17 @@ static const Slang::Guid IID_SlangCacheFileSystem = SLANG_UUID_CacheFileSystem; void Linkage::setFileSystem(ISlangFileSystem* inFileSystem) { // Set the fileSystem - fileSystem = inFileSystem; + m_fileSystem = inFileSystem; // Release what's there - fileSystemExt.setNull(); - cacheFileSystem.setNull(); + m_fileSystemExt.setNull(); + m_cacheFileSystem.setNull(); // If nullptr passed in set up default if (inFileSystem == nullptr) { - cacheFileSystem = new Slang::CacheFileSystem(Slang::OSFileSystemExt::getSingleton()); - fileSystemExt = cacheFileSystem; + m_cacheFileSystem = new Slang::CacheFileSystem(Slang::OSFileSystemExt::getSingleton()); + m_fileSystemExt = m_cacheFileSystem; } else { @@ -2507,34 +2507,34 @@ void Linkage::setFileSystem(ISlangFileSystem* inFileSystem) inFileSystem->queryInterface(IID_SlangCacheFileSystem, (void**)&cacheFileSystemPtr); if (cacheFileSystemPtr) { - cacheFileSystem = cacheFileSystemPtr; - fileSystemExt = cacheFileSystemPtr; + m_cacheFileSystem = cacheFileSystemPtr; + m_fileSystemExt = cacheFileSystemPtr; } else { if (m_requireCacheFileSystem) { - cacheFileSystem = new Slang::CacheFileSystem(inFileSystem); - fileSystemExt = cacheFileSystem; + m_cacheFileSystem = new Slang::CacheFileSystem(inFileSystem); + m_fileSystemExt = m_cacheFileSystem; } else { // See if we have the full ISlangFileSystemExt interface, if we do just use it - inFileSystem->queryInterface(IID_ISlangFileSystemExt, (void**)fileSystemExt.writeRef()); + inFileSystem->queryInterface(IID_ISlangFileSystemExt, (void**)m_fileSystemExt.writeRef()); // If not wrap with CacheFileSystem that emulates ISlangFileSystemExt from the ISlangFileSystem interface - if (!fileSystemExt) + if (!m_fileSystemExt) { // Construct a wrapper to emulate the extended interface behavior - cacheFileSystem = new Slang::CacheFileSystem(fileSystem); - fileSystemExt = cacheFileSystem; + m_cacheFileSystem = new Slang::CacheFileSystem(m_fileSystem); + m_fileSystemExt = m_cacheFileSystem; } } } } // Set the file system used on the source manager - getSourceManager()->setFileSystemExt(fileSystemExt); + getSourceManager()->setFileSystemExt(m_fileSystemExt); } void Linkage::setRequireCacheFileSystem(bool requireCacheFileSystem) @@ -2544,7 +2544,7 @@ void Linkage::setRequireCacheFileSystem(bool requireCacheFileSystem) return; } - ComPtr scopeFileSystem(fileSystem); + ComPtr scopeFileSystem(m_fileSystem); m_requireCacheFileSystem = requireCacheFileSystem; setFileSystem(scopeFileSystem); @@ -3478,17 +3478,44 @@ SLANG_API SlangResult spSaveRepro( using namespace Slang; auto request = asInternal(inRequest); - MemoryStream stream(FileAccess::Write); + OwnedMemoryStream stream(FileAccess::Write); SLANG_RETURN_ON_FAIL(StateSerializeUtil::saveState(request, &stream)); RefPtr listBlob(new ListBlob); - listBlob->m_data.swapWith(stream.m_contents); + + // Put the content of the stream in the blob + stream.swapContents(listBlob->m_data); *outBlob = listBlob.detach(); return SLANG_OK; } +SLANG_API SlangResult spEnableReproCapture( + SlangCompileRequest* inRequest) +{ + using namespace Slang; + auto request = asInternal(inRequest); + + request->getLinkage()->setRequireCacheFileSystem(true); + return SLANG_OK; +} + +SLANG_API SlangResult spExtractRepro(SlangSession* session, const void* reproData, size_t reproDataSize, ISlangFileSystemExt* fileSystem) +{ + using namespace Slang; + SLANG_UNUSED(session); + + List buffer; + { + MemoryStreamBase memoryStream(FileAccess::Read, reproData, reproDataSize); + SLANG_RETURN_ON_FAIL(StateSerializeUtil::loadState(&memoryStream, buffer)); + } + + StateSerializeUtil::RequestState* requestState = StateSerializeUtil::getRequest(buffer); + return StateSerializeUtil::extractFiles(requestState, fileSystem); +} + // Reflection API SLANG_API SlangResult spCompileRequest_getProgram( -- cgit v1.2.3