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 : : #ifndef LIBPLACEBO_SHADERS_CUSTOM_H_
19 : : #define LIBPLACEBO_SHADERS_CUSTOM_H_
20 : :
21 : : #include <stdlib.h>
22 : :
23 : : // Functions for writing custom shaders and hooking them into the `pl_renderer`
24 : : // pipeline, as well as compatibility functions for parsing shaders in mpv
25 : : // format.
26 : :
27 : : #include <libplacebo/shaders.h>
28 : : #include <libplacebo/dispatch.h>
29 : : #include <libplacebo/colorspace.h>
30 : :
31 : : PL_API_BEGIN
32 : :
33 : : // Parameters describing custom shader text to be embedded into a `pl_shader`
34 : : // object. All of the strings are optional and can be left as NULL, but without
35 : : // a `body` in particular, the shader will do nothing useful on its own.
36 : : struct pl_custom_shader {
37 : : // The prelude contains text such as extra #defines, #extension pragmas,
38 : : // or other parts of the shader that must be placed at the very
39 : : // beginning (before input layout declarations etc.)
40 : : //
41 : : // Note: #extension pragmas do not need to be emitted to enable support for
42 : : // resource types already attached to the shader (e.g. SSBOs), compute
43 : : // shaders, or GPU capabilities known to libplacebo (e.g. subgroups).
44 : : const char *prelude;
45 : :
46 : : // The header contains text such as helper function definitions, extra
47 : : // uniforms, shared memory variables or buffer descriptions.
48 : : const char *header;
49 : :
50 : : // A friendly name for the shader. (Optional)
51 : : const char *description;
52 : :
53 : : // The "primary" GLSL code. This will be effectively appended to the "main"
54 : : // function. It lives in an environment given by the `input` signature, and
55 : : // is expected to return results in a way given by the `output` signature.
56 : : //
57 : : // Note: In the case of PL_SHADER_SIG_COLOR, the output `vec4 color` is
58 : : // allocated by `pl_shader_custom`, the user merely needs to assign to it.
59 : : //
60 : : // Note: For ease of development it can be useful to have the main logic
61 : : // live inside a helper function defined as part of `header`, and specify
62 : : // the `body` as a single line that simply calls the helper function.
63 : : const char *body;
64 : : enum pl_shader_sig input;
65 : : enum pl_shader_sig output;
66 : :
67 : : // Extra descriptors, variables and vertex attributes to attach to the
68 : : // resulting `pl_shader_res`.
69 : : //
70 : : // Note: The names inside these will possibly be replaced by fresh
71 : : // identifiers internally, so users should avoid looking for exact string
72 : : // matches for the given names inside the `pl_shader_res`.
73 : : const struct pl_shader_desc *descriptors;
74 : : int num_descriptors;
75 : : const struct pl_shader_var *variables;
76 : : int num_variables;
77 : : const struct pl_shader_va *vertex_attribs;
78 : : int num_vertex_attribs;
79 : : const struct pl_shader_const *constants;
80 : : int num_constants;
81 : :
82 : : // If true, this shader must be a compute shader. The desired workgroup
83 : : // size and shared memory usage can be optionally specified, or 0 if no
84 : : // specific work group size or shared memory size restrictions apply.
85 : : //
86 : : // See also: `pl_shader_res.compute_group_size`
87 : : bool compute;
88 : : size_t compute_shmem;
89 : : int compute_group_size[2];
90 : :
91 : : // Fixes the output size requirements of the shader to exact dimensions.
92 : : // Optional, if left as 0, means the shader can be dispatched at any size.
93 : : int output_w;
94 : : int output_h;
95 : : };
96 : :
97 : : // Append custom shader code, including extra descriptors and variables, to an
98 : : // existing `pl_shader` object. Returns whether successful. This function may
99 : : // fail in the event that e.g. the custom shader requires compute shaders on
100 : : // an unsupported GPU, or exceeds the GPU's shared memory capabilities.
101 : : PL_API bool pl_shader_custom(pl_shader sh, const struct pl_custom_shader *params);
102 : :
103 : : // Which "rendering stages" are available for user shader hooking purposes.
104 : : // Except where otherwise noted, all stages are "non-resizable", i.e. the
105 : : // shaders already have specific output size requirements.
106 : : enum pl_hook_stage {
107 : : // Hook stages for the untouched planes, as made available by the source.
108 : : // These are all resizable, i.e. there are no specific output stage
109 : : // requirements.
110 : : PL_HOOK_RGB_INPUT = 1 << 0,
111 : : PL_HOOK_LUMA_INPUT = 1 << 1,
112 : : PL_HOOK_CHROMA_INPUT = 1 << 2,
113 : : PL_HOOK_ALPHA_INPUT = 1 << 3,
114 : : PL_HOOK_XYZ_INPUT = 1 << 4,
115 : :
116 : : // Hook stages for the scaled/aligned planes
117 : : PL_HOOK_CHROMA_SCALED = 1 << 5,
118 : : PL_HOOK_ALPHA_SCALED = 1 << 6,
119 : :
120 : : PL_HOOK_NATIVE = 1 << 7, // Combined image in its native color space
121 : : PL_HOOK_RGB = 1 << 8, // After conversion to RGB (resizable)
122 : : PL_HOOK_LINEAR = 1 << 9, // After linearization but before scaling
123 : : PL_HOOK_SIGMOID = 1 << 10, // After sigmoidization
124 : : PL_HOOK_PRE_KERNEL = 1 << 11, // Immediately before the main scaler kernel
125 : : PL_HOOK_POST_KERNEL = 1 << 12, // Immediately after the main scaler kernel
126 : : PL_HOOK_SCALED = 1 << 13, // After scaling, before color management
127 : : PL_HOOK_PRE_OUTPUT = 1 << 14, // After color management, before blending/rotation
128 : : PL_HOOK_OUTPUT = 1 << 15, // After blending/rotation, before dithering
129 : : };
130 : :
131 : : // Returns true if a given hook stage is resizable
132 : 19 : static inline bool pl_hook_stage_resizable(enum pl_hook_stage stage) {
133 [ - - + ]: 19 : switch (stage) {
134 : : case PL_HOOK_RGB_INPUT:
135 : : case PL_HOOK_LUMA_INPUT:
136 : : case PL_HOOK_CHROMA_INPUT:
137 : : case PL_HOOK_ALPHA_INPUT:
138 : : case PL_HOOK_XYZ_INPUT:
139 : : case PL_HOOK_NATIVE:
140 : : case PL_HOOK_RGB:
141 : : return true;
142 : :
143 : 0 : case PL_HOOK_CHROMA_SCALED:
144 : : case PL_HOOK_ALPHA_SCALED:
145 : : case PL_HOOK_LINEAR:
146 : : case PL_HOOK_SIGMOID:
147 : : case PL_HOOK_PRE_KERNEL:
148 : : case PL_HOOK_POST_KERNEL:
149 : : case PL_HOOK_SCALED:
150 : : case PL_HOOK_PRE_OUTPUT:
151 : : case PL_HOOK_OUTPUT:
152 : 0 : return false;
153 : : }
154 : :
155 : 0 : abort();
156 : : }
157 : :
158 : : // The different forms of communicating image data between the renderer and
159 : : // the hooks
160 : : enum pl_hook_sig {
161 : : PL_HOOK_SIG_NONE, // No data is passed, no data is received/returned
162 : : PL_HOOK_SIG_COLOR, // `vec4 color` already pre-sampled in a `pl_shader`
163 : : PL_HOOK_SIG_TEX, // `pl_tex` containing the image data
164 : : PL_HOOK_SIG_COUNT,
165 : : };
166 : :
167 : : struct pl_hook_params {
168 : : // GPU objects associated with the `pl_renderer`, which the user may
169 : : // use for their own purposes.
170 : : pl_gpu gpu;
171 : : pl_dispatch dispatch;
172 : :
173 : : // Helper function to fetch a new temporary texture, using renderer-backed
174 : : // storage. This is guaranteed to have sane image usage requirements and a
175 : : // 16-bit or floating point format. The user does not need to free/destroy
176 : : // this texture in any way. May return NULL.
177 : : pl_tex (*get_tex)(void *priv, int width, int height);
178 : : void *priv;
179 : :
180 : : // Which stage triggered the hook to run.
181 : : enum pl_hook_stage stage;
182 : :
183 : : // For `PL_HOOK_SIG_COLOR`, this contains the existing shader object with
184 : : // the color already pre-sampled into `vec4 color`. The user may modify
185 : : // this as much as they want, as long as they don't dispatch/finalize/reset
186 : : // it.
187 : : //
188 : : // Note that this shader might have specific output size requirements,
189 : : // depending on the exact shader stage hooked by the user, and may already
190 : : // be a compute shader.
191 : : pl_shader sh;
192 : :
193 : : // For `PL_HOOK_SIG_TEX`, this contains the texture that the user should
194 : : // sample from.
195 : : //
196 : : // Note: This texture object is owned by the renderer, and users must not
197 : : // modify its contents. It will not be touched for the duration of a frame,
198 : : // but the contents are lost in between frames.
199 : : pl_tex tex;
200 : :
201 : : // The effective current rectangle of the image we're rendering in this
202 : : // shader, i.e. the effective rect of the content we're interested in,
203 : : // as a crop of either `sh` or `tex` (depending on the signature).
204 : : //
205 : : // Note: This is still set even for `PL_HOOK_SIG_NONE`!
206 : : pl_rect2df rect;
207 : :
208 : : // The current effective colorspace and representation, of either the
209 : : // pre-sampled color (in `sh`), or the contents of `tex`, respectively.
210 : : //
211 : : // Note: This is still set even for `PL_HOOK_SIG_NONE`!
212 : : struct pl_color_repr repr;
213 : : struct pl_color_space color;
214 : : int components;
215 : :
216 : : // The representation and colorspace of the original image, for reference.
217 : : const struct pl_color_repr *orig_repr;
218 : : const struct pl_color_space *orig_color;
219 : :
220 : : // The (cropped) source and destination rectangles of the overall
221 : : // rendering. These are functionallty equivalent to `image.crop` and
222 : : // `target.crop`, respectively, but `src_rect` in particular may change as
223 : : // a result of previous hooks being executed. (e.g. prescalers)
224 : : pl_rect2df src_rect;
225 : : pl_rect2d dst_rect;
226 : : };
227 : :
228 : : struct pl_hook_res {
229 : : // If true, the hook is assumed to have "failed" or errored in some way,
230 : : // and all other fields are ignored.
231 : : bool failed;
232 : :
233 : : // What type of output this hook is returning.
234 : : // Note: If this is `PL_HOOK_SIG_NONE`, all other fields are ignored.
235 : : enum pl_hook_sig output;
236 : :
237 : : // For `PL_HOOK_SIG_COLOR`, this *must* be set to a valid `pl_shader`
238 : : // object containing the sampled color value (i.e. with an output signature
239 : : // of `PL_SHADER_SIG_COLOR`), and *should* be allocated from the given
240 : : // `pl_dispatch` object. Ignored otherwise.
241 : : pl_shader sh;
242 : :
243 : : // For `PL_HOOK_SIG_TEX`, this *must* contain the texture object containing
244 : : // the result of rendering the hook. This *should* be a texture allocated
245 : : // using the given `get_tex` callback, to ensure the format and texture
246 : : // usage flags are compatible with what the renderer expects.
247 : : pl_tex tex;
248 : :
249 : : // For shaders that return some sort of output, this contains the
250 : : // new/altered versions of the existing "current texture" metadata.
251 : : struct pl_color_repr repr;
252 : : struct pl_color_space color;
253 : : int components;
254 : :
255 : : // This contains the new effective rect of the contents. This may be
256 : : // different from the original `rect` for resizable passes. Ignored for
257 : : // non-resizable passes.
258 : : pl_rect2df rect;
259 : : };
260 : :
261 : : enum pl_hook_par_mode {
262 : : PL_HOOK_PAR_VARIABLE, // normal shader variable
263 : : PL_HOOK_PAR_DYNAMIC, // dynamic shader variable, e.g. per-frame changing
264 : : PL_HOOK_PAR_CONSTANT, // fixed at compile time (e.g. for array sizes),
265 : : // must be scalar (non-vector/matrix)
266 : : PL_HOOK_PAR_DEFINE, // defined in the preprocessor, must be `int`
267 : : PL_HOOK_PAR_MODE_COUNT,
268 : : };
269 : :
270 : : typedef union pl_var_data {
271 : : int i;
272 : : unsigned u;
273 : : float f;
274 : : } pl_var_data;
275 : :
276 : : struct pl_hook_par {
277 : : // Name as used in the shader.
278 : : const char *name;
279 : :
280 : : // Type of this shader parameter, and how it's manifested in the shader.
281 : : enum pl_var_type type;
282 : : enum pl_hook_par_mode mode;
283 : :
284 : : // Human-readable explanation of this parameter. (Optional)
285 : : const char *description;
286 : :
287 : : // Mutable data pointer to current value of variable.
288 : : pl_var_data *data;
289 : :
290 : : // Default/initial value, and lower/upper bounds.
291 : : pl_var_data initial;
292 : : pl_var_data minimum;
293 : : pl_var_data maximum;
294 : :
295 : : // Human-readable names for the variants of an integer option. This array
296 : : // can be indexed directly by integer values, ranging from `minimum.i` to
297 : : // `maximum.i`. May be NULL, in which case options are unnamed.
298 : : const char * const *names;
299 : : };
300 : :
301 : : // Struct describing a hook.
302 : : //
303 : : // Note: Users may freely create their own instances of this struct, there is
304 : : // nothing particularly special about `pl_mpv_user_shader_parse`.
305 : : struct pl_hook {
306 : : enum pl_hook_stage stages; // Which stages to hook on
307 : : enum pl_hook_sig input; // Which input signature this hook expects
308 : : void *priv; // Arbitrary user context
309 : :
310 : : // Custom tunable shader parameters exported by this hook. These may be
311 : : // updated at any time by the user, to influence the behavior of the hook.
312 : : // Contents are arbitrary and subject to the method of hook construction.
313 : : const struct pl_hook_par *parameters;
314 : : int num_parameters;
315 : :
316 : : // Called at the beginning of passes, to reset/initialize the hook. (Optional)
317 : : void (*reset)(void *priv);
318 : :
319 : : // The hook function itself. Called by the renderer at any of the indicated
320 : : // hook stages. See `pl_hook_res` for more info on the return values.
321 : : struct pl_hook_res (*hook)(void *priv, const struct pl_hook_params *params);
322 : :
323 : : // Unique signature identifying this hook, used to disable misbehaving hooks.
324 : : // All hooks with the same signature will be disabled, should they fail to
325 : : // execute during run-time.
326 : : uint64_t signature;
327 : : };
328 : :
329 : : // Compatibility layer with `mpv` user shaders. See the mpv man page for more
330 : : // information on the format. Will return `NULL` if the shader fails parsing.
331 : : //
332 : : // The resulting `pl_hook` objects should be destroyed with the corresponding
333 : : // destructor when no longer needed.
334 : : PL_API const struct pl_hook *
335 : : pl_mpv_user_shader_parse(pl_gpu gpu, const char *shader_text, size_t shader_len);
336 : :
337 : : PL_API void pl_mpv_user_shader_destroy(const struct pl_hook **hook);
338 : :
339 : : PL_API_END
340 : :
341 : : #endif // LIBPLACEBO_SHADERS_CUSTOM_H_
|