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;
}
|