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 const struct pl_shader_desc *descriptors;
70 int num_descriptors;
71 const struct pl_shader_var *variables;
72 int num_variables;
73 const struct pl_shader_va *vertex_attribs;
74 int num_vertex_attribs;
75 const struct pl_shader_const *constants;
76 int num_constants;
77
78 // If true, this shader must be a compute shader. The desired workgroup
79 // size and shared memory usage can be optionally specified, or 0 if no
80 // specific work group size or shared memory size restrictions apply.
81 //
82 // See also: `pl_shader_res.compute_group_size`
83 bool compute;
84 size_t compute_shmem;
85 int compute_group_size[2];
86
87 // Fixes the output size requirements of the shader to exact dimensions.
88 // Optional, if left as 0, means the shader can be dispatched at any size.
89 int output_w;
90 int output_h;
91 };
92
93 // Append custom shader code, including extra descriptors and variables, to an
94 // existing `pl_shader` object. Returns whether successful. This function may
95 // fail in the event that e.g. the custom shader requires compute shaders on
96 // an unsupported GPU, or exceeds the GPU's shared memory capabilities.
97 bool pl_shader_custom(pl_shader sh, const struct pl_custom_shader *params);
98
99 // Which "rendering stages" are available for user shader hooking purposes.
100 // Except where otherwise noted, all stages are "non-resizable", i.e. the
101 // shaders already have specific output size requirements.
102 enum pl_hook_stage {
103 // Hook stages for the untouched planes, as made available by the source.
104 // These are all resizable, i.e. there are no specific output stage
105 // requirements.
106 PL_HOOK_RGB_INPUT = 1 << 0,
107 PL_HOOK_LUMA_INPUT = 1 << 1,
108 PL_HOOK_CHROMA_INPUT = 1 << 2,
109 PL_HOOK_ALPHA_INPUT = 1 << 3,
110 PL_HOOK_XYZ_INPUT = 1 << 4,
111
112 // Hook stages for the scaled/aligned planes
113 PL_HOOK_CHROMA_SCALED = 1 << 5,
114 PL_HOOK_ALPHA_SCALED = 1 << 6,
115
116 PL_HOOK_NATIVE = 1 << 7, // Combined image in its native color space
117 PL_HOOK_RGB = 1 << 8, // After conversion to RGB (resizable)
118 PL_HOOK_LINEAR = 1 << 9, // After linearization but before scaling
119 PL_HOOK_SIGMOID = 1 << 10, // After sigmoidization
120 PL_HOOK_PRE_OVERLAY = 1 << 11, // Before applying on-image overlays
121 PL_HOOK_PRE_KERNEL = 1 << 12, // Immediately before the main scaler kernel (after overlays)
122 PL_HOOK_POST_KERNEL = 1 << 13, // Immediately after the main scaler kernel
123 PL_HOOK_SCALED = 1 << 14, // After scaling, before color management
124 PL_HOOK_OUTPUT = 1 << 15, // After color management, before dithering
125 };
126
127 // Returns true if a given hook stage is resizable
pl_hook_stage_resizable(enum pl_hook_stage stage)128 static inline bool pl_hook_stage_resizable(enum pl_hook_stage stage) {
129 switch (stage) {
130 case PL_HOOK_RGB_INPUT:
131 case PL_HOOK_LUMA_INPUT:
132 case PL_HOOK_CHROMA_INPUT:
133 case PL_HOOK_ALPHA_INPUT:
134 case PL_HOOK_XYZ_INPUT:
135 case PL_HOOK_NATIVE:
136 case PL_HOOK_RGB:
137 return true;
138
139 case PL_HOOK_CHROMA_SCALED:
140 case PL_HOOK_ALPHA_SCALED:
141 case PL_HOOK_LINEAR:
142 case PL_HOOK_SIGMOID:
143 case PL_HOOK_PRE_OVERLAY:
144 case PL_HOOK_PRE_KERNEL:
145 case PL_HOOK_POST_KERNEL:
146 case PL_HOOK_SCALED:
147 case PL_HOOK_OUTPUT:
148 return false;
149 }
150
151 abort();
152 }
153
154 // The different forms of communicating image data between the renderer and
155 // the hooks
156 enum pl_hook_sig {
157 PL_HOOK_SIG_NONE, // No data is passed, no data is received/returned
158 PL_HOOK_SIG_COLOR, // `vec4 color` already pre-sampled in a `pl_shader`
159 PL_HOOK_SIG_TEX, // `pl_tex` containing the image data
160 PL_HOOK_SIG_COUNT,
161 };
162
163 struct pl_hook_params {
164 // GPU objects associated with the `pl_renderer`, which the user may
165 // use for their own purposes.
166 pl_gpu gpu;
167 pl_dispatch dispatch;
168
169 // Helper function to fetch a new temporary texture, using renderer-backed
170 // storage. This is guaranteed to have sane image usage requirements and a
171 // 16-bit or floating point format. The user does not need to free/destroy
172 // this texture in any way. May return NULL.
173 pl_tex (*get_tex)(void *priv, int width, int height);
174 void *priv;
175
176 // Which stage triggered the hook to run.
177 enum pl_hook_stage stage;
178
179 // For `PL_HOOK_SIG_COLOR`, this contains the existing shader object with
180 // the color already pre-sampled into `vec4 color`. The user may modify
181 // this as much as they want, as long as they don't dispatch/finalize/reset
182 // it.
183 //
184 // Note that this shader might have specific output size requirements,
185 // depending on the exact shader stage hooked by the user, and may already
186 // be a compute shader.
187 pl_shader sh;
188
189 // For `PL_HOOK_SIG_TEX`, this contains the texture that the user should
190 // sample from.
191 //
192 // Note: This texture object is owned by the renderer, and users must not
193 // modify its contents. It will not be touched for the duration of a frame,
194 // but the contents are lost in between frames.
195 pl_tex tex;
196
197 // The effective current rectangle of the image we're rendering in this
198 // shader, i.e. the effective rect of the content we're interested in,
199 // as a crop of either `sh` or `tex` (depending on the signature).
200 //
201 // Note: This is still set even for `PL_HOOK_SIG_NONE`!
202 struct pl_rect2df rect;
203
204 // The current effective colorspace and representation, of either the
205 // pre-sampled color (in `sh`), or the contents of `tex`, respectively.
206 //
207 // Note: This is still set even for `PL_HOOK_SIG_NONE`!
208 struct pl_color_repr repr;
209 struct pl_color_space color;
210 int components;
211
212 // The (cropped) source and destination rectangles of the overall
213 // rendering. These are functionallty equivalent to `image.crop` and
214 // `target.crop`, respectively, but `src_rect` in particular may change as
215 // a result of previous hooks being executed. (e.g. prescalers)
216 struct pl_rect2df src_rect;
217 struct pl_rect2d dst_rect;
218 };
219
220 struct pl_hook_res {
221 // If true, the hook is assumed to have "failed" or errored in some way,
222 // and all other fields are ignored.
223 bool failed;
224
225 // What type of output this hook is returning.
226 // Note: If this is `PL_HOOK_SIG_NONE`, all other fields are ignored.
227 enum pl_hook_sig output;
228
229 // For `PL_HOOK_SIG_COLOR`, this *must* be set to a valid `pl_shader`
230 // object containing the sampled color value (i.e. with an output signature
231 // of `PL_SHADER_SIG_COLOR`), and *should* be allocated from the given
232 // `pl_dispatch` object. Ignored otherwise.
233 pl_shader sh;
234
235 // For `PL_HOOK_SIG_TEX`, this *must* contain the texture object containing
236 // the result of rendering the hook. This *should* be a texture allocated
237 // using the given `get_tex` callback, to ensure the format and texture
238 // usage flags are compatible with what the renderer expects.
239 pl_tex tex;
240
241 // For shaders that return some sort of output, this contains the
242 // new/altered versions of the existing "current texture" metadata.
243 struct pl_color_repr repr;
244 struct pl_color_space color;
245 int components;
246
247 // This contains the new effective rect of the contents. This may be
248 // different from the original `rect` for resizable passes. Ignored for
249 // non-resizable passes.
250 struct pl_rect2df rect;
251 };
252
253 // Struct describing a hook.
254 //
255 // Note: Users may freely create their own instances of this struct, there is
256 // nothing particularly special about `pl_mpv_user_shader_parse`.
257 struct pl_hook {
258 enum pl_hook_stage stages; // Which stages to hook on
259 enum pl_hook_sig input; // Which input signature this hook expects
260 void *priv; // Arbitrary user context
261
262 // Called at the beginning of passes, to reset/initialize the hook. (Optional)
263 void (*reset)(void *priv);
264
265 // The hook function itself. Called by the renderer at any of the indicated
266 // hook stages. See `pl_hook_res` for more info on the return values.
267 struct pl_hook_res (*hook)(void *priv, const struct pl_hook_params *params);
268 };
269
270 // Compatibility layer with `mpv` user shaders. See the mpv man page for more
271 // information on the format. Will return `NULL` if the shader fails parsing.
272 //
273 // The resulting `pl_hook` objects should be destroyed with the corresponding
274 // destructor when no longer needed.
275 const struct pl_hook *pl_mpv_user_shader_parse(pl_gpu gpu,
276 const char *shader_text,
277 size_t shader_len);
278
279 void pl_mpv_user_shader_destroy(const struct pl_hook **hook);
280
281 PL_API_END
282
283 #endif // LIBPLACEBO_SHADERS_CUSTOM_H_
284