LCOV - code coverage report
Current view: top level - src - gpu.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 548 631 86.8 %
Date: 2025-03-29 09:04:10 Functions: 58 74 78.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 495 832 59.5 %

           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 "common.h"
      19                 :            : #include "gpu.h"
      20                 :            : 
      21                 :            : #define require(expr) pl_require(gpu, expr)
      22                 :            : 
      23                 :          9 : void pl_gpu_destroy(pl_gpu gpu)
      24                 :            : {
      25         [ +  - ]:          9 :     if (!gpu)
      26                 :            :         return;
      27                 :            : 
      28                 :          9 :     struct pl_gpu_fns *impl = PL_PRIV(gpu);
      29                 :          9 :     pl_dispatch_destroy(&impl->dp);
      30                 :          9 :     impl->destroy(gpu);
      31                 :            : }
      32                 :            : 
      33                 :         26 : pl_dispatch pl_gpu_dispatch(pl_gpu gpu)
      34                 :            : {
      35                 :         26 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
      36                 :         26 :     return impl->dp;
      37                 :            : }
      38                 :            : 
      39                 :        950 : pl_cache pl_gpu_cache(pl_gpu gpu)
      40                 :            : {
      41         [ +  + ]:        950 :     if (!gpu)
      42                 :            :         return NULL;
      43                 :        949 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
      44                 :        949 :     return atomic_load(&impl->cache);
      45                 :            : }
      46                 :            : 
      47                 :          4 : void pl_gpu_set_cache(pl_gpu gpu, pl_cache cache)
      48                 :            : {
      49                 :          4 :     struct pl_gpu_fns *impl = PL_PRIV(gpu);
      50                 :          4 :     atomic_store(&impl->cache, cache);
      51                 :          4 : }
      52                 :            : 
      53                 :       4840 : bool pl_fmt_is_ordered(pl_fmt fmt)
      54                 :            : {
      55                 :       4840 :     bool ret = !fmt->opaque;
      56         [ +  + ]:      15011 :     for (int i = 0; i < fmt->num_components; i++)
      57                 :      10171 :         ret &= fmt->sample_order[i] == i;
      58                 :       4840 :     return ret;
      59                 :            : }
      60                 :            : 
      61                 :        174 : bool pl_fmt_is_float(pl_fmt fmt)
      62                 :            : {
      63      [ -  -  + ]:        174 :     switch (fmt->type) {
      64                 :            :     case PL_FMT_UNKNOWN: // more likely than not
      65                 :            :     case PL_FMT_FLOAT:
      66                 :            :     case PL_FMT_UNORM:
      67                 :            :     case PL_FMT_SNORM:
      68                 :            :         return true;
      69                 :            : 
      70                 :          0 :     case PL_FMT_UINT:
      71                 :            :     case PL_FMT_SINT:
      72                 :          0 :         return false;
      73                 :            : 
      74                 :            :     case PL_FMT_TYPE_COUNT:
      75                 :            :         break;
      76                 :            :     }
      77                 :            : 
      78                 :          0 :     pl_unreachable();
      79                 :            : }
      80                 :            : 
      81                 :          0 : bool pl_fmt_has_modifier(pl_fmt fmt, uint64_t modifier)
      82                 :            : {
      83         [ #  # ]:          0 :     if (!fmt)
      84                 :            :         return false;
      85                 :            : 
      86         [ #  # ]:          0 :     for (int i = 0; i < fmt->num_modifiers; i++) {
      87         [ #  # ]:          0 :         if (fmt->modifiers[i] == modifier)
      88                 :            :             return true;
      89                 :            :     }
      90                 :            : 
      91                 :            :     return false;
      92                 :            : }
      93                 :            : 
      94                 :       9204 : pl_fmt pl_find_fmt(pl_gpu gpu, enum pl_fmt_type type, int num_components,
      95                 :            :                     int min_depth, int host_bits, enum pl_fmt_caps caps)
      96                 :            : {
      97         [ +  + ]:     147801 :     for (int n = 0; n < gpu->num_formats; n++) {
      98                 :     147251 :         pl_fmt fmt = gpu->formats[n];
      99   [ +  +  +  + ]:     147251 :         if (fmt->type != type || fmt->num_components != num_components)
     100                 :     131974 :             continue;
     101         [ +  + ]:      15277 :         if ((fmt->caps & caps) != caps)
     102                 :       4735 :             continue;
     103                 :            : 
     104                 :            :         // When specifying some particular host representation, ensure the
     105                 :            :         // format is non-opaque, ordered and unpadded
     106   [ +  +  -  + ]:      10542 :         if (host_bits && fmt->opaque)
     107                 :          0 :             continue;
     108         [ +  + ]:       6723 :         if (host_bits && fmt->texel_size * 8 != host_bits * num_components)
     109                 :       1883 :             continue;
     110   [ +  +  -  + ]:       8659 :         if (host_bits && !pl_fmt_is_ordered(fmt))
     111                 :          0 :             continue;
     112                 :            : 
     113         [ +  + ]:      28087 :         for (int i = 0; i < fmt->num_components; i++) {
     114         [ +  + ]:      19433 :             if (fmt->component_depth[i] < min_depth)
     115                 :          5 :                 goto next_fmt;
     116   [ +  +  -  + ]:      19428 :             if (host_bits && fmt->host_bits[i] != host_bits)
     117                 :          0 :                 goto next_fmt;
     118                 :            :         }
     119                 :            : 
     120                 :            :         return fmt;
     121                 :            : 
     122                 :     138597 : next_fmt: ; // equivalent to `continue`
     123                 :            :     }
     124                 :            : 
     125                 :            :     // ran out of formats
     126                 :        550 :     PL_TRACE(gpu, "No matching format found");
     127                 :        550 :     return NULL;
     128                 :            : }
     129                 :            : 
     130                 :       4154 : pl_fmt pl_find_vertex_fmt(pl_gpu gpu, enum pl_fmt_type type, int comps)
     131                 :            : {
     132                 :            :     static const size_t sizes[] = {
     133                 :            :         [PL_FMT_FLOAT] = sizeof(float),
     134                 :            :         [PL_FMT_UNORM] = sizeof(unsigned),
     135                 :            :         [PL_FMT_UINT]  = sizeof(unsigned),
     136                 :            :         [PL_FMT_SNORM] = sizeof(int),
     137                 :            :         [PL_FMT_SINT]  = sizeof(int),
     138                 :            :     };
     139                 :            : 
     140                 :       4154 :     return pl_find_fmt(gpu, type, comps, 0, 8 * sizes[type], PL_FMT_CAP_VERTEX);
     141                 :            : }
     142                 :            : 
     143                 :          6 : pl_fmt pl_find_named_fmt(pl_gpu gpu, const char *name)
     144                 :            : {
     145         [ +  - ]:          6 :     if (!name)
     146                 :            :         return NULL;
     147                 :            : 
     148         [ +  + ]:        208 :     for (int i = 0; i < gpu->num_formats; i++) {
     149                 :        204 :         pl_fmt fmt = gpu->formats[i];
     150         [ +  + ]:        204 :         if (strcmp(name, fmt->name) == 0)
     151                 :          2 :             return fmt;
     152                 :            :     }
     153                 :            : 
     154                 :            :     // ran out of formats
     155                 :            :     return NULL;
     156                 :            : }
     157                 :            : 
     158                 :          0 : pl_fmt pl_find_fourcc(pl_gpu gpu, uint32_t fourcc)
     159                 :            : {
     160         [ #  # ]:          0 :     if (!fourcc)
     161                 :            :         return NULL;
     162                 :            : 
     163         [ #  # ]:          0 :     for (int i = 0; i < gpu->num_formats; i++) {
     164                 :          0 :         pl_fmt fmt = gpu->formats[i];
     165         [ #  # ]:          0 :         if (fourcc == fmt->fourcc)
     166                 :          0 :             return fmt;
     167                 :            :     }
     168                 :            : 
     169                 :            :     // ran out of formats
     170                 :            :     return NULL;
     171                 :            : }
     172                 :            : 
     173                 :          6 : static inline bool check_mod(pl_gpu gpu, pl_fmt fmt, uint64_t mod)
     174                 :            : {
     175         [ +  - ]:         22 :     for (int i = 0; i < fmt->num_modifiers; i++) {
     176         [ +  + ]:         22 :         if (fmt->modifiers[i] == mod)
     177                 :            :             return true;
     178                 :            :     }
     179                 :            : 
     180                 :            : 
     181                 :          0 :     PL_ERR(gpu, "DRM modifier %s not available for format %s. Available modifiers:",
     182                 :            :            PRINT_DRM_MOD(mod), fmt->name);
     183         [ #  # ]:          0 :     for (int i = 0; i < fmt->num_modifiers; i++)
     184                 :          0 :         PL_ERR(gpu, "    %s", PRINT_DRM_MOD(fmt->modifiers[i]));
     185                 :            : 
     186                 :            :     return false;
     187                 :            : }
     188                 :            : 
     189                 :       2022 : pl_tex pl_tex_create(pl_gpu gpu, const struct pl_tex_params *params)
     190                 :            : {
     191         [ -  + ]:       2022 :     require(params->format);
     192   [ +  +  -  + ]:       2022 :     require(!params->import_handle || !params->export_handle);
     193   [ +  +  -  + ]:       2022 :     require(!params->import_handle || !params->initial_data);
     194         [ +  + ]:       2022 :     if (params->export_handle) {
     195         [ -  + ]:         10 :         require(params->export_handle & gpu->export_caps.tex);
     196         [ -  + ]:         10 :         require(PL_ISPOT(params->export_handle));
     197                 :            :     }
     198         [ +  + ]:       2022 :     if (params->import_handle) {
     199         [ -  + ]:          6 :         require(params->import_handle & gpu->import_caps.tex);
     200         [ -  + ]:          6 :         require(PL_ISPOT(params->import_handle));
     201         [ +  - ]:          6 :         if (params->import_handle == PL_HANDLE_DMA_BUF) {
     202         [ -  + ]:          6 :             if (!check_mod(gpu, params->format, params->shared_mem.drm_format_mod))
     203                 :          0 :                 goto error;
     204         [ +  - ]:          6 :             if (params->shared_mem.stride_w)
     205   [ +  -  -  + ]:          6 :                 require(params->w && params->shared_mem.stride_w >= params->w);
     206         [ -  + ]:          6 :             if (params->shared_mem.stride_h)
     207   [ #  #  #  # ]:          0 :                 require(params->h && params->shared_mem.stride_h >= params->h);
     208         [ #  # ]:          0 :         } else if (params->import_handle == PL_HANDLE_MTL_TEX) {
     209         [ #  # ]:          0 :             require(params->shared_mem.plane <= 2);
     210                 :            :         }
     211                 :            :     }
     212                 :            : 
     213                 :            :     switch (pl_tex_params_dimension(*params)) {
     214                 :            :     case 1:
     215         [ -  + ]:        591 :         require(params->w > 0);
     216         [ -  + ]:        591 :         require(params->w <= gpu->limits.max_tex_1d_dim);
     217         [ -  + ]:        591 :         require(!params->renderable);
     218   [ +  +  -  + ]:        591 :         require(!params->blit_src || gpu->limits.blittable_1d_3d);
     219   [ +  +  -  + ]:        591 :         require(!params->blit_dst || gpu->limits.blittable_1d_3d);
     220         [ -  + ]:        591 :         require(!params->format->num_planes);
     221                 :            :         break;
     222                 :            :     case 2:
     223   [ +  -  -  + ]:        872 :         require(params->w > 0 && params->h > 0);
     224         [ -  + ]:        872 :         require(params->w <= gpu->limits.max_tex_2d_dim);
     225         [ -  + ]:        872 :         require(params->h <= gpu->limits.max_tex_2d_dim);
     226                 :            :         break;
     227                 :            :     case 3:
     228   [ +  -  +  -  :        559 :         require(params->w > 0 && params->h > 0 && params->d > 0);
                   -  + ]
     229         [ -  + ]:        559 :         require(params->w <= gpu->limits.max_tex_3d_dim);
     230         [ -  + ]:        559 :         require(params->h <= gpu->limits.max_tex_3d_dim);
     231         [ -  + ]:        559 :         require(params->d <= gpu->limits.max_tex_3d_dim);
     232         [ -  + ]:        559 :         require(!params->renderable);
     233   [ +  +  -  + ]:        559 :         require(!params->blit_src || gpu->limits.blittable_1d_3d);
     234   [ +  +  -  + ]:        559 :         require(!params->blit_dst || gpu->limits.blittable_1d_3d);
     235         [ -  + ]:        559 :         require(!params->format->num_planes);
     236                 :            :         break;
     237                 :            :     }
     238                 :            : 
     239                 :       2022 :     enum pl_fmt_caps fmt_caps = params->format->caps;
     240                 :       2022 :     bool fmt_opaque = params->format->opaque;
     241         [ +  + ]:       2025 :     for (int i = 0; i < params->format->num_planes; i++) {
     242                 :          3 :         pl_fmt pfmt = params->format->planes[i].format;
     243                 :          3 :         fmt_caps |= pfmt->caps;
     244                 :          3 :         fmt_opaque &= pfmt->opaque;
     245                 :            :     }
     246                 :            : 
     247   [ +  +  -  + ]:       2022 :     require(!params->host_readable || fmt_caps & PL_FMT_CAP_HOST_READABLE);
     248   [ +  +  -  + ]:       2022 :     require(!params->host_writable || !fmt_opaque);
     249   [ +  +  -  + ]:       2022 :     require(!params->sampleable || fmt_caps & PL_FMT_CAP_SAMPLEABLE);
     250   [ +  +  -  + ]:       2022 :     require(!params->renderable || fmt_caps & PL_FMT_CAP_RENDERABLE);
     251   [ +  +  -  + ]:       2022 :     require(!params->storable   || fmt_caps & PL_FMT_CAP_STORABLE);
     252   [ +  +  -  + ]:       2022 :     require(!params->blit_src   || fmt_caps & PL_FMT_CAP_BLITTABLE);
     253   [ +  +  -  + ]:       2022 :     require(!params->blit_dst   || fmt_caps & PL_FMT_CAP_BLITTABLE);
     254                 :            : 
     255                 :       2022 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
     256                 :       2022 :     return impl->tex_create(gpu, params);
     257                 :            : 
     258                 :            : error:
     259         [ #  # ]:          0 :     if (params->debug_tag)
     260                 :          0 :         PL_ERR(gpu, "  for texture: %s", params->debug_tag);
     261                 :            :     return NULL;
     262                 :            : }
     263                 :            : 
     264                 :       2190 : void pl_tex_destroy(pl_gpu gpu, pl_tex *tex)
     265                 :            : {
     266         [ +  + ]:       2190 :     if (!*tex)
     267                 :            :         return;
     268                 :            : 
     269                 :       1878 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
     270                 :       1878 :     impl->tex_destroy(gpu, *tex);
     271                 :       1878 :     *tex = NULL;
     272                 :            : }
     273                 :            : 
     274                 :        665 : static bool pl_tex_params_superset(struct pl_tex_params a, struct pl_tex_params b)
     275                 :            : {
     276         [ +  - ]:        649 :     return a.w == b.w && a.h == b.h && a.d == b.d &&
     277         [ +  + ]:        649 :            a.format          == b.format &&
     278   [ -  +  -  - ]:        647 :            (a.sampleable     || !b.sampleable) &&
     279   [ +  +  +  - ]:        647 :            (a.renderable     || !b.renderable) &&
     280   [ +  +  +  - ]:        647 :            (a.storable       || !b.storable) &&
     281   [ +  +  +  - ]:        647 :            (a.blit_src       || !b.blit_src) &&
     282   [ +  +  +  - ]:        647 :            (a.blit_dst       || !b.blit_dst) &&
     283   [ +  +  +  +  :       1312 :            (a.host_writable  || !b.host_writable) &&
                   +  - ]
     284   [ +  -  +  - ]:        647 :            (a.host_readable  || !b.host_readable);
     285                 :            : }
     286                 :            : 
     287                 :        753 : bool pl_tex_recreate(pl_gpu gpu, pl_tex *tex, const struct pl_tex_params *params)
     288                 :            : {
     289         [ -  + ]:        753 :     if (params->initial_data) {
     290                 :          0 :         PL_ERR(gpu, "pl_tex_recreate may not be used with `initial_data`!");
     291                 :          0 :         return false;
     292                 :            :     }
     293                 :            : 
     294         [ -  + ]:        753 :     if (params->import_handle) {
     295                 :          0 :         PL_ERR(gpu, "pl_tex_recreate may not be used with `import_handle`!");
     296                 :          0 :         return false;
     297                 :            :     }
     298                 :            : 
     299   [ +  +  +  + ]:        753 :     if (*tex && pl_tex_params_superset((*tex)->params, *params)) {
     300                 :        647 :         pl_tex_invalidate(gpu, *tex);
     301                 :        647 :         return true;
     302                 :            :     }
     303                 :            : 
     304         [ +  - ]:        212 :     PL_DEBUG(gpu, "(Re)creating %dx%dx%d texture with format %s: %s",
     305                 :            :              params->w, params->h, params->d, params->format->name,
     306                 :            :              PL_DEF(params->debug_tag, "unknown"));
     307                 :            : 
     308                 :        106 :     pl_tex_destroy(gpu, tex);
     309                 :        106 :     *tex = pl_tex_create(gpu, params);
     310                 :            : 
     311                 :        106 :     return !!*tex;
     312                 :            : }
     313                 :            : 
     314                 :        432 : void pl_tex_clear_ex(pl_gpu gpu, pl_tex dst, const union pl_clear_color color)
     315                 :            : {
     316         [ -  + ]:        432 :     require(dst->params.blit_dst);
     317                 :            : 
     318                 :        432 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
     319         [ +  - ]:        432 :     if (impl->tex_invalidate)
     320                 :        432 :         impl->tex_invalidate(gpu, dst);
     321                 :        432 :     impl->tex_clear_ex(gpu, dst, color);
     322                 :            :     return;
     323                 :            : 
     324                 :            : error:
     325                 :            :     if (dst->params.debug_tag)
     326                 :            :         PL_ERR(gpu, "  for texture: %s", dst->params.debug_tag);
     327                 :            : }
     328                 :            : 
     329                 :        174 : void pl_tex_clear(pl_gpu gpu, pl_tex dst, const float color[4])
     330                 :            : {
     331         [ -  + ]:        174 :     if (!pl_fmt_is_float(dst->params.format)) {
     332                 :          0 :         PL_ERR(gpu, "Cannot call `pl_tex_clear` on integer textures, please "
     333                 :            :                "use `pl_tex_clear_ex` instead.");
     334                 :          0 :         return;
     335                 :            :     }
     336                 :            : 
     337                 :        174 :     const union pl_clear_color col = {
     338                 :        174 :         .f = { color[0], color[1], color[2], color[3] },
     339                 :            :     };
     340                 :            : 
     341                 :        174 :     pl_tex_clear_ex(gpu, dst, col);
     342                 :            : }
     343                 :            : 
     344                 :       3357 : void pl_tex_invalidate(pl_gpu gpu, pl_tex tex)
     345                 :            : {
     346                 :       3357 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
     347         [ +  - ]:       3357 :     if (impl->tex_invalidate)
     348                 :       3357 :         impl->tex_invalidate(gpu, tex);
     349                 :       3357 : }
     350                 :            : 
     351                 :            : static void strip_coords(pl_tex tex, pl_rect3d *rc)
     352                 :            : {
     353   [ +  +  +  +  :       2926 :     if (!tex->params.d) {
             +  +  +  + ]
     354                 :       1926 :         rc->z0 = 0;
     355                 :       1926 :         rc->z1 = 1;
     356                 :            :     }
     357                 :            : 
     358   [ +  +  +  +  :       2926 :     if (!tex->params.h) {
             +  +  +  + ]
     359                 :        734 :         rc->y0 = 0;
     360                 :        734 :         rc->y1 = 1;
     361                 :            :     }
     362                 :            : }
     363                 :            : 
     364                 :       2674 : static void infer_rc(pl_tex tex, pl_rect3d *rc)
     365                 :            : {
     366   [ +  -  +  + ]:       2674 :     if (!rc->x0 && !rc->x1)
     367                 :       2002 :         rc->x1 = tex->params.w;
     368   [ +  -  +  + ]:       2674 :     if (!rc->y0 && !rc->y1)
     369                 :       2024 :         rc->y1 = tex->params.h;
     370   [ +  -  +  + ]:       2674 :     if (!rc->z0 && !rc->z1)
     371                 :       2078 :         rc->z1 = tex->params.d;
     372                 :       2674 : }
     373                 :            : 
     374                 :        252 : void pl_tex_blit(pl_gpu gpu, const struct pl_tex_blit_params *params)
     375                 :            : {
     376                 :        252 :     pl_tex src = params->src, dst = params->dst;
     377         [ -  + ]:        252 :     require(src && dst);
     378                 :        252 :     pl_fmt src_fmt = src->params.format;
     379                 :        252 :     pl_fmt dst_fmt = dst->params.format;
     380         [ -  + ]:        252 :     require(src_fmt->internal_size == dst_fmt->internal_size);
     381         [ -  + ]:        252 :     require((src_fmt->type == PL_FMT_UINT) == (dst_fmt->type == PL_FMT_UINT));
     382         [ -  + ]:        252 :     require((src_fmt->type == PL_FMT_SINT) == (dst_fmt->type == PL_FMT_SINT));
     383         [ -  + ]:        252 :     require(src->params.blit_src);
     384         [ -  + ]:        252 :     require(dst->params.blit_dst);
     385   [ -  +  -  - ]:        252 :     require(params->sample_mode != PL_TEX_SAMPLE_LINEAR || (src_fmt->caps & PL_FMT_CAP_LINEAR));
     386                 :            : 
     387                 :        252 :     struct pl_tex_blit_params fixed = *params;
     388                 :        252 :     infer_rc(src, &fixed.src_rc);
     389                 :        252 :     infer_rc(dst, &fixed.dst_rc);
     390                 :            :     strip_coords(src, &fixed.src_rc);
     391                 :            :     strip_coords(dst, &fixed.dst_rc);
     392                 :            : 
     393   [ +  -  -  + ]:        252 :     require(fixed.src_rc.x0 >= 0 && fixed.src_rc.x0 < src->params.w);
     394   [ +  -  -  + ]:        252 :     require(fixed.src_rc.x1 > 0 && fixed.src_rc.x1 <= src->params.w);
     395   [ +  -  -  + ]:        252 :     require(fixed.dst_rc.x0 >= 0 && fixed.dst_rc.x0 < dst->params.w);
     396   [ +  -  -  + ]:        252 :     require(fixed.dst_rc.x1 > 0 && fixed.dst_rc.x1 <= dst->params.w);
     397                 :            : 
     398         [ +  + ]:        252 :     if (src->params.h) {
     399   [ +  -  -  + ]:        200 :         require(fixed.src_rc.y0 >= 0 && fixed.src_rc.y0 < src->params.h);
     400   [ +  -  -  + ]:        200 :         require(fixed.src_rc.y1 > 0 && fixed.src_rc.y1 <= src->params.h);
     401                 :            :     }
     402                 :            : 
     403         [ +  + ]:        252 :     if (dst->params.h) {
     404   [ +  -  -  + ]:        200 :         require(fixed.dst_rc.y0 >= 0 && fixed.dst_rc.y0 < dst->params.h);
     405   [ +  -  -  + ]:        200 :         require(fixed.dst_rc.y1 > 0 && fixed.dst_rc.y1 <= dst->params.h);
     406                 :            :     }
     407                 :            : 
     408         [ +  + ]:        252 :     if (src->params.d) {
     409   [ +  -  -  + ]:         52 :         require(fixed.src_rc.z0 >= 0 && fixed.src_rc.z0 < src->params.d);
     410   [ +  -  -  + ]:         52 :         require(fixed.src_rc.z1 > 0 && fixed.src_rc.z1 <= src->params.d);
     411                 :            :     }
     412                 :            : 
     413         [ +  + ]:        252 :     if (dst->params.d) {
     414   [ +  -  -  + ]:         52 :         require(fixed.dst_rc.z0 >= 0 && fixed.dst_rc.z0 < dst->params.d);
     415   [ +  -  -  + ]:         52 :         require(fixed.dst_rc.z1 > 0 && fixed.dst_rc.z1 <= dst->params.d);
     416                 :            :     }
     417                 :            : 
     418                 :            :     pl_rect3d full = {0, 0, 0, dst->params.w, dst->params.h, dst->params.d};
     419                 :            :     strip_coords(dst, &full);
     420                 :            : 
     421                 :        252 :     pl_rect3d rcnorm = fixed.dst_rc;
     422                 :        252 :     pl_rect3d_normalize(&rcnorm);
     423   [ +  -  +  -  :        252 :     if (pl_rect3d_eq(rcnorm, full))
          +  -  +  -  +  
                -  +  - ]
     424                 :        252 :         pl_tex_invalidate(gpu, dst);
     425                 :            : 
     426                 :        252 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
     427                 :        252 :     impl->tex_blit(gpu, &fixed);
     428                 :        252 :     return;
     429                 :            : 
     430                 :            : error:
     431                 :            :     if (src->params.debug_tag || dst->params.debug_tag) {
     432                 :            :         PL_ERR(gpu, "  for textures: src %s, dst %s",
     433                 :            :                PL_DEF(src->params.debug_tag, "(unknown)"),
     434                 :            :                PL_DEF(dst->params.debug_tag, "(unknown)"));
     435                 :            :     }
     436                 :            : }
     437                 :            : 
     438                 :       2170 : static bool fix_tex_transfer(pl_gpu gpu, struct pl_tex_transfer_params *params)
     439                 :            : {
     440                 :       2170 :     pl_tex tex = params->tex;
     441                 :       2170 :     pl_fmt fmt = tex->params.format;
     442                 :       2170 :     pl_rect3d rc = params->rc;
     443                 :            : 
     444                 :            :     // Infer the default values
     445                 :       2170 :     infer_rc(tex, &rc);
     446                 :            :     strip_coords(tex, &rc);
     447                 :            : 
     448   [ +  +  -  + ]:       2170 :     if (!params->row_pitch || !tex->params.w)
     449                 :       1568 :         params->row_pitch = pl_rect_w(rc) * fmt->texel_size;
     450   [ +  +  +  + ]:       2170 :     if (!params->depth_pitch || !tex->params.d)
     451                 :       1981 :         params->depth_pitch = pl_rect_h(rc) * params->row_pitch;
     452                 :            : 
     453         [ -  + ]:       2170 :     require(params->row_pitch);
     454         [ -  + ]:       2170 :     require(params->depth_pitch);
     455         [ +  + ]:       2170 :     params->rc = rc;
     456                 :            : 
     457                 :            :     // Check the parameters for sanity
     458                 :            :     switch (pl_tex_params_dimension(tex->params))
     459                 :            :     {
     460                 :            :     case 3:
     461         [ -  + ]:        644 :         require(rc.z1 > rc.z0);
     462   [ +  -  -  + ]:        644 :         require(rc.z0 >= 0 && rc.z0 <  tex->params.d);
     463   [ +  -  -  + ]:        644 :         require(rc.z1 >  0 && rc.z1 <= tex->params.d);
     464         [ -  + ]:        644 :         require(params->depth_pitch >= pl_rect_h(rc) * params->row_pitch);
     465         [ -  + ]:        644 :         require(params->depth_pitch % params->row_pitch == 0);
     466                 :            :         // fall through
     467                 :            :     case 2:
     468         [ -  + ]:       1540 :         require(rc.y1 > rc.y0);
     469   [ +  -  -  + ]:       1540 :         require(rc.y0 >= 0 && rc.y0 <  tex->params.h);
     470   [ +  -  -  + ]:       1540 :         require(rc.y1 >  0 && rc.y1 <= tex->params.h);
     471         [ -  + ]:       1540 :         require(params->row_pitch >= pl_rect_w(rc) * fmt->texel_size);
     472         [ -  + ]:       1540 :         require(params->row_pitch % fmt->texel_align == 0);
     473                 :            :         // fall through
     474                 :            :     case 1:
     475         [ -  + ]:       2170 :         require(rc.x1 > rc.x0);
     476   [ +  -  -  + ]:       2170 :         require(rc.x0 >= 0 && rc.x0 <  tex->params.w);
     477   [ +  -  -  + ]:       2170 :         require(rc.x1 >  0 && rc.x1 <= tex->params.w);
     478                 :            :         break;
     479                 :            :     }
     480                 :            : 
     481         [ -  + ]:       2170 :     require(!params->buf ^ !params->ptr); // exactly one
     482         [ +  + ]:       2170 :     if (params->buf) {
     483                 :            :         pl_buf buf = params->buf;
     484                 :        568 :         size_t size = pl_tex_transfer_size(params);
     485         [ -  + ]:        568 :         require(params->buf_offset + size >= params->buf_offset); // overflow check
     486         [ -  + ]:        568 :         require(params->buf_offset + size <= buf->params.size);
     487         [ -  + ]:        568 :         require(gpu->limits.buf_transfer);
     488                 :            :     }
     489                 :            : 
     490   [ +  +  -  + ]:       2170 :     require(!params->callback || gpu->limits.callbacks);
     491                 :            :     return true;
     492                 :            : 
     493                 :            : error:
     494                 :            :     if (tex->params.debug_tag)
     495                 :            :         PL_ERR(gpu, "  for texture: %s", tex->params.debug_tag);
     496                 :            :     return false;
     497                 :            : }
     498                 :            : 
     499                 :       1130 : bool pl_tex_upload(pl_gpu gpu, const struct pl_tex_transfer_params *params)
     500                 :            : {
     501                 :       1130 :     pl_tex tex = params->tex;
     502         [ -  + ]:       1130 :     require(tex->params.host_writable);
     503                 :            : 
     504                 :       1130 :     struct pl_tex_transfer_params fixed = *params;
     505         [ -  + ]:       1130 :     if (!fix_tex_transfer(gpu, &fixed))
     506                 :          0 :         goto error;
     507                 :            : 
     508                 :       1130 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
     509                 :       1130 :     return impl->tex_upload(gpu, &fixed);
     510                 :            : 
     511                 :            : error:
     512         [ #  # ]:          0 :     if (tex->params.debug_tag)
     513                 :          0 :         PL_ERR(gpu, "  for texture: %s", tex->params.debug_tag);
     514                 :            :     return false;
     515                 :            : }
     516                 :            : 
     517                 :       1040 : bool pl_tex_download(pl_gpu gpu, const struct pl_tex_transfer_params *params)
     518                 :            : {
     519                 :       1040 :     pl_tex tex = params->tex;
     520         [ -  + ]:       1040 :     require(tex->params.host_readable);
     521                 :            : 
     522                 :       1040 :     struct pl_tex_transfer_params fixed = *params;
     523         [ -  + ]:       1040 :     if (!fix_tex_transfer(gpu, &fixed))
     524                 :          0 :         goto error;
     525                 :            : 
     526                 :       1040 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
     527                 :       1040 :     return impl->tex_download(gpu, &fixed);
     528                 :            : 
     529                 :            : error:
     530         [ #  # ]:          0 :     if (tex->params.debug_tag)
     531                 :          0 :         PL_ERR(gpu, "  for texture: %s", tex->params.debug_tag);
     532                 :            :     return false;
     533                 :            : }
     534                 :            : 
     535                 :          4 : bool pl_tex_poll(pl_gpu gpu, pl_tex tex, uint64_t t)
     536                 :            : {
     537                 :          4 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
     538   [ +  -  +  - ]:          4 :     return impl->tex_poll ? impl->tex_poll(gpu, tex, t) : false;
     539                 :            : }
     540                 :            : 
     541                 :       1232 : pl_buf pl_buf_create(pl_gpu gpu, const struct pl_buf_params *params)
     542                 :            : {
     543                 :            :     struct pl_buf_params params_rounded;
     544                 :            : 
     545   [ +  +  -  + ]:       1232 :     require(!params->import_handle || !params->export_handle);
     546         [ +  + ]:       1232 :     if (params->export_handle) {
     547         [ -  + ]:          6 :         require(PL_ISPOT(params->export_handle));
     548         [ -  + ]:          6 :         require(params->export_handle & gpu->export_caps.buf);
     549                 :            :     }
     550         [ +  + ]:       1232 :     if (params->import_handle) {
     551         [ -  + ]:         22 :         require(PL_ISPOT(params->import_handle));
     552         [ -  + ]:         22 :         require(params->import_handle & gpu->import_caps.buf);
     553                 :            :         const struct pl_shared_mem *shmem = &params->shared_mem;
     554         [ -  + ]:         22 :         require(shmem->offset + params->size <= shmem->size);
     555   [ +  +  -  + ]:         22 :         require(params->import_handle != PL_HANDLE_DMA_BUF || !shmem->drm_format_mod);
     556                 :            : 
     557                 :            :         // Fix misalignment on host pointer imports
     558         [ +  + ]:         22 :         if (params->import_handle == PL_HANDLE_HOST_PTR) {
     559                 :         20 :             uintptr_t page_mask = ~(gpu->limits.align_host_ptr - 1);
     560                 :         20 :             uintptr_t ptr_base = (uintptr_t) shmem->handle.ptr & page_mask;
     561                 :         20 :             size_t ptr_offset = (uintptr_t) shmem->handle.ptr - ptr_base;
     562                 :         20 :             size_t buf_offset = ptr_offset + shmem->offset;
     563                 :         20 :             size_t ptr_size = PL_ALIGN2(ptr_offset + shmem->size,
     564                 :            :                                         gpu->limits.align_host_ptr);
     565                 :            : 
     566   [ +  +  -  + ]:         20 :             if (ptr_base != (uintptr_t) shmem->handle.ptr || ptr_size > shmem->size) {
     567                 :            :                 static bool warned_rounding = false;
     568         [ +  + ]:         18 :                 if (!warned_rounding) {
     569                 :          1 :                     warned_rounding = true;
     570                 :          1 :                     PL_WARN(gpu, "Imported host pointer is not page-aligned. "
     571                 :            :                             "This should normally be fine on most platforms, "
     572                 :            :                             "but may cause issues in some rare circumstances.");
     573                 :            :                 }
     574                 :            : 
     575                 :         18 :                 PL_TRACE(gpu, "Rounding imported host pointer %p + %zu -> %zu to "
     576                 :            :                          "nearest page boundaries: %p + %zu -> %zu",
     577                 :            :                           shmem->handle.ptr, shmem->offset, shmem->size,
     578                 :            :                           (void *) ptr_base, buf_offset, ptr_size);
     579                 :            :             }
     580                 :            : 
     581                 :         20 :             params_rounded = *params;
     582                 :         20 :             params_rounded.shared_mem.handle.ptr = (void *) ptr_base;
     583                 :         20 :             params_rounded.shared_mem.offset = buf_offset;
     584                 :         20 :             params_rounded.shared_mem.size = ptr_size;
     585                 :            :             params = &params_rounded;
     586                 :            :         }
     587                 :            :     }
     588                 :            : 
     589   [ +  -  -  + ]:       1232 :     require(params->size > 0 && params->size <= gpu->limits.max_buf_size);
     590   [ +  +  -  + ]:       1232 :     require(!params->uniform || params->size <= gpu->limits.max_ubo_size);
     591   [ +  +  -  + ]:       1232 :     require(!params->storable || params->size <= gpu->limits.max_ssbo_size);
     592   [ +  +  -  + ]:       1232 :     require(!params->drawable || params->size <= gpu->limits.max_vbo_size);
     593         [ +  + ]:       1232 :     if (params->host_mapped) {
     594         [ -  + ]:          7 :         require(params->size <= gpu->limits.max_mapped_size);
     595   [ -  +  -  - ]:          7 :         require(params->memory_type != PL_BUF_MEM_DEVICE ||
     596                 :            :                 params->size <= gpu->limits.max_mapped_vram);
     597                 :            :     }
     598                 :            : 
     599         [ +  + ]:       1232 :     if (params->format) {
     600                 :            :         pl_fmt fmt = params->format;
     601         [ -  + ]:         18 :         require(params->size <= gpu->limits.max_buffer_texels * fmt->texel_size);
     602   [ -  +  -  - ]:         18 :         require(!params->uniform || (fmt->caps & PL_FMT_CAP_TEXEL_UNIFORM));
     603   [ +  -  -  + ]:         18 :         require(!params->storable || (fmt->caps & PL_FMT_CAP_TEXEL_STORAGE));
     604                 :            :     }
     605                 :            : 
     606                 :       1232 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
     607                 :       1232 :     pl_buf buf = impl->buf_create(gpu, params);
     608         [ +  + ]:       1232 :     if (buf)
     609   [ +  +  -  + ]:       1228 :         require(!params->host_mapped || buf->data);
     610                 :            : 
     611                 :            :     return buf;
     612                 :            : 
     613                 :            : error:
     614                 :            :     if (params->debug_tag)
     615                 :            :         PL_ERR(gpu, "  for buffer: %s", params->debug_tag);
     616                 :            :     return NULL;
     617                 :            : }
     618                 :            : 
     619                 :       2888 : void pl_buf_destroy(pl_gpu gpu, pl_buf *buf)
     620                 :            : {
     621         [ +  + ]:       2888 :     if (!*buf)
     622                 :            :         return;
     623                 :            : 
     624                 :       1228 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
     625                 :       1228 :     impl->buf_destroy(gpu, *buf);
     626                 :       1228 :     *buf = NULL;
     627                 :            : }
     628                 :            : 
     629                 :          0 : static bool pl_buf_params_superset(struct pl_buf_params a, struct pl_buf_params b)
     630                 :            : {
     631                 :          0 :     return a.size            >= b.size &&
     632         [ #  # ]:          0 :            a.memory_type     == b.memory_type &&
     633         [ #  # ]:          0 :            a.format          == b.format &&
     634   [ #  #  #  # ]:          0 :            (a.host_writable  || !b.host_writable) &&
     635   [ #  #  #  # ]:          0 :            (a.host_readable  || !b.host_readable) &&
     636   [ #  #  #  # ]:          0 :            (a.host_mapped    || !b.host_mapped) &&
     637   [ #  #  #  # ]:          0 :            (a.uniform        || !b.uniform) &&
     638   [ #  #  #  #  :          0 :            (a.storable       || !b.storable) &&
                   #  # ]
     639   [ #  #  #  # ]:          0 :            (a.drawable       || !b.drawable);
     640                 :            : }
     641                 :            : 
     642                 :          0 : bool pl_buf_recreate(pl_gpu gpu, pl_buf *buf, const struct pl_buf_params *params)
     643                 :            : {
     644                 :            : 
     645         [ #  # ]:          0 :     if (params->initial_data) {
     646                 :          0 :         PL_ERR(gpu, "pl_buf_recreate may not be used with `initial_data`!");
     647                 :          0 :         return false;
     648                 :            :     }
     649                 :            : 
     650   [ #  #  #  # ]:          0 :     if (*buf && pl_buf_params_superset((*buf)->params, *params))
     651                 :            :         return true;
     652                 :            : 
     653                 :          0 :     PL_INFO(gpu, "(Re)creating %zu buffer", params->size);
     654                 :          0 :     pl_buf_destroy(gpu, buf);
     655                 :          0 :     *buf = pl_buf_create(gpu, params);
     656                 :            : 
     657                 :          0 :     return !!*buf;
     658                 :            : }
     659                 :            : 
     660                 :        650 : void pl_buf_write(pl_gpu gpu, pl_buf buf, size_t buf_offset,
     661                 :            :                   const void *data, size_t size)
     662                 :            : {
     663         [ -  + ]:        650 :     require(buf->params.host_writable);
     664         [ -  + ]:        650 :     require(buf_offset + size <= buf->params.size);
     665         [ -  + ]:        650 :     require(buf_offset == PL_ALIGN2(buf_offset, 4));
     666                 :            : 
     667                 :        650 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
     668                 :        650 :     impl->buf_write(gpu, buf, buf_offset, data, size);
     669                 :            :     return;
     670                 :            : 
     671                 :            : error:
     672                 :            :     if (buf->params.debug_tag)
     673                 :            :         PL_ERR(gpu, "  for buffer: %s", buf->params.debug_tag);
     674                 :            : }
     675                 :            : 
     676                 :        280 : bool pl_buf_read(pl_gpu gpu, pl_buf buf, size_t buf_offset,
     677                 :            :                  void *dest, size_t size)
     678                 :            : {
     679         [ -  + ]:        280 :     require(buf->params.host_readable);
     680         [ -  + ]:        280 :     require(buf_offset + size <= buf->params.size);
     681                 :            : 
     682                 :        280 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
     683                 :        280 :     return impl->buf_read(gpu, buf, buf_offset, dest, size);
     684                 :            : 
     685                 :            : error:
     686                 :            :     if (buf->params.debug_tag)
     687                 :            :         PL_ERR(gpu, "  for buffer: %s", buf->params.debug_tag);
     688                 :            :     return false;
     689                 :            : }
     690                 :            : 
     691                 :          5 : void pl_buf_copy(pl_gpu gpu, pl_buf dst, size_t dst_offset,
     692                 :            :                  pl_buf src, size_t src_offset, size_t size)
     693                 :            : {
     694         [ -  + ]:          5 :     require(src_offset + size <= src->params.size);
     695         [ -  + ]:          5 :     require(dst_offset + size <= dst->params.size);
     696         [ -  + ]:          5 :     require(src != dst);
     697                 :            : 
     698                 :          5 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
     699                 :          5 :     impl->buf_copy(gpu, dst, dst_offset, src, src_offset, size);
     700                 :            :     return;
     701                 :            : 
     702                 :            : error:
     703                 :            :     if (src->params.debug_tag || dst->params.debug_tag) {
     704                 :            :         PL_ERR(gpu, "  for buffers: src %s, dst %s",
     705                 :            :                src->params.debug_tag, dst->params.debug_tag);
     706                 :            :     }
     707                 :            : }
     708                 :            : 
     709                 :          4 : bool pl_buf_export(pl_gpu gpu, pl_buf buf)
     710                 :            : {
     711         [ -  + ]:          4 :     require(buf->params.export_handle || buf->params.import_handle);
     712                 :            : 
     713                 :          4 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
     714                 :          4 :     return impl->buf_export(gpu, buf);
     715                 :            : 
     716                 :            : error:
     717                 :            :     if (buf->params.debug_tag)
     718                 :            :         PL_ERR(gpu, "  for buffer: %s", buf->params.debug_tag);
     719                 :            :     return false;
     720                 :            : }
     721                 :            : 
     722                 :         52 : bool pl_buf_poll(pl_gpu gpu, pl_buf buf, uint64_t t)
     723                 :            : {
     724                 :         52 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
     725   [ +  +  +  - ]:         52 :     return impl->buf_poll ? impl->buf_poll(gpu, buf, t) : false;
     726                 :            : }
     727                 :            : 
     728                 :      23722 : size_t pl_var_type_size(enum pl_var_type type)
     729                 :            : {
     730         [ -  + ]:      23722 :     switch (type) {
     731                 :            :     case PL_VAR_SINT:  return sizeof(int);
     732                 :            :     case PL_VAR_UINT:  return sizeof(unsigned int);
     733                 :            :     case PL_VAR_FLOAT: return sizeof(float);
     734                 :            :     case PL_VAR_INVALID: // fall through
     735                 :            :     case PL_VAR_TYPE_COUNT: break;
     736                 :            :     }
     737                 :            : 
     738                 :          0 :     pl_unreachable();
     739                 :            : }
     740                 :            : 
     741                 :            : #define PL_VAR(TYPE, NAME, M, V)                        \
     742                 :            :     struct pl_var pl_var_##NAME(const char *name) {     \
     743                 :            :         return (struct pl_var) {                        \
     744                 :            :             .name  = name,                              \
     745                 :            :             .type  = PL_VAR_##TYPE,                     \
     746                 :            :             .dim_m = M,                                 \
     747                 :            :             .dim_v = V,                                 \
     748                 :            :             .dim_a = 1,                                 \
     749                 :            :         };                                              \
     750                 :            :     }
     751                 :            : 
     752                 :       1169 : PL_VAR(FLOAT, float,    1, 1)
     753                 :        551 : PL_VAR(FLOAT, vec2,     1, 2)
     754                 :        831 : PL_VAR(FLOAT, vec3,     1, 3)
     755                 :          4 : PL_VAR(FLOAT, vec4,     1, 4)
     756                 :        645 : PL_VAR(FLOAT, mat2,     2, 2)
     757                 :          0 : PL_VAR(FLOAT, mat2x3,   2, 3)
     758                 :          0 : PL_VAR(FLOAT, mat2x4,   2, 4)
     759                 :       1025 : PL_VAR(FLOAT, mat3,     3, 3)
     760                 :          0 : PL_VAR(FLOAT, mat3x4,   3, 4)
     761                 :          0 : PL_VAR(FLOAT, mat4x2,   4, 2)
     762                 :          0 : PL_VAR(FLOAT, mat4x3,   4, 3)
     763                 :          0 : PL_VAR(FLOAT, mat4,     4, 4)
     764                 :         90 : PL_VAR(SINT,  int,      1, 1)
     765                 :          0 : PL_VAR(SINT,  ivec2,    1, 2)
     766                 :          0 : PL_VAR(SINT,  ivec3,    1, 3)
     767                 :          0 : PL_VAR(SINT,  ivec4,    1, 4)
     768                 :         44 : PL_VAR(UINT,  uint,     1, 1)
     769                 :          0 : PL_VAR(UINT,  uvec2,    1, 2)
     770                 :          0 : PL_VAR(UINT,  uvec3,    1, 3)
     771                 :          0 : PL_VAR(UINT,  uvec4,    1, 4)
     772                 :            : 
     773                 :            : #undef PL_VAR
     774                 :            : 
     775                 :            : const struct pl_named_var pl_var_glsl_types[] = {
     776                 :            :     // float vectors
     777                 :            :     { "float",  { .type = PL_VAR_FLOAT, .dim_m = 1, .dim_v = 1, .dim_a = 1, }},
     778                 :            :     { "vec2",   { .type = PL_VAR_FLOAT, .dim_m = 1, .dim_v = 2, .dim_a = 1, }},
     779                 :            :     { "vec3",   { .type = PL_VAR_FLOAT, .dim_m = 1, .dim_v = 3, .dim_a = 1, }},
     780                 :            :     { "vec4",   { .type = PL_VAR_FLOAT, .dim_m = 1, .dim_v = 4, .dim_a = 1, }},
     781                 :            :     // float matrices
     782                 :            :     { "mat2",   { .type = PL_VAR_FLOAT, .dim_m = 2, .dim_v = 2, .dim_a = 1, }},
     783                 :            :     { "mat2x3", { .type = PL_VAR_FLOAT, .dim_m = 2, .dim_v = 3, .dim_a = 1, }},
     784                 :            :     { "mat2x4", { .type = PL_VAR_FLOAT, .dim_m = 2, .dim_v = 4, .dim_a = 1, }},
     785                 :            :     { "mat3",   { .type = PL_VAR_FLOAT, .dim_m = 3, .dim_v = 3, .dim_a = 1, }},
     786                 :            :     { "mat3x4", { .type = PL_VAR_FLOAT, .dim_m = 3, .dim_v = 4, .dim_a = 1, }},
     787                 :            :     { "mat4x2", { .type = PL_VAR_FLOAT, .dim_m = 4, .dim_v = 2, .dim_a = 1, }},
     788                 :            :     { "mat4x3", { .type = PL_VAR_FLOAT, .dim_m = 4, .dim_v = 3, .dim_a = 1, }},
     789                 :            :     { "mat4",   { .type = PL_VAR_FLOAT, .dim_m = 4, .dim_v = 4, .dim_a = 1, }},
     790                 :            :     // integer vectors
     791                 :            :     { "int",    { .type = PL_VAR_SINT,  .dim_m = 1, .dim_v = 1, .dim_a = 1, }},
     792                 :            :     { "ivec2",  { .type = PL_VAR_SINT,  .dim_m = 1, .dim_v = 2, .dim_a = 1, }},
     793                 :            :     { "ivec3",  { .type = PL_VAR_SINT,  .dim_m = 1, .dim_v = 3, .dim_a = 1, }},
     794                 :            :     { "ivec4",  { .type = PL_VAR_SINT,  .dim_m = 1, .dim_v = 4, .dim_a = 1, }},
     795                 :            :     // unsigned integer vectors
     796                 :            :     { "uint",   { .type = PL_VAR_UINT,  .dim_m = 1, .dim_v = 1, .dim_a = 1, }},
     797                 :            :     { "uvec2",  { .type = PL_VAR_UINT,  .dim_m = 1, .dim_v = 2, .dim_a = 1, }},
     798                 :            :     { "uvec3",  { .type = PL_VAR_UINT,  .dim_m = 1, .dim_v = 3, .dim_a = 1, }},
     799                 :            :     { "uvec4",  { .type = PL_VAR_UINT,  .dim_m = 1, .dim_v = 4, .dim_a = 1, }},
     800                 :            : 
     801                 :            :     {0},
     802                 :            : };
     803                 :            : 
     804                 :            : #define MAX_DIM 4
     805                 :            : 
     806                 :       6301 : const char *pl_var_glsl_type_name(struct pl_var var)
     807                 :            : {
     808                 :            :     static const char *types[PL_VAR_TYPE_COUNT][MAX_DIM+1][MAX_DIM+1] = {
     809                 :            :     // float vectors
     810                 :            :     [PL_VAR_FLOAT][1][1] = "float",
     811                 :            :     [PL_VAR_FLOAT][1][2] = "vec2",
     812                 :            :     [PL_VAR_FLOAT][1][3] = "vec3",
     813                 :            :     [PL_VAR_FLOAT][1][4] = "vec4",
     814                 :            :     // float matrices
     815                 :            :     [PL_VAR_FLOAT][2][2] = "mat2",
     816                 :            :     [PL_VAR_FLOAT][2][3] = "mat2x3",
     817                 :            :     [PL_VAR_FLOAT][2][4] = "mat2x4",
     818                 :            :     [PL_VAR_FLOAT][3][2] = "mat3x2",
     819                 :            :     [PL_VAR_FLOAT][3][3] = "mat3",
     820                 :            :     [PL_VAR_FLOAT][3][4] = "mat3x4",
     821                 :            :     [PL_VAR_FLOAT][4][2] = "mat4x2",
     822                 :            :     [PL_VAR_FLOAT][4][3] = "mat4x3",
     823                 :            :     [PL_VAR_FLOAT][4][4] = "mat4",
     824                 :            :     // integer vectors
     825                 :            :     [PL_VAR_SINT][1][1] = "int",
     826                 :            :     [PL_VAR_SINT][1][2] = "ivec2",
     827                 :            :     [PL_VAR_SINT][1][3] = "ivec3",
     828                 :            :     [PL_VAR_SINT][1][4] = "ivec4",
     829                 :            :     // unsigned integer vectors
     830                 :            :     [PL_VAR_UINT][1][1] = "uint",
     831                 :            :     [PL_VAR_UINT][1][2] = "uvec2",
     832                 :            :     [PL_VAR_UINT][1][3] = "uvec3",
     833                 :            :     [PL_VAR_UINT][1][4] = "uvec4",
     834                 :            :     };
     835                 :            : 
     836   [ +  -  +  - ]:       6301 :     if (var.dim_v > MAX_DIM || var.dim_m > MAX_DIM)
     837                 :            :         return NULL;
     838                 :            : 
     839                 :       6301 :     return types[var.type][var.dim_m][var.dim_v];
     840                 :            : }
     841                 :            : 
     842                 :        686 : struct pl_var pl_var_from_fmt(pl_fmt fmt, const char *name)
     843                 :            : {
     844                 :            :     static const enum pl_var_type vartypes[] = {
     845                 :            :         [PL_FMT_FLOAT] = PL_VAR_FLOAT,
     846                 :            :         [PL_FMT_UNORM] = PL_VAR_FLOAT,
     847                 :            :         [PL_FMT_SNORM] = PL_VAR_FLOAT,
     848                 :            :         [PL_FMT_UINT]  = PL_VAR_UINT,
     849                 :            :         [PL_FMT_SINT]  = PL_VAR_SINT,
     850                 :            :     };
     851                 :            : 
     852         [ -  + ]:        686 :     pl_assert(fmt->type < PL_ARRAY_SIZE(vartypes));
     853                 :        686 :     return (struct pl_var) {
     854                 :        686 :         .type  = vartypes[fmt->type],
     855                 :            :         .name  = name,
     856                 :        686 :         .dim_v = fmt->num_components,
     857                 :            :         .dim_m = 1,
     858                 :            :         .dim_a = 1,
     859                 :            :     };
     860                 :            : }
     861                 :            : 
     862                 :      11735 : struct pl_var_layout pl_var_host_layout(size_t offset, const struct pl_var *var)
     863                 :            : {
     864                 :      11735 :     size_t col_size = pl_var_type_size(var->type) * var->dim_v;
     865                 :      11735 :     return (struct pl_var_layout) {
     866                 :            :         .offset = offset,
     867                 :            :         .stride = col_size,
     868                 :      11735 :         .size   = col_size * var->dim_m * var->dim_a,
     869                 :            :     };
     870                 :            : }
     871                 :            : 
     872                 :        959 : struct pl_var_layout pl_std140_layout(size_t offset, const struct pl_var *var)
     873                 :            : {
     874                 :        959 :     size_t el_size = pl_var_type_size(var->type);
     875                 :            : 
     876                 :            :     // std140 packing rules:
     877                 :            :     // 1. The size of generic values is their size in bytes
     878                 :            :     // 2. The size of vectors is the vector length * the base count
     879                 :            :     // 3. Matrices are treated like arrays of column vectors
     880                 :            :     // 4. The size of array rows is that of the element size rounded up to
     881                 :            :     // the nearest multiple of vec4
     882                 :            :     // 5. All values are aligned to a multiple of their size (stride for arrays),
     883                 :            :     // with the exception of vec3 which is aligned like vec4
     884                 :        959 :     size_t stride = el_size * var->dim_v;
     885                 :            :     size_t align = stride;
     886         [ +  + ]:        959 :     if (var->dim_v == 3)
     887                 :        515 :         align += el_size;
     888         [ +  + ]:        959 :     if (var->dim_m * var->dim_a > 1)
     889                 :        469 :         stride = align = PL_ALIGN2(align, sizeof(float[4]));
     890                 :            : 
     891                 :        959 :     return (struct pl_var_layout) {
     892                 :        959 :         .offset = PL_ALIGN2(offset, align),
     893                 :            :         .stride = stride,
     894                 :        959 :         .size   = stride * var->dim_m * var->dim_a,
     895                 :            :     };
     896                 :            : }
     897                 :            : 
     898                 :       1369 : struct pl_var_layout pl_std430_layout(size_t offset, const struct pl_var *var)
     899                 :            : {
     900                 :       1369 :     size_t el_size = pl_var_type_size(var->type);
     901                 :            : 
     902                 :            :     // std430 packing rules: like std140, except arrays/matrices are always
     903                 :            :     // "tightly" packed, even arrays/matrices of vec3s
     904                 :       1369 :     size_t stride = el_size * var->dim_v;
     905                 :            :     size_t align = stride;
     906         [ +  + ]:       1369 :     if (var->dim_v == 3)
     907                 :        486 :         align += el_size;
     908         [ +  + ]:       1369 :     if (var->dim_m * var->dim_a > 1)
     909                 :            :         stride = align;
     910                 :            : 
     911                 :       1369 :     return (struct pl_var_layout) {
     912                 :       1369 :         .offset = PL_ALIGN2(offset, align),
     913                 :            :         .stride = stride,
     914                 :       1369 :         .size   = stride * var->dim_m * var->dim_a,
     915                 :            :     };
     916                 :            : }
     917                 :            : 
     918                 :        637 : void memcpy_layout(void *dst_p, struct pl_var_layout dst_layout,
     919                 :            :                    const void *src_p, struct pl_var_layout src_layout)
     920                 :            : {
     921                 :        637 :     uintptr_t src = (uintptr_t) src_p + src_layout.offset;
     922                 :        637 :     uintptr_t dst = (uintptr_t) dst_p + dst_layout.offset;
     923                 :            : 
     924         [ +  + ]:        637 :     if (src_layout.stride == dst_layout.stride) {
     925         [ -  + ]:        574 :         pl_assert(dst_layout.size == src_layout.size);
     926                 :        574 :         memcpy((void *) dst, (const void *) src, src_layout.size);
     927                 :        574 :         return;
     928                 :            :     }
     929                 :            : 
     930                 :         63 :     size_t stride = PL_MIN(src_layout.stride, dst_layout.stride);
     931                 :         63 :     uintptr_t end = src + src_layout.size;
     932         [ +  + ]:        252 :     while (src < end) {
     933         [ -  + ]:        189 :         pl_assert(dst < dst + dst_layout.size);
     934                 :        189 :         memcpy((void *) dst, (const void *) src, stride);
     935                 :        189 :         src += src_layout.stride;
     936                 :        189 :         dst += dst_layout.stride;
     937                 :            :     }
     938                 :            : }
     939                 :            : 
     940                 :       4817 : int pl_desc_namespace(pl_gpu gpu, enum pl_desc_type type)
     941                 :            : {
     942                 :       4817 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
     943                 :       4817 :     int ret = impl->desc_namespace(gpu, type);
     944         [ -  + ]:       4817 :     pl_assert(ret >= 0 && ret < PL_DESC_TYPE_COUNT);
     945                 :       4817 :     return ret;
     946                 :            : }
     947                 :            : 
     948                 :        154 : const char *pl_desc_access_glsl_name(enum pl_desc_access mode)
     949                 :            : {
     950   [ +  +  -  + ]:        154 :     switch (mode) {
     951                 :            :     case PL_DESC_ACCESS_READWRITE: return "";
     952                 :         15 :     case PL_DESC_ACCESS_READONLY:  return "readonly";
     953                 :        101 :     case PL_DESC_ACCESS_WRITEONLY: return "writeonly";
     954                 :            :     case PL_DESC_ACCESS_COUNT: break;
     955                 :            :     }
     956                 :            : 
     957                 :          0 :     pl_unreachable();
     958                 :            : }
     959                 :            : 
     960                 :            : const struct pl_blend_params pl_alpha_overlay = {
     961                 :            :     .src_rgb    = PL_BLEND_SRC_ALPHA,
     962                 :            :     .dst_rgb    = PL_BLEND_ONE_MINUS_SRC_ALPHA,
     963                 :            :     .src_alpha  = PL_BLEND_ONE,
     964                 :            :     .dst_alpha  = PL_BLEND_ONE_MINUS_SRC_ALPHA,
     965                 :            : };
     966                 :            : 
     967         [ +  - ]:        492 : static inline void log_shader_sources(pl_log log, enum pl_log_level level,
     968                 :            :                                       const struct pl_pass_params *params)
     969                 :            : {
     970   [ +  +  +  - ]:        492 :     if (!pl_msg_test(log, level) || !params->glsl_shader)
     971                 :            :         return;
     972                 :            : 
     973      [ +  +  - ]:        303 :     switch (params->type) {
     974                 :        215 :     case PL_PASS_RASTER:
     975         [ +  - ]:        215 :         if (!params->vertex_shader)
     976                 :            :             return;
     977                 :        215 :         pl_msg(log, level, "vertex shader source:");
     978                 :        215 :         pl_msg_source(log, level, params->vertex_shader);
     979                 :        215 :         pl_msg(log, level, "fragment shader source:");
     980                 :        215 :         pl_msg_source(log, level, params->glsl_shader);
     981                 :        215 :         return;
     982                 :            : 
     983                 :         88 :     case PL_PASS_COMPUTE:
     984                 :         88 :         pl_msg(log, level, "compute shader source:");
     985                 :         88 :         pl_msg_source(log, level, params->glsl_shader);
     986                 :         88 :         return;
     987                 :            : 
     988                 :            :     case PL_PASS_INVALID:
     989                 :            :     case PL_PASS_TYPE_COUNT:
     990                 :            :         break;
     991                 :            :     }
     992                 :            : 
     993                 :          0 :     pl_unreachable();
     994                 :            : }
     995                 :            : 
     996                 :        492 : static void log_spec_constants(pl_log log, enum pl_log_level lev,
     997                 :            :                                const struct pl_pass_params *params,
     998                 :            :                                const void *constant_data)
     999                 :            : {
    1000   [ +  +  +  -  :        646 :     if (!constant_data || !params->num_constants || !pl_msg_test(log, lev))
                   +  - ]
    1001                 :            :         return;
    1002                 :            : 
    1003                 :        154 :     pl_msg(log, lev, "Specialization constant values:");
    1004                 :            : 
    1005                 :        154 :     uintptr_t data_base = (uintptr_t) constant_data;
    1006         [ +  + ]:       1187 :     for (int i = 0; i < params->num_constants; i++) {
    1007                 :            :         union {
    1008                 :            :             int i;
    1009                 :            :             unsigned u;
    1010                 :            :             float f;
    1011                 :       1033 :         } *data = (void *) (data_base + params->constants[i].offset);
    1012                 :       1033 :         int id = params->constants[i].id;
    1013                 :            : 
    1014   [ +  +  +  - ]:       1033 :         switch (params->constants[i].type) {
    1015                 :         98 :         case PL_VAR_SINT:  pl_msg(log, lev, "  constant_id=%d: %d", id, data->i); break;
    1016                 :         53 :         case PL_VAR_UINT:  pl_msg(log, lev, "  constant_id=%d: %u", id, data->u); break;
    1017                 :        882 :         case PL_VAR_FLOAT: pl_msg(log, lev, "  constant_id=%d: %f", id, data->f); break;
    1018                 :          0 :         default: pl_unreachable();
    1019                 :            :         }
    1020                 :            :     }
    1021                 :            : }
    1022                 :            : 
    1023                 :        492 : pl_pass pl_pass_create(pl_gpu gpu, const struct pl_pass_params *params)
    1024                 :            : {
    1025         [ -  + ]:        492 :     require(params->glsl_shader);
    1026   [ +  -  +  - ]:        492 :     switch(params->type) {
    1027                 :        404 :     case PL_PASS_RASTER:
    1028         [ -  + ]:        404 :         require(params->vertex_shader);
    1029         [ +  - ]:        404 :         require(params->vertex_stride % gpu->limits.align_vertex_stride == 0);
    1030         [ +  + ]:       1240 :         for (int i = 0; i < params->num_vertex_attribs; i++) {
    1031                 :        836 :             struct pl_vertex_attrib va = params->vertex_attribs[i];
    1032         [ -  + ]:        836 :             require(va.name);
    1033         [ -  + ]:        836 :             require(va.fmt);
    1034         [ -  + ]:        836 :             require(va.fmt->caps & PL_FMT_CAP_VERTEX);
    1035         [ -  + ]:        836 :             require(va.offset + va.fmt->texel_size <= params->vertex_stride);
    1036                 :            :         }
    1037                 :            : 
    1038         [ -  + ]:        404 :         require(params->target_format);
    1039         [ -  + ]:        404 :         require(params->target_format->caps & PL_FMT_CAP_RENDERABLE);
    1040   [ +  +  -  + ]:        404 :         require(!params->blend_params || params->target_format->caps & PL_FMT_CAP_BLENDABLE);
    1041   [ +  +  +  - ]:        404 :         require(!params->blend_params || params->load_target);
    1042                 :            :         break;
    1043                 :         88 :     case PL_PASS_COMPUTE:
    1044         [ +  - ]:         88 :         require(gpu->glsl.compute);
    1045                 :            :         break;
    1046                 :            :     case PL_PASS_INVALID:
    1047                 :            :     case PL_PASS_TYPE_COUNT:
    1048                 :          0 :         pl_unreachable();
    1049                 :            :     }
    1050                 :            : 
    1051                 :            :     size_t num_var_comps = 0;
    1052         [ +  + ]:       1018 :     for (int i = 0; i < params->num_variables; i++) {
    1053                 :        526 :         struct pl_var var = params->variables[i];
    1054                 :        526 :         num_var_comps += var.dim_v * var.dim_m * var.dim_a;
    1055         [ -  + ]:        526 :         require(var.name);
    1056         [ -  + ]:        526 :         require(pl_var_glsl_type_name(var));
    1057                 :            :     }
    1058         [ -  + ]:        492 :     require(num_var_comps <= gpu->limits.max_variable_comps);
    1059                 :            : 
    1060         [ +  - ]:        492 :     require(params->num_constants <= gpu->limits.max_constants);
    1061         [ +  + ]:       1525 :     for (int i = 0; i < params->num_constants; i++)
    1062         [ -  + ]:       1033 :         require(params->constants[i].type);
    1063                 :            : 
    1064         [ +  + ]:       1553 :     for (int i = 0; i < params->num_descriptors; i++) {
    1065                 :       1061 :         struct pl_desc desc = params->descriptors[i];
    1066         [ -  + ]:       1061 :         require(desc.name);
    1067                 :            : 
    1068                 :            :         // enforce disjoint descriptor bindings for each namespace
    1069                 :       1061 :         int namespace = pl_desc_namespace(gpu, desc.type);
    1070         [ +  + ]:       2034 :         for (int j = i+1; j < params->num_descriptors; j++) {
    1071                 :        973 :             struct pl_desc other = params->descriptors[j];
    1072   [ +  +  -  + ]:        973 :             require(desc.binding != other.binding ||
    1073                 :            :                     namespace != pl_desc_namespace(gpu, other.type));
    1074                 :            :         }
    1075                 :            :     }
    1076                 :            : 
    1077         [ -  + ]:        492 :     require(params->push_constants_size <= gpu->limits.max_pushc_size);
    1078         [ -  + ]:        492 :     require(params->push_constants_size == PL_ALIGN2(params->push_constants_size, 4));
    1079                 :            : 
    1080                 :        492 :     log_shader_sources(gpu->log, PL_LOG_DEBUG, params);
    1081                 :        492 :     log_spec_constants(gpu->log, PL_LOG_DEBUG, params, params->constant_data);
    1082                 :            : 
    1083                 :        492 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
    1084                 :        492 :     pl_pass pass = impl->pass_create(gpu, params);
    1085         [ -  + ]:        492 :     if (!pass)
    1086                 :          0 :         goto error;
    1087                 :            : 
    1088                 :            :     return pass;
    1089                 :            : 
    1090                 :            : error:
    1091                 :          0 :     log_shader_sources(gpu->log, PL_LOG_ERR, params);
    1092                 :          0 :     pl_log_stack_trace(gpu->log, PL_LOG_ERR);
    1093                 :          0 :     pl_debug_abort();
    1094                 :            :     return NULL;
    1095                 :            : }
    1096                 :            : 
    1097                 :        492 : void pl_pass_destroy(pl_gpu gpu, pl_pass *pass)
    1098                 :            : {
    1099         [ +  - ]:        492 :     if (!*pass)
    1100                 :            :         return;
    1101                 :            : 
    1102                 :        492 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
    1103                 :        492 :     impl->pass_destroy(gpu, *pass);
    1104                 :        492 :     *pass = NULL;
    1105                 :            : }
    1106                 :            : 
    1107                 :       2420 : void pl_pass_run(pl_gpu gpu, const struct pl_pass_run_params *params)
    1108                 :            : {
    1109                 :       2420 :     pl_pass pass = params->pass;
    1110                 :       2420 :     struct pl_pass_run_params new = *params;
    1111                 :            : 
    1112         [ +  + ]:       6735 :     for (int i = 0; i < pass->params.num_descriptors; i++) {
    1113                 :       4315 :         struct pl_desc desc = pass->params.descriptors[i];
    1114                 :       4315 :         struct pl_desc_binding db = params->desc_bindings[i];
    1115         [ -  + ]:       4315 :         require(db.object);
    1116         [ +  + ]:       6989 :         for (int j = 0; j < i; j++)
    1117         [ -  + ]:       2674 :             require(db.object != params->desc_bindings[j].object);
    1118                 :            : 
    1119   [ +  +  +  +  :       4315 :         switch (desc.type) {
             -  +  -  - ]
    1120                 :       3663 :         case PL_DESC_SAMPLED_TEX: {
    1121                 :            :             pl_tex tex = db.object;
    1122                 :       3663 :             pl_fmt fmt = tex->params.format;
    1123         [ -  + ]:       3663 :             require(tex->params.sampleable);
    1124   [ +  +  -  + ]:       3663 :             require(db.sample_mode != PL_TEX_SAMPLE_LINEAR || (fmt->caps & PL_FMT_CAP_LINEAR));
    1125                 :            :             break;
    1126                 :            :         }
    1127                 :        115 :         case PL_DESC_STORAGE_IMG: {
    1128                 :            :             pl_tex tex = db.object;
    1129                 :        115 :             pl_fmt fmt = tex->params.format;
    1130         [ -  + ]:        115 :             require(tex->params.storable);
    1131   [ +  +  -  + ]:        115 :             require(desc.access != PL_DESC_ACCESS_READWRITE || (fmt->caps & PL_FMT_CAP_READWRITE));
    1132                 :            :             break;
    1133                 :            :         }
    1134                 :        496 :         case PL_DESC_BUF_UNIFORM: {
    1135                 :            :             pl_buf buf = db.object;
    1136         [ -  + ]:        496 :             require(buf->params.uniform);
    1137                 :            :             break;
    1138                 :            :         }
    1139                 :         23 :         case PL_DESC_BUF_STORAGE: {
    1140                 :            :             pl_buf buf = db.object;
    1141         [ -  + ]:         23 :             require(buf->params.storable);
    1142                 :            :             break;
    1143                 :            :         }
    1144                 :          0 :         case PL_DESC_BUF_TEXEL_UNIFORM: {
    1145                 :            :             pl_buf buf = db.object;
    1146   [ #  #  #  # ]:          0 :             require(buf->params.uniform && buf->params.format);
    1147                 :            :             break;
    1148                 :            :         }
    1149                 :         18 :         case PL_DESC_BUF_TEXEL_STORAGE: {
    1150                 :            :             pl_buf buf = db.object;
    1151                 :         18 :             pl_fmt fmt = buf->params.format;
    1152   [ +  -  -  + ]:         18 :             require(buf->params.storable && buf->params.format);
    1153   [ +  -  -  + ]:         18 :             require(desc.access != PL_DESC_ACCESS_READWRITE || (fmt->caps & PL_FMT_CAP_READWRITE));
    1154                 :            :             break;
    1155                 :            :         }
    1156                 :            :         case PL_DESC_INVALID:
    1157                 :            :         case PL_DESC_TYPE_COUNT:
    1158                 :          0 :             pl_unreachable();
    1159                 :            :         }
    1160                 :            :     }
    1161                 :            : 
    1162         [ +  + ]:       3530 :     for (int i = 0; i < params->num_var_updates; i++) {
    1163                 :       1110 :         struct pl_var_update vu = params->var_updates[i];
    1164   [ +  -  -  + ]:       1110 :         require(vu.index >= 0 && vu.index < pass->params.num_variables);
    1165         [ -  + ]:       1110 :         require(vu.data);
    1166                 :            :     }
    1167                 :            : 
    1168   [ +  +  -  + ]:       2420 :     require(params->push_constants || !pass->params.push_constants_size);
    1169                 :            : 
    1170   [ +  +  -  - ]:       2420 :     switch (pass->params.type) {
    1171                 :       2306 :     case PL_PASS_RASTER: {
    1172   [ +  +  -  - ]:       2306 :         switch (pass->params.vertex_type) {
    1173                 :         20 :         case PL_PRIM_TRIANGLE_LIST:
    1174         [ -  + ]:         20 :             require(params->vertex_count % 3 == 0);
    1175                 :            :             // fall through
    1176                 :            :         case PL_PRIM_TRIANGLE_STRIP:
    1177         [ -  + ]:       2306 :             require(params->vertex_count >= 3);
    1178                 :            :             break;
    1179                 :            :         case PL_PRIM_TYPE_COUNT:
    1180                 :          0 :             pl_unreachable();
    1181                 :            :         }
    1182                 :            : 
    1183         [ -  + ]:       2306 :         require(!params->vertex_data ^ !params->vertex_buf);
    1184         [ +  + ]:       2306 :         if (params->vertex_buf) {
    1185                 :            :             pl_buf vertex_buf = params->vertex_buf;
    1186         [ -  + ]:        471 :             require(vertex_buf->params.drawable);
    1187   [ +  -  +  + ]:        471 :             if (!params->index_data && !params->index_buf) {
    1188                 :            :                 // Cannot bounds check indexed draws
    1189                 :        466 :                 size_t vert_size = params->vertex_count * pass->params.vertex_stride;
    1190         [ -  + ]:        466 :                 require(params->buf_offset + vert_size <= vertex_buf->params.size);
    1191                 :            :             }
    1192                 :            :         }
    1193                 :            : 
    1194   [ +  +  -  + ]:       2306 :         require(!params->index_data || !params->index_buf);
    1195         [ +  + ]:       2306 :         if (params->index_buf) {
    1196                 :            :             pl_buf index_buf = params->index_buf;
    1197         [ -  + ]:          5 :             require(!params->vertex_data);
    1198         [ -  + ]:          5 :             require(index_buf->params.drawable);
    1199                 :          5 :             size_t index_size = pl_index_buf_size(params);
    1200         [ -  + ]:          5 :             require(params->index_offset + index_size <= index_buf->params.size);
    1201                 :            :         }
    1202                 :            : 
    1203                 :       2306 :         pl_tex target = params->target;
    1204         [ -  + ]:       2306 :         require(target);
    1205                 :          0 :         require(pl_tex_params_dimension(target->params) == 2);
    1206         [ -  + ]:       2306 :         require(target->params.format->signature == pass->params.target_format->signature);
    1207         [ -  + ]:       2306 :         require(target->params.renderable);
    1208                 :            :         pl_rect2d *vp = &new.viewport;
    1209                 :            :         pl_rect2d *sc = &new.scissors;
    1210                 :            : 
    1211                 :            :         // Sanitize viewport/scissors
    1212   [ +  -  +  + ]:       2306 :         if (!vp->x0 && !vp->x1)
    1213                 :       1837 :             vp->x1 = target->params.w;
    1214   [ +  -  +  + ]:       2306 :         if (!vp->y0 && !vp->y1)
    1215                 :       1837 :             vp->y1 = target->params.h;
    1216                 :            : 
    1217   [ +  -  +  + ]:       2306 :         if (!sc->x0 && !sc->x1)
    1218                 :         24 :             sc->x1 = target->params.w;
    1219   [ +  -  +  + ]:       2306 :         if (!sc->y0 && !sc->y1)
    1220                 :         24 :             sc->y1 = target->params.h;
    1221                 :            : 
    1222                 :            :         // Constrain the scissors to the target dimension (to sanitize the
    1223                 :            :         // underlying graphics API calls)
    1224         [ +  - ]:       2306 :         sc->x0 = PL_CLAMP(sc->x0, 0, target->params.w);
    1225         [ +  - ]:       2306 :         sc->y0 = PL_CLAMP(sc->y0, 0, target->params.h);
    1226         [ +  - ]:       2306 :         sc->x1 = PL_CLAMP(sc->x1, 0, target->params.w);
    1227         [ +  - ]:       2306 :         sc->y1 = PL_CLAMP(sc->y1, 0, target->params.h);
    1228                 :            : 
    1229                 :            :         // Scissors wholly outside target -> silently drop pass (also needed
    1230                 :            :         // to ensure we don't cause UB by specifying invalid scissors)
    1231   [ +  -  +  - ]:       2306 :         if (!pl_rect_w(*sc) || !pl_rect_h(*sc))
    1232                 :            :             return;
    1233                 :            : 
    1234         [ -  + ]:       2306 :         require(pl_rect_w(*vp) > 0);
    1235         [ -  + ]:       2306 :         require(pl_rect_h(*vp) > 0);
    1236         [ -  + ]:       2306 :         require(pl_rect_w(*sc) > 0);
    1237         [ -  + ]:       2306 :         require(pl_rect_h(*sc) > 0);
    1238                 :            : 
    1239         [ +  + ]:       2306 :         if (!pass->params.load_target)
    1240                 :       2154 :             pl_tex_invalidate(gpu, target);
    1241                 :            :         break;
    1242                 :            :     }
    1243                 :            :     case PL_PASS_COMPUTE:
    1244         [ +  + ]:        456 :         for (int i = 0; i < PL_ARRAY_SIZE(params->compute_groups); i++) {
    1245         [ -  + ]:        342 :             require(params->compute_groups[i] >= 0);
    1246         [ -  + ]:        342 :             require(params->compute_groups[i] <= gpu->limits.max_dispatch[i]);
    1247                 :            :         }
    1248                 :            :         break;
    1249                 :            :     case PL_PASS_INVALID:
    1250                 :            :     case PL_PASS_TYPE_COUNT:
    1251                 :          0 :         pl_unreachable();
    1252                 :            :     }
    1253                 :            : 
    1254                 :       2420 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
    1255                 :       2420 :     impl->pass_run(gpu, &new);
    1256                 :            : 
    1257                 :            : error:
    1258                 :       2420 :     return;
    1259                 :            : }
    1260                 :            : 
    1261                 :        363 : void pl_gpu_flush(pl_gpu gpu)
    1262                 :            : {
    1263                 :        363 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
    1264         [ +  - ]:        363 :     if (impl->gpu_flush)
    1265                 :        363 :         impl->gpu_flush(gpu);
    1266                 :        363 : }
    1267                 :            : 
    1268                 :        697 : void pl_gpu_finish(pl_gpu gpu)
    1269                 :            : {
    1270                 :        697 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
    1271                 :        697 :     impl->gpu_finish(gpu);
    1272                 :        697 : }
    1273                 :            : 
    1274                 :         11 : bool pl_gpu_is_failed(pl_gpu gpu)
    1275                 :            : {
    1276                 :         11 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
    1277         [ +  - ]:         11 :     if (!impl->gpu_is_failed)
    1278                 :            :         return false;
    1279                 :            : 
    1280                 :         11 :     return impl->gpu_is_failed(gpu);
    1281                 :            : }
    1282                 :            : 
    1283                 :       1860 : pl_timer pl_timer_create(pl_gpu gpu)
    1284                 :            : {
    1285                 :       1860 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
    1286         [ +  + ]:       1860 :     if (!impl->timer_create)
    1287                 :            :         return NULL;
    1288                 :            : 
    1289                 :       1404 :     return impl->timer_create(gpu);
    1290                 :            : }
    1291                 :            : 
    1292                 :       1860 : void pl_timer_destroy(pl_gpu gpu, pl_timer *timer)
    1293                 :            : {
    1294         [ +  + ]:       1860 :     if (!*timer)
    1295                 :            :         return;
    1296                 :            : 
    1297                 :       1369 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
    1298                 :       1369 :     impl->timer_destroy(gpu, *timer);
    1299                 :       1369 :     *timer = NULL;
    1300                 :            : }
    1301                 :            : 
    1302                 :       4746 : uint64_t pl_timer_query(pl_gpu gpu, pl_timer timer)
    1303                 :            : {
    1304         [ +  + ]:       4746 :     if (!timer)
    1305                 :            :         return 0;
    1306                 :            : 
    1307                 :       4255 :     const struct pl_gpu_fns *impl = PL_PRIV(gpu);
    1308                 :       4255 :     return impl->timer_query(gpu, timer);
    1309                 :            : }

Generated by: LCOV version 1.16