164 if (glsl.empty())
throw Exception(
"Gpgpu.newShader: empty GLSL");
166#if defined(EVE_HAS_SHADERC)
168 return compileComputeGlslInProcess(glsl);
173 const std::string glslc = findGlslc();
175 throw Exception(
"Gpgpu.newShader: glslc not found on Windows "
176 "(install the Vulkan SDK or set VULKAN_SDK)");
178 char tmpDir[MAX_PATH];
179 if (GetTempPathA(MAX_PATH, tmpDir) == 0)
180 throw Exception(
"Gpgpu.newShader: GetTempPath failed");
181 char inPath[MAX_PATH];
182 if (GetTempFileNameA(tmpDir,
"eve", 0, inPath) == 0)
183 throw Exception(
"Gpgpu.newShader: GetTempFileName failed");
184 std::string outPath = std::string(inPath) +
".spv";
188 if (fopen_s(&
f, inPath,
"wb") != 0 || !
f) {
190 throw Exception(
"Gpgpu.newShader: failed to write temp GLSL");
192 fwrite(glsl.data(), 1, glsl.size(),
f);
199 const std::string errPath = outPath +
".err";
200 std::string cmd =
"\"" + glslc +
"\" -fshader-stage=comp \"" + inPath +
"\" -o \"" +
204 PROCESS_INFORMATION pi{};
205 SECURITY_ATTRIBUTES sa{};
206 sa.nLength =
sizeof(sa);
207 sa.bInheritHandle = TRUE;
208 HANDLE errFile = CreateFileA(errPath.c_str(), GENERIC_WRITE, FILE_SHARE_READ, &sa,
209 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
nullptr);
210 if (errFile != INVALID_HANDLE_VALUE) {
211 si.dwFlags = STARTF_USESTDHANDLES;
212 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
213 si.hStdOutput = errFile;
214 si.hStdError = errFile;
216 char *mutableCmd = _strdup(cmd.c_str());
218 CreateProcessA(glslc.c_str(), mutableCmd,
nullptr,
nullptr, TRUE, CREATE_NO_WINDOW,
219 nullptr,
nullptr, &si, &pi);
221 if (errFile != INVALID_HANDLE_VALUE) CloseHandle(errFile);
223 const DWORD errCode = GetLastError();
225 DeleteFileA(outPath.c_str());
226 DeleteFileA(errPath.c_str());
227 throw Exception(
"Gpgpu.newShader: failed to launch glslc (error %lu)", errCode);
229 WaitForSingleObject(pi.hProcess, INFINITE);
231 GetExitCodeProcess(pi.hProcess, &exitCode);
232 CloseHandle(pi.hProcess);
233 CloseHandle(pi.hThread);
238 if (fopen_s(&ef, errPath.c_str(),
"rb") == 0 && ef) {
241 while ((
n = fread(buf, 1,
sizeof(buf) - 1, ef)) > 0) {
247 DeleteFileA(outPath.c_str());
248 DeleteFileA(errPath.c_str());
249 throw Exception(
"Gpgpu.newShader: glslc failed (exit %lu):\n%s", exitCode, err.c_str());
251 DeleteFileA(errPath.c_str());
254 if (fopen_s(&
f, outPath.c_str(),
"rb") != 0 || !
f) {
255 DeleteFileA(outPath.c_str());
256 throw Exception(
"Gpgpu.newShader: failed to open compiled SPIR-V");
258 fseek(
f, 0, SEEK_END);
260 fseek(
f, 0, SEEK_SET);
261 std::vector<uint8_t> bytes(
static_cast<size_t>(sz > 0 ? sz : 0));
262 if (sz > 0 && fread(bytes.data(), 1,
static_cast<size_t>(sz),
f) !=
static_cast<size_t>(sz)) {
264 DeleteFileA(outPath.c_str());
265 throw Exception(
"Gpgpu.newShader: failed to read compiled SPIR-V");
268 DeleteFileA(outPath.c_str());
269 return loadSpirvBytes(bytes.data(), bytes.size());
271 char inPath[] =
"/tmp/eve_comp_XXXXXX";
272 int fd = mkstemp(inPath);
273 if (fd < 0)
throw Exception(
"Gpgpu.newShader: mkstemp failed");
274 std::string outPath = std::string(inPath) +
".spv";
276 ssize_t
n = write(fd, glsl.data(), glsl.size());
278 if (
n < 0 ||
size_t(
n) != glsl.size()) {
280 throw Exception(
"Gpgpu.newShader: failed to write temp GLSL");
285 std::string(
"glslc -fshader-stage=comp \"") + inPath +
"\" -o \"" + outPath +
"\" 2>&1";
286 FILE *pipe = popen(cmd.c_str(),
"r");
290 while (fgets(buf,
sizeof(buf), pipe)) err += buf;
291 int status = pclose(pipe);
294 unlink(outPath.c_str());
295 throw Exception(
"Gpgpu.newShader: glslc failed:\n%s", err.c_str());
299 throw Exception(
"Gpgpu.newShader: glslc not available (popen failed)");
302 FILE *
f = fopen(outPath.c_str(),
"rb");
304 unlink(outPath.c_str());
305 throw Exception(
"Gpgpu.newShader: failed to open compiled SPIR-V");
307 fseek(
f, 0, SEEK_END);
309 fseek(
f, 0, SEEK_SET);
310 std::vector<uint8_t> bytes(
static_cast<size_t>(sz > 0 ? sz : 0));
311 if (sz > 0 && fread(bytes.data(), 1,
static_cast<size_t>(sz),
f) !=
static_cast<size_t>(sz)) {
313 unlink(outPath.c_str());
314 throw Exception(
"Gpgpu.newShader: failed to read compiled SPIR-V");
317 unlink(outPath.c_str());
318 return loadSpirvBytes(bytes.data(), bytes.size());