/* * This file is part of libplacebo. * * libplacebo is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * libplacebo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with libplacebo. If not, see . */ #include "config_internal.h" #include extern "C" { #include "pl_alloc.h" #include "pl_thread.h" } #include #include #include #include "glslang.h" #if (GLSLANG_VERSION_MAJOR * 1000 + GLSLANG_VERSION_MINOR) >= 11013 #include #define DefaultTBuiltInResource *GetDefaultResources() #endif using namespace glslang; static pl_static_mutex pl_glslang_mutex = PL_STATIC_MUTEX_INITIALIZER; static int pl_glslang_refcount; bool pl_glslang_init(void) { bool ret = true; pl_static_mutex_lock(&pl_glslang_mutex); if (pl_glslang_refcount++ == 0) ret = InitializeProcess(); pl_static_mutex_unlock(&pl_glslang_mutex); return ret; } void pl_glslang_uninit(void) { pl_static_mutex_lock(&pl_glslang_mutex); if (--pl_glslang_refcount == 0) FinalizeProcess(); pl_static_mutex_unlock(&pl_glslang_mutex); } struct pl_glslang_res *pl_glslang_compile(struct pl_glsl_version glsl_ver, struct pl_spirv_version spirv_ver, enum glsl_shader_stage stage, const char *text) { assert(pl_glslang_refcount); struct pl_glslang_res *res = pl_zalloc_ptr(NULL, res); EShLanguage lang; switch (stage) { case GLSL_SHADER_VERTEX: lang = EShLangVertex; break; case GLSL_SHADER_FRAGMENT: lang = EShLangFragment; break; case GLSL_SHADER_COMPUTE: lang = EShLangCompute; break; default: abort(); } TShader *shader = new TShader(lang); shader->setEnvClient(EShClientVulkan, (EShTargetClientVersion) spirv_ver.env_version); shader->setEnvTarget(EShTargetSpv, (EShTargetLanguageVersion) spirv_ver.spv_version); shader->setStrings(&text, 1); TBuiltInResource limits = DefaultTBuiltInResource; limits.maxComputeWorkGroupSizeX = glsl_ver.max_group_size[0]; limits.maxComputeWorkGroupSizeY = glsl_ver.max_group_size[1]; limits.maxComputeWorkGroupSizeZ = glsl_ver.max_group_size[2]; limits.minProgramTexelOffset = glsl_ver.min_gather_offset; limits.maxProgramTexelOffset = glsl_ver.max_gather_offset; if (!shader->parse(&limits, 0, true, EShMsgDefault)) { res->error_msg = pl_str0dup0(res, shader->getInfoLog()); delete shader; return res; } TProgram *prog = new TProgram(); prog->addShader(shader); if (!prog->link(EShMsgDefault)) { res->error_msg = pl_str0dup0(res, prog->getInfoLog()); delete shader; delete prog; return res; } SpvOptions options; options.disableOptimizer = false; options.stripDebugInfo = true; options.optimizeSize = true; options.validate = true; std::vector spirv; GlslangToSpv(*prog->getIntermediate(lang), spirv, &options); res->success = true; res->size = spirv.size() * sizeof(unsigned int); res->data = pl_memdup(res, spirv.data(), res->size), delete shader; delete prog; return res; }