LCOV - code coverage report
Current view: top level - src - shaders.h (source / functions) Hit Total Coverage
Test: Code coverage Lines: 15 17 88.2 %
Date: 2025-03-29 09:04:10 Functions: 2 2 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 33 61 54.1 %

           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                 :            : }

Generated by: LCOV version 1.16