yum-mirror/slang

Making it easier to work with shaders

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

aryaReflection API Wasm Bindings Part1 (#5936)1b5679f95

master
11.9 KiB459 linesraw
1#pragma once
2
3#include <emscripten.h>
4#include <emscripten/val.h>
5#include <optional>
6#include <slang-com-ptr.h>
7#include <slang.h>
8#include <stdint.h>
9#include <string>
10#include <unordered_map>
11#include <vector>
12
13/**
14The web assembly binding here is designed to make javascript code as simple and native as possible.
15The big issue being handled here is lifetime management of objects created in the Slang API.
16
17The idea here is to make lifetime management as coarse grained as possible from the javascript side.
18Only two types of objects need to be explicitly deleted by javascript: GlobalSession and Session.
19
20All the remaining objects returned by member functions of Session will have their lifetime managed
21by the owning session in the C++ side. This way, the javascript code will never need to worry about
22freeing small objects like ComponentType, EntryPoint, Module, TypeLayoutReflection,
23VariableLayoutReflection, ProgramLayout etc.
24
25When a Session is no longer needed, the javascript code should explicitly delete it, this will allow
26us to free all the objects we allocated from the session in one single explicit call.
27
28By making explicit memory management as coarse grained as possible, we are making memory management
29efficient, simple, and less error prone.
30*/
31
32namespace Slang
33{
34class LanguageServerCore;
35}
36
37namespace slang
38{
39namespace wgsl
40{
41
42class TypeLayoutReflection;
43class TypeReflection;
44class VariableLayoutReflection;
45class VariableReflection;
46class FunctionReflection;
47class GenericReflection;
48
49
50class Error
51{
52public:
53    // Can be
54    // "USER": User did not call the API correctly
55    // "INTERNAL": Slang failed due to a bug
56    std::string type;
57    std::string message;
58    SlangResult result;
59};
60
61Error getLastError();
62
63// returns mapping of codegen target from string to SlangCompileTarget
64// in the form of [{name: STRING, value: INT}, ...].
65emscripten::val getCompileTargets();
66
67class DeclReflection
68{
69public:
70    std::string getName();
71    slang::DeclReflection::Kind getKind();
72    uint32_t getChildrenCount();
73    slang::wgsl::DeclReflection* getChild(uint32_t index);
74    slang::wgsl::TypeReflection* getType();
75    slang::wgsl::VariableReflection* asVariable();
76    slang::wgsl::FunctionReflection* asFunction();
77    slang::wgsl::GenericReflection* asGeneric();
78    slang::wgsl::DeclReflection* getParent();
79
80    slang::DeclReflection* interface() const { return (slang::DeclReflection*)this; };
81};
82
83class GenericReflection
84{
85
86public:
87    std::string getName();
88    slang::wgsl::DeclReflection* asDecl();
89    uint32_t getTypeParameterCount();
90    slang::wgsl::VariableReflection* getTypeParameter(unsigned index);
91    uint32_t getValueParameterCount();
92    slang::wgsl::VariableReflection* getValueParameter(unsigned index);
93    // uint32_t getTypeParameterConstraintCount(VariableReflection* typeParam);
94    // slang::wgsl::TypeReflection* getTypeParameterConstraintType(
95    //     VariableReflection* typeParam,
96    //     unsigned index);
97    slang::wgsl::DeclReflection* getInnerDecl();
98    SlangDeclKind getInnerKind();
99    slang::wgsl::GenericReflection* getOuterGenericContainer();
100    // TypeReflection* getConcreteType(slang::wgsl::VariableReflection* typeParam);
101    // int64_t getConcreteIntVal(slang::wgsl::VariableReflection* valueParam);
102    // GenericReflection* applySpecializations(slang::wgsl::GenericReflection* generic);
103
104    slang::GenericReflection* interface() const { return (slang::GenericReflection*)this; };
105};
106
107class TypeReflection
108{
109
110public:
111    slang::TypeReflection::ScalarType getScalarType();
112    slang::TypeReflection::Kind getKind();
113    uint32_t getFieldCount();
114    slang::wgsl::VariableReflection* getFieldByIndex(uint32_t index);
115
116    slang::TypeReflection* interface() const { return (slang::TypeReflection*)this; };
117};
118
119
120class UserAttribute
121{
122
123public:
124    std::string getName();
125    uint32_t getArgumentCount();
126    float getArgumentValueFloat(uint32_t index);
127    std::string getArgumentValueString(uint32_t index);
128    slang::wgsl::TypeReflection* getArgumentType(uint32_t index);
129    slang::UserAttribute* interface() const { return (slang::UserAttribute*)this; };
130};
131
132
133class VariableReflection
134{
135public:
136    std::string getName();
137    slang::wgsl::TypeReflection* getType();
138    Modifier* findModifier(Modifier::ID id);
139    uint32_t getUserAttributeCount();
140    slang::wgsl::UserAttribute* getUserAttributeByIndex(uint32_t index);
141    // slang::wgsl::UserAttribute* findUserAttributeByName(SlangSession* globalSession, std::string
142    // name);
143    bool hasDefaultValue();
144    // slang::wgsl::GenericReflection* getGenericContainer();
145    // slang::wgsl::VariableReflection* applySpecializations(slang::wgsl::GenericReflection*
146    // generic);
147    slang::VariableReflection* interface() const { return (slang::VariableReflection*)this; }
148};
149
150
151class TypeLayoutReflection
152{
153public:
154    BindingType getDescriptorSetDescriptorRangeType(uint32_t setIndex, uint32_t rangeIndex);
155    slang::TypeLayoutReflection* interface() const { return (slang::TypeLayoutReflection*)this; }
156};
157
158class VariableLayoutReflection
159{
160public:
161    std::string getName();
162    slang::wgsl::TypeLayoutReflection* getTypeLayout();
163    uint32_t getBindingIndex();
164
165    slang::VariableLayoutReflection* interface() const
166    {
167        return (slang::VariableLayoutReflection*)this;
168    }
169};
170
171class EntryPointReflection
172{
173
174public:
175    struct ThreadGroupSize
176    {
177        uint32_t x;
178        uint32_t y;
179        uint32_t z;
180    };
181
182    ThreadGroupSize getComputeThreadGroupSize();
183    slang::EntryPointReflection* interface() const { return (slang::EntryPointReflection*)this; };
184};
185class FunctionReflection
186{
187
188public:
189    std::string getName();
190    uint32_t getUserAttributeCount();
191    slang::wgsl::UserAttribute* getUserAttributeByIndex(uint32_t index);
192    slang::FunctionReflection* interface() const { return (slang::FunctionReflection*)this; };
193};
194
195class ProgramLayout
196{
197public:
198    uint32_t getParameterCount();
199    slang::wgsl::VariableLayoutReflection* getParameterByIndex(uint32_t index);
200
201    slang::wgsl::TypeLayoutReflection* getGlobalParamsTypeLayout();
202
203    slang::wgsl::EntryPointReflection* findEntryPointByName(std::string name);
204
205    slang::wgsl::FunctionReflection* findFunctionByName(std::string name);
206
207    slang::ProgramLayout* interface() const { return (slang::ProgramLayout*)this; }
208
209    emscripten::val toJsonObject();
210};
211
212class Session;
213class ComponentType
214{
215public:
216    IComponentType* m_interface;
217    Session* m_session;
218
219public:
220    ComponentType(slang::IComponentType* interface, Session* session)
221        : m_interface(interface), m_session(session)
222    {
223    }
224
225    // Returns ComponentType or null.
226    emscripten::val link();
227
228    std::string getEntryPointCode(int entryPointIndex, int targetIndex);
229
230    // Returns UInt8Array or null.
231    emscripten::val getEntryPointCodeBlob(int entryPointIndex, int targetIndex);
232    std::string getTargetCode(int targetIndex);
233
234    // Returns UInt8Array or null.
235    emscripten::val getTargetCodeBlob(int targetIndex);
236
237    slang::wgsl::ProgramLayout* getLayout(uint32_t targetIndex);
238
239    slang::IComponentType* interface() const { return m_interface; }
240
241    // returns [{hash: HASH, string: STRING}, ...]
242    emscripten::val loadStrings();
243};
244
245class EntryPoint : public ComponentType
246{
247public:
248    EntryPoint(slang::IComponentType* interface, Session* session)
249        : ComponentType(interface, session)
250    {
251    }
252    std::string getName() const
253    {
254        return entryPointInterface()->getFunctionReflection()->getName();
255    }
256
257private:
258    slang::IEntryPoint* entryPointInterface() const
259    {
260        return static_cast<slang::IEntryPoint*>(interface());
261    }
262};
263
264class Module : public ComponentType
265{
266public:
267    Module(slang::IComponentType* interface, Session* session)
268        : ComponentType(interface, session)
269    {
270    }
271
272    // Returns EntryPoint or null.
273    emscripten::val findEntryPointByName(const std::string& name);
274
275    // Returns EntryPoint or null.
276    emscripten::val findAndCheckEntryPoint(const std::string& name, int stage);
277
278    // Returns EntryPoint or null.
279    emscripten::val getDefinedEntryPoint(int index);
280
281    int getDefinedEntryPointCount();
282
283    slang::IModule* moduleInterface() const { return static_cast<slang::IModule*>(interface()); }
284};
285
286class Session
287{
288public:
289    Session(slang::ISession* interface)
290        : m_interface(interface)
291    {
292    }
293    ~Session();
294
295    // Returns Module or null.
296    emscripten::val loadModuleFromSource(
297        const std::string& slangCode,
298        const std::string& name,
299        const std::string& path);
300
301    // `components` is a javascript array of ComponentType/Module/EntryPoint objects.
302    // Returns ComponentType or null.
303    emscripten::val createCompositeComponentType(emscripten::val components);
304
305    slang::ISession* interface() const { return m_interface; }
306
307    void addComponentType(slang::IComponentType* componentType)
308    {
309        m_componentTypes.push_back(Slang::ComPtr<slang::IComponentType>(componentType));
310    }
311
312private:
313    std::vector<Slang::ComPtr<slang::IComponentType>> m_componentTypes;
314    Slang::ComPtr<slang::ISession> m_interface;
315};
316
317class GlobalSession
318{
319public:
320    GlobalSession(slang::IGlobalSession* interface)
321        : m_interface(interface)
322    {
323    }
324
325    Session* createSession(int compileTarget);
326
327    slang::IGlobalSession* interface() const { return m_interface; }
328
329private:
330    Slang::ComPtr<slang::IGlobalSession> m_interface;
331};
332
333GlobalSession* createGlobalSession();
334
335namespace lsp
336{
337struct Position
338{
339    int line = -1;
340    int character = -1;
341};
342
343struct Range
344{
345    Position start;
346    Position end;
347};
348
349struct Location
350{
351    std::string uri;
352    Range range;
353};
354
355struct TextEdit
356{
357    Range range;
358    std::string text;
359};
360
361struct MarkupContent
362{
363    std::string kind;
364    std::string value;
365};
366
367struct Hover
368{
369    MarkupContent contents;
370    Range range;
371};
372
373struct CompletionItem
374{
375    std::string label;
376    int kind;
377    std::string detail;
378    std::string data;
379    std::optional<MarkupContent> documentation;
380    std::optional<TextEdit> textEdit;
381    std::optional<std::vector<std::string>> commitCharacters;
382};
383
384struct CompletionContext
385{
386    int triggerKind = 1;
387    std::string triggerCharacter;
388};
389
390struct ParameterInformation
391{
392    uint32_t label[2] = {0, 0};
393    MarkupContent documentation;
394};
395
396struct SignatureInformation
397{
398    std::string label;
399    MarkupContent documentation;
400    std::vector<ParameterInformation> parameters;
401};
402
403struct SignatureHelp
404{
405    std::vector<SignatureInformation> signatures;
406    uint32_t activeSignature = 0;
407    uint32_t activeParameter = 0;
408};
409
410struct DocumentSymbol
411{
412    std::string name;
413    std::string detail;
414    int kind = 0;
415    Range range;
416    Range selectionRange;
417    std::vector<DocumentSymbol> children;
418};
419
420struct Diagnostics
421{
422    std::string code;
423    Range range;
424    std::string message;
425    int severity;
426};
427
428class LanguageServer
429{
430private:
431    Slang::LanguageServerCore* m_core = nullptr;
432    void init();
433
434public:
435    LanguageServer();
436    ~LanguageServer();
437    void didOpenTextDocument(std::string uri, std::string text);
438    void didCloseTextDocument(std::string uri);
439    void didChangeTextDocument(std::string uri, const std::vector<lsp::TextEdit>& changes);
440    std::optional<lsp::Hover> hover(std::string uri, lsp::Position position);
441    std::optional<std::vector<lsp::Location>> gotoDefinition(
442        std::string uri,
443        lsp::Position position);
444    std::optional<std::vector<lsp::CompletionItem>> completion(
445        std::string uri,
446        lsp::Position position,
447        CompletionContext context);
448    std::optional<lsp::CompletionItem> completionResolve(lsp::CompletionItem args);
449    std::optional<std::vector<uint32_t>> semanticTokens(std::string uri);
450    std::optional<lsp::SignatureHelp> signatureHelp(std::string uri, lsp::Position position);
451    std::optional<std::vector<lsp::DocumentSymbol>> documentSymbol(std::string uri);
452    std::optional<std::vector<lsp::Diagnostics>> getDiagnostics(std::string uri);
453};
454
455LanguageServer* createLanguageServer();
456} // namespace lsp
457
458} // namespace wgsl
459} // namespace slang