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 #pragma once
19
20 #include <stdio.h>
21
22 #include "common.h"
23 #include "log.h"
24 #include "gpu.h"
25
26 // This represents an identifier (e.g. name of function, uniform etc.) for
27 // a shader resource. The generated identifiers are immutable, but only live
28 // until pl_shader_reset - so make copies when passing to external stuff.
29 typedef const char * ident_t;
30
31 enum pl_shader_buf {
32 SH_BUF_PRELUDE, // extra #defines etc.
33 SH_BUF_HEADER, // previous passes, helper function definitions, etc.
34 SH_BUF_BODY, // partial contents of the "current" function
35 SH_BUF_FOOTER, // will be appended to the end of the current function
36 SH_BUF_COUNT,
37 };
38
39 struct pl_shader {
40 pl_log log;
41 struct pl_shader_res res; // for accumulating some of the fields
42 PL_ARRAY(struct pl_ref *) tmp; // only used for var/va/desc names and data
43 bool failed;
44 bool mutable;
45 int output_w;
46 int output_h;
47 pl_str buffers[SH_BUF_COUNT];
48 bool is_compute;
49 bool flexible_work_groups;
50 enum pl_sampler_type sampler_type;
51 char sampler_prefix;
52 int fresh;
53
54 // mutable versions of the fields from pl_shader_res
55 PL_ARRAY(struct pl_shader_va) vas;
56 PL_ARRAY(struct pl_shader_var) vars;
57 PL_ARRAY(struct pl_shader_desc) descs;
58 PL_ARRAY(struct pl_shader_const) consts;
59 PL_ARRAY(const char *) steps;
60 };
61
62 // Helper functions for convenience
63 #define SH_PARAMS(sh) ((sh)->res.params)
64 #define SH_GPU(sh) (SH_PARAMS(sh).gpu)
65 #define SH_TMP(sh) ((sh)->tmp.elem[0])
66
67 // Returns the GLSL version, defaulting to desktop 130.
68 struct pl_glsl_version sh_glsl(const pl_shader sh);
69
70 #define SH_FAIL(sh, ...) do { \
71 sh->failed = true; \
72 PL_ERR(sh, __VA_ARGS__); \
73 } while (0)
74
75 // Attempt enabling compute shaders for this pass, if possible
76 bool sh_try_compute(pl_shader sh, int bw, int bh, bool flex, size_t mem);
77
78 // Attempt merging a secondary shader into the current shader. Returns NULL if
79 // merging fails (e.g. incompatible signatures); otherwise returns an identifier
80 // corresponding to the generated subpass function.
81 ident_t sh_subpass(pl_shader sh, const pl_shader sub);
82
83 // Helpers for adding new variables/descriptors/etc. with fresh, unique
84 // identifier names. These will never conflict with other identifiers, even
85 // if the shaders are merged together.
86 ident_t sh_fresh(pl_shader sh, const char *name);
87
88 // Add a new shader var and return its identifier
89 ident_t sh_var(pl_shader sh, struct pl_shader_var sv);
90
91 // Add a new shader desc and return its identifier.
92 ident_t sh_desc(pl_shader sh, struct pl_shader_desc sd);
93
94 // Add a new shader constant and return its identifier.
95 ident_t sh_const(pl_shader sh, struct pl_shader_const sc);
96
97 // Helper functions for `sh_const`
98 ident_t sh_const_int(pl_shader sh, const char *name, int val);
99 ident_t sh_const_uint(pl_shader sh, const char *name, unsigned int val);
100 ident_t sh_const_float(pl_shader sh, const char *name, float val);
101 #define SH_INT(val) sh_const_int(sh, "const", val)
102 #define SH_UINT(val) sh_const_uint(sh, "const", val)
103 #define SH_FLOAT(val) sh_const_float(sh, "const", val)
104
105 // Add a new vec2 vertex attribute from a pl_rect2df, or returns NULL on failure.
106 ident_t sh_attr_vec2(pl_shader sh, const char *name,
107 const struct pl_rect2df *rc);
108
109 // Bind a texture under a given transformation and make its attributes
110 // available as well. If an output pointer for one of the attributes is left
111 // as NULL, that attribute will not be added. Returns NULL on failure. `rect`
112 // is optional, and defaults to the full texture if left as NULL.
113 //
114 // Note that for e.g. compute shaders, the vec2 out_pos might be a macro that
115 // expands to an expensive computation, and should be cached by the user.
116 ident_t sh_bind(pl_shader sh, pl_tex tex,
117 enum pl_tex_address_mode address_mode,
118 enum pl_tex_sample_mode sample_mode,
119 const char *name, const struct pl_rect2df *rect,
120 ident_t *out_pos, ident_t *out_size, ident_t *out_pt);
121
122 // Incrementally build up a buffer by adding new variable elements to the
123 // buffer, resizing buf.buffer_vars if necessary. Returns whether or not the
124 // variable could be successfully added (which may fail if you try exceeding
125 // the size limits of the buffer type). If successful, the layout is stored
126 // in *out_layout (may be NULL).
127 bool sh_buf_desc_append(void *alloc, pl_gpu gpu,
128 struct pl_shader_desc *buf_desc,
129 struct pl_var_layout *out_layout,
130 const struct pl_var new_var);
131
132 size_t sh_buf_desc_size(const struct pl_shader_desc *buf_desc);
133
134
135 // Underlying function for appending text to a shader
136 void sh_append(pl_shader sh, enum pl_shader_buf buf, const char *fmt, ...)
137 PL_PRINTF(3, 4);
138
139 void sh_append_str(pl_shader sh, enum pl_shader_buf buf, pl_str str);
140
141 #define GLSLP(...) sh_append(sh, SH_BUF_PRELUDE, __VA_ARGS__)
142 #define GLSLH(...) sh_append(sh, SH_BUF_HEADER, __VA_ARGS__)
143 #define GLSL(...) sh_append(sh, SH_BUF_BODY, __VA_ARGS__)
144 #define GLSLF(...) sh_append(sh, SH_BUF_FOOTER, __VA_ARGS__)
145
146 // Attach a description to a shader
sh_describe(pl_shader sh,const char * desc)147 static inline void sh_describe(pl_shader sh, const char *desc)
148 {
149 PL_ARRAY_APPEND(sh, sh->steps, desc);
150 };
151
152 // Requires that the share is mutable, has an output signature compatible
153 // with the given input signature, as well as an output size compatible with
154 // the given size requirements. Errors and returns false otherwise.
155 bool sh_require(pl_shader sh, enum pl_shader_sig insig, int w, int h);
156
157 // Shader resources
158
159 enum pl_shader_obj_type {
160 PL_SHADER_OBJ_INVALID = 0,
161 PL_SHADER_OBJ_PEAK_DETECT,
162 PL_SHADER_OBJ_SAMPLER,
163 PL_SHADER_OBJ_DITHER,
164 PL_SHADER_OBJ_ICC,
165 PL_SHADER_OBJ_LUT,
166 PL_SHADER_OBJ_AV1_GRAIN,
167 };
168
169 struct pl_shader_obj {
170 enum pl_shader_obj_type type;
171 pl_gpu gpu;
172 void (*uninit)(pl_gpu gpu, void *priv);
173 void *priv;
174 };
175
176 // Returns (*ptr)->priv, or NULL on failure
177 void *sh_require_obj(pl_shader sh, pl_shader_obj *ptr,
178 enum pl_shader_obj_type type, size_t priv_size,
179 void (*uninit)(pl_gpu gpu, void *priv));
180
181 #define SH_OBJ(sh, ptr, type, t, uninit) \
182 ((t*) sh_require_obj(sh, ptr, type, sizeof(t), uninit))
183
184 // Initializes a PRNG. The resulting string will directly evaluate to a
185 // pseudorandom, uniformly distributed float from [0.0,1.0]. Since this
186 // algorithm works by mutating a state variable, if the user wants to use the
187 // resulting PRNG inside a subfunction, they must add an extra `inout float %s`
188 // with the name of `state` to the signature. (Optional)
189 //
190 // If `temporal` is set, the PRNG will vary across frames.
191 ident_t sh_prng(pl_shader sh, bool temporal, ident_t *state);
192
193 enum sh_lut_method {
194 SH_LUT_AUTO = 0, // pick whatever makes the most sense
195 SH_LUT_TEXTURE, // upload as texture
196 SH_LUT_UNIFORM, // uniform array
197 SH_LUT_LITERAL, // constant / literal array in shader source (fallback)
198 };
199
200 struct sh_lut_params {
201 pl_shader_obj *object;
202
203 // Method and type of the LUT we intend to generate.
204 enum sh_lut_method method;
205 enum pl_var_type type;
206
207 // LUT dimensions. Unused dimensions may be left as 0.
208 int width;
209 int height;
210 int depth;
211 int comps;
212
213 // If true, LUT takes a vecN coordinate and linearly interpolates values,
214 // rather than taking an ivecN. Requires `type == PL_VAR_FLOAT`!
215 bool linear;
216
217 // If true, the LUT will always be regenerated, even if the dimensions have
218 // not changed.
219 bool update;
220
221 // Alternate way of triggering shader invalidations. If the signature
222 // does not match the LUT's signature, it will be regenerated.
223 uint64_t signature;
224
225 // If set to true, shader objects will be preserved and updated in-place
226 // rather than being treated as read-only.
227 bool dynamic;
228
229 // Will be called with a zero-initialized buffer whenever the data needs to
230 // be computed, which happens whenever the size is changed, the shader
231 // object is invalidated, or `update` is set to true.
232 //
233 // Note: Interpretation of `data` is according to `pl_var_type`.
234 void (*fill)(void *data, const struct sh_lut_params *params);
235 void *priv;
236 };
237
238 // Makes a table of values available as a shader variable, using an a given
239 // method (falling back if needed). The resulting identifier can be sampled
240 // directly as %s(pos), where pos is a vector with the right number of
241 // dimensions. `pos` must be an integer vector within the bounds of the array,
242 // unless the method is `SH_LUT_LINEAR`, in which case it's a float vector that
243 // gets interpolated and clamped as needed. Returns NULL on error.
244 ident_t sh_lut(pl_shader sh, const struct sh_lut_params *params);
245
246 // Returns a GLSL-version appropriate "bvec"-like type. For GLSL 130+, this
247 // returns bvecN. For GLSL 120, this returns vecN instead. The intended use of
248 // this function is with mix(), which only accepts bvec in GLSL 130+.
249 const char *sh_bvec(const pl_shader sh, int dims);
250
251 // Returns the appropriate `texture`-equivalent function for the shader and
252 // given texture.
sh_tex_fn(const pl_shader sh,const struct pl_tex_params params)253 static inline const char *sh_tex_fn(const pl_shader sh,
254 const struct pl_tex_params params)
255 {
256 static const char *suffixed[] = {
257 [1] = "texture1D",
258 [2] = "texture2D",
259 [3] = "texture3D",
260 };
261
262 int dims = pl_tex_params_dimension(params);
263 return sh_glsl(sh).version >= 130 ? "texture" : suffixed[dims];
264 }
265