yum-mirror/slang

Making it easier to work with shaders

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

Jay KwakAdd command-line arguments to examples (#7835)13dd01489

master
7.3 KiB250 linesraw
1#include "test-base.h"
2
3#ifdef _WIN32
4// clang-format off
5// include ordering sensitive
6#    include <windows.h>
7#    include <shellapi.h>
8#    include <io.h>
9#    include <fcntl.h>
10// clang-format on
11#include <iostream>
12#include <string>
13#endif
14
15static rhi::DeviceType parseApiString(const char* apiStr)
16{
17    static const struct
18    {
19        const char* name;
20        rhi::DeviceType type;
21    } apiTable[] = {
22#ifdef _WIN32
23        {"d3d11", rhi::DeviceType::D3D11},
24        {"d3d12", rhi::DeviceType::D3D12},
25#endif
26        {"vulkan", rhi::DeviceType::Vulkan},
27#ifdef __APPLE__
28        {"metal", rhi::DeviceType::Metal},
29#endif
30        {"cpu", rhi::DeviceType::CPU},
31        {"cuda", rhi::DeviceType::CUDA},
32        {"webgpu", rhi::DeviceType::WGPU}};
33
34    for (auto& api : apiTable)
35    {
36        if (strcmp(apiStr, api.name) == 0)
37        {
38            return api.type;
39        }
40    }
41    return rhi::DeviceType::Default; // Invalid/unknown
42}
43
44#ifdef _WIN32
45static std::string wstringToString(const std::wstring& wstr)
46{
47    char buffer[256];
48    wcstombs(buffer, wstr.c_str(), sizeof(buffer));
49    return std::string(buffer);
50}
51#endif
52
53// Simple output function that works for both console and WIN32 apps
54static void printOutput(const char* text)
55{
56    printf("%s", text);
57#ifdef _WIN32
58    OutputDebugStringA(text);
59#endif
60}
61
62#ifdef _WIN32
63// For WIN32 apps, allocate a console window to show help text
64static bool ensureConsoleVisible()
65{
66    // Check if we already have a console (running from cmd.exe or already allocated)
67    if (GetConsoleWindow() != NULL)
68    {
69        // We already have a console, just use it
70        return false; // No new window created
71    }
72
73    // Check if stdout is connected to a console or redirected
74    HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
75    if (hStdOut != INVALID_HANDLE_VALUE)
76    {
77        DWORD fileType = GetFileType(hStdOut);
78        switch (fileType)
79        {
80        case FILE_TYPE_CHAR: // Console
81        case FILE_TYPE_DISK: // File redirection
82        case FILE_TYPE_PIPE: // Pipe redirection
83            // Output goes to console or is redirected, don't create a console
84            return false;
85        }
86        // FILE_TYPE_UNKNOWN or other cases: proceed to create console
87    }
88
89    // No console exists and output isn't redirected, so allocate a new one
90    if (AllocConsole())
91    {
92        // Redirect stdout to the console
93        freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
94        freopen_s((FILE**)stderr, "CONOUT$", "w", stderr);
95        freopen_s((FILE**)stdin, "CONIN$", "r", stdin);
96
97        // Make sure cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
98        // point to console as well
99        std::ios::sync_with_stdio(true);
100
101        // Set console title
102        SetConsoleTitleA("Triangle Example - Help");
103        return true; // New window was created
104    }
105
106    return false; // Failed to create console
107}
108#endif
109
110int TestBase::parseOption(int argc, char** argv)
111{
112    // Parse command line arguments for help, API selection, and test mode
113#ifdef _WIN32
114    wchar_t** szArglist;
115    szArglist = CommandLineToArgvW(GetCommandLineW(), &argc);
116#endif
117
118    for (int i = 0; i < argc; i++)
119    {
120#ifdef _WIN32
121        std::string arg = wstringToString(szArglist[i]);
122#else
123        std::string arg = argv[i];
124#endif
125
126        if (arg == "--test-mode" || arg == "-test-mode")
127        {
128            m_isTestMode = true;
129        }
130        else if (arg == "-h" || arg == "--help")
131        {
132            m_showHelp = true;
133        }
134        else if ((arg == "-api" || arg == "--api") && i + 1 < argc)
135        {
136            i++; // Move to the next argument which should be the API name
137#ifdef _WIN32
138            std::string apiStr = wstringToString(szArglist[i]);
139#else
140            std::string apiStr = argv[i];
141#endif
142
143            rhi::DeviceType newType = parseApiString(apiStr.c_str());
144            if (newType != rhi::DeviceType::Default)
145            {
146                m_deviceType = newType;
147            }
148            else
149            {
150#ifdef _WIN32
151                // For WIN32 apps, ensure we have a visible console window for errors too
152                ensureConsoleVisible();
153#endif
154                std::string errorMsg = "Unknown API: " + apiStr + "\n";
155                printOutput(errorMsg.c_str());
156                m_showHelp = true;
157            }
158        }
159    }
160
161#ifdef _WIN32
162    LocalFree(szArglist);
163#endif
164
165    return 0;
166}
167
168void TestBase::printEntrypointHashes(
169    int entryPointCount,
170    int targetCount,
171    ComPtr<slang::IComponentType>& composedProgram)
172{
173    for (int targetIndex = 0; targetIndex < targetCount; targetIndex++)
174    {
175        for (int entryPointIndex = 0; entryPointIndex < entryPointCount; entryPointIndex++)
176        {
177            ComPtr<slang::IBlob> entryPointHashBlob;
178            composedProgram->getEntryPointHash(
179                entryPointIndex,
180                targetIndex,
181                entryPointHashBlob.writeRef());
182
183            Slang::StringBuilder strBuilder;
184            strBuilder << "callIdx: " << m_globalCounter << ", entrypoint: " << entryPointIndex
185                       << ", target: " << targetIndex << ", hash: ";
186            m_globalCounter++;
187
188            uint8_t* buffer = (uint8_t*)entryPointHashBlob->getBufferPointer();
189            for (size_t i = 0; i < entryPointHashBlob->getBufferSize(); i++)
190            {
191                strBuilder << Slang::StringUtil::makeStringWithFormat("%.2X", buffer[i]);
192            }
193            fprintf(stdout, "%s\n", strBuilder.begin());
194        }
195    }
196}
197
198void TestBase::printUsage(const char* programName) const
199{
200#ifdef _WIN32
201    // For WIN32 apps, ensure we have a visible console window
202    bool createdNewWindow = ensureConsoleVisible();
203#endif
204
205    // Use printOutput to ensure output appears in both console and debug output (for WIN32 apps)
206    std::string usage = "Usage: " + std::string(programName) + " [options]\n\n";
207    printOutput(usage.c_str());
208    printOutput("Options:\n");
209    printOutput(" -h, --help                     Show this help message\n");
210    printOutput(" -api (");
211#ifdef _WIN32
212    printOutput("d3d11|d3d12|");
213#endif
214    printOutput("vulkan");
215#ifdef __APPLE__
216    printOutput("|metal");
217#endif
218    printOutput("|cpu|cuda|webgpu)\n");
219#ifdef _WIN32
220    printOutput("                                Use a given rendering API (Default: d3d12)\n");
221#elif defined(__APPLE__)
222    printOutput("                                Use a given rendering API (Default: metal)\n");
223#else
224    printOutput("                                Use a given rendering API (Default: vulkan)\n");
225#endif
226    printOutput(" -test-mode                     Print hash values of compiled shader entry points "
227                "and skip rendering\n");
228    printOutput("\n");
229    printOutput("Supported APIs:\n");
230#ifdef _WIN32
231    printOutput("  d3d11    - Direct3D 11\n");
232    printOutput("  d3d12    - Direct3D 12\n");
233#endif
234    printOutput("  vulkan   - Vulkan\n");
235#ifdef __APPLE__
236    printOutput("  metal    - Metal (macOS/iOS)\n");
237#endif
238    printOutput("  cpu      - CPU execution\n");
239    printOutput("  cuda     - CUDA\n");
240    printOutput("  webgpu   - WebGPU\n");
241
242#ifdef _WIN32
243    // For WIN32 apps, only prompt if we created a new console window
244    if (createdNewWindow)
245    {
246        printOutput("\nPress Enter to continue or close this window...\n");
247        getchar(); // Wait for user input
248    }
249#endif
250}