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 : : #pragma once
19 : :
20 : : #include <stdio.h>
21 : : #include <limits.h>
22 : :
23 : : #include "common.h"
24 : : #include "cache.h"
25 : : #include "log.h"
26 : : #include "gpu.h"
27 : :
28 : : #include <libplacebo/shaders.h>
29 : :
30 : : // This represents an identifier (e.g. name of function, uniform etc.) for
31 : : // a shader resource. Not human-readable.
32 : :
33 : : typedef unsigned short ident_t;
34 : : #define $ "_%hx"
35 : : #define NULL_IDENT 0u
36 : :
37 : : #define sh_mkident(id, name) ((ident_t) id)
38 : : #define sh_ident_tostr(id) pl_asprintf(sh->tmp, $, id)
39 : :
40 : : enum {
41 : : IDENT_BITS = 8 * sizeof(ident_t),
42 : : IDENT_MASK = (uintptr_t) USHRT_MAX,
43 : : IDENT_SENTINEL = (uintptr_t) 0x20230319 << IDENT_BITS,
44 : : };
45 : :
46 : : // Functions to pack/unpack an identifier into a `const char *` name field.
47 : : // Used to defer string templating of friendly names until actually necessary
48 : : static inline const char *sh_ident_pack(ident_t id)
49 : : {
50 [ + + ]: 27642 : return (const char *)(uintptr_t) (IDENT_SENTINEL | id);
51 : : }
52 : :
53 : : static inline ident_t sh_ident_unpack(const char *name)
54 : : {
55 : 25716 : uintptr_t uname = (uintptr_t) name;
56 [ - + - + : 25716 : assert((uname & ~IDENT_MASK) == IDENT_SENTINEL);
- + - + -
+ - + - +
- + - + -
- - + - +
- + - + -
+ - + - +
- + ]
57 [ - + + + ]: 25716 : return uname & IDENT_MASK;
58 : : }
59 : :
60 : : enum pl_shader_buf {
61 : : SH_BUF_PRELUDE, // extra #defines etc.
62 : : SH_BUF_HEADER, // previous passes, helper function definitions, etc.
63 : : SH_BUF_BODY, // partial contents of the "current" function
64 : : SH_BUF_FOOTER, // will be appended to the end of the current function
65 : : SH_BUF_COUNT,
66 : : };
67 : :
68 : : enum pl_shader_type {
69 : : SH_AUTO,
70 : : SH_COMPUTE,
71 : : SH_FRAGMENT
72 : : };
73 : :
74 : : struct sh_info {
75 : : // public-facing struct
76 : : struct pl_shader_info_t info;
77 : :
78 : : // internal fields
79 : : void *tmp;
80 : : pl_rc_t rc;
81 : : pl_str desc;
82 : : PL_ARRAY(const char *) steps;
83 : : };
84 : :
85 : : struct pl_shader_t {
86 : : pl_log log;
87 : : void *tmp; // temporary allocations (freed on pl_shader_reset)
88 : : struct sh_info *info;
89 : : pl_str data; // pooled/recycled scratch buffer for small allocations
90 : : PL_ARRAY(pl_shader_obj) obj;
91 : : bool failed;
92 : : bool mutable;
93 : : ident_t name;
94 : : enum pl_shader_sig input, output;
95 : : int output_w;
96 : : int output_h;
97 : : bool transpose;
98 : : pl_str_builder buffers[SH_BUF_COUNT];
99 : : enum pl_shader_type type;
100 : : bool flexible_work_groups;
101 : : int group_size[2];
102 : : size_t shmem;
103 : : enum pl_sampler_type sampler_type;
104 : : char sampler_prefix;
105 : : unsigned short prefix; // pre-processed version of res.params.id
106 : : unsigned short fresh;
107 : :
108 : : // Note: internally, these `pl_shader_va` etc. use raw ident_t fields
109 : : // instead of `const char *` wherever a name is required! These are
110 : : // translated to legal strings either in `pl_shader_finalize`, or inside
111 : : // the `pl_dispatch` shader compilation step.
112 : : PL_ARRAY(struct pl_shader_va) vas;
113 : : PL_ARRAY(struct pl_shader_var) vars;
114 : : PL_ARRAY(struct pl_shader_desc) descs;
115 : : PL_ARRAY(struct pl_shader_const) consts;
116 : :
117 : : // cached result of `pl_shader_finalize`
118 : : struct pl_shader_res result;
119 : : };
120 : :
121 : : // Free temporary resources associated with a shader. Normally called by
122 : : // pl_shader_reset(), but used internally to reduce memory waste.
123 : : void sh_deref(pl_shader sh);
124 : :
125 : : // Same as `pl_shader_finalize` but doesn't generate `sh->res`, instead returns
126 : : // the string builder to be used to finalize the shader. Assumes the caller
127 : : // will access the shader's internal fields directly.
128 : : pl_str_builder sh_finalize_internal(pl_shader sh);
129 : :
130 : : // Helper functions for convenience
131 : : #define SH_PARAMS(sh) ((sh)->info->info.params)
132 : : #define SH_GPU(sh) (SH_PARAMS(sh).gpu)
133 : : #define SH_CACHE(sh) pl_gpu_cache(SH_GPU(sh))
134 : :
135 : : // Returns the GLSL version, defaulting to desktop 130.
136 : : struct pl_glsl_version sh_glsl(const pl_shader sh);
137 : :
138 : : #define SH_FAIL(sh, ...) do { \
139 : : sh->failed = true; \
140 : : PL_ERR(sh, __VA_ARGS__); \
141 : : } while (0)
142 : :
143 : : // Attempt enabling compute shaders for this pass, if possible
144 : : bool sh_try_compute(pl_shader sh, int bw, int bh, bool flex, size_t mem);
145 : :
146 : : // Attempt merging a secondary shader into the current shader. Returns NULL if
147 : : // merging fails (e.g. incompatible signatures); otherwise returns an identifier
148 : : // corresponding to the generated subpass function.
149 : : //
150 : : // If successful, the subpass shader is set to an undefined failure state and
151 : : // must be explicitly reset/aborted before being re-used.
152 : : ident_t sh_subpass(pl_shader sh, pl_shader sub);
153 : :
154 : : // Helpers for adding new variables/descriptors/etc. with fresh, unique
155 : : // identifier names. These will never conflict with other identifiers, even
156 : : // if the shaders are merged together.
157 : : ident_t sh_fresh(pl_shader sh, const char *name);
158 : :
159 : : // Add a new shader var and return its identifier
160 : : ident_t sh_var(pl_shader sh, struct pl_shader_var sv);
161 : :
162 : : // Helper functions for `sh_var`
163 : : ident_t sh_var_int(pl_shader sh, const char *name, int val, bool dynamic);
164 : : ident_t sh_var_uint(pl_shader sh, const char *name, unsigned int val, bool dynamic);
165 : : ident_t sh_var_float(pl_shader sh, const char *name, float val, bool dynamic);
166 : : ident_t sh_var_mat3(pl_shader sh, const char *name, pl_matrix3x3 val);
167 : : #define SH_INT_DYN(val) sh_var_int(sh, "const", val, true)
168 : : #define SH_UINT_DYN(val) sh_var_uint(sh, "const", val, true)
169 : : #define SH_FLOAT_DYN(val) sh_var_float(sh, "const", val, true)
170 : : #define SH_MAT3(val) sh_var_mat3(sh, "mat", val)
171 : :
172 : : // Add a new shader desc and return its identifier.
173 : : ident_t sh_desc(pl_shader sh, struct pl_shader_desc sd);
174 : :
175 : : // Add a new shader constant and return its identifier.
176 : : ident_t sh_const(pl_shader sh, struct pl_shader_const sc);
177 : :
178 : : // Helper functions for `sh_const`
179 : : ident_t sh_const_int(pl_shader sh, const char *name, int val);
180 : : ident_t sh_const_uint(pl_shader sh, const char *name, unsigned int val);
181 : : ident_t sh_const_float(pl_shader sh, const char *name, float val);
182 : : #define SH_INT(val) sh_const_int(sh, "const", val)
183 : : #define SH_UINT(val) sh_const_uint(sh, "const", val)
184 : : #define SH_FLOAT(val) sh_const_float(sh, "const", val)
185 : :
186 : : // Add a new shader va and return its identifier
187 : : ident_t sh_attr(pl_shader sh, struct pl_shader_va sva);
188 : :
189 : : // Helper to add a a vec2 VA from a pl_rect2df. Returns NULL_IDENT on failure.
190 : : ident_t sh_attr_vec2(pl_shader sh, const char *name, const pl_rect2df *rc);
191 : :
192 : : // Bind a texture under a given transformation and make its attributes
193 : : // available as well. If an output pointer for one of the attributes is left
194 : : // as NULL, that attribute will not be added. Returns NULL on failure. `rect`
195 : : // is optional, and defaults to the full texture if left as NULL.
196 : : //
197 : : // Note that for e.g. compute shaders, the vec2 out_pos might be a macro that
198 : : // expands to an expensive computation, and should be cached by the user.
199 : : ident_t sh_bind(pl_shader sh, pl_tex tex,
200 : : enum pl_tex_address_mode address_mode,
201 : : enum pl_tex_sample_mode sample_mode,
202 : : const char *name, const pl_rect2df *rect,
203 : : ident_t *out_pos, ident_t *out_pt);
204 : :
205 : : // Incrementally build up a buffer by adding new variable elements to the
206 : : // buffer, resizing buf.buffer_vars if necessary. Returns whether or not the
207 : : // variable could be successfully added (which may fail if you try exceeding
208 : : // the size limits of the buffer type). If successful, the layout is stored
209 : : // in *out_layout (may be NULL).
210 : : bool sh_buf_desc_append(void *alloc, pl_gpu gpu,
211 : : struct pl_shader_desc *buf_desc,
212 : : struct pl_var_layout *out_layout,
213 : : const struct pl_var new_var);
214 : :
215 : : size_t sh_buf_desc_size(const struct pl_shader_desc *buf_desc);
216 : :
217 : :
218 : : // Underlying function for appending text to a shader
219 : : #define sh_append(sh, buf, ...) \
220 : : pl_str_builder_addf((sh)->buffers[buf], __VA_ARGS__)
221 : :
222 : : #define sh_append_str(sh, buf, str) \
223 : : pl_str_builder_str((sh)->buffers[buf], str)
224 : :
225 : : #define GLSLP(...) sh_append(sh, SH_BUF_PRELUDE, __VA_ARGS__)
226 : : #define GLSLH(...) sh_append(sh, SH_BUF_HEADER, __VA_ARGS__)
227 : : #define GLSL(...) sh_append(sh, SH_BUF_BODY, __VA_ARGS__)
228 : : #define GLSLF(...) sh_append(sh, SH_BUF_FOOTER, __VA_ARGS__)
229 : :
230 : : // Attach a description to a shader
231 : : void sh_describef(pl_shader sh, const char *fmt, ...)
232 : : PL_PRINTF(2, 3);
233 : :
234 : 3367 : static inline void sh_describe(pl_shader sh, const char *desc)
235 : : {
236 [ + + - + : 3367 : PL_ARRAY_APPEND(sh->info, sh->info->steps, desc);
- + ]
237 : 3367 : };
238 : :
239 : : // Requires that the share is mutable, has an output signature compatible
240 : : // with the given input signature, as well as an output size compatible with
241 : : // the given size requirements. Errors and returns false otherwise.
242 : : bool sh_require(pl_shader sh, enum pl_shader_sig insig, int w, int h);
243 : :
244 : : // Shader resources
245 : :
246 : : enum pl_shader_obj_type {
247 : : PL_SHADER_OBJ_INVALID = 0,
248 : : PL_SHADER_OBJ_COLOR_MAP,
249 : : PL_SHADER_OBJ_SAMPLER,
250 : : PL_SHADER_OBJ_DITHER,
251 : : PL_SHADER_OBJ_LUT,
252 : : PL_SHADER_OBJ_AV1_GRAIN,
253 : : PL_SHADER_OBJ_FILM_GRAIN,
254 : : PL_SHADER_OBJ_RESHAPE,
255 : : };
256 : :
257 : : struct pl_shader_obj_t {
258 : : enum pl_shader_obj_type type;
259 : : pl_rc_t rc;
260 : : pl_gpu gpu;
261 : : void (*uninit)(pl_gpu gpu, void *priv);
262 : : void *priv;
263 : : };
264 : :
265 : : // Returns (*ptr)->priv, or NULL on failure
266 : : void *sh_require_obj(pl_shader sh, pl_shader_obj *ptr,
267 : : enum pl_shader_obj_type type, size_t priv_size,
268 : : void (*uninit)(pl_gpu gpu, void *priv));
269 : :
270 : : #define SH_OBJ(sh, ptr, type, t, uninit) \
271 : : ((t*) sh_require_obj(sh, ptr, type, sizeof(t), uninit))
272 : :
273 : : // Initializes a PRNG. The resulting string will directly evaluate to a
274 : : // pseudorandom, uniformly distributed vec3 from [0.0,1.0]. Since this
275 : : // algorithm works by mutating a state variable, if the user wants to use the
276 : : // resulting PRNG inside a subfunction, they must add an extra `inout prng_t %s`
277 : : // with the contents of `state` to the signature. (Optional)
278 : : //
279 : : // If `temporal` is set, the PRNG will vary across frames.
280 : : ident_t sh_prng(pl_shader sh, bool temporal, ident_t *state);
281 : :
282 : : // Backing memory type
283 : : enum sh_lut_type {
284 : : SH_LUT_AUTO = 0, // pick whatever makes the most sense
285 : : SH_LUT_TEXTURE, // upload as texture
286 : : SH_LUT_UNIFORM, // uniform array
287 : : SH_LUT_LITERAL, // constant / literal array in shader source (fallback)
288 : : };
289 : :
290 : : // Interpolation method
291 : : enum sh_lut_method {
292 : : SH_LUT_NONE = 0, // no interpolation, integer indices
293 : : SH_LUT_LINEAR, // linear interpolation, vecN indices in range [0,1]
294 : : SH_LUT_CUBIC, // (bi/tri)cubic interpolation
295 : : SH_LUT_TETRAHEDRAL, // tetrahedral interpolation for vec3, equivalent to
296 : : // SH_LUT_LINEAR for lower dimensions
297 : : };
298 : :
299 : : struct sh_lut_params {
300 : : pl_shader_obj *object;
301 : :
302 : : // Type of the LUT we intend to generate.
303 : : //
304 : : // Note: If `var_type` is PL_VAR_*INT, `method` must be SH_LUT_NONE.
305 : : enum pl_var_type var_type;
306 : : enum sh_lut_type lut_type;
307 : : enum sh_lut_method method;
308 : :
309 : : // For SH_LUT_TEXTURE, this can be used to override the texture's internal
310 : : // format, in which case it takes precedence over the default for `type`.
311 : : pl_fmt fmt;
312 : :
313 : : // LUT dimensions. Unused dimensions may be left as 0.
314 : : int width;
315 : : int height;
316 : : int depth;
317 : : int comps;
318 : :
319 : : // If true, the LUT will always be regenerated, even if the dimensions have
320 : : // not changed.
321 : : bool update;
322 : :
323 : : // Alternate way of triggering shader invalidations. If the signature
324 : : // does not match the LUT's signature, it will be regenerated.
325 : : uint64_t signature;
326 : :
327 : : // If set to true, shader objects will be preserved and updated in-place
328 : : // rather than being treated as read-only.
329 : : bool dynamic;
330 : :
331 : : // If set , generated shader objects are automatically cached in this
332 : : // cache. Requires `signature` to be set (and uniquely identify the LUT).
333 : : pl_cache cache;
334 : :
335 : : // Will be called with a zero-initialized buffer whenever the data needs to
336 : : // be computed, which happens whenever the size is changed, the shader
337 : : // object is invalidated, or `update` is set to true.
338 : : //
339 : : // Note: Interpretation of `data` is according to `type` and `fmt`.
340 : : void (*fill)(void *data, const struct sh_lut_params *params);
341 : : void *priv;
342 : :
343 : : // Debug tag to track LUT source
344 : : pl_debug_tag debug_tag;
345 : : };
346 : :
347 : : #define sh_lut_params(...) (&(struct sh_lut_params) { \
348 : : .debug_tag = PL_DEBUG_TAG, \
349 : : __VA_ARGS__ \
350 : : })
351 : :
352 : : // Makes a table of values available as a shader variable, using an a given
353 : : // method (falling back if needed). The resulting identifier can be sampled
354 : : // directly as %s(pos), where pos is a vector with the right number of
355 : : // dimensions. `pos` must be an integer vector within the bounds of the array,
356 : : // unless the method is `SH_LUT_LINEAR`, in which case it's a float vector that
357 : : // gets interpolated and clamped as needed. Returns NULL on error.
358 : : ident_t sh_lut(pl_shader sh, const struct sh_lut_params *params);
359 : :
360 : : static inline uint8_t sh_num_comps(uint8_t mask)
361 : : {
362 [ - + ]: 38 : pl_assert((mask & 0xF) == mask);
363 : 144 : return __builtin_popcount(mask);
364 : : }
365 : :
366 [ - + ]: 106 : static inline const char *sh_float_type(uint8_t mask)
367 : : {
368 [ - + + - : 106 : switch (sh_num_comps(mask)) {
+ ]
369 : : case 1: return "float";
370 : 0 : case 2: return "vec2";
371 : 88 : case 3: return "vec3";
372 : 2 : case 4: return "vec4";
373 : : }
374 : :
375 : 0 : pl_unreachable();
376 : : }
377 : :
378 : : static inline const char *sh_swizzle(uint8_t mask)
379 : : {
380 : : static const char * const swizzles[0x10] = {
381 : : NULL, "r", "g", "rg", "b", "rb", "gb", "rgb",
382 : : "a", "ra", "ga", "rga", "ba", "rba", "gba", "rgba",
383 : : };
384 : :
385 [ - + ]: 68 : pl_assert(mask <= PL_ARRAY_SIZE(swizzles));
386 [ - + ]: 106 : return swizzles[mask];
387 : : }
|