summaryrefslogtreecommitdiffstats
path: root/src/glsl/glslang.cc
blob: 2bc923c6560fc273421fce92ffc005e8c37e2d54 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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;
}