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