yum-mirror/slang

Making it easier to work with shaders

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

Yong HeAdd Slang Byte Code generation and interpreter. (#6896)c39c29bf4

master
6.8 KiB234 linesraw
1namespace SlangITool
2{
3static void printCallback(const char* message, void* userData)
4{
5    auto stdWriters = (StdWriters*)userData;
6    if (stdWriters)
7    {
8        stdWriters->getOut().print("%s", message);
9    }
10}
11
12static SlangResult compileAndInterpret(
13    slang::IGlobalSession* sharedSession,
14    StdWriters* stdWriters,
15    UnownedStringSlice fileName,
16    const char* entryPointName,
17    bool disasm,
18    int argc,
19    const char* const* argv)
20{
21    auto maybePrintDiagnostic = [&](const ComPtr<slang::IBlob>& diagnosticBlob)
22    {
23        if (diagnosticBlob)
24        {
25            const char* diagText = (const char*)diagnosticBlob->getBufferPointer();
26            stdWriters->getError().print("%s\n", diagText);
27        }
28    };
29
30    ComPtr<slang::IGlobalSession> globalSession;
31    SLANG_RETURN_ON_FAIL(slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()));
32    slang::TargetDesc targetDesc = {};
33    targetDesc.format = SLANG_HOST_VM;
34    slang::SessionDesc sessionDesc = {};
35    sessionDesc.targetCount = 1;
36    sessionDesc.targets = &targetDesc;
37    sessionDesc.compilerOptionEntryCount = 0;
38    String pathName = Path::getParentDirectory(fileName);
39    String moduleName = Path::getFileNameWithoutExt(fileName);
40    const char* searchPaths[] = {pathName.getBuffer()};
41    if (pathName.getLength())
42    {
43        sessionDesc.searchPathCount = 1;
44        sessionDesc.searchPaths = searchPaths;
45    }
46    ComPtr<slang::ISession> session;
47    SLANG_RETURN_ON_FAIL(globalSession->createSession(sessionDesc, session.writeRef()));
48
49    ComPtr<slang::IBlob> diagnosticBlob;
50    auto module = session->loadModule(moduleName.getBuffer(), diagnosticBlob.writeRef());
51    if (!module)
52    {
53        maybePrintDiagnostic(diagnosticBlob);
54        return SLANG_FAIL;
55    }
56    ComPtr<slang::IEntryPoint> entryPoint;
57    if (SLANG_FAILED(module->findAndCheckEntryPoint(
58            entryPointName,
59            SLANG_STAGE_DISPATCH,
60            entryPoint.writeRef(),
61            diagnosticBlob.writeRef())))
62    {
63        maybePrintDiagnostic(diagnosticBlob);
64        return SLANG_FAIL;
65    }
66
67    ComPtr<slang::IComponentType> compositeComponent;
68    slang::IComponentType* components[] = {module, entryPoint.get()};
69    if (SLANG_FAILED(session->createCompositeComponentType(
70            components,
71            2,
72            compositeComponent.writeRef(),
73            diagnosticBlob.writeRef())))
74    {
75        maybePrintDiagnostic(diagnosticBlob);
76        return SLANG_FAIL;
77    }
78
79    ComPtr<slang::IComponentType> linkedProgram;
80    if (SLANG_FAILED(compositeComponent->link(linkedProgram.writeRef(), diagnosticBlob.writeRef())))
81    {
82        maybePrintDiagnostic(diagnosticBlob);
83        return SLANG_FAIL;
84    }
85    ComPtr<slang::IBlob> code;
86
87    if (SLANG_FAILED(linkedProgram->getTargetCode(0, code.writeRef(), diagnosticBlob.writeRef())))
88    {
89        maybePrintDiagnostic(diagnosticBlob);
90        return SLANG_FAIL;
91    }
92
93    if (code->getBufferSize() == 0)
94    {
95        return SLANG_FAIL;
96    }
97
98    if (disasm)
99    {
100        ComPtr<slang::IBlob> disasmBlob;
101        if (SLANG_FAILED(slang_disassembleByteCode(code, disasmBlob.writeRef())))
102        {
103            maybePrintDiagnostic(diagnosticBlob);
104            return SLANG_FAIL;
105        }
106        const char* disasmText = (const char*)disasmBlob->getBufferPointer();
107        stdWriters->getOut().print("%s\n", disasmText);
108        return SLANG_OK;
109    }
110
111    // Create a byte code runner and interpret the code.
112    ComPtr<slang::IByteCodeRunner> runner;
113    slang::ByteCodeRunnerDesc runnerDesc = {};
114    SLANG_RETURN_ON_FAIL(slang_createByteCodeRunner(&runnerDesc, runner.writeRef()));
115    runner->setPrintCallback(printCallback, stdWriters);
116
117    if (SLANG_FAILED(runner->loadModule(code)))
118    {
119        runner->getErrorString(diagnosticBlob.writeRef());
120        maybePrintDiagnostic(diagnosticBlob);
121    }
122    auto funcIndex = runner->findFunctionByName(entryPointName);
123    if (funcIndex < 0)
124    {
125        stdWriters->getError().print("Function '%s' not found in byte code.\n", entryPointName);
126        return SLANG_FAIL;
127    }
128
129    if (SLANG_FAILED(runner->selectFunctionByIndex((uint32_t)funcIndex)))
130    {
131        runner->getErrorString(diagnosticBlob.writeRef());
132        maybePrintDiagnostic(diagnosticBlob);
133        return SLANG_FAIL;
134    }
135
136    struct Arguments
137    {
138        uint32_t argc;
139        const char* const* argv;
140    };
141    Arguments args;
142    args.argc = argc;
143    args.argv = argv;
144    void* arguments = nullptr;
145    size_t argSize = 0;
146    slang::ByteCodeFuncInfo funcInfo;
147    if (SLANG_FAILED(runner->getFunctionInfo((uint32_t)funcIndex, &funcInfo)))
148    {
149        runner->getErrorString(diagnosticBlob.writeRef());
150        maybePrintDiagnostic(diagnosticBlob);
151        return SLANG_FAIL;
152    }
153    if (funcInfo.parameterCount == 2)
154    {
155        arguments = &args;
156        argSize = sizeof(Arguments);
157    }
158    if (SLANG_FAILED(runner->execute(arguments, argSize)))
159    {
160        runner->getErrorString(diagnosticBlob.writeRef());
161        maybePrintDiagnostic(diagnosticBlob);
162        return SLANG_FAIL;
163    }
164    return SLANG_OK;
165}
166
167SlangResult innerMain(
168    StdWriters* stdWriters,
169    slang::IGlobalSession* sharedSession,
170    int argc,
171    const char* const* argv)
172{
173    StdWriters::setSingleton(stdWriters);
174
175    // Assume we will used the shared session
176    ComPtr<slang::IGlobalSession> session(sharedSession);
177
178    // The sharedSession always has a pre-loaded core module.
179    // This differed test checks if the command line has an option to setup the core module.
180    // If so we *don't* use the sharedSession, and create a new session without the core module just
181    // for this compilation.
182    if (TestToolUtil::hasDeferredCoreModule(Index(argc - 1), argv + 1))
183    {
184        SLANG_RETURN_ON_FAIL(
185            slang_createGlobalSessionWithoutCoreModule(SLANG_API_VERSION, session.writeRef()));
186    }
187
188    String entryPointName = toSlice("main");
189    UnownedStringSlice fileName;
190    bool disasm = false;
191    int innerArgIndex = 0;
192    if (argc < 2)
193    {
194        return SLANG_FAIL;
195    }
196    for (auto i = 1; i < argc; i++)
197    {
198        auto arg = UnownedStringSlice(argv[i]);
199        if (arg == "-entry")
200        {
201            entryPointName = UnownedStringSlice(argv[++i]);
202        }
203        else if (arg == "-disasm")
204        {
205            disasm = true;
206        }
207        else if (arg.startsWith("-"))
208        {
209            return SLANG_FAIL;
210        }
211        else
212        {
213            fileName = arg;
214            innerArgIndex = i;
215            break;
216        }
217    }
218    if (!fileName.getLength())
219    {
220        return SLANG_FAIL;
221    }
222
223    auto result = compileAndInterpret(
224        session,
225        stdWriters,
226        fileName,
227        entryPointName.getBuffer(),
228        disasm,
229        argc - innerArgIndex,
230        argv + innerArgIndex);
231
232    return result;
233}
234} // namespace SlangITool