LCOV - code coverage report
Current view: top level - src - dummy.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 143 161 88.8 %
Date: 2025-03-29 09:04:10 Functions: 15 18 83.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 55 72 76.4 %

           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 <limits.h>
      19                 :            : #include <string.h>
      20                 :            : 
      21                 :            : #include "gpu.h"
      22                 :            : 
      23                 :            : #include <libplacebo/dummy.h>
      24                 :            : 
      25                 :            : const struct pl_gpu_dummy_params pl_gpu_dummy_default_params = { PL_GPU_DUMMY_DEFAULTS };
      26                 :            : static const struct pl_gpu_fns pl_fns_dummy;
      27                 :            : 
      28                 :            : struct priv {
      29                 :            :     struct pl_gpu_fns impl;
      30                 :            :     struct pl_gpu_dummy_params params;
      31                 :            : };
      32                 :            : 
      33                 :          2 : pl_gpu pl_gpu_dummy_create(pl_log log, const struct pl_gpu_dummy_params *params)
      34                 :            : {
      35         [ +  - ]:          2 :     params = PL_DEF(params, &pl_gpu_dummy_default_params);
      36                 :            : 
      37                 :          2 :     struct pl_gpu_t *gpu = pl_zalloc_obj(NULL, gpu, struct priv);
      38                 :          2 :     gpu->log = log;
      39                 :          2 :     gpu->glsl = params->glsl;
      40                 :          2 :     gpu->limits = params->limits;
      41                 :            : 
      42                 :          2 :     struct priv *p = PL_PRIV(gpu);
      43                 :          2 :     p->impl = pl_fns_dummy;
      44                 :          2 :     p->params = *params;
      45                 :            : 
      46                 :            :     // Forcibly override these, because we know for sure what the values are
      47                 :          2 :     gpu->limits.align_tex_xfer_pitch = 1;
      48                 :          2 :     gpu->limits.align_tex_xfer_offset = 1;
      49                 :          2 :     gpu->limits.align_vertex_stride = 1;
      50                 :            : 
      51                 :            :     // Set up the dummy formats, add one for each possible format type that we
      52                 :            :     // can represent on the host
      53                 :            :     PL_ARRAY(pl_fmt) formats = {0};
      54         [ +  + ]:         12 :     for (enum pl_fmt_type type = 1; type < PL_FMT_TYPE_COUNT; type++) {
      55         [ +  + ]:         50 :         for (int comps = 1; comps <= 4; comps++) {
      56         [ +  + ]:        200 :             for (int depth = 8; depth < 128; depth *= 2) {
      57         [ +  + ]:        160 :                 if (type == PL_FMT_FLOAT && depth < 16)
      58                 :            :                     continue;
      59                 :            : 
      60                 :            :                 static const char *cnames[] = {
      61                 :            :                     [1] = "r",
      62                 :            :                     [2] = "rg",
      63                 :            :                     [3] = "rgb",
      64                 :            :                     [4] = "rgba",
      65                 :            :                 };
      66                 :            : 
      67                 :            :                 static const char *tnames[] = {
      68                 :            :                     [PL_FMT_UNORM] = "",
      69                 :            :                     [PL_FMT_SNORM] = "s",
      70                 :            :                     [PL_FMT_UINT]  = "u",
      71                 :            :                     [PL_FMT_SINT]  = "i",
      72                 :            :                     [PL_FMT_FLOAT] = "f",
      73                 :            :                 };
      74                 :            : 
      75                 :        152 :                 const char *tname = tnames[type];
      76         [ +  + ]:        152 :                 if (type == PL_FMT_FLOAT && depth == 16)
      77                 :            :                     tname = "hf";
      78                 :            : 
      79                 :        152 :                 struct pl_fmt_t *fmt = pl_alloc_ptr(gpu, fmt);
      80                 :        152 :                 *fmt = (struct pl_fmt_t) {
      81                 :        152 :                     .name = pl_asprintf(fmt, "%s%d%s", cnames[comps], depth, tname),
      82                 :            :                     .type = type,
      83                 :            :                     .num_components = comps,
      84                 :            :                     .opaque = false,
      85                 :            :                     .gatherable = true,
      86                 :        152 :                     .internal_size = comps * depth / 8,
      87                 :            :                     .texel_size = comps * depth / 8,
      88                 :            :                     .texel_align = 1,
      89                 :            :                     .caps = PL_FMT_CAP_SAMPLEABLE | PL_FMT_CAP_LINEAR |
      90                 :            :                             PL_FMT_CAP_RENDERABLE | PL_FMT_CAP_BLENDABLE |
      91                 :            :                             PL_FMT_CAP_VERTEX | PL_FMT_CAP_HOST_READABLE,
      92                 :            :                 };
      93                 :            : 
      94         [ +  + ]:        532 :                 for (int i = 0; i < comps; i++) {
      95                 :        380 :                     fmt->component_depth[i] = depth;
      96                 :        380 :                     fmt->host_bits[i] = depth;
      97                 :        380 :                     fmt->sample_order[i] = i;
      98                 :            :                 }
      99                 :            : 
     100         [ +  - ]:        152 :                 if (gpu->glsl.compute)
     101                 :        152 :                     fmt->caps |= PL_FMT_CAP_STORABLE;
     102   [ +  -  +  - ]:        152 :                 if (gpu->limits.max_buffer_texels && gpu->limits.max_ubo_size)
     103                 :        152 :                     fmt->caps |= PL_FMT_CAP_TEXEL_UNIFORM;
     104   [ +  -  +  - ]:        152 :                 if (gpu->limits.max_buffer_texels && gpu->limits.max_ssbo_size)
     105                 :        152 :                     fmt->caps |= PL_FMT_CAP_TEXEL_STORAGE;
     106                 :            : 
     107                 :        152 :                 fmt->glsl_type = pl_var_glsl_type_name(pl_var_from_fmt(fmt, ""));
     108                 :        152 :                 fmt->glsl_format = pl_fmt_glsl_format(fmt, comps);
     109                 :        152 :                 fmt->fourcc = pl_fmt_fourcc(fmt);
     110         [ +  + ]:        152 :                 if (!fmt->glsl_format)
     111                 :         80 :                     fmt->caps &= ~(PL_FMT_CAP_STORABLE | PL_FMT_CAP_TEXEL_STORAGE);
     112   [ +  +  +  +  :        152 :                 PL_ARRAY_APPEND(gpu, formats, fmt);
                   -  + ]
     113                 :            :             }
     114                 :            :         }
     115                 :            :     }
     116                 :            : 
     117                 :          2 :     gpu->formats = formats.elem;
     118                 :          2 :     gpu->num_formats = formats.num;
     119                 :          2 :     return pl_gpu_finalize(gpu);
     120                 :            : }
     121                 :            : 
     122                 :          2 : static void dumb_destroy(pl_gpu gpu)
     123                 :            : {
     124                 :          2 :     pl_free((void *) gpu);
     125                 :          2 : }
     126                 :            : 
     127                 :          2 : void pl_gpu_dummy_destroy(pl_gpu *gpu)
     128                 :            : {
     129                 :          2 :     pl_gpu_destroy(*gpu);
     130                 :          2 :     *gpu = NULL;
     131                 :          2 : }
     132                 :            : 
     133                 :            : struct buf_priv {
     134                 :            :     uint8_t *data;
     135                 :            : };
     136                 :            : 
     137                 :          5 : static pl_buf dumb_buf_create(pl_gpu gpu, const struct pl_buf_params *params)
     138                 :            : {
     139                 :          5 :     struct pl_buf_t *buf = pl_zalloc_obj(NULL, buf, struct buf_priv);
     140                 :          5 :     buf->params = *params;
     141                 :          5 :     buf->params.initial_data = NULL;
     142                 :            : 
     143                 :          5 :     struct buf_priv *p = PL_PRIV(buf);
     144                 :          5 :     p->data = malloc(params->size);
     145         [ -  + ]:          5 :     if (!p->data) {
     146                 :          0 :         PL_ERR(gpu, "Failed allocating memory for dummy buffer!");
     147                 :          0 :         pl_free(buf);
     148                 :          0 :         return NULL;
     149                 :            :     }
     150                 :            : 
     151         [ +  + ]:          5 :     if (params->initial_data)
     152                 :            :         memcpy(p->data, params->initial_data, params->size);
     153         [ +  + ]:          5 :     if (params->host_mapped)
     154                 :          1 :         buf->data = p->data;
     155                 :            : 
     156                 :            :     return buf;
     157                 :            : }
     158                 :            : 
     159                 :          5 : static void dumb_buf_destroy(pl_gpu gpu, pl_buf buf)
     160                 :            : {
     161                 :          5 :     struct buf_priv *p = PL_PRIV(buf);
     162                 :          5 :     free(p->data);
     163                 :          5 :     pl_free((void *) buf);
     164                 :          5 : }
     165                 :            : 
     166                 :          0 : uint8_t *pl_buf_dummy_data(pl_buf buf)
     167                 :            : {
     168                 :          0 :     struct buf_priv *p = PL_PRIV(buf);
     169                 :          0 :     return p->data;
     170                 :            : }
     171                 :            : 
     172                 :          1 : static void dumb_buf_write(pl_gpu gpu, pl_buf buf, size_t buf_offset,
     173                 :            :                            const void *data, size_t size)
     174                 :            : {
     175                 :          1 :     struct buf_priv *p = PL_PRIV(buf);
     176                 :          1 :     memcpy(p->data + buf_offset, data, size);
     177                 :          1 : }
     178                 :            : 
     179                 :          3 : static bool dumb_buf_read(pl_gpu gpu, pl_buf buf, size_t buf_offset,
     180                 :            :                           void *dest, size_t size)
     181                 :            : {
     182                 :          3 :     struct buf_priv *p = PL_PRIV(buf);
     183                 :          3 :     memcpy(dest, p->data + buf_offset, size);
     184                 :          3 :     return true;
     185                 :            : }
     186                 :            : 
     187                 :          1 : static void dumb_buf_copy(pl_gpu gpu, pl_buf dst, size_t dst_offset,
     188                 :            :                           pl_buf src, size_t src_offset, size_t size)
     189                 :            : {
     190                 :          1 :     struct buf_priv *dstp = PL_PRIV(dst);
     191                 :          1 :     struct buf_priv *srcp = PL_PRIV(src);
     192                 :          1 :     memcpy(dstp->data + dst_offset, srcp->data + src_offset, size);
     193                 :          1 : }
     194                 :            : 
     195                 :            : struct tex_priv {
     196                 :            :     void *data;
     197                 :            : };
     198                 :            : 
     199                 :            : static size_t tex_size(pl_gpu gpu, pl_tex tex)
     200                 :            : {
     201                 :        460 :     size_t size = tex->params.format->texel_size * tex->params.w;
     202                 :        920 :     size *= PL_DEF(tex->params.h, 1);
     203         [ +  + ]:        460 :     size *= PL_DEF(tex->params.d, 1);
     204                 :            :     return size;
     205                 :            : }
     206                 :            : 
     207                 :        460 : static pl_tex dumb_tex_create(pl_gpu gpu, const struct pl_tex_params *params)
     208                 :            : {
     209                 :        460 :     struct pl_tex_t *tex = pl_zalloc_obj(NULL, tex, void *);
     210                 :        460 :     tex->params = *params;
     211                 :        460 :     tex->params.initial_data = NULL;
     212                 :            : 
     213         [ +  + ]:        460 :     struct tex_priv *p = PL_PRIV(tex);
     214                 :        460 :     p->data = malloc(tex_size(gpu, tex));
     215         [ -  + ]:        460 :     if (!p->data) {
     216                 :          0 :         PL_ERR(gpu, "Failed allocating memory for dummy texture!");
     217                 :          0 :         pl_free(tex);
     218                 :          0 :         return NULL;
     219                 :            :     }
     220                 :            : 
     221         [ +  + ]:        460 :     if (params->initial_data)
     222                 :            :         memcpy(p->data, params->initial_data, tex_size(gpu, tex));
     223                 :            : 
     224                 :            :     return tex;
     225                 :            : }
     226                 :            : 
     227                 :          1 : pl_tex pl_tex_dummy_create(pl_gpu gpu, const struct pl_tex_dummy_params *params)
     228                 :            : {
     229                 :            :     // Only do minimal sanity checking, since this is just a dummy texture
     230   [ +  -  +  -  :          1 :     pl_assert(params->format && params->w >= 0 && params->h >= 0 && params->d >= 0);
             +  -  -  + ]
     231                 :            : 
     232                 :          1 :     struct pl_tex_t *tex = pl_zalloc_obj(NULL, tex, struct tex_priv);
     233                 :          1 :     tex->sampler_type = params->sampler_type;
     234                 :          1 :     tex->params = (struct pl_tex_params) {
     235                 :          1 :         .w = params->w,
     236                 :          1 :         .h = params->h,
     237                 :          1 :         .d = params->d,
     238                 :          1 :         .format = params->format,
     239                 :            :         .sampleable = true,
     240                 :          1 :         .user_data = params->user_data,
     241                 :            :     };
     242                 :            : 
     243                 :          1 :     return tex;
     244                 :            : }
     245                 :            : 
     246                 :        461 : static void dumb_tex_destroy(pl_gpu gpu, pl_tex tex)
     247                 :            : {
     248                 :        461 :     struct tex_priv *p = PL_PRIV(tex);
     249         [ +  + ]:        461 :     if (p->data)
     250                 :        460 :         free(p->data);
     251                 :        461 :     pl_free((void *) tex);
     252                 :        461 : }
     253                 :            : 
     254                 :          2 : uint8_t *pl_tex_dummy_data(pl_tex tex)
     255                 :            : {
     256                 :          2 :     struct tex_priv *p = PL_PRIV(tex);
     257                 :          2 :     return p->data;
     258                 :            : }
     259                 :            : 
     260                 :        228 : static bool dumb_tex_upload(pl_gpu gpu, const struct pl_tex_transfer_params *params)
     261                 :            : {
     262                 :        228 :     pl_tex tex = params->tex;
     263                 :        228 :     struct tex_priv *p = PL_PRIV(tex);
     264         [ -  + ]:        228 :     pl_assert(p->data);
     265                 :            : 
     266                 :        228 :     const uint8_t *src = params->ptr;
     267                 :            :     uint8_t *dst = p->data;
     268         [ -  + ]:        228 :     if (params->buf) {
     269                 :          0 :         struct buf_priv *bufp = PL_PRIV(params->buf);
     270                 :          0 :         src = (uint8_t *) bufp->data + params->buf_offset;
     271                 :            :     }
     272                 :            : 
     273                 :        228 :     size_t texel_size = tex->params.format->texel_size;
     274                 :        228 :     size_t row_size = pl_rect_w(params->rc) * texel_size;
     275         [ +  + ]:       1596 :     for (int z = params->rc.z0; z < params->rc.z1; z++) {
     276                 :       1368 :         size_t src_plane = z * params->depth_pitch;
     277                 :       1368 :         size_t dst_plane = z * tex->params.h * tex->params.w * texel_size;
     278         [ +  + ]:      22116 :         for (int y = params->rc.y0; y < params->rc.y1; y++) {
     279                 :      20748 :             size_t src_row = src_plane + y * params->row_pitch;
     280                 :      20748 :             size_t dst_row = dst_plane + y * tex->params.w * texel_size;
     281                 :      20748 :             size_t pos = params->rc.x0 * texel_size;
     282                 :      20748 :             memcpy(&dst[dst_row + pos], &src[src_row + pos], row_size);
     283                 :            :         }
     284                 :            :     }
     285                 :            : 
     286                 :        228 :     return true;
     287                 :            : }
     288                 :            : 
     289                 :        228 : static bool dumb_tex_download(pl_gpu gpu, const struct pl_tex_transfer_params *params)
     290                 :            : {
     291                 :        228 :     pl_tex tex = params->tex;
     292                 :        228 :     struct tex_priv *p = PL_PRIV(tex);
     293         [ -  + ]:        228 :     pl_assert(p->data);
     294                 :            : 
     295                 :            :     const uint8_t *src = p->data;
     296                 :        228 :     uint8_t *dst = params->ptr;
     297         [ -  + ]:        228 :     if (params->buf) {
     298                 :          0 :         struct buf_priv *bufp = PL_PRIV(params->buf);
     299                 :          0 :         dst = (uint8_t *) bufp->data + params->buf_offset;
     300                 :            :     }
     301                 :            : 
     302                 :        228 :     size_t texel_size = tex->params.format->texel_size;
     303                 :        228 :     size_t row_size = pl_rect_w(params->rc) * texel_size;
     304         [ +  + ]:       1596 :     for (int z = params->rc.z0; z < params->rc.z1; z++) {
     305                 :       1368 :         size_t src_plane = z * tex->params.h * tex->params.w * texel_size;
     306                 :       1368 :         size_t dst_plane = z * params->depth_pitch;
     307         [ +  + ]:      22116 :         for (int y = params->rc.y0; y < params->rc.y1; y++) {
     308                 :      20748 :             size_t src_row = src_plane + y * tex->params.w * texel_size;
     309                 :      20748 :             size_t dst_row = dst_plane + y * params->row_pitch;
     310                 :      20748 :             size_t pos = params->rc.x0 * texel_size;
     311                 :      20748 :             memcpy(&dst[dst_row + pos], &src[src_row + pos], row_size);
     312                 :            :         }
     313                 :            :     }
     314                 :            : 
     315                 :        228 :     return true;
     316                 :            : }
     317                 :            : 
     318                 :          0 : static int dumb_desc_namespace(pl_gpu gpu, enum pl_desc_type type)
     319                 :            : {
     320                 :          0 :     return 0; // safest behavior: never alias bindings
     321                 :            : }
     322                 :            : 
     323                 :          0 : static pl_pass dumb_pass_create(pl_gpu gpu, const struct pl_pass_params *params)
     324                 :            : {
     325                 :          0 :     PL_ERR(gpu, "Creating render passes is not supported for dummy GPUs");
     326                 :          0 :     return NULL;
     327                 :            : }
     328                 :            : 
     329                 :        228 : static void dumb_gpu_finish(pl_gpu gpu)
     330                 :            : {
     331                 :            :     // no-op
     332                 :        228 : }
     333                 :            : 
     334                 :            : static const struct pl_gpu_fns pl_fns_dummy = {
     335                 :            :     .destroy = dumb_destroy,
     336                 :            :     .buf_create = dumb_buf_create,
     337                 :            :     .buf_destroy = dumb_buf_destroy,
     338                 :            :     .buf_write = dumb_buf_write,
     339                 :            :     .buf_read = dumb_buf_read,
     340                 :            :     .buf_copy = dumb_buf_copy,
     341                 :            :     .tex_create = dumb_tex_create,
     342                 :            :     .tex_destroy = dumb_tex_destroy,
     343                 :            :     .tex_upload = dumb_tex_upload,
     344                 :            :     .tex_download = dumb_tex_download,
     345                 :            :     .desc_namespace = dumb_desc_namespace,
     346                 :            :     .pass_create = dumb_pass_create,
     347                 :            :     .gpu_finish = dumb_gpu_finish,
     348                 :            : };

Generated by: LCOV version 1.16