Branch data Line data Source code
1 : : /*
2 : : * This file is part of libplacebo.
3 : : *
4 : : * libplacebo is free software; you can redistribute it and/or
5 : : * modify it under the terms of the GNU Lesser General Public
6 : : * License as published by the Free Software Foundation; either
7 : : * version 2.1 of the License, or (at your option) any later version.
8 : : *
9 : : * libplacebo is distributed in the hope that it will be useful,
10 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : : * GNU Lesser General Public License for more details.
13 : : *
14 : : * You should have received a copy of the GNU Lesser General Public
15 : : * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
16 : : */
17 : :
18 : : #include <stdlib.h>
19 : : #include <shaderc/shaderc.h>
20 : :
21 : : #include "hash.h"
22 : : #include "spirv.h"
23 : : #include "utils.h"
24 : :
25 : : const struct spirv_compiler pl_spirv_shaderc;
26 : :
27 : : struct priv {
28 : : shaderc_compiler_t compiler;
29 : : };
30 : :
31 : 3 : static void shaderc_destroy(pl_spirv spirv)
32 : : {
33 : 3 : struct priv *p = PL_PRIV(spirv);
34 : 3 : shaderc_compiler_release(p->compiler);
35 : 3 : pl_free((void *) spirv);
36 : 3 : }
37 : :
38 : 3 : static pl_spirv shaderc_create(pl_log log, struct pl_spirv_version spirv_ver)
39 : : {
40 : 3 : struct pl_spirv_t *spirv = pl_alloc_obj(NULL, spirv, struct priv);
41 : 3 : *spirv = (struct pl_spirv_t) {
42 : 3 : .signature = pl_str0_hash(pl_spirv_shaderc.name),
43 : : .impl = &pl_spirv_shaderc,
44 : : .version = spirv_ver,
45 : : .log = log,
46 : : };
47 : :
48 : 3 : struct priv *p = PL_PRIV(spirv);
49 : 3 : p->compiler = shaderc_compiler_initialize();
50 [ - + ]: 3 : if (!p->compiler)
51 : 0 : goto error;
52 : :
53 : 3 : unsigned int ver = 0, rev = 0;
54 : 3 : shaderc_get_spv_version(&ver, &rev);
55 : 3 : PL_INFO(spirv, "shaderc SPIR-V version %u.%u rev %u",
56 : : ver >> 16, (ver >> 8) & 0xff, rev);
57 : :
58 : : // Clamp to supported version by shaderc
59 [ - + ]: 3 : if (ver < spirv->version.spv_version) {
60 [ # # ]: 0 : spirv->version.spv_version = ver;
61 : 0 : spirv->version.env_version = pl_spirv_version_to_vulkan(ver);
62 : : }
63 : :
64 : 3 : pl_hash_merge(&spirv->signature, (uint64_t) spirv->version.spv_version << 32 |
65 : 3 : spirv->version.env_version);
66 : 3 : pl_hash_merge(&spirv->signature, (uint64_t) ver << 32 | rev);
67 : 3 : return spirv;
68 : :
69 : : error:
70 : : shaderc_destroy(spirv);
71 : 0 : return NULL;
72 : : }
73 : :
74 : 266 : static pl_str shaderc_compile(pl_spirv spirv, void *alloc,
75 : : struct pl_glsl_version glsl_ver,
76 : : enum glsl_shader_stage stage,
77 : : const char *shader)
78 : : {
79 : 266 : struct priv *p = PL_PRIV(spirv);
80 : 266 : const size_t len = strlen(shader);
81 : :
82 : 266 : shaderc_compile_options_t opts = shaderc_compile_options_initialize();
83 [ - + ]: 266 : if (!opts)
84 : 0 : return (pl_str) {0};
85 : :
86 : 266 : shaderc_compile_options_set_optimization_level(opts,
87 : : shaderc_optimization_level_performance);
88 : 266 : shaderc_compile_options_set_target_spirv(opts, spirv->version.spv_version);
89 : 266 : shaderc_compile_options_set_target_env(opts, shaderc_target_env_vulkan,
90 : 266 : spirv->version.env_version);
91 : :
92 [ + + ]: 1064 : for (int i = 0; i < 3; i++) {
93 : 798 : shaderc_compile_options_set_limit(opts,
94 : 798 : shaderc_limit_max_compute_work_group_size_x + i,
95 : 798 : glsl_ver.max_group_size[i]);
96 : : }
97 : :
98 : 266 : shaderc_compile_options_set_limit(opts,
99 : : shaderc_limit_min_program_texel_offset,
100 : 266 : glsl_ver.min_gather_offset);
101 : 266 : shaderc_compile_options_set_limit(opts,
102 : : shaderc_limit_max_program_texel_offset,
103 : 266 : glsl_ver.max_gather_offset);
104 : :
105 : : static const shaderc_shader_kind kinds[] = {
106 : : [GLSL_SHADER_VERTEX] = shaderc_glsl_vertex_shader,
107 : : [GLSL_SHADER_FRAGMENT] = shaderc_glsl_fragment_shader,
108 : : [GLSL_SHADER_COMPUTE] = shaderc_glsl_compute_shader,
109 : : };
110 : :
111 : : static const char * const file_name = "input";
112 : : static const char * const entry_point = "main";
113 : :
114 : : shaderc_compilation_result_t res;
115 : 266 : res = shaderc_compile_into_spv(p->compiler, shader, len, kinds[stage],
116 : : file_name, entry_point, opts);
117 : :
118 : 266 : int errs = shaderc_result_get_num_errors(res),
119 : 266 : warn = shaderc_result_get_num_warnings(res);
120 : :
121 [ + - + + ]: 266 : enum pl_log_level lev = errs ? PL_LOG_ERR : warn ? PL_LOG_INFO : PL_LOG_DEBUG;
122 : :
123 : 266 : int s = shaderc_result_get_compilation_status(res);
124 : : bool success = s == shaderc_compilation_status_success;
125 [ - + ]: 266 : if (!success)
126 : : lev = PL_LOG_ERR;
127 : :
128 : 266 : const char *msg = shaderc_result_get_error_message(res);
129 [ + + ]: 266 : if (msg[0])
130 : 18 : PL_MSG(spirv, lev, "shaderc output:\n%s", msg);
131 : :
132 : : static const char *results[] = {
133 : : [shaderc_compilation_status_success] = "success",
134 : : [shaderc_compilation_status_invalid_stage] = "invalid stage",
135 : : [shaderc_compilation_status_compilation_error] = "error",
136 : : [shaderc_compilation_status_internal_error] = "internal error",
137 : : [shaderc_compilation_status_null_result_object] = "no result",
138 : : [shaderc_compilation_status_invalid_assembly] = "invalid assembly",
139 : : };
140 : :
141 [ + - ]: 266 : const char *status = s < PL_ARRAY_SIZE(results) ? results[s] : "unknown";
142 : 266 : PL_MSG(spirv, lev, "shaderc compile status '%s' (%d errors, %d warnings)",
143 : : status, errs, warn);
144 : :
145 : : pl_str ret = {0};
146 [ + - ]: 266 : if (success) {
147 : 266 : void *bytes = (void *) shaderc_result_get_bytes(res);
148 [ - + ]: 266 : pl_assert(bytes);
149 : 266 : ret.len = shaderc_result_get_length(res);
150 : 266 : ret.buf = pl_memdup(alloc, bytes, ret.len);
151 : :
152 [ - + ]: 266 : if (pl_msg_test(spirv->log, PL_LOG_TRACE)) {
153 : : shaderc_compilation_result_t dis;
154 : 0 : dis = shaderc_compile_into_spv_assembly(p->compiler, shader, len,
155 : : kinds[stage], file_name,
156 : : entry_point, opts);
157 : 0 : PL_TRACE(spirv, "Generated SPIR-V:\n%.*s",
158 : : (int) shaderc_result_get_length(dis),
159 : : shaderc_result_get_bytes(dis));
160 : 0 : shaderc_result_release(dis);
161 : : }
162 : : }
163 : :
164 : 266 : shaderc_result_release(res);
165 : 266 : shaderc_compile_options_release(opts);
166 : 266 : return ret;
167 : : }
168 : :
169 : : const struct spirv_compiler pl_spirv_shaderc = {
170 : : .name = "shaderc",
171 : : .destroy = shaderc_destroy,
172 : : .create = shaderc_create,
173 : : .compile = shaderc_compile,
174 : : };
|