LCOV - code coverage report
Current view: top level - src/glsl - spirv_shaderc.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 57 65 87.7 %
Date: 2025-03-29 09:04:10 Functions: 3 3 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 15 26 57.7 %

           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 <stdlib.h>
      19                 :            : #include <shaderc/shaderc.h>
      20                 :            : 
      21                 :            : #include "hash.h"
      22                 :            : #include "spirv.h"
      23                 :            : #include "utils.h"
      24                 :            : 
      25                 :            : const struct spirv_compiler pl_spirv_shaderc;
      26                 :            : 
      27                 :            : struct priv {
      28                 :            :     shaderc_compiler_t compiler;
      29                 :            : };
      30                 :            : 
      31                 :          3 : static void shaderc_destroy(pl_spirv spirv)
      32                 :            : {
      33                 :          3 :     struct priv *p = PL_PRIV(spirv);
      34                 :          3 :     shaderc_compiler_release(p->compiler);
      35                 :          3 :     pl_free((void *) spirv);
      36                 :          3 : }
      37                 :            : 
      38                 :          3 : static pl_spirv shaderc_create(pl_log log, struct pl_spirv_version spirv_ver)
      39                 :            : {
      40                 :          3 :     struct pl_spirv_t *spirv = pl_alloc_obj(NULL, spirv, struct priv);
      41                 :          3 :     *spirv = (struct pl_spirv_t) {
      42                 :          3 :         .signature = pl_str0_hash(pl_spirv_shaderc.name),
      43                 :            :         .impl      = &pl_spirv_shaderc,
      44                 :            :         .version   = spirv_ver,
      45                 :            :         .log       = log,
      46                 :            :     };
      47                 :            : 
      48                 :          3 :     struct priv *p = PL_PRIV(spirv);
      49                 :          3 :     p->compiler = shaderc_compiler_initialize();
      50         [ -  + ]:          3 :     if (!p->compiler)
      51                 :          0 :         goto error;
      52                 :            : 
      53                 :          3 :     unsigned int ver = 0, rev = 0;
      54                 :          3 :     shaderc_get_spv_version(&ver, &rev);
      55                 :          3 :     PL_INFO(spirv, "shaderc SPIR-V version %u.%u rev %u",
      56                 :            :             ver >> 16, (ver >> 8) & 0xff, rev);
      57                 :            : 
      58                 :            :     // Clamp to supported version by shaderc
      59         [ -  + ]:          3 :     if (ver < spirv->version.spv_version) {
      60         [ #  # ]:          0 :         spirv->version.spv_version = ver;
      61                 :          0 :         spirv->version.env_version = pl_spirv_version_to_vulkan(ver);
      62                 :            :     }
      63                 :            : 
      64                 :          3 :     pl_hash_merge(&spirv->signature, (uint64_t) spirv->version.spv_version << 32 |
      65                 :          3 :                                                 spirv->version.env_version);
      66                 :          3 :     pl_hash_merge(&spirv->signature, (uint64_t) ver << 32 | rev);
      67                 :          3 :     return spirv;
      68                 :            : 
      69                 :            : error:
      70                 :            :     shaderc_destroy(spirv);
      71                 :          0 :     return NULL;
      72                 :            : }
      73                 :            : 
      74                 :        266 : static pl_str shaderc_compile(pl_spirv spirv, void *alloc,
      75                 :            :                               struct pl_glsl_version glsl_ver,
      76                 :            :                               enum glsl_shader_stage stage,
      77                 :            :                               const char *shader)
      78                 :            : {
      79                 :        266 :     struct priv *p = PL_PRIV(spirv);
      80                 :        266 :     const size_t len = strlen(shader);
      81                 :            : 
      82                 :        266 :     shaderc_compile_options_t opts = shaderc_compile_options_initialize();
      83         [ -  + ]:        266 :     if (!opts)
      84                 :          0 :         return (pl_str) {0};
      85                 :            : 
      86                 :        266 :     shaderc_compile_options_set_optimization_level(opts,
      87                 :            :             shaderc_optimization_level_performance);
      88                 :        266 :     shaderc_compile_options_set_target_spirv(opts, spirv->version.spv_version);
      89                 :        266 :     shaderc_compile_options_set_target_env(opts, shaderc_target_env_vulkan,
      90                 :        266 :                                                  spirv->version.env_version);
      91                 :            : 
      92         [ +  + ]:       1064 :     for (int i = 0; i < 3; i++) {
      93                 :        798 :         shaderc_compile_options_set_limit(opts,
      94                 :        798 :                 shaderc_limit_max_compute_work_group_size_x + i,
      95                 :        798 :                 glsl_ver.max_group_size[i]);
      96                 :            :     }
      97                 :            : 
      98                 :        266 :     shaderc_compile_options_set_limit(opts,
      99                 :            :             shaderc_limit_min_program_texel_offset,
     100                 :        266 :             glsl_ver.min_gather_offset);
     101                 :        266 :     shaderc_compile_options_set_limit(opts,
     102                 :            :             shaderc_limit_max_program_texel_offset,
     103                 :        266 :             glsl_ver.max_gather_offset);
     104                 :            : 
     105                 :            :     static const shaderc_shader_kind kinds[] = {
     106                 :            :         [GLSL_SHADER_VERTEX]   = shaderc_glsl_vertex_shader,
     107                 :            :         [GLSL_SHADER_FRAGMENT] = shaderc_glsl_fragment_shader,
     108                 :            :         [GLSL_SHADER_COMPUTE]  = shaderc_glsl_compute_shader,
     109                 :            :     };
     110                 :            : 
     111                 :            :     static const char * const file_name = "input";
     112                 :            :     static const char * const entry_point = "main";
     113                 :            : 
     114                 :            :     shaderc_compilation_result_t res;
     115                 :        266 :     res = shaderc_compile_into_spv(p->compiler, shader, len, kinds[stage],
     116                 :            :                                    file_name, entry_point, opts);
     117                 :            : 
     118                 :        266 :     int errs = shaderc_result_get_num_errors(res),
     119                 :        266 :         warn = shaderc_result_get_num_warnings(res);
     120                 :            : 
     121   [ +  -  +  + ]:        266 :     enum pl_log_level lev = errs ? PL_LOG_ERR : warn ? PL_LOG_INFO : PL_LOG_DEBUG;
     122                 :            : 
     123                 :        266 :     int s = shaderc_result_get_compilation_status(res);
     124                 :            :     bool success = s == shaderc_compilation_status_success;
     125         [ -  + ]:        266 :     if (!success)
     126                 :            :         lev = PL_LOG_ERR;
     127                 :            : 
     128                 :        266 :     const char *msg = shaderc_result_get_error_message(res);
     129         [ +  + ]:        266 :     if (msg[0])
     130                 :         18 :         PL_MSG(spirv, lev, "shaderc output:\n%s", msg);
     131                 :            : 
     132                 :            :     static const char *results[] = {
     133                 :            :         [shaderc_compilation_status_success]            = "success",
     134                 :            :         [shaderc_compilation_status_invalid_stage]      = "invalid stage",
     135                 :            :         [shaderc_compilation_status_compilation_error]  = "error",
     136                 :            :         [shaderc_compilation_status_internal_error]     = "internal error",
     137                 :            :         [shaderc_compilation_status_null_result_object] = "no result",
     138                 :            :         [shaderc_compilation_status_invalid_assembly]   = "invalid assembly",
     139                 :            :     };
     140                 :            : 
     141         [ +  - ]:        266 :     const char *status = s < PL_ARRAY_SIZE(results) ? results[s] : "unknown";
     142                 :        266 :     PL_MSG(spirv, lev, "shaderc compile status '%s' (%d errors, %d warnings)",
     143                 :            :            status, errs, warn);
     144                 :            : 
     145                 :            :     pl_str ret = {0};
     146         [ +  - ]:        266 :     if (success) {
     147                 :        266 :         void *bytes = (void *) shaderc_result_get_bytes(res);
     148         [ -  + ]:        266 :         pl_assert(bytes);
     149                 :        266 :         ret.len = shaderc_result_get_length(res);
     150                 :        266 :         ret.buf = pl_memdup(alloc, bytes, ret.len);
     151                 :            : 
     152         [ -  + ]:        266 :         if (pl_msg_test(spirv->log, PL_LOG_TRACE)) {
     153                 :            :             shaderc_compilation_result_t dis;
     154                 :          0 :             dis = shaderc_compile_into_spv_assembly(p->compiler, shader, len,
     155                 :            :                                                     kinds[stage], file_name,
     156                 :            :                                                     entry_point, opts);
     157                 :          0 :             PL_TRACE(spirv, "Generated SPIR-V:\n%.*s",
     158                 :            :                      (int) shaderc_result_get_length(dis),
     159                 :            :                      shaderc_result_get_bytes(dis));
     160                 :          0 :             shaderc_result_release(dis);
     161                 :            :         }
     162                 :            :     }
     163                 :            : 
     164                 :        266 :     shaderc_result_release(res);
     165                 :        266 :     shaderc_compile_options_release(opts);
     166                 :        266 :     return ret;
     167                 :            : }
     168                 :            : 
     169                 :            : const struct spirv_compiler pl_spirv_shaderc = {
     170                 :            :     .name       = "shaderc",
     171                 :            :     .destroy    = shaderc_destroy,
     172                 :            :     .create     = shaderc_create,
     173                 :            :     .compile    = shaderc_compile,
     174                 :            : };

Generated by: LCOV version 1.16