LCOV - code coverage report
Current view: top level - src - shaders.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 386 450 85.8 %
Date: 2025-03-29 09:04:10 Functions: 39 41 95.1 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 211 320 65.9 %

           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                 :            : #include <stdio.h>
      19                 :            : #include <math.h>
      20                 :            : 
      21                 :            : #include "common.h"
      22                 :            : #include "log.h"
      23                 :            : #include "shaders.h"
      24                 :            : 
      25                 :          0 : pl_shader_info pl_shader_info_ref(pl_shader_info pinfo)
      26                 :            : {
      27                 :            :     struct sh_info *info = (struct sh_info *) pinfo;
      28         [ #  # ]:          0 :     if (!info)
      29                 :            :         return NULL;
      30                 :            : 
      31                 :          0 :     pl_rc_ref(&info->rc);
      32                 :          0 :     return &info->info;
      33                 :            : }
      34                 :            : 
      35                 :         41 : void pl_shader_info_deref(pl_shader_info *pinfo)
      36                 :            : {
      37                 :         41 :     struct sh_info *info = (struct sh_info *) *pinfo;
      38         [ +  - ]:         41 :     if (!info)
      39                 :            :         return;
      40                 :            : 
      41         [ +  - ]:         41 :     if (pl_rc_deref(&info->rc))
      42                 :         41 :         pl_free(info);
      43                 :         41 :     *pinfo = NULL;
      44                 :            : }
      45                 :            : 
      46                 :         41 : static struct sh_info *sh_info_alloc(void *alloc)
      47                 :            : {
      48                 :         41 :     struct sh_info *info = pl_zalloc_ptr(alloc, info);
      49                 :         41 :     info->tmp = pl_tmp(info);
      50                 :         41 :     pl_rc_init(&info->rc);
      51                 :         41 :     return info;
      52                 :            : }
      53                 :            : 
      54                 :            : // Re-use `sh_info` allocation if possible, allocate new otherwise
      55                 :       2766 : static struct sh_info *sh_info_recycle(struct sh_info *info)
      56                 :            : {
      57         [ -  + ]:       2766 :     if (!pl_rc_deref(&info->rc))
      58                 :          0 :         return sh_info_alloc(NULL);
      59                 :            : 
      60                 :       2766 :     memset(&info->info, 0, sizeof(info->info)); // reset public fields
      61                 :       2766 :     pl_free_children(info->tmp);
      62                 :       2766 :     pl_rc_ref(&info->rc);
      63                 :       2766 :     info->desc.len = 0;
      64                 :       2766 :     info->steps.num = 0;
      65                 :       2766 :     return info;
      66                 :            : }
      67                 :            : 
      68                 :            : static uint8_t reverse_bits(uint8_t x)
      69                 :            : {
      70                 :            :     static const uint8_t reverse_nibble[16] = {
      71                 :            :         0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
      72                 :            :         0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf,
      73                 :            :     };
      74                 :            : 
      75                 :       2795 :     return reverse_nibble[x & 0xF] << 4 | reverse_nibble[x >> 4];
      76                 :            : }
      77                 :            : 
      78                 :       2807 : static void init_shader(pl_shader sh, const struct pl_shader_params *params)
      79                 :            : {
      80         [ +  + ]:       2807 :     if (params) {
      81                 :       2795 :         sh->info->info.params = *params;
      82                 :            : 
      83                 :            :         // To avoid collisions for shaders with very high number of
      84                 :            :         // identifiers, pack the shader ID into the highest bits (MSB -> LSB)
      85                 :            :         pl_static_assert(sizeof(sh->prefix) > sizeof(params->id));
      86                 :            :         const int shift = 8 * (sizeof(sh->prefix) - sizeof(params->id));
      87                 :       2795 :         sh->prefix = reverse_bits(params->id) << shift;
      88                 :            :     }
      89                 :            : 
      90                 :       2807 :     sh->name = sh_fresh(sh, "main");
      91                 :       2807 : }
      92                 :            : 
      93                 :         41 : pl_shader pl_shader_alloc(pl_log log, const struct pl_shader_params *params)
      94                 :            : {
      95                 :            :     static const int glsl_ver_req = 130;
      96   [ +  +  -  +  :         41 :     if (params && params->glsl.version && params->glsl.version < 130) {
                   -  - ]
      97                 :          0 :         pl_err(log, "Requested GLSL version %d too low (required: %d)",
      98                 :            :                params->glsl.version, glsl_ver_req);
      99                 :          0 :         return NULL;
     100                 :            :     }
     101                 :            : 
     102                 :         41 :     pl_shader sh = pl_alloc_ptr(NULL, sh);
     103                 :         41 :     *sh = (struct pl_shader_t) {
     104                 :            :         .log        = log,
     105                 :         41 :         .tmp        = pl_tmp(sh),
     106                 :         41 :         .info       = sh_info_alloc(NULL),
     107                 :            :         .mutable    = true,
     108                 :            :     };
     109                 :            : 
     110         [ +  + ]:        205 :     for (int i = 0; i < PL_ARRAY_SIZE(sh->buffers); i++)
     111                 :        164 :         sh->buffers[i] = pl_str_builder_alloc(sh);
     112                 :            : 
     113                 :         41 :     init_shader(sh, params);
     114                 :         41 :     return sh;
     115                 :            : }
     116                 :            : 
     117                 :            : static void sh_obj_deref(pl_shader_obj obj);
     118                 :            : 
     119                 :       5561 : void sh_deref(pl_shader sh)
     120                 :            : {
     121                 :       5561 :     pl_free_children(sh->tmp);
     122                 :            : 
     123         [ +  + ]:       7539 :     for (int i = 0; i < sh->obj.num; i++)
     124                 :       1978 :         sh_obj_deref(sh->obj.elem[i]);
     125                 :       5561 :     sh->obj.num = 0;
     126                 :       5561 : }
     127                 :            : 
     128                 :         41 : void pl_shader_free(pl_shader *psh)
     129                 :            : {
     130                 :         41 :     pl_shader sh = *psh;
     131         [ +  - ]:         41 :     if (!sh)
     132                 :            :         return;
     133                 :            : 
     134                 :         41 :     sh_deref(sh);
     135                 :         41 :     pl_shader_info_deref((pl_shader_info *) &sh->info);
     136                 :         41 :     pl_free_ptr(psh);
     137                 :            : }
     138                 :            : 
     139                 :       2766 : void pl_shader_reset(pl_shader sh, const struct pl_shader_params *params)
     140                 :            : {
     141                 :       2766 :     sh_deref(sh);
     142                 :            : 
     143                 :       5532 :     struct pl_shader_t new = {
     144                 :       2766 :         .log            = sh->log,
     145                 :       2766 :         .tmp            = sh->tmp,
     146                 :       2766 :         .info           = sh_info_recycle(sh->info),
     147                 :       2766 :         .data.buf       = sh->data.buf,
     148                 :            :         .mutable        = true,
     149                 :            : 
     150                 :            :         // Preserve array allocations
     151                 :       2766 :         .obj.elem       = sh->obj.elem,
     152                 :       2766 :         .vas.elem       = sh->vas.elem,
     153                 :       2766 :         .vars.elem      = sh->vars.elem,
     154                 :       2766 :         .descs.elem     = sh->descs.elem,
     155                 :       2766 :         .consts.elem    = sh->consts.elem,
     156                 :            :     };
     157                 :            : 
     158                 :            :     // Preserve buffer allocations
     159                 :       2766 :     memcpy(new.buffers, sh->buffers, sizeof(new.buffers));
     160         [ +  + ]:      13830 :     for (int i = 0; i < PL_ARRAY_SIZE(new.buffers); i++)
     161                 :      11064 :         pl_str_builder_reset(new.buffers[i]);
     162                 :            : 
     163                 :       2766 :     *sh = new;
     164                 :       2766 :     init_shader(sh, params);
     165                 :       2766 : }
     166                 :            : 
     167                 :      11385 : static void *sh_alloc(pl_shader sh, size_t size, size_t align)
     168                 :            : {
     169                 :      11385 :     const size_t offset = PL_ALIGN2(sh->data.len, align);
     170                 :      11385 :     const size_t req_size = offset + size;
     171         [ +  + ]:      11385 :     if (req_size <= pl_get_size(sh->data.buf)) {
     172                 :      10540 :         sh->data.len = offset + size;
     173                 :      10540 :         return sh->data.buf + offset;
     174                 :            :     }
     175                 :            : 
     176                 :            :     // We can't realloc this buffer because various pointers will be left
     177                 :            :     // dangling, so just reparent it onto `sh->tmp` (so it will be cleaned
     178                 :            :     // up when the shader is next reset) and allocate a new, larger buffer
     179                 :            :     // in its place
     180                 :        845 :     const size_t new_size = PL_MAX(req_size << 1, 256);
     181                 :        845 :     pl_steal(sh->tmp, sh->data.buf);
     182                 :        845 :     sh->data.buf = pl_alloc(sh, new_size);
     183                 :        845 :     sh->data.len = size;
     184                 :        845 :     return sh->data.buf;
     185                 :            : }
     186                 :            : 
     187                 :       7268 : static void *sh_memdup(pl_shader sh, const void *data, size_t size, size_t align)
     188                 :            : {
     189         [ +  - ]:       7268 :     if (!size)
     190                 :            :         return NULL;
     191                 :            : 
     192                 :       7268 :     void *dst = sh_alloc(sh, size, align);
     193         [ -  + ]:       7268 :     assert(data);
     194                 :            :     memcpy(dst, data, size);
     195                 :       7268 :     return dst;
     196                 :            : }
     197                 :            : 
     198                 :          0 : bool pl_shader_is_failed(const pl_shader sh)
     199                 :            : {
     200                 :          0 :     return sh->failed;
     201                 :            : }
     202                 :            : 
     203                 :      18518 : struct pl_glsl_version sh_glsl(const pl_shader sh)
     204                 :            : {
     205         [ -  + ]:      18518 :     if (SH_PARAMS(sh).glsl.version)
     206                 :          0 :         return SH_PARAMS(sh).glsl;
     207                 :            : 
     208         [ +  + ]:      18518 :     if (SH_GPU(sh))
     209                 :      18517 :         return SH_GPU(sh)->glsl;
     210                 :            : 
     211                 :          1 :     return (struct pl_glsl_version) { .version = 130 };
     212                 :            : }
     213                 :            : 
     214                 :        104 : bool sh_try_compute(pl_shader sh, int bw, int bh, bool flex, size_t mem)
     215                 :            : {
     216         [ -  + ]:        104 :     pl_assert(bw && bh);
     217                 :            :     int *sh_bw = &sh->group_size[0];
     218                 :            :     int *sh_bh = &sh->group_size[1];
     219                 :            : 
     220                 :        104 :     struct pl_glsl_version glsl = sh_glsl(sh);
     221         [ +  + ]:        104 :     if (!glsl.compute) {
     222                 :          4 :         PL_TRACE(sh, "Disabling compute shader due to missing `compute` support");
     223                 :          4 :         return false;
     224                 :            :     }
     225                 :            : 
     226         [ -  + ]:        100 :     if (sh->shmem + mem > glsl.max_shmem_size) {
     227                 :          0 :         PL_TRACE(sh, "Disabling compute shader due to insufficient shmem");
     228                 :          0 :         return false;
     229                 :            :     }
     230                 :            : 
     231         [ -  + ]:        100 :     if (sh->type == SH_FRAGMENT) {
     232                 :          0 :         PL_TRACE(sh, "Disabling compute shader because shader is already marked "
     233                 :            :                  "as fragment shader");
     234                 :          0 :         return false;
     235                 :            :     }
     236                 :            : 
     237         [ +  - ]:        100 :     if (bw > glsl.max_group_size[0] ||
     238         [ +  - ]:        100 :         bh > glsl.max_group_size[1] ||
     239         [ -  + ]:        100 :         (bw * bh) > glsl.max_group_threads)
     240                 :            :     {
     241         [ #  # ]:          0 :         if (!flex) {
     242                 :          0 :             PL_TRACE(sh, "Disabling compute shader due to exceeded group "
     243                 :            :                      "thread count.");
     244                 :          0 :             return false;
     245                 :            :         } else {
     246                 :            :             // Pick better group sizes
     247                 :          0 :             bw = PL_MIN(bw, glsl.max_group_size[0]);
     248                 :          0 :             bh = glsl.max_group_threads / bw;
     249                 :            :         }
     250                 :            :     }
     251                 :            : 
     252                 :        100 :     sh->shmem += mem;
     253                 :            : 
     254                 :            :     // If the current shader is either not a compute shader, or we have no
     255                 :            :     // choice but to override the metadata, always do so
     256   [ -  +  -  -  :        100 :     if (sh->type != SH_COMPUTE || (sh->flexible_work_groups && !flex)) {
                   -  - ]
     257                 :        100 :         *sh_bw = bw;
     258                 :        100 :         *sh_bh = bh;
     259                 :        100 :         sh->type = SH_COMPUTE;
     260                 :        100 :         sh->flexible_work_groups = flex;
     261                 :        100 :         return true;
     262                 :            :     }
     263                 :            : 
     264                 :            :     // If both shaders are flexible, pick the larger of the two
     265   [ #  #  #  # ]:          0 :     if (sh->flexible_work_groups && flex) {
     266                 :          0 :         *sh_bw = PL_MAX(*sh_bw, bw);
     267                 :          0 :         *sh_bh = PL_MAX(*sh_bh, bh);
     268         [ #  # ]:          0 :         pl_assert(*sh_bw * *sh_bh <= glsl.max_group_threads);
     269                 :            :         return true;
     270                 :            :     }
     271                 :            : 
     272                 :            :     // At this point we're looking only at a non-flexible compute shader
     273         [ #  # ]:          0 :     pl_assert(sh->type == SH_COMPUTE && !sh->flexible_work_groups);
     274         [ #  # ]:          0 :     if (!flex) {
     275                 :            :         // Ensure parameters match
     276   [ #  #  #  # ]:          0 :         if (bw != *sh_bw || bh != *sh_bh) {
     277                 :          0 :             PL_TRACE(sh, "Disabling compute shader due to incompatible group "
     278                 :            :                      "sizes %dx%d and %dx%d", *sh_bw, *sh_bh, bw, bh);
     279                 :          0 :             sh->shmem -= mem;
     280                 :          0 :             return false;
     281                 :            :         }
     282                 :            :     }
     283                 :            : 
     284                 :            :     return true;
     285                 :            : }
     286                 :            : 
     287                 :       8720 : bool pl_shader_is_compute(const pl_shader sh)
     288                 :            : {
     289                 :       8720 :     return sh->type == SH_COMPUTE;
     290                 :            : }
     291                 :            : 
     292                 :       2662 : bool pl_shader_output_size(const pl_shader sh, int *w, int *h)
     293                 :            : {
     294   [ +  +  +  - ]:       2662 :     if (!sh->output_w || !sh->output_h)
     295                 :            :         return false;
     296                 :            : 
     297         [ +  + ]:        998 :     *w = sh->transpose ? sh->output_h : sh->output_w;
     298         [ +  + ]:        998 :     *h = sh->transpose ? sh->output_w : sh->output_h;
     299                 :        998 :     return true;
     300                 :            : }
     301                 :            : 
     302                 :      33188 : ident_t sh_fresh(pl_shader sh, const char *name)
     303                 :            : {
     304                 :      33188 :     unsigned short id = ++sh->fresh;
     305         [ -  + ]:      33188 :     assert(!(sh->prefix & id));
     306                 :      33188 :     id |= sh->prefix;
     307                 :            : 
     308         [ -  + ]:      33188 :     assert(name);
     309                 :      33188 :     return sh_mkident(id, name);
     310                 :            : }
     311                 :            : 
     312                 :            : static inline ident_t sh_fresh_name(pl_shader sh, const char **pname)
     313                 :            : {
     314                 :      16794 :     ident_t id = sh_fresh(sh, *pname);
     315                 :       4757 :     *pname = sh_ident_pack(id);
     316                 :            :     return id;
     317                 :            : }
     318                 :            : 
     319                 :       4673 : ident_t sh_var(pl_shader sh, struct pl_shader_var sv)
     320                 :            : {
     321                 :            :     ident_t id = sh_fresh_name(sh, &sv.var.name);
     322                 :       4673 :     struct pl_var_layout layout = pl_var_host_layout(0, &sv.var);
     323                 :       4673 :     sv.data = sh_memdup(sh, sv.data, layout.size, layout.stride);
     324   [ +  +  +  +  :       4673 :     PL_ARRAY_APPEND(sh, sh->vars, sv);
                   -  + ]
     325                 :       4673 :     return id;
     326                 :            : }
     327                 :            : 
     328                 :         72 : ident_t sh_var_int(pl_shader sh, const char *name, int val, bool dynamic)
     329                 :            : {
     330                 :         72 :     return sh_var(sh, (struct pl_shader_var) {
     331                 :         72 :         .var     = pl_var_int(name),
     332                 :            :         .data    = &val,
     333                 :            :         .dynamic = dynamic,
     334                 :            :     });
     335                 :            : }
     336                 :            : 
     337                 :         36 : ident_t sh_var_uint(pl_shader sh, const char *name, unsigned int val, bool dynamic)
     338                 :            : {
     339                 :         36 :     return sh_var(sh, (struct pl_shader_var) {
     340                 :         36 :         .var     = pl_var_uint(name),
     341                 :            :         .data    = &val,
     342                 :            :         .dynamic = dynamic,
     343                 :            :     });
     344                 :            : }
     345                 :            : 
     346                 :       1120 : ident_t sh_var_float(pl_shader sh, const char *name, float val, bool dynamic)
     347                 :            : {
     348                 :       1120 :     return sh_var(sh, (struct pl_shader_var) {
     349                 :       1120 :         .var     = pl_var_float(name),
     350                 :            :         .data    = &val,
     351                 :            :         .dynamic = dynamic,
     352                 :            :     });
     353                 :            : }
     354                 :            : 
     355                 :        188 : ident_t sh_var_mat3(pl_shader sh, const char *name, pl_matrix3x3 val)
     356                 :            : {
     357                 :        188 :     return sh_var(sh, (struct pl_shader_var) {
     358                 :        188 :         .var     = pl_var_mat3(name),
     359                 :        188 :         .data    = PL_TRANSPOSE_3X3(val.m),
     360                 :            :     });
     361                 :            : }
     362                 :            : 
     363                 :       3122 : ident_t sh_desc(pl_shader sh, struct pl_shader_desc sd)
     364                 :            : {
     365   [ +  +  -  - ]:       3122 :     switch (sd.desc.type) {
     366                 :         24 :     case PL_DESC_BUF_UNIFORM:
     367                 :            :     case PL_DESC_BUF_STORAGE:;
     368                 :         24 :         size_t bsize = sizeof(sd.buffer_vars[0]) * sd.num_buffer_vars;
     369                 :         24 :         sd.buffer_vars = sh_memdup(sh, sd.buffer_vars, bsize,
     370                 :            :                                    alignof(struct pl_buffer_var));
     371         [ +  + ]:        108 :         for (int i = 0; i < sd.num_buffer_vars; i++) {
     372                 :         84 :             struct pl_var *bv = &sd.buffer_vars[i].var;
     373                 :         84 :             const char *name = bv->name;
     374                 :         84 :             GLSLP("#define %s "$"\n", name, sh_fresh_name(sh, &bv->name));
     375                 :            :         }
     376                 :            :         break;
     377                 :            : 
     378                 :       3098 :     case PL_DESC_BUF_TEXEL_UNIFORM:
     379                 :            :     case PL_DESC_BUF_TEXEL_STORAGE:
     380                 :            :     case PL_DESC_SAMPLED_TEX:
     381                 :            :     case PL_DESC_STORAGE_IMG:
     382         [ -  + ]:       3098 :         pl_assert(!sd.num_buffer_vars);
     383                 :            :         break;
     384                 :            : 
     385                 :            :     case PL_DESC_INVALID:
     386                 :            :     case PL_DESC_TYPE_COUNT:
     387                 :          0 :         pl_unreachable();
     388                 :            :     }
     389                 :            : 
     390                 :            :     ident_t id = sh_fresh_name(sh, &sd.desc.name);
     391   [ +  +  -  +  :       3122 :     PL_ARRAY_APPEND(sh, sh->descs, sd);
                   -  + ]
     392                 :       3122 :     return id;
     393                 :            : }
     394                 :            : 
     395                 :       9555 : ident_t sh_const(pl_shader sh, struct pl_shader_const sc)
     396                 :            : {
     397   [ -  +  -  - ]:       9555 :     if (SH_PARAMS(sh).dynamic_constants && !sc.compile_time) {
     398                 :          0 :         return sh_var(sh, (struct pl_shader_var) {
     399                 :            :             .var = {
     400                 :            :                 .name = sc.name,
     401                 :            :                 .type = sc.type,
     402                 :            :                 .dim_v = 1,
     403                 :            :                 .dim_m = 1,
     404                 :            :                 .dim_a = 1,
     405                 :            :             },
     406                 :            :             .data = sc.data,
     407                 :            :         });
     408                 :            :     }
     409                 :            : 
     410                 :            :     ident_t id = sh_fresh_name(sh, &sc.name);
     411                 :            : 
     412                 :       9555 :     pl_gpu gpu = SH_GPU(sh);
     413   [ +  +  +  + ]:       9555 :     if (gpu && gpu->limits.max_constants) {
     414   [ +  +  +  + ]:       2575 :         if (!sc.compile_time || gpu->limits.array_size_constants) {
     415                 :       2571 :             size_t size = pl_var_type_size(sc.type);
     416                 :       2571 :             sc.data = sh_memdup(sh, sc.data, size, size);
     417   [ +  +  +  +  :       2571 :             PL_ARRAY_APPEND(sh, sh->consts, sc);
                   -  + ]
     418                 :       2571 :             return id;
     419                 :            :         }
     420                 :            :     }
     421                 :            : 
     422                 :            :     // Fallback for GPUs without specialization constants
     423   [ +  +  +  - ]:       6984 :     switch (sc.type) {
     424                 :            :     case PL_VAR_SINT:
     425                 :         74 :         GLSLH("const int "$" = %d; \n", id, *(int *) sc.data);
     426                 :         74 :         return id;
     427                 :            :     case PL_VAR_UINT:
     428                 :        196 :         GLSLH("const uint "$" = uint(%u); \n", id, *(unsigned int *) sc.data);
     429                 :        196 :         return id;
     430                 :            :     case PL_VAR_FLOAT:
     431                 :       6714 :         GLSLH("const float "$" = float(%f); \n", id, *(float *) sc.data);
     432                 :       6714 :         return id;
     433                 :            :     case PL_VAR_INVALID:
     434                 :            :     case PL_VAR_TYPE_COUNT:
     435                 :            :         break;
     436                 :            :     }
     437                 :            : 
     438                 :          0 :     pl_unreachable();
     439                 :            : }
     440                 :            : 
     441                 :        126 : ident_t sh_const_int(pl_shader sh, const char *name, int val)
     442                 :            : {
     443                 :        126 :     return sh_const(sh, (struct pl_shader_const) {
     444                 :            :         .type = PL_VAR_SINT,
     445                 :            :         .name = name,
     446                 :            :         .data = &val,
     447                 :            :     });
     448                 :            : }
     449                 :            : 
     450                 :        256 : ident_t sh_const_uint(pl_shader sh, const char *name, unsigned int val)
     451                 :            : {
     452                 :        256 :     return sh_const(sh, (struct pl_shader_const) {
     453                 :            :         .type = PL_VAR_UINT,
     454                 :            :         .name = name,
     455                 :            :         .data = &val,
     456                 :            :     });
     457                 :            : }
     458                 :            : 
     459                 :       9093 : ident_t sh_const_float(pl_shader sh, const char *name, float val)
     460                 :            : {
     461                 :       9093 :     return sh_const(sh, (struct pl_shader_const) {
     462                 :            :         .type = PL_VAR_FLOAT,
     463                 :            :         .name = name,
     464                 :            :         .data = &val,
     465                 :            :     });
     466                 :            : }
     467                 :            : 
     468                 :       4117 : ident_t sh_attr(pl_shader sh, struct pl_shader_va sva)
     469                 :            : {
     470                 :       4117 :     const size_t vsize = sva.attr.fmt->texel_size;
     471                 :       4117 :     uint8_t *data = sh_alloc(sh, vsize * 4, vsize);
     472         [ +  + ]:      20585 :     for (int i = 0; i < 4; i++) {
     473                 :      16468 :         memcpy(data, sva.data[i], vsize);
     474                 :      16468 :         sva.data[i] = data;
     475                 :      16468 :         data += vsize;
     476                 :            :     }
     477                 :            : 
     478                 :            :     ident_t id = sh_fresh_name(sh, &sva.attr.name);
     479   [ +  +  -  +  :       4117 :     PL_ARRAY_APPEND(sh, sh->vas, sva);
                   -  + ]
     480                 :       4117 :     return id;
     481                 :            : }
     482                 :            : 
     483                 :       4117 : ident_t sh_attr_vec2(pl_shader sh, const char *name, const pl_rect2df *rc)
     484                 :            : {
     485                 :       4117 :     pl_gpu gpu = SH_GPU(sh);
     486         [ -  + ]:       4117 :     if (!gpu) {
     487                 :          0 :         SH_FAIL(sh, "Failed adding vertex attr '%s': No GPU available!", name);
     488                 :          0 :         return NULL_IDENT;
     489                 :            :     }
     490                 :            : 
     491                 :       4117 :     pl_fmt fmt = pl_find_vertex_fmt(gpu, PL_FMT_FLOAT, 2);
     492         [ -  + ]:       4117 :     if (!fmt) {
     493                 :          0 :         SH_FAIL(sh, "Failed adding vertex attr '%s': no vertex fmt!", name);
     494                 :          0 :         return NULL_IDENT;
     495                 :            :     }
     496                 :            : 
     497                 :       4117 :     float verts[4][2] = {
     498                 :       4117 :         { rc->x0, rc->y0 },
     499                 :       4117 :         { rc->x1, rc->y0 },
     500                 :       4117 :         { rc->x0, rc->y1 },
     501                 :            :         { rc->x1, rc->y1 },
     502                 :            :     };
     503                 :            : 
     504                 :       4117 :     return sh_attr(sh, (struct pl_shader_va) {
     505                 :            :         .attr = {
     506                 :            :             .name     = name,
     507                 :            :             .fmt      = fmt,
     508                 :            :         },
     509                 :            :         .data = { verts[0], verts[1], verts[2], verts[3] },
     510                 :            :     });
     511                 :            : }
     512                 :            : 
     513         [ -  + ]:       2292 : ident_t sh_bind(pl_shader sh, pl_tex tex,
     514                 :            :                 enum pl_tex_address_mode address_mode,
     515                 :            :                 enum pl_tex_sample_mode sample_mode,
     516                 :            :                 const char *name, const pl_rect2df *rect,
     517                 :            :                 ident_t *out_pos, ident_t *out_pt)
     518                 :            : {
     519                 :            :     if (pl_tex_params_dimension(tex->params) != 2) {
     520                 :          0 :         SH_FAIL(sh, "Failed binding texture '%s': not a 2D texture!", name);
     521                 :          0 :         return NULL_IDENT;
     522                 :            :     }
     523                 :            : 
     524         [ -  + ]:       2292 :     if (!tex->params.sampleable) {
     525                 :          0 :         SH_FAIL(sh, "Failed binding texture '%s': texture not sampleable!", name);
     526                 :          0 :         return NULL_IDENT;
     527                 :            :     }
     528                 :            : 
     529                 :       2292 :     ident_t itex = sh_desc(sh, (struct pl_shader_desc) {
     530                 :            :         .desc = {
     531                 :            :             .name = name,
     532                 :            :             .type = PL_DESC_SAMPLED_TEX,
     533                 :            :         },
     534                 :            :         .binding = {
     535                 :            :             .object = tex,
     536                 :            :             .address_mode = address_mode,
     537                 :            :             .sample_mode = sample_mode,
     538                 :            :         },
     539                 :            :     });
     540                 :            : 
     541                 :            :     float sx, sy;
     542         [ +  - ]:       2292 :     if (tex->sampler_type == PL_SAMPLER_RECT) {
     543                 :            :         sx = 1.0;
     544                 :            :         sy = 1.0;
     545                 :            :     } else {
     546                 :       2292 :         sx = 1.0 / tex->params.w;
     547                 :       2292 :         sy = 1.0 / tex->params.h;
     548                 :            :     }
     549                 :            : 
     550         [ +  + ]:       2292 :     if (out_pos) {
     551                 :       2268 :         pl_rect2df full = {
     552                 :       2268 :             .x1 = tex->params.w,
     553                 :       2268 :             .y1 = tex->params.h,
     554                 :            :         };
     555                 :            : 
     556         [ +  + ]:       2268 :         rect = PL_DEF(rect, &full);
     557                 :       2268 :         *out_pos = sh_attr_vec2(sh, "tex_coord", &(pl_rect2df) {
     558                 :       2268 :             .x0 = sx * rect->x0, .y0 = sy * rect->y0,
     559                 :       2268 :             .x1 = sx * rect->x1, .y1 = sy * rect->y1,
     560                 :            :         });
     561                 :            :     }
     562                 :            : 
     563         [ +  + ]:       2292 :     if (out_pt) {
     564                 :        379 :         *out_pt = sh_var(sh, (struct pl_shader_var) {
     565                 :        379 :             .var  = pl_var_vec2("tex_pt"),
     566                 :        379 :             .data = &(float[2]) {sx, sy},
     567                 :            :         });
     568                 :            :     }
     569                 :            : 
     570                 :            :     return itex;
     571                 :            : }
     572                 :            : 
     573                 :        957 : bool sh_buf_desc_append(void *alloc, pl_gpu gpu,
     574                 :            :                         struct pl_shader_desc *buf_desc,
     575                 :            :                         struct pl_var_layout *out_layout,
     576                 :            :                         const struct pl_var new_var)
     577                 :            : {
     578                 :        957 :     struct pl_buffer_var bv = { .var = new_var };
     579                 :            :     size_t cur_size = sh_buf_desc_size(buf_desc);
     580                 :            : 
     581   [ +  +  -  - ]:        957 :     switch (buf_desc->desc.type) {
     582                 :        953 :     case PL_DESC_BUF_UNIFORM:
     583                 :        953 :         bv.layout = pl_std140_layout(cur_size, &new_var);
     584         [ -  + ]:        953 :         if (bv.layout.offset + bv.layout.size > gpu->limits.max_ubo_size)
     585                 :            :             return false;
     586                 :            :         break;
     587                 :          4 :     case PL_DESC_BUF_STORAGE:
     588                 :          4 :         bv.layout = pl_std430_layout(cur_size, &new_var);
     589         [ -  + ]:          4 :         if (bv.layout.offset + bv.layout.size > gpu->limits.max_ssbo_size)
     590                 :            :             return false;
     591                 :            :         break;
     592                 :            :     case PL_DESC_INVALID:
     593                 :            :     case PL_DESC_SAMPLED_TEX:
     594                 :            :     case PL_DESC_STORAGE_IMG:
     595                 :            :     case PL_DESC_BUF_TEXEL_UNIFORM:
     596                 :            :     case PL_DESC_BUF_TEXEL_STORAGE:
     597                 :            :     case PL_DESC_TYPE_COUNT:
     598                 :          0 :         pl_unreachable();
     599                 :            :     }
     600                 :            : 
     601         [ +  + ]:        957 :     if (out_layout)
     602                 :        949 :         *out_layout = bv.layout;
     603   [ +  +  +  +  :        957 :     PL_ARRAY_APPEND_RAW(alloc, buf_desc->buffer_vars, buf_desc->num_buffer_vars, bv);
                   -  + ]
     604                 :        957 :     return true;
     605                 :            : }
     606                 :            : 
     607                 :       1949 : size_t sh_buf_desc_size(const struct pl_shader_desc *buf_desc)
     608                 :            : {
     609   [ +  +  +  + ]:       2906 :     if (!buf_desc->num_buffer_vars)
     610                 :            :         return 0;
     611                 :            : 
     612                 :            :     const struct pl_buffer_var *last;
     613                 :        957 :     last = &buf_desc->buffer_vars[buf_desc->num_buffer_vars - 1];
     614                 :        957 :     return last->layout.offset + last->layout.size;
     615                 :            : }
     616                 :            : 
     617                 :       1119 : void sh_describef(pl_shader sh, const char *fmt, ...)
     618                 :            : {
     619                 :            :     va_list ap;
     620                 :       1119 :     va_start(ap, fmt);
     621                 :       1119 :     sh_describe(sh, pl_vasprintf(sh->info->tmp, fmt, ap));
     622                 :       1119 :     va_end(ap);
     623                 :       1119 : }
     624                 :            : 
     625                 :            : static const char *insigs[] = {
     626                 :            :     [PL_SHADER_SIG_NONE]  = "",
     627                 :            :     [PL_SHADER_SIG_COLOR] = "vec4 color",
     628                 :            : };
     629                 :            : 
     630                 :            : static const char *outsigs[] = {
     631                 :            :     [PL_SHADER_SIG_NONE]  = "void",
     632                 :            :     [PL_SHADER_SIG_COLOR] = "vec4",
     633                 :            : };
     634                 :            : 
     635                 :            : static const char *retvals[] = {
     636                 :            :     [PL_SHADER_SIG_NONE]  = "",
     637                 :            :     [PL_SHADER_SIG_COLOR] = "return color;",
     638                 :            : };
     639                 :            : 
     640                 :            : // libplacebo currently only allows 2D samplers for shader signatures
     641                 :            : static const char *samplers2D[] = {
     642                 :            :     [PL_SAMPLER_NORMAL]     = "sampler2D",
     643                 :            :     [PL_SAMPLER_RECT]       = "sampler2DRect",
     644                 :            :     [PL_SAMPLER_EXTERNAL]   = "samplerExternalOES",
     645                 :            : };
     646                 :            : 
     647                 :        843 : ident_t sh_subpass(pl_shader sh, pl_shader sub)
     648                 :            : {
     649         [ -  + ]:        843 :     pl_assert(sh->mutable);
     650                 :            : 
     651         [ -  + ]:        843 :     if (sh->prefix == sub->prefix) {
     652                 :          0 :         PL_TRACE(sh, "Can't merge shaders: conflicting identifiers!");
     653                 :          0 :         return NULL_IDENT;
     654                 :            :     }
     655                 :            : 
     656                 :            :     // Check for shader compatibility
     657         [ +  - ]:        843 :     int res_w = PL_DEF(sh->output_w, sub->output_w),
     658         [ +  - ]:        843 :         res_h = PL_DEF(sh->output_h, sub->output_h);
     659                 :            : 
     660   [ +  +  +  - ]:        843 :     if ((sub->output_w && res_w != sub->output_w) ||
     661   [ +  +  -  + ]:        843 :         (sub->output_h && res_h != sub->output_h))
     662                 :            :     {
     663                 :          0 :         PL_TRACE(sh, "Can't merge shaders: incompatible sizes: %dx%d and %dx%d",
     664                 :            :                  sh->output_w, sh->output_h, sub->output_w, sub->output_h);
     665                 :          0 :         return NULL_IDENT;
     666                 :            :     }
     667                 :            : 
     668         [ +  + ]:        843 :     if (sub->type == SH_COMPUTE) {
     669                 :          4 :         int subw = sub->group_size[0],
     670                 :          4 :             subh = sub->group_size[1];
     671                 :          4 :         bool flex = sub->flexible_work_groups;
     672                 :            : 
     673         [ -  + ]:          4 :         if (!sh_try_compute(sh, subw, subh, flex, sub->shmem)) {
     674                 :          0 :             PL_TRACE(sh, "Can't merge shaders: incompatible block sizes or "
     675                 :            :                      "exceeded shared memory resource capabilities");
     676                 :          0 :             return NULL_IDENT;
     677                 :            :         }
     678                 :            :     }
     679                 :            : 
     680                 :        843 :     sh->output_w = res_w;
     681                 :        843 :     sh->output_h = res_h;
     682                 :            : 
     683                 :            :     // Append the prelude and header
     684                 :        843 :     pl_str_builder_concat(sh->buffers[SH_BUF_PRELUDE], sub->buffers[SH_BUF_PRELUDE]);
     685                 :        843 :     pl_str_builder_concat(sh->buffers[SH_BUF_HEADER], sub->buffers[SH_BUF_HEADER]);
     686                 :            : 
     687                 :            :     // Append the body as a new header function
     688         [ -  + ]:        843 :     if (sub->input == PL_SHADER_SIG_SAMPLER) {
     689         [ #  # ]:          0 :         pl_assert(sub->sampler_prefix);
     690                 :          0 :         GLSLH("%s "$"(%c%s src_tex, vec2 tex_coord) {\n",
     691                 :            :               outsigs[sub->output], sub->name,
     692                 :            :               sub->sampler_prefix, samplers2D[sub->sampler_type]);
     693                 :            :     } else {
     694                 :        843 :         GLSLH("%s "$"(%s) {\n",
     695                 :            :               outsigs[sub->output], sub->name, insigs[sub->input]);
     696                 :            :     }
     697                 :        843 :     pl_str_builder_concat(sh->buffers[SH_BUF_HEADER], sub->buffers[SH_BUF_BODY]);
     698                 :        843 :     GLSLH("%s\n}\n\n", retvals[sub->output]);
     699                 :            : 
     700                 :            :     // Steal all inputs and objects from the subpass
     701                 :            : #define ARRAY_STEAL(arr) do                 \
     702                 :            : {                                           \
     703                 :            :     PL_ARRAY_CONCAT(sh, sh->arr, sub->arr); \
     704                 :            :     sub->arr.num = 0;                       \
     705                 :            : } while (0)
     706                 :            : 
     707   [ +  +  -  + ]:        843 :     ARRAY_STEAL(obj);
     708   [ +  +  +  + ]:        843 :     ARRAY_STEAL(vas);
     709   [ +  +  -  + ]:        843 :     ARRAY_STEAL(vars);
     710   [ +  +  +  + ]:        843 :     ARRAY_STEAL(descs);
     711   [ +  +  -  + ]:        843 :     ARRAY_STEAL(consts);
     712                 :            : #undef ARRAY_STEAL
     713                 :            : 
     714                 :            :     // Steal the scratch buffer (if it holds data)
     715         [ +  + ]:        843 :     if (sub->data.len) {
     716                 :        817 :         pl_steal(sh->tmp, sub->data.buf);
     717                 :        817 :         sub->data = (pl_str) {0};
     718                 :            :     }
     719                 :            : 
     720                 :            :     // Steal all temporary allocations and mark the child as unusable
     721                 :        843 :     pl_steal(sh->tmp, sub->tmp);
     722                 :        843 :     sub->tmp = pl_tmp(sub);
     723                 :        843 :     sub->failed = true;
     724                 :            : 
     725                 :            :     // Steal the shader steps array (and allocations)
     726         [ -  + ]:        843 :     pl_assert(pl_rc_count(&sub->info->rc) == 1);
     727   [ +  +  -  + ]:        843 :     PL_ARRAY_CONCAT(sh->info, sh->info->steps, sub->info->steps);
     728                 :        843 :     pl_steal(sh->info->tmp, sub->info->tmp);
     729                 :        843 :     sub->info->tmp = pl_tmp(sub->info);
     730                 :        843 :     sub->info->steps.num = 0; // sanity
     731                 :            : 
     732                 :        843 :     return sub->name;
     733                 :            : }
     734                 :            : 
     735                 :       1951 : pl_str_builder sh_finalize_internal(pl_shader sh)
     736                 :            : {
     737         [ -  + ]:       1951 :     pl_assert(sh->mutable); // this function should only ever be called once
     738         [ +  - ]:       1951 :     if (sh->failed)
     739                 :            :         return NULL;
     740                 :            : 
     741                 :            :     // Padding for readability
     742                 :       1951 :     GLSLP("\n");
     743                 :            : 
     744                 :            :     // Concatenate everything onto the prelude to form the final output
     745                 :       1951 :     pl_str_builder_concat(sh->buffers[SH_BUF_PRELUDE], sh->buffers[SH_BUF_HEADER]);
     746                 :            : 
     747         [ +  + ]:       1951 :     if (sh->input == PL_SHADER_SIG_SAMPLER) {
     748         [ -  + ]:          1 :         pl_assert(sh->sampler_prefix);
     749                 :          1 :         GLSLP("%s "$"(%c%s src_tex, vec2 tex_coord) {\n",
     750                 :            :               outsigs[sh->output], sh->name,
     751                 :            :               sh->sampler_prefix,
     752                 :            :               samplers2D[sh->sampler_type]);
     753                 :            :     } else {
     754                 :       1950 :         GLSLP("%s "$"(%s) {\n", outsigs[sh->output], sh->name, insigs[sh->input]);
     755                 :            :     }
     756                 :            : 
     757                 :       1951 :     pl_str_builder_concat(sh->buffers[SH_BUF_PRELUDE], sh->buffers[SH_BUF_BODY]);
     758                 :       1951 :     pl_str_builder_concat(sh->buffers[SH_BUF_PRELUDE], sh->buffers[SH_BUF_FOOTER]);
     759                 :       1951 :     GLSLP("%s\n}\n\n", retvals[sh->output]);
     760                 :            : 
     761                 :            :     // Generate the shader info
     762                 :       1951 :     struct sh_info *info = sh->info;
     763                 :       1951 :     info->info.steps = info->steps.elem;
     764                 :       1951 :     info->info.num_steps = info->steps.num;
     765                 :       1951 :     info->info.description = "(unknown shader)";
     766                 :            : 
     767                 :            :     // Generate pretty description
     768         [ +  + ]:       5318 :     for (int i = 0; i < info->steps.num; i++) {
     769                 :       3367 :         const char *step = info->steps.elem[i];
     770                 :            : 
     771                 :            :         // Prevent duplicates. We're okay using a weak equality check here
     772                 :            :         // because most pass descriptions are static strings.
     773         [ +  + ]:       5186 :         for (int j = 0; j < i; j++) {
     774         [ +  + ]:       1887 :             if (info->steps.elem[j] == step)
     775                 :         68 :                 goto next_step;
     776                 :            :         }
     777                 :            : 
     778                 :            :         int count = 1;
     779         [ +  + ]:       5198 :         for (int j = i+1; j < info->steps.num; j++) {
     780         [ +  + ]:       1899 :             if (info->steps.elem[j] == step)
     781                 :         68 :                 count++;
     782                 :            :         }
     783                 :            : 
     784         [ +  + ]:       3299 :         const char *prefix = i > 0 ? ", " : "";
     785         [ +  + ]:       3299 :         if (count > 1) {
     786                 :         36 :             pl_str_append_asprintf(info, &info->desc, "%s%s x%d",
     787                 :            :                                    prefix, step, count);
     788                 :            :         } else {
     789                 :       3263 :             pl_str_append_asprintf(info, &info->desc, "%s%s", prefix, step);
     790                 :            :         }
     791                 :            : 
     792                 :       3367 : next_step: ;
     793                 :            :     }
     794                 :            : 
     795         [ +  + ]:       1951 :     if (info->desc.len)
     796                 :       1902 :         info->info.description = (char *) info->desc.buf;
     797                 :            : 
     798                 :       1951 :     sh->mutable = false;
     799                 :       1951 :     return sh->buffers[SH_BUF_PRELUDE];
     800                 :            : }
     801                 :            : 
     802                 :          6 : const struct pl_shader_res *pl_shader_finalize(pl_shader sh)
     803                 :            : {
     804         [ +  - ]:          6 :     if (sh->failed) {
     805                 :            :         return NULL;
     806         [ -  + ]:          6 :     } else if (!sh->mutable) {
     807                 :          0 :         return &sh->result;
     808                 :            :     }
     809                 :            : 
     810                 :          6 :     pl_shader_info info = &sh->info->info;
     811                 :          6 :     pl_str_builder glsl = sh_finalize_internal(sh);
     812                 :            : 
     813                 :            :     // Turn ident_t into friendly strings before passing it to users
     814                 :            : #define FIX_IDENT(name) \
     815                 :            :     name = sh_ident_tostr(sh_ident_unpack(name))
     816         [ +  + ]:          7 :     for (int i = 0; i < sh->vas.num; i++)
     817         [ -  + ]:          1 :         FIX_IDENT(sh->vas.elem[i].attr.name);
     818         [ +  + ]:          8 :     for (int i = 0; i < sh->vars.num; i++)
     819         [ -  + ]:          2 :         FIX_IDENT(sh->vars.elem[i].var.name);
     820         [ +  + ]:         24 :     for (int i = 0; i < sh->consts.num; i++)
     821         [ -  + ]:         18 :         FIX_IDENT(sh->consts.elem[i].name);
     822         [ +  + ]:         12 :     for (int i = 0; i < sh->descs.num; i++) {
     823                 :          6 :         struct pl_shader_desc *sd = &sh->descs.elem[i];
     824         [ -  + ]:          6 :         FIX_IDENT(sd->desc.name);
     825         [ -  + ]:          6 :         for (int j = 0; j < sd->num_buffer_vars; j++)
     826         [ #  # ]:          0 :             FIX_IDENT(sd->buffer_vars[j].var.name);
     827                 :            :     }
     828                 :            : #undef FIX_IDENT
     829                 :            : 
     830                 :          6 :     sh->result = (struct pl_shader_res) {
     831                 :            :         .info               = info,
     832                 :          6 :         .glsl               = (char *) pl_str_builder_exec(glsl).buf,
     833                 :          6 :         .name               = sh_ident_tostr(sh->name),
     834                 :          6 :         .input              = sh->input,
     835                 :          6 :         .output             = sh->output,
     836                 :          6 :         .compute_group_size = { sh->group_size[0], sh->group_size[1] },
     837                 :          6 :         .compute_shmem      = sh->shmem,
     838                 :          6 :         .vertex_attribs     = sh->vas.elem,
     839                 :          6 :         .num_vertex_attribs = sh->vas.num,
     840                 :          6 :         .variables          = sh->vars.elem,
     841                 :          6 :         .num_variables      = sh->vars.num,
     842                 :          6 :         .descriptors        = sh->descs.elem,
     843                 :          6 :         .num_descriptors    = sh->descs.num,
     844                 :          6 :         .constants          = sh->consts.elem,
     845                 :          6 :         .num_constants      = sh->consts.num,
     846                 :            :         // deprecated fields
     847                 :            :         .params             = info->params,
     848                 :          6 :         .steps              = info->steps,
     849                 :          6 :         .num_steps          = info->num_steps,
     850                 :          6 :         .description        = info->description,
     851                 :            :     };
     852                 :            : 
     853                 :          6 :     return &sh->result;
     854                 :            : }
     855                 :            : 
     856                 :       7047 : bool sh_require(pl_shader sh, enum pl_shader_sig insig, int w, int h)
     857                 :            : {
     858         [ -  + ]:       7047 :     if (sh->failed) {
     859                 :          0 :         SH_FAIL(sh, "Attempting to modify a failed shader!");
     860                 :          0 :         return false;
     861                 :            :     }
     862                 :            : 
     863         [ -  + ]:       7047 :     if (!sh->mutable) {
     864                 :          0 :         SH_FAIL(sh, "Attempted to modify an immutable shader!");
     865                 :          0 :         return false;
     866                 :            :     }
     867                 :            : 
     868   [ +  +  -  +  :       7047 :     if ((w && sh->output_w && sh->output_w != w) ||
             -  -  +  + ]
     869   [ -  +  -  - ]:        400 :         (h && sh->output_h && sh->output_h != h))
     870                 :            :     {
     871                 :          0 :         SH_FAIL(sh, "Illegal sequence of shader operations: Incompatible "
     872                 :            :                 "output size requirements %dx%d and %dx%d",
     873                 :            :                 sh->output_w, sh->output_h, w, h);
     874                 :          0 :         return false;
     875                 :            :     }
     876                 :            : 
     877                 :            :     static const char *names[] = {
     878                 :            :         [PL_SHADER_SIG_NONE]  = "PL_SHADER_SIG_NONE",
     879                 :            :         [PL_SHADER_SIG_COLOR] = "PL_SHADER_SIG_COLOR",
     880                 :            :     };
     881                 :            : 
     882                 :            :     // If we require an input, but there is none available - just get it from
     883                 :            :     // the user by turning it into an explicit input signature.
     884   [ +  +  +  + ]:       7047 :     if (!sh->output && insig) {
     885         [ -  + ]:         41 :         pl_assert(!sh->input);
     886                 :         41 :         sh->input = insig;
     887         [ -  + ]:       7006 :     } else if (sh->output != insig) {
     888                 :          0 :         SH_FAIL(sh, "Illegal sequence of shader operations! Current output "
     889                 :            :                 "signature is '%s', but called operation expects '%s'!",
     890                 :            :                 names[sh->output], names[insig]);
     891                 :          0 :         return false;
     892                 :            :     }
     893                 :            : 
     894                 :            :     // All of our shaders end up returning a vec4 color
     895                 :       7047 :     sh->output = PL_SHADER_SIG_COLOR;
     896         [ +  + ]:       7047 :     sh->output_w = PL_DEF(sh->output_w, w);
     897         [ +  + ]:       7047 :     sh->output_h = PL_DEF(sh->output_h, h);
     898                 :       7047 :     return true;
     899                 :            : }
     900                 :            : 
     901                 :       2110 : static void sh_obj_deref(pl_shader_obj obj)
     902                 :            : {
     903         [ +  + ]:       2110 :     if (!pl_rc_deref(&obj->rc))
     904                 :            :         return;
     905                 :            : 
     906         [ +  - ]:        132 :     if (obj->uninit)
     907                 :        132 :         obj->uninit(obj->gpu, obj->priv);
     908                 :            : 
     909                 :        132 :     pl_free(obj);
     910                 :            : }
     911                 :            : 
     912                 :        408 : void pl_shader_obj_destroy(pl_shader_obj *ptr)
     913                 :            : {
     914                 :        408 :     pl_shader_obj obj = *ptr;
     915         [ +  + ]:        408 :     if (!obj)
     916                 :            :         return;
     917                 :            : 
     918                 :        132 :     sh_obj_deref(obj);
     919                 :        132 :     *ptr = NULL;
     920                 :            : }
     921                 :            : 
     922                 :       1978 : void *sh_require_obj(pl_shader sh, pl_shader_obj *ptr,
     923                 :            :                      enum pl_shader_obj_type type, size_t priv_size,
     924                 :            :                      void (*uninit)(pl_gpu gpu, void *priv))
     925                 :            : {
     926         [ -  + ]:       1978 :     if (!ptr)
     927                 :            :         return NULL;
     928                 :            : 
     929                 :       1978 :     pl_shader_obj obj = *ptr;
     930   [ +  +  -  + ]:       1978 :     if (obj && obj->gpu != SH_GPU(sh)) {
     931                 :          0 :         SH_FAIL(sh, "Passed pl_shader_obj belongs to different GPU!");
     932                 :          0 :         return NULL;
     933                 :            :     }
     934                 :            : 
     935         [ -  + ]:       1846 :     if (obj && obj->type != type) {
     936                 :          0 :         SH_FAIL(sh, "Passed pl_shader_obj of wrong type! Shader objects must "
     937                 :            :                 "always be used with the same type of shader.");
     938                 :          0 :         return NULL;
     939                 :            :     }
     940                 :            : 
     941                 :            :     if (!obj) {
     942                 :        132 :         obj = pl_zalloc_ptr(NULL, obj);
     943                 :        132 :         pl_rc_init(&obj->rc);
     944                 :        132 :         obj->gpu = SH_GPU(sh);
     945                 :        132 :         obj->type = type;
     946                 :        132 :         obj->priv = pl_zalloc(obj, priv_size);
     947                 :        132 :         obj->uninit = uninit;
     948                 :            :     }
     949                 :            : 
     950   [ +  +  -  +  :       1978 :     PL_ARRAY_APPEND(sh, sh->obj, obj);
                   -  + ]
     951                 :       1978 :     pl_rc_ref(&obj->rc);
     952                 :            : 
     953                 :       1978 :     *ptr = obj;
     954                 :       1978 :     return obj->priv;
     955                 :            : }
     956                 :            : 
     957                 :         40 : ident_t sh_prng(pl_shader sh, bool temporal, ident_t *p_state)
     958                 :            : {
     959                 :         40 :     ident_t randfun = sh_fresh(sh, "rand"),
     960                 :         40 :             state = sh_fresh(sh, "state");
     961                 :            : 
     962                 :            :     // Based on pcg3d (http://jcgt.org/published/0009/03/02/)
     963                 :         40 :     GLSLP("#define prng_t uvec3\n");
     964                 :         40 :     GLSLH("vec3 "$"(inout uvec3 s) {                    \n"
     965                 :            :           "    s = 1664525u * s + uvec3(1013904223u);   \n"
     966                 :            :           "    s.x += s.y * s.z;                        \n"
     967                 :            :           "    s.y += s.z * s.x;                        \n"
     968                 :            :           "    s.z += s.x * s.y;                        \n"
     969                 :            :           "    s ^= s >> 16u;                           \n"
     970                 :            :           "    s.x += s.y * s.z;                        \n"
     971                 :            :           "    s.y += s.z * s.x;                        \n"
     972                 :            :           "    s.z += s.x * s.y;                        \n"
     973                 :            :           "    return vec3(s) * 1.0/float(0xFFFFFFFFu); \n"
     974                 :            :           "}                                            \n",
     975                 :            :           randfun);
     976                 :            : 
     977         [ +  + ]:         40 :     if (temporal) {
     978                 :         36 :         GLSL("uvec3 "$" = uvec3(gl_FragCoord.xy, "$"); \n",
     979                 :            :              state, SH_UINT_DYN(SH_PARAMS(sh).index));
     980                 :            :     } else {
     981                 :          4 :         GLSL("uvec3 "$" = uvec3(gl_FragCoord.xy, 0.0); \n", state);
     982                 :            :     }
     983                 :            : 
     984         [ -  + ]:         40 :     if (p_state)
     985                 :          0 :         *p_state = state;
     986                 :            : 
     987                 :         40 :     ident_t res = sh_fresh(sh, "RAND");
     988                 :         40 :     GLSLH("#define "$" ("$"("$"))\n", res, randfun, state);
     989                 :         40 :     return res;
     990                 :            : }

Generated by: LCOV version 1.16