yum-mirror/slang

Making it easier to work with shaders

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

Ellie HermaszewskaPerf improvements to IR serialization (#7751)28758e0e4

master
11.9 KiB413 linesraw
1#pragma once
2
3#include "slang-signal.h"
4#include "slang.h"
5
6#include <assert.h>
7#include <cstddef>
8#include <cstring>
9#include <stdint.h>
10#include <type_traits>
11
12#define VARIADIC_TEMPLATE
13
14namespace Slang
15{
16
17/// Signed 32-bit integer.
18///
19/// This type should be used when the exact size
20/// in bits is important (e.g., when dealing with
21/// explicit binary file formats, etc.). Otherwise
22/// prefer the plain `Int` type or a semantically
23/// richer type like `Count` or `Index`.
24///
25typedef int32_t Int32;
26
27/// Unsigned 32-bit integer.
28///
29/// This type should be used when the exact size
30/// in bits is important (e.g., when dealing with
31/// explicit binary file formats, etc.). Otherwise
32/// prefer the plain `Int` type or a semantically
33/// richer type like `Count` or `Index`.
34///
35typedef uint32_t UInt32;
36
37/// Signed 64-bit integer.
38///
39/// This type should be used when the exact size
40/// in bits is important (e.g., when dealing with
41/// explicit binary file formats, etc.). Otherwise
42/// prefer the plain `Int` type or a semantically
43/// richer type like `Count` or `Index`.
44///
45typedef int64_t Int64;
46
47/// Unsigned 64-bit integer.
48///
49/// This type should be used when the exact size
50/// in bits is important (e.g., when dealing with
51/// explicit binary file formats, etc.). Otherwise
52/// prefer the plain `Int` type or a semantically
53/// richer type like `Count` or `Index`.
54///
55typedef uint64_t UInt64;
56
57/// "Default" integer type for the Slang codebase.
58///
59/// When there is not a clear reason to another
60/// integer type, use this one.
61///
62/// Note that this type is currently defined to be
63/// the same as the `SlangInt` type exposed through
64/// the public Slang API, but this may not be the
65/// case forever.
66///
67typedef SlangInt Int;
68
69/// "Default" unsigned integer type for the Slang codebase.
70///
71/// Only use this type when you explicitly need
72/// an unsigned type that's the same size as `Int`.
73/// Otherwise you should probably just be using `Int`.
74///
75/// Note that this type is currently defined to be
76/// the same as the `SlangUInt` type exposed through
77/// the public Slang API, but this may not be the
78/// case forever.
79///
80typedef SlangUInt UInt;
81
82static const UInt kMaxUInt = ~UInt(0);
83static const Int kMaxInt = Int(kMaxUInt >> 1);
84
85typedef intptr_t PtrInt;
86
87/// Default type for indices.
88///
89/// This is (and should always be) an alias for `Int`.
90///
91/// Use this type to document the intention that an
92/// integer parameter/variable/etc. represents an
93/// index into some kind of sequence, or any other
94/// kind of ordinal number.
95///
96typedef Int Index;
97
98static const Index kMaxIndex = kMaxInt;
99
100/// Unsigned equivalent of `Index`.
101///
102/// Please don't use this unless you have a good reason.
103///
104typedef UInt UIndex;
105
106/// Default type for counts.
107///
108/// This is (and should always be) an alias for `Int`.
109///
110/// Use this type to document the intention that an
111/// integer parameter/variable/etc. represents a
112/// count of the number of elements in some container,
113/// or any other kind of cardinal number.
114///
115typedef Int Count;
116
117/// Unsigned equivalent of `Count`.
118///
119/// Please don't use this unless you have a good reason.
120///
121typedef UInt UCount;
122
123
124/// Explicit type for when manipulating bytes.
125///
126/// Use this type to document the intention that a
127/// parameter/variable/etc. represents an 8-bit byte, with
128/// no particular interpretation of that byte as
129/// any higher-level type.
130///
131/// Note that the `char` types have special semantics
132/// when it comes to "type punning" that are not shared
133/// with other types like `uint8_t`. Using a variation
134/// of `char` here helps avoid the possibility of undefined
135/// behavior when code reads other types to/from arrays
136/// of `Byte`s.
137///
138/// We are not using `std::byte` here because that is
139/// defined as an `enum class` and does not support
140/// mathematical or bitwise operations, which a lot
141/// of the Slang codebase does on `Byte`s.
142///
143typedef unsigned char Byte;
144
145/// Preferred integer type for sizes measured in bytes.
146///
147/// Use this type to document the intention that an
148/// integer parameter/variable/etc. represents the
149/// size of something, in bytes, rather than being
150/// some other kind of integer.
151///
152/// Note that this type is unsigned, despite the stated
153/// default in the Slang codebase being signed integer
154/// types. The reason for this is that variables
155/// holding sizes are often compared against the
156/// result of the `sizeof` operator, which yields
157/// a `size_t`. Our hands are, to some extent, tied
158/// on this matter.
159///
160using Size = size_t;
161
162// TODO(JS):
163// Perhaps these should be named Utf8, Utf16 and UnicodePoint/Rune/etc? For now, just keep it simple
164//
165typedef char Char8;
166// 16 bit character. Note much like in utf8, a character may or may not represent a code point (it
167// can be part of a code point).
168typedef uint16_t Char16;
169
170// Can always hold a unicode code point.
171typedef uint32_t Char32;
172
173template<typename T>
174inline T&& _Move(T& obj)
175{
176    return static_cast<T&&>(obj);
177}
178
179template<typename T>
180inline void Swap(T& v0, T& v1)
181{
182    T tmp = _Move(v0);
183    v0 = _Move(v1);
184    v1 = _Move(tmp);
185}
186
187// Make these interfaces have more convenient names
188typedef ISlangCastable ICastable;
189typedef ISlangClonable IClonable;
190
191// Convenience function for using clonable
192template<typename T>
193SLANG_FORCE_INLINE T* clone(IClonable* clonable)
194{
195    return (T*)clonable->clone(T::getTypeGuid());
196}
197
198template<typename T>
199inline bool isBitSet(T value, T bitToTest)
200{
201    static_assert(sizeof(T) <= sizeof(uint32_t), "Only support up to 32 bit enums");
202    return (T)((uint32_t)value & (uint32_t)bitToTest) == bitToTest;
203}
204
205template<typename To, typename From>
206typename std::enable_if_t<
207    sizeof(To) == sizeof(From) && std::is_trivially_copyable_v<From> &&
208        std::is_trivially_copyable_v<To> && std::is_trivially_constructible_v<To>,
209    To>
210bitCast(const From& src)
211{
212    To dst;
213    std::memcpy(&dst, &src, sizeof(To));
214    return dst;
215}
216
217} // namespace Slang
218
219// SLANG_DEFER
220template<typename F>
221class SlangDeferImpl
222{
223    F f;
224
225public:
226    SlangDeferImpl(F&& f)
227        : f(Slang::_Move(f))
228    {
229    }
230    ~SlangDeferImpl() { f(); }
231};
232
233#ifndef SLANG_DEFER_LAMBDA
234#define SLANG_DEFER_LAMBDA(x) auto SLANG_CONCAT(slang_defer_, __LINE__) = SlangDeferImpl(x)
235#define SLANG_DEFER(x) auto SLANG_CONCAT(slang_defer_, __LINE__) = SlangDeferImpl([&]() { x; })
236#endif
237
238//
239// Some macros for avoiding boilerplate
240// TODO: could probably deduce the size with templates, and move the whole
241// thing into a template
242//
243#if __cplusplus >= 202002L
244#define SLANG_COMPONENTWISE_EQUALITY_1(type) bool operator==(const type& other) const = default;
245#define SLANG_COMPONENTWISE_EQUALITY_2(type) bool operator==(const type& other) const = default;
246#define SLANG_COMPONENTWISE_EQUALITY_3(type) bool operator==(const type& other) const = default;
247#else
248#define SLANG_COMPONENTWISE_EQUALITY_1(type) \
249    bool operator==(const type& other) const \
250    {                                        \
251        const auto& [m1] = *this;            \
252        const auto& [o1] = other;            \
253        return m1 == o1;                     \
254    }                                        \
255    bool operator!=(const type& other) const \
256    {                                        \
257        return !(*this == other);            \
258    }
259
260#define SLANG_COMPONENTWISE_EQUALITY_2(type) \
261    bool operator==(const type& other) const \
262    {                                        \
263        const auto& [m1, m2] = *this;        \
264        const auto& [o1, o2] = other;        \
265        return m1 == o1 && m2 == o2;         \
266    }                                        \
267    bool operator!=(const type& other) const \
268    {                                        \
269        return !(*this == other);            \
270    }
271
272#define SLANG_COMPONENTWISE_EQUALITY_3(type)     \
273    bool operator==(const type& other) const     \
274    {                                            \
275        const auto& [m1, m2, m3] = *this;        \
276        const auto& [o1, o2, o3] = other;        \
277        return m1 == o1 && m2 == o2 && m3 == o3; \
278    }                                            \
279    bool operator!=(const type& other) const     \
280    {                                            \
281        return !(*this == other);                \
282    }
283#endif
284
285// TODO: Shouldn't these be SLANG_ prefixed?
286#ifdef _MSC_VER
287#define UNREACHABLE_RETURN(x)
288#else
289#define UNREACHABLE_RETURN(x) return x;
290#endif
291
292#if SLANG_GCC
293#define SLANG_EXHAUSTIVE_SWITCH_BEGIN \
294    _Pragma("GCC diagnostic push");   \
295    _Pragma("GCC diagnostic error \"-Wswitch-enum\"");
296#define SLANG_EXHAUSTIVE_SWITCH_END _Pragma("GCC diagnostic pop");
297#elif SLANG_CLANG
298#define SLANG_EXHAUSTIVE_SWITCH_BEGIN \
299    _Pragma("clang diagnostic push"); \
300    _Pragma("clang diagnostic error \"-Wswitch-enum\"");
301#define SLANG_EXHAUSTIVE_SWITCH_END _Pragma("clang diagnostic pop");
302#elif SLANG_VC
303#define SLANG_EXHAUSTIVE_SWITCH_BEGIN \
304    _Pragma("warning(push)");         \
305    _Pragma("warning(error : 4062)");
306#define SLANG_EXHAUSTIVE_SWITCH_END _Pragma("warning(pop)");
307#else
308#define SLANG_EXHAUSTIVE_SWITCH_BEGIN
309#define SLANG_EXHAUSTIVE_SWITCH_END
310#endif
311
312#if SLANG_GCC
313#define SLANG_ALLOW_DEPRECATED_BEGIN \
314    _Pragma("GCC diagnostic push");  \
315    _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"");
316#define SLANG_ALLOW_DEPRECATED_END _Pragma("GCC diagnostic pop");
317#elif SLANG_CLANG
318#define SLANG_ALLOW_DEPRECATED_BEGIN  \
319    _Pragma("clang diagnostic push"); \
320    _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"");
321#define SLANG_ALLOW_DEPRECATED_END _Pragma("clang diagnostic pop");
322#elif SLANG_VC
323#define SLANG_ALLOW_DEPRECATED_BEGIN \
324    _Pragma("warning(push)");        \
325    _Pragma("warning(disable : 4996)");
326#define SLANG_ALLOW_DEPRECATED_END _Pragma("warning(pop)");
327#else
328#define SLANG_ALLOW_DEPRECATED_BEGIN
329#define SLANG_ALLOW_DEPRECATED_END
330#endif
331
332//
333// Use `SLANG_ASSUME(myBoolExpression);` to inform the compiler that the condition is true.
334// Do not rely on side effects of the condition being performed.
335//
336#if defined(__cpp_assume)
337#define SLANG_ASSUME(X) [[assume(X)]]
338#elif SLANG_GCC
339#define SLANG_ASSUME(X)              \
340    do                               \
341    {                                \
342        if (!(X))                    \
343            __builtin_unreachable(); \
344    } while (0)
345#elif SLANG_CLANG
346#define SLANG_ASSUME(X) __builtin_assume(X)
347#elif SLANG_VC
348#define SLANG_ASSUME(X) __assume(X)
349#else
350[[noreturn]] inline void invokeUndefinedBehaviour() {}
351#define SLANG_ASSUME(X)                 \
352    do                                  \
353    {                                   \
354        if (!(X))                       \
355            invokeUndefinedBehaviour(); \
356    } while (0)
357#endif
358
359//
360// Assertions abort in debug builds, but inform the compiler of true
361// assumptions in release builds
362//
363#ifdef _DEBUG
364#define SLANG_ASSERT(VALUE)               \
365    do                                    \
366    {                                     \
367        if (!(VALUE)) [[unlikely]]        \
368            SLANG_ASSERT_FAILURE(#VALUE); \
369    } while (0)
370#else
371#define SLANG_ASSERT(VALUE) SLANG_ASSUME(VALUE)
372#endif
373
374#define SLANG_RELEASE_ASSERT(VALUE) \
375    if (VALUE) [[likely]]           \
376    {                               \
377    }                               \
378    else                            \
379        SLANG_ASSERT_FAILURE(#VALUE)
380
381template<typename T>
382void slang_use_obj(T&)
383{
384}
385
386#define SLANG_UNREFERENCED_PARAMETER(P) slang_use_obj(P)
387#define SLANG_UNREFERENCED_VARIABLE(P) slang_use_obj(P)
388
389#if defined(SLANG_RT_DYNAMIC)
390#if defined(_MSC_VER)
391#ifdef SLANG_RT_DYNAMIC_EXPORT
392#define SLANG_RT_API SLANG_DLL_EXPORT
393#else
394#define SLANG_RT_API __declspec(dllimport)
395#endif
396#else
397// TODO: need to consider compiler capabilities
398// #     ifdef SLANG_RT_DYNAMIC_EXPORT
399#define SLANG_RT_API SLANG_DLL_EXPORT
400// #     endif
401#endif
402#endif
403
404#if defined(_MSC_VER)
405#define SLANG_ATTR_PRINTF(string_index, varargs_index)
406#else
407#define SLANG_ATTR_PRINTF(string_index, varargs_index) \
408    __attribute__((format(printf, string_index, varargs_index)))
409#endif
410
411#ifndef SLANG_RT_API
412#define SLANG_RT_API
413#endif