diff options
Diffstat (limited to 'src/glsl/glslang.cc')
-rw-r--r-- | src/glsl/glslang.cc | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/src/glsl/glslang.cc b/src/glsl/glslang.cc new file mode 100644 index 0000000..2bc923c --- /dev/null +++ b/src/glsl/glslang.cc @@ -0,0 +1,121 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "config_internal.h" + +#include <assert.h> + +extern "C" { +#include "pl_alloc.h" +#include "pl_thread.h" +} + +#include <glslang/Public/ShaderLang.h> +#include <glslang/SPIRV/GlslangToSpv.h> +#include <glslang/build_info.h> + +#include "glslang.h" + +#if (GLSLANG_VERSION_MAJOR * 1000 + GLSLANG_VERSION_MINOR) >= 11013 +#include <glslang/Public/ResourceLimits.h> +#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<unsigned int> 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; +} |