yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Jay KwakDisable Link-Time-Optimization by default (#7345)7f04adbfb

master
10.7 KiB389 linesraw
1#ifndef SLANG_CORE_BLOB_H
2#define SLANG_CORE_BLOB_H
3
4#include "../core/slang-com-object.h"
5#include "slang-com-helper.h"
6#include "slang-com-ptr.h"
7#include "slang-list.h"
8#include "slang-string.h"
9#include "slang.h"
10
11#include <stdarg.h>
12
13namespace Slang
14{
15
16/** Base class for simple blobs.
17 */
18class BlobBase : public ComBaseObject, public ISlangBlob, public ICastable
19{
20public:
21    // ISlangUnknown
22    SLANG_COM_BASE_IUNKNOWN_ALL
23
24    // ICastable
25    virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE;
26
27protected:
28    ISlangUnknown* getInterface(const Guid& guid);
29    void* getObject(const Guid& guid);
30};
31
32/** A blob that uses a `StringRepresentation` for its storage.
33
34By design the StringBlob owns a unique reference to the StringRepresentation.
35This is because StringBlob, implements an interface which should work across threads.
36*/
37class StringBlob : public BlobBase
38{
39public:
40    SLANG_CLASS_GUID(0xf7e0e93c, 0xde70, 0x4531, {0x9c, 0x9f, 0xdd, 0xa3, 0xf6, 0xc6, 0xc0, 0xdd});
41
42    // ICastable
43    virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE;
44
45    // ISlangBlob
46    SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE
47    {
48        return m_slice.begin();
49    }
50    SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_slice.getLength(); }
51
52    /// Since in is not being moved will *always* create a new representation, unless the in is
53    /// empty
54    static ComPtr<ISlangBlob> create(const String& in);
55    /// Create from a slice
56    static ComPtr<ISlangBlob> create(const UnownedStringSlice& slice);
57
58    /// Moves from in into the created blob.
59    /// NOTE! That will only use the representation from in, if it is *unique*
60    /// otherwise it will make a new copy.
61    static ComPtr<ISlangBlob> moveCreate(String& in);
62    static ComPtr<ISlangBlob> moveCreate(String&& in);
63
64    /// Dtor
65    ~StringBlob();
66
67protected:
68    /// Init with a rep when can't be owned.
69    void _setWithCopy(StringRepresentation* rep);
70    /// Init with a representation that has been moved.
71    void _setWithMove(StringRepresentation* rep);
72
73    /// Create a unique copy of rep.
74    /// If nullptr will work (if rep is empty, will return that)
75    static StringRepresentation* _createUniqueCopy(StringRepresentation* rep);
76
77    /// Rep can only be nullptr or have a single ref
78    void _setUniqueRep(StringRepresentation* rep);
79
80    void* getObject(const Guid& guid);
81
82    UnownedTerminatedStringSlice m_slice; ///< The contents
83    StringRepresentation* m_uniqueRep =
84        nullptr; ///< Holds actual bytes. Can be nullptr if it's an empty string.
85};
86
87class ListBlob : public BlobBase
88{
89public:
90    typedef BlobBase Super;
91    typedef ListBlob ThisType;
92
93    // ICastable
94    virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE;
95    // ISlangBlob
96    SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE
97    {
98        return m_data.getBuffer();
99    }
100    SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_data.getCount(); }
101
102    static ComPtr<ISlangBlob> create(const List<uint8_t>& data)
103    {
104        return ComPtr<ISlangBlob>(new ListBlob(data));
105    }
106
107    static ComPtr<ISlangBlob> moveCreate(List<uint8_t>& data)
108    {
109        return ComPtr<ISlangBlob>(new ListBlob(_Move(data)));
110    }
111
112protected:
113    explicit ListBlob(const List<uint8_t>& data)
114        : m_data(data)
115    {
116    }
117    // Move ctor
118    explicit ListBlob(List<uint8_t>&& data)
119        : m_data(data)
120    {
121    }
122
123    void* getObject(const Guid& guid);
124
125    void operator=(const ThisType& rhs) = delete;
126
127    List<uint8_t> m_data;
128};
129
130class ScopedAllocation
131{
132public:
133    typedef ScopedAllocation ThisType;
134    // Returns the allocation if successful.
135    void* allocate(size_t size)
136    {
137        deallocate();
138        if (size > 0)
139        {
140            m_data = ::malloc(size);
141        }
142        m_sizeInBytes = size;
143        m_capacityInBytes = size;
144        return m_data;
145    }
146    /// Allocate size including a 0 byte at `size`.
147    void* allocateTerminated(size_t size)
148    {
149        SLANG_ASSUME(size != std::numeric_limits<size_t>::max());
150        uint8_t* data = (uint8_t*)allocate(size + 1);
151        data[size] = 0;
152        m_sizeInBytes = size;
153        return data;
154    }
155    /// Deallocates if holds an allocation
156    void deallocate()
157    {
158        if (m_data)
159        {
160            ::free(m_data);
161            m_data = nullptr;
162        }
163        m_sizeInBytes = 0;
164        m_capacityInBytes = 0;
165    }
166    // Reallocate so the buffer is the specified capacity/size. Contents of buffer up to size remain
167    // intact.
168    void reallocate(size_t capacity)
169    {
170        if (capacity != m_capacityInBytes)
171        {
172            m_data = ::realloc(m_data, capacity);
173            m_sizeInBytes = capacity;
174            m_capacityInBytes = capacity;
175        }
176    }
177    /// Makes this no longer own the allocation. Returns the allocated data (or nullptr if no
178    /// allocation)
179    void* detach()
180    {
181        void* data = m_data;
182        m_data = nullptr;
183        m_sizeInBytes = 0;
184        m_capacityInBytes = 0;
185        return data;
186    }
187    /// Attach some data.
188    /// NOTE! data must be a pointer that was returned from malloc, otherwise will incorrectly free.
189    void attach(void* data, size_t size)
190    {
191        deallocate();
192        m_data = data;
193        m_sizeInBytes = size;
194        m_capacityInBytes = size;
195    }
196
197    void* set(const void* data, size_t size)
198    {
199        void* dst = allocate(size);
200        if (dst)
201        {
202            memcpy(dst, data, size);
203        }
204        return dst;
205    }
206
207    /// Get the allocated data. Returns nullptr if there is no allocated data
208    void* getData() const { return m_data; }
209    /// Get the size of the allocated data.
210    size_t getSizeInBytes() const { return m_sizeInBytes; }
211    /// Get the capacity in bytes
212    size_t getCapacityInBytes() const { return m_capacityInBytes; }
213
214    void setSizeInBytes(size_t size)
215    {
216        SLANG_ASSERT(size <= m_capacityInBytes);
217        m_sizeInBytes = size;
218    }
219
220    void swap(ThisType& rhs)
221    {
222        Swap(m_data, rhs.m_data);
223        Swap(m_sizeInBytes, rhs.m_sizeInBytes);
224        Swap(m_capacityInBytes, rhs.m_capacityInBytes);
225    }
226
227    /// True if has zero termination, at the byte at m_sizeInBytes
228    bool isTerminated() const
229    {
230        return m_capacityInBytes > m_sizeInBytes && ((const char*)m_data)[m_sizeInBytes] == 0;
231    }
232
233    ScopedAllocation()
234        : m_data(nullptr), m_sizeInBytes(0), m_capacityInBytes(0)
235    {
236    }
237
238    ~ScopedAllocation() { deallocate(); }
239
240private:
241    // disable
242    ScopedAllocation(const ThisType& rhs) = delete;
243    void operator=(const ThisType& rhs) = delete;
244
245    void* m_data;
246    size_t m_sizeInBytes;
247    size_t m_capacityInBytes;
248};
249
250/** A blob that manages some raw data that it owns.
251 */
252class RawBlob : public BlobBase
253{
254public:
255    // ICastable
256    virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE;
257    // ISlangBlob
258    SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE
259    {
260        return m_data.getData();
261    }
262    SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE
263    {
264        return m_data.getSizeInBytes();
265    }
266
267    static ComPtr<ISlangBlob> moveCreate(ScopedAllocation& alloc)
268    {
269        RawBlob* blob = new RawBlob;
270        blob->m_data.swap(alloc);
271        return ComPtr<ISlangBlob>(blob);
272    }
273
274    /// Create a blob that will retain (a copy of) raw data.
275    static inline ComPtr<ISlangBlob> create(void const* inData, size_t size)
276    {
277        return ComPtr<ISlangBlob>(new RawBlob(inData, size));
278    }
279
280protected:
281    // Ctor
282    // NOTE! Takes a copy of the input data
283    RawBlob(const void* data, size_t size) { memcpy(m_data.allocateTerminated(size), data, size); }
284
285    void* getObject(const Guid& guid);
286
287    RawBlob() = default;
288
289    ScopedAllocation m_data;
290};
291
292// A blob that does not own it's contained data.
293class UnownedRawBlob : public BlobBase
294{
295public:
296    // ISlangBlob
297    SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_data; }
298    SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_dataSizeInBytes; }
299
300    static inline ComPtr<ISlangBlob> create(void const* inData, size_t size)
301    {
302        return ComPtr<ISlangBlob>(new UnownedRawBlob(inData, size));
303    }
304
305protected:
306    // Ctor
307    UnownedRawBlob(const void* data, size_t size)
308        : m_data(data), m_dataSizeInBytes(size)
309    {
310    }
311
312    UnownedRawBlob() = default;
313
314    const void* m_data;
315    size_t m_dataSizeInBytes;
316};
317
318/** A Blob that has no ref counting and exists typically for entire execution.
319The memory it references is *not* owned by the blob.
320This is useful when a Blob is useful to represent some global immutable chunk of memory.
321*/
322class StaticBlob : public ISlangBlob, public ICastable
323{
324public:
325    // ISlangUnknown
326    SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject)
327        SLANG_OVERRIDE;
328    SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return 1; }
329    SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; }
330
331    // ICastable
332    virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE;
333
334    // ISlangBlob
335    SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_data; }
336    SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_dataCount; }
337
338    StaticBlob(const void* data, size_t dataCount)
339        : m_data(data), m_dataCount(dataCount)
340    {
341    }
342
343protected:
344    ISlangUnknown* getInterface(const Guid& guid);
345    void* getObject(const Guid& guid);
346
347    const void* m_data;
348    size_t m_dataCount;
349};
350
351class ScopeBlob : public BlobBase
352{
353public:
354    // ICastable
355    virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE;
356
357    // ISlangBlob
358    SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE
359    {
360        return m_blob->getBufferPointer();
361    }
362    SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE
363    {
364        return m_blob->getBufferSize();
365    }
366
367    static inline ComPtr<ISlangBlob> create(ISlangBlob* blob, ISlangUnknown* scope)
368    {
369        return ComPtr<ISlangBlob>(new ScopeBlob(blob, scope));
370    }
371
372protected:
373    // Ctor
374    ScopeBlob(ISlangBlob* blob, ISlangUnknown* scope)
375        : m_blob(blob), m_scope(scope)
376    {
377        // Cache the ICastable interface if there is one.
378        blob->queryInterface(SLANG_IID_PPV_ARGS(m_castable.writeRef()));
379    }
380
381    ComPtr<ISlangUnknown> m_scope;
382    ComPtr<ISlangBlob> m_blob;
383    ComPtr<ICastable>
384        m_castable; ///< Set if the blob has this interface. Set to nullptr if does not.
385};
386
387} // namespace Slang
388
389#endif // SLANG_CORE_BLOB_H