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