7#if defined(EVE_HAS_SHADERC)
8#include <shaderc/shaderc.h>
21constexpr std::uint32_t kSpirvMagic = 0x07230203u;
23std::runtime_error compileFailure(
const std::string &
message) {
return std::runtime_error(
message); }
26std::vector<std::uint32_t> spirvWords(
const void *data, std::size_t
size) {
27 if (!data ||
size < 4 || (
size % 4) != 0)
28 throw compileFailure(
"compiled SPIR-V has an invalid size");
29 const auto *words =
static_cast<const std::uint32_t *
>(data);
30 if (words[0] != kSpirvMagic)
throw compileFailure(
"compiled SPIR-V has a bad magic number");
31 return std::vector<std::uint32_t>(words, words +
size / 4);
44#if !defined(EVE_HAS_SHADERC)
47const char *stageArgument(
GlslStage stage) {
57std::vector<std::uint32_t> readCompiledFile(
const std::string &
path,
bool remove) {
60 if (fopen_s(&
file,
path.c_str(),
"rb") != 0)
file =
nullptr;
65 if (remove) std::remove(
path.c_str());
66 throw compileFailure(
"failed to open compiled SPIR-V");
68 std::fseek(
file, 0, SEEK_END);
70 std::fseek(
file, 0, SEEK_SET);
71 std::vector<std::uint8_t>
bytes(
static_cast<std::size_t
>(
size > 0 ?
size : 0));
72 const bool shortRead =
73 size > 0 && std::fread(
bytes.data(), 1,
static_cast<std::size_t
>(
size),
file) !=
static_cast<std::size_t
>(
size);
75 if (remove) std::remove(
path.c_str());
76 if (shortRead)
throw compileFailure(
"failed to read compiled SPIR-V");
83std::string findGlslc() {
84 if (
const char *sdk = std::getenv(
"VULKAN_SDK"); sdk && *sdk) {
85 for (
const char *sub : {
"\\bin\\glslc.exe",
"\\Bin\\glslc.exe"}) {
86 std::string
path = std::string(sdk) + sub;
87 if (GetFileAttributesA(
path.c_str()) != INVALID_FILE_ATTRIBUTES)
return path;
91 WIN32_FIND_DATAA entry{};
92 HANDLE find = FindFirstFileA(
"C:\\VulkanSDK\\*", &entry);
93 if (find != INVALID_HANDLE_VALUE) {
95 if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
96 std::string
path = std::string(
"C:\\VulkanSDK\\") + entry.cFileName +
"\\Bin\\glslc.exe";
97 if (GetFileAttributesA(
path.c_str()) != INVALID_FILE_ATTRIBUTES) {
102 }
while (FindNextFileA(find, &entry));
105 FILE *pipe = _popen(
"where glslc 2>nul",
"r");
116 const int status = _pclose(pipe);
129std::vector<std::uint32_t> compileWithExternalGlslc(
const std::string &
source,
GlslStage stage,
130 const std::string &debugName) {
131 const std::string glslc = findGlslc();
133 throw compileFailure(
134 "no GLSL compiler available: this build has no in-process shaderc and no "
135 "glslc.exe was found (install the Vulkan SDK or set VULKAN_SDK)");
137 char tempDir[MAX_PATH];
138 if (GetTempPathA(MAX_PATH, tempDir) == 0)
throw compileFailure(
"GetTempPath failed");
139 char inputPath[MAX_PATH];
140 if (GetTempFileNameA(tempDir,
"eve", 0, inputPath) == 0)
throw compileFailure(
"GetTempFileName failed");
141 const std::string outputPath = std::string(inputPath) +
".spv";
142 const std::string errorPath = outputPath +
".err";
143 struct TemporaryFiles {
145 const std::string &
output;
146 const std::string &
error;
148 DeleteFileA(
error.c_str());
149 DeleteFileA(
output.c_str());
153 } temporary{inputPath, outputPath, errorPath};
156 FILE *
file =
nullptr;
157 if (fopen_s(&
file, inputPath,
"wb") != 0 || !
file)
throw compileFailure(
"failed to write temp GLSL");
161 const bool flushed = fflush(
file) == 0;
162 const bool closed = fclose(
file) == 0;
163 if (written !=
source.size() || !flushed || !closed)
164 throw compileFailure(
"failed to write the complete temp GLSL");
167 std::string command =
"\"" + glslc +
"\" -fshader-stage=" + stageArgument(stage) +
" \"" + inputPath +
168 "\" -o \"" + outputPath +
"\"";
169 STARTUPINFOEXA startup{};
170 startup.StartupInfo.cb =
sizeof(startup);
171 PROCESS_INFORMATION process{};
172 SECURITY_ATTRIBUTES security{};
173 security.nLength =
sizeof(security);
174 security.bInheritHandle = TRUE;
176 CreateFileA(errorPath.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, &security, CREATE_ALWAYS,
177 FILE_ATTRIBUTE_NORMAL,
nullptr);
179 CreateFileA(
"NUL", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, &security, OPEN_EXISTING,
180 FILE_ATTRIBUTE_NORMAL,
nullptr);
181 if (diagnostics == INVALID_HANDLE_VALUE ||
input == INVALID_HANDLE_VALUE) {
182 if (diagnostics != INVALID_HANDLE_VALUE) CloseHandle(diagnostics);
183 if (
input != INVALID_HANDLE_VALUE) CloseHandle(
input);
184 throw compileFailure(
"failed to create compiler standard handles");
186 struct StandardHandles {
192 } handles{diagnostics,
input};
195 SIZE_T attributeBytes = 0;
196 InitializeProcThreadAttributeList(
nullptr, 1, 0, &attributeBytes);
197 std::vector<std::uint8_t> attributes(attributeBytes);
198 startup.lpAttributeList =
reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST
>(attributes.data());
199 if (!InitializeProcThreadAttributeList(startup.lpAttributeList, 1, 0, &attributeBytes))
200 throw compileFailure(
"failed to initialize process attributes");
201 struct AttributeList {
202 LPPROC_THREAD_ATTRIBUTE_LIST
value;
203 ~AttributeList() { DeleteProcThreadAttributeList(
value); }
204 } attributeList{startup.lpAttributeList};
205 HANDLE inherited[] = {diagnostics,
input};
206 if (!UpdateProcThreadAttribute(startup.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherited,
207 sizeof(inherited),
nullptr,
nullptr))
208 throw compileFailure(
"failed to restrict compiler handle inheritance");
209 startup.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
210 startup.StartupInfo.hStdInput =
input;
211 startup.StartupInfo.hStdOutput = diagnostics;
212 startup.StartupInfo.hStdError = diagnostics;
213 if (!CreateProcessA(glslc.c_str(), command.data(),
nullptr,
nullptr, TRUE,
214 CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT,
nullptr,
nullptr, &startup.StartupInfo,
216 throw compileFailure(
"failed to launch glslc (error " + std::to_string(GetLastError()) +
")");
218 WaitForSingleObject(process.hProcess, INFINITE);
220 GetExitCodeProcess(process.hProcess, &exitCode);
221 CloseHandle(process.hProcess);
222 CloseHandle(process.hThread);
226 CreateFileA(errorPath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
227 nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
nullptr);
228 if (reader != INVALID_HANDLE_VALUE) {
235 throw compileFailure(
"glslc failed for " + debugName +
" (exit " + std::to_string(exitCode) +
238 return readCompiledFile(outputPath,
false);
244std::vector<std::uint32_t> compileWithExternalGlslc(
const std::string &
source,
GlslStage stage,
245 const std::string &debugName) {
246 char inputPath[] =
"/tmp/eve_shader_XXXXXX";
248 if (
descriptor < 0)
throw compileFailure(
"mkstemp failed");
249 const std::string outputPath = std::string(inputPath) +
".spv";
253 if (written < 0 ||
static_cast<std::size_t
>(written) !=
source.size()) {
255 throw compileFailure(
"failed to write temp GLSL");
259 const std::string command = std::string(
"glslc -fshader-stage=") + stageArgument(stage) +
" \"" + inputPath +
260 "\" -o \"" + outputPath +
"\" 2>&1";
261 FILE *pipe = popen(command.c_str(),
"r");
264 throw compileFailure(
"glslc not available (popen failed)");
269 const int status = pclose(pipe);
272 unlink(outputPath.c_str());
273 throw compileFailure(
"glslc failed for " + debugName +
":\n" + errors);
275 return readCompiledFile(outputPath,
true);
279bool externalGlslcAvailable() {
280 FILE *pipe = popen(
"command -v glslc >/dev/null 2>&1",
"r");
281 if (!pipe)
return false;
282 return pclose(pipe) == 0;
289#if defined(EVE_HAS_SHADERC)
290std::vector<std::uint32_t> compileInProcess(
const std::string &
source,
GlslStage stage,
const std::string &debugName) {
291 struct CompilerContext {
292 shaderc_compiler_t
compiler = shaderc_compiler_initialize();
293 shaderc_compile_options_t
options =
nullptr;
295 if (!
compiler)
throw compileFailure(
"shaderc_compiler_initialize failed");
296 options = shaderc_compile_options_initialize();
299 throw compileFailure(
"shaderc_compile_options_initialize failed");
301 shaderc_compile_options_set_target_env(
options, shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_0);
302 shaderc_compile_options_set_target_spirv(
options, shaderc_spirv_version_1_0);
305 shaderc_compile_options_release(
options);
311 thread_local CompilerContext
context;
312 shaderc_shader_kind
kind = shaderc_glsl_vertex_shader;
318 shaderc_compilation_result_t result = shaderc_compile_into_spv(
320 if (!result)
throw compileFailure(
"shaderc returned no compilation result");
321 struct CompilationResult {
322 shaderc_compilation_result_t
value;
323 ~CompilationResult() { shaderc_result_release(
value); }
324 } ownedResult{result};
325 if (shaderc_result_get_compilation_status(result) != shaderc_compilation_status_success)
326 throw compileFailure(
"shaderc failed:\n" + std::string(shaderc_result_get_error_message(result)));
327 const std::size_t
length = shaderc_result_get_length(result);
328 return spirvWords(shaderc_result_get_bytes(result),
length);
335#if defined(EVE_HAS_SHADERC)
339 static const bool available = !findGlslc().empty();
342 static const bool available = externalGlslcAvailable();
348 const std::string &debugName) {
349 if (
source.empty())
throw compileFailure(std::string(
"empty ") + stageName(stage) +
" GLSL source");
350#if defined(EVE_HAS_SHADERC)
351 return compileInProcess(
source, stage, debugName);
353 return compileWithExternalGlslc(
source, stage, debugName);
wgpu::PopErrorScopeStatus status
onnx_detail::CompilerQueue compiler
std::unique_ptr< gpgpu::GpuBuffer > buffer
const SquirrelValueOptions & options
const UnitySourceAsset & source
const VegetationPresetContext & context
卡牌游戏 UI 工具模块:工厂 + 脚本绑定入口。 功能参考 ycarowr/UiCard:扇形手牌布局、抽牌/洗牌、悬浮放大、拖拽到落牌区、 敌方手牌(背面/偷看)、费用不足置灰,以及可实时调节的布局...
bool glslRuntimeCompilationAvailable()
Whether this build can compile GLSL text to SPIR-V at runtime.
std::vector< std::uint32_t > compileGlslToSpirv(const std::string &source, GlslStage stage, const std::string &debugName)
Compile GLSL text to SPIR-V words.
GlslStage
GLSL stage accepted by compileGlslToSpirv.