LCOV - code coverage report
Current view: top level - src/opengl - gpu_pass.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 309 379 81.5 %
Date: 2025-03-29 09:04:10 Functions: 11 11 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 124 222 55.9 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * This file is part of libplacebo.
       3                 :            :  *
       4                 :            :  * libplacebo is free software; you can redistribute it and/or
       5                 :            :  * modify it under the terms of the GNU Lesser General Public
       6                 :            :  * License as published by the Free Software Foundation; either
       7                 :            :  * version 2.1 of the License, or (at your option) any later version.
       8                 :            :  *
       9                 :            :  * libplacebo is distributed in the hope that it will be useful,
      10                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12                 :            :  * GNU Lesser General Public License for more details.
      13                 :            :  *
      14                 :            :  * You should have received a copy of the GNU Lesser General Public
      15                 :            :  * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
      16                 :            :  */
      17                 :            : 
      18                 :            : #include "gpu.h"
      19                 :            : #include "cache.h"
      20                 :            : #include "formats.h"
      21                 :            : #include "utils.h"
      22                 :            : 
      23                 :       3608 : int gl_desc_namespace(pl_gpu gpu, enum pl_desc_type type)
      24                 :            : {
      25                 :       3608 :     return (int) type;
      26                 :            : }
      27                 :            : 
      28                 :            : struct gl_cache_header {
      29                 :            :     GLenum format;
      30                 :            : };
      31                 :            : 
      32                 :        332 : static GLuint load_cached_program(pl_gpu gpu, pl_cache cache, pl_cache_obj *obj)
      33                 :            : {
      34                 :            :     const gl_funcs *gl = gl_funcs_get(gpu);
      35         [ -  + ]:        332 :     if (!gl_test_ext(gpu, "GL_ARB_get_program_binary", 41, 30))
      36                 :            :         return 0;
      37                 :            : 
      38         [ +  + ]:        332 :     if (!pl_cache_get(cache, obj))
      39                 :            :         return 0;
      40                 :            : 
      41         [ -  + ]:          1 :     if (obj->size < sizeof(struct gl_cache_header))
      42                 :            :         return 0;
      43                 :            : 
      44                 :          1 :     GLuint prog = gl->CreateProgram();
      45         [ -  + ]:          1 :     if (!gl_check_err(gpu, "load_cached_program: glCreateProgram"))
      46                 :            :         return 0;
      47                 :            : 
      48                 :          1 :     struct gl_cache_header *header = (struct gl_cache_header *) obj->data;
      49         [ +  - ]:          1 :     pl_str rest = (pl_str) { obj->data, obj->size };
      50                 :            :     rest = pl_str_drop(rest, sizeof(*header));
      51                 :          1 :     gl->ProgramBinary(prog, header->format, rest.buf, rest.len);
      52                 :          1 :     gl->GetError(); // discard potential useless error
      53                 :            : 
      54                 :          1 :     GLint status = 0;
      55                 :          1 :     gl->GetProgramiv(prog, GL_LINK_STATUS, &status);
      56         [ -  + ]:          1 :     if (status)
      57                 :            :         return prog;
      58                 :            : 
      59                 :          0 :     gl->DeleteProgram(prog);
      60                 :          0 :     gl_check_err(gpu, "load_cached_program: glProgramBinary");
      61                 :          0 :     return 0;
      62                 :            : }
      63                 :            : 
      64                 :            : static enum pl_log_level gl_log_level(GLint status, GLint log_length)
      65                 :            : {
      66                 :        959 :     if (!status) {
      67                 :            :         return PL_LOG_ERR;
      68   [ +  -  +  - ]:        959 :     } else if (log_length > 0) {
      69                 :            :         return PL_LOG_INFO;
      70                 :            :     } else {
      71                 :        959 :         return PL_LOG_DEBUG;
      72                 :            :     }
      73                 :            : }
      74                 :            : 
      75                 :        628 : static bool gl_attach_shader(pl_gpu gpu, GLuint program, GLenum type, const char *src)
      76                 :            : {
      77                 :            :     const gl_funcs *gl = gl_funcs_get(gpu);
      78                 :        628 :     GLuint shader = gl->CreateShader(type);
      79                 :        628 :     gl->ShaderSource(shader, 1, &src, NULL);
      80                 :        628 :     gl->CompileShader(shader);
      81                 :            : 
      82                 :        628 :     GLint status = 0;
      83                 :        628 :     gl->GetShaderiv(shader, GL_COMPILE_STATUS, &status);
      84                 :        628 :     GLint log_length = 0;
      85                 :        628 :     gl->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
      86                 :            : 
      87         [ +  - ]:        628 :     enum pl_log_level level = gl_log_level(status, log_length);
      88         [ +  - ]:        628 :     if (pl_msg_test(gpu->log, level)) {
      89                 :        250 :         GLchar *logstr = pl_zalloc(NULL, log_length + 1);
      90                 :        250 :         gl->GetShaderInfoLog(shader, log_length, NULL, logstr);
      91                 :        250 :         PL_MSG(gpu, level, "shader compile log (status=%d): %s", status, logstr);
      92                 :        250 :         pl_free(logstr);
      93                 :            :     }
      94                 :            : 
      95   [ +  -  -  + ]:        628 :     if (!status || !gl_check_err(gpu, "gl_attach_shader"))
      96                 :          0 :         goto error;
      97                 :            : 
      98                 :        628 :     gl->AttachShader(program, shader);
      99                 :        628 :     gl->DeleteShader(shader);
     100                 :        628 :     return true;
     101                 :            : 
     102                 :            : error:
     103                 :          0 :     gl->DeleteShader(shader);
     104                 :          0 :     return false;
     105                 :            : }
     106                 :            : 
     107                 :        331 : static GLuint gl_compile_program(pl_gpu gpu, const struct pl_pass_params *params)
     108                 :            : {
     109                 :            :     const gl_funcs *gl = gl_funcs_get(gpu);
     110                 :        331 :     GLuint prog = gl->CreateProgram();
     111                 :            :     bool ok = true;
     112                 :            : 
     113   [ +  +  -  - ]:        331 :     switch (params->type) {
     114                 :         34 :     case PL_PASS_COMPUTE:
     115                 :         34 :         ok &= gl_attach_shader(gpu, prog, GL_COMPUTE_SHADER, params->glsl_shader);
     116                 :         34 :         break;
     117                 :        297 :     case PL_PASS_RASTER:
     118                 :        297 :         ok &= gl_attach_shader(gpu, prog, GL_VERTEX_SHADER, params->vertex_shader);
     119                 :        297 :         ok &= gl_attach_shader(gpu, prog, GL_FRAGMENT_SHADER, params->glsl_shader);
     120         [ +  + ]:        913 :         for (int i = 0; i < params->num_vertex_attribs; i++)
     121                 :        616 :             gl->BindAttribLocation(prog, i, params->vertex_attribs[i].name);
     122                 :            :         break;
     123                 :            :     case PL_PASS_INVALID:
     124                 :            :     case PL_PASS_TYPE_COUNT:
     125                 :          0 :         pl_unreachable();
     126                 :            :     }
     127                 :            : 
     128   [ +  -  -  + ]:        331 :     if (!ok || !gl_check_err(gpu, "gl_compile_program: attach shader"))
     129                 :          0 :         goto error;
     130                 :            : 
     131                 :        331 :     gl->LinkProgram(prog);
     132                 :        331 :     GLint status = 0;
     133                 :        331 :     gl->GetProgramiv(prog, GL_LINK_STATUS, &status);
     134                 :        331 :     GLint log_length = 0;
     135                 :        331 :     gl->GetProgramiv(prog, GL_INFO_LOG_LENGTH, &log_length);
     136                 :            : 
     137         [ +  - ]:        331 :     enum pl_log_level level = gl_log_level(status, log_length);
     138         [ +  - ]:        331 :     if (pl_msg_test(gpu->log, level)) {
     139                 :        142 :         GLchar *logstr = pl_zalloc(NULL, log_length + 1);
     140                 :        142 :         gl->GetProgramInfoLog(prog, log_length, NULL, logstr);
     141                 :        142 :         PL_MSG(gpu, level, "shader link log (status=%d): %s", status, logstr);
     142                 :        142 :         pl_free(logstr);
     143                 :            :     }
     144                 :            : 
     145         [ -  + ]:        331 :     if (!gl_check_err(gpu, "gl_compile_program: link program"))
     146                 :          0 :         goto error;
     147                 :            : 
     148                 :            :     return prog;
     149                 :            : 
     150                 :          0 : error:
     151                 :          0 :     gl->DeleteProgram(prog);
     152                 :          0 :     PL_ERR(gpu, "Failed compiling/linking GLSL program");
     153                 :          0 :     return 0;
     154                 :            : }
     155                 :            : 
     156                 :            : // For pl_pass.priv
     157                 :            : struct pl_pass_gl {
     158                 :            :     GLuint program;
     159                 :            :     GLuint vao;         // the VAO object
     160                 :            :     uint64_t vao_id;    // buf_gl.id of VAO
     161                 :            :     size_t vao_offset;  // VBO offset of VAO
     162                 :            :     GLuint buffer;      // VBO for raw vertex pointers
     163                 :            :     GLuint index_buffer;
     164                 :            :     GLint *var_locs;
     165                 :            : };
     166                 :            : 
     167                 :        332 : void gl_pass_destroy(pl_gpu gpu, pl_pass pass)
     168                 :            : {
     169                 :            :     const gl_funcs *gl = gl_funcs_get(gpu);
     170                 :            :     if (!MAKE_CURRENT()) {
     171                 :          0 :         PL_ERR(gpu, "Failed uninitializing pass, leaking resources!");
     172                 :          0 :         return;
     173                 :            :     }
     174                 :            : 
     175                 :        332 :     struct pl_pass_gl *pass_gl = PL_PRIV(pass);
     176         [ +  - ]:        332 :     if (pass_gl->vao)
     177                 :        332 :         gl->DeleteVertexArrays(1, &pass_gl->vao);
     178                 :        332 :     gl->DeleteBuffers(1, &pass_gl->index_buffer);
     179                 :        332 :     gl->DeleteBuffers(1, &pass_gl->buffer);
     180                 :        332 :     gl->DeleteProgram(pass_gl->program);
     181                 :            : 
     182                 :        332 :     gl_check_err(gpu, "gl_pass_destroy");
     183                 :            :     RELEASE_CURRENT();
     184                 :        332 :     pl_free((void *) pass);
     185                 :            : }
     186                 :            : 
     187                 :        334 : static void gl_update_va(pl_gpu gpu, pl_pass pass, size_t vbo_offset)
     188                 :            : {
     189                 :            :     const gl_funcs *gl = gl_funcs_get(gpu);
     190         [ +  + ]:        954 :     for (int i = 0; i < pass->params.num_vertex_attribs; i++) {
     191                 :        620 :         const struct pl_vertex_attrib *va = &pass->params.vertex_attribs[i];
     192                 :        620 :         const struct gl_format **glfmtp = PL_PRIV(va->fmt);
     193                 :        620 :         const struct gl_format *glfmt = *glfmtp;
     194                 :            : 
     195                 :            :         bool norm = false;
     196      [ -  -  + ]:        620 :         switch (va->fmt->type) {
     197                 :          0 :         case PL_FMT_UNORM:
     198                 :            :         case PL_FMT_SNORM:
     199                 :            :             norm = true;
     200                 :          0 :             break;
     201                 :            : 
     202                 :            :         case PL_FMT_UNKNOWN:
     203                 :            :         case PL_FMT_FLOAT:
     204                 :            :         case PL_FMT_UINT:
     205                 :            :         case PL_FMT_SINT:
     206                 :            :             break;
     207                 :            :         case PL_FMT_TYPE_COUNT:
     208                 :          0 :             pl_unreachable();
     209                 :            :         }
     210                 :            : 
     211                 :        620 :         gl->EnableVertexAttribArray(i);
     212                 :        620 :         gl->VertexAttribPointer(i, va->fmt->num_components, glfmt->type, norm,
     213                 :        620 :                                 pass->params.vertex_stride,
     214                 :        620 :                                 (void *) (va->offset + vbo_offset));
     215                 :            :     }
     216                 :        334 : }
     217                 :            : 
     218                 :        332 : pl_pass gl_pass_create(pl_gpu gpu, const struct pl_pass_params *params)
     219                 :            : {
     220                 :            :     const gl_funcs *gl = gl_funcs_get(gpu);
     221                 :            :     if (!MAKE_CURRENT())
     222                 :          0 :         return NULL;
     223                 :            : 
     224                 :            :     struct pl_gl *p = PL_PRIV(gpu);
     225                 :        332 :     struct pl_pass_t *pass = pl_zalloc_obj(NULL, pass, struct pl_pass_gl);
     226                 :        332 :     struct pl_pass_gl *pass_gl = PL_PRIV(pass);
     227                 :        332 :     pl_cache cache = pl_gpu_cache(gpu);
     228                 :        332 :     pass->params = pl_pass_params_copy(pass, params);
     229                 :            : 
     230                 :        332 :     pl_cache_obj obj = { .key = CACHE_KEY_GL_PROG };
     231         [ +  + ]:        332 :     if (cache) {
     232         [ -  + ]:          2 :         pl_hash_merge(&obj.key, pl_str0_hash(params->glsl_shader));
     233         [ -  + ]:          2 :         if (params->type == PL_PASS_RASTER)
     234                 :          0 :             pl_hash_merge(&obj.key, pl_str0_hash(params->vertex_shader));
     235                 :            :     }
     236                 :            : 
     237                 :            :     // Load/Compile program
     238         [ +  + ]:        332 :     if ((pass_gl->program = load_cached_program(gpu, cache, &obj))) {
     239                 :          1 :         PL_DEBUG(gpu, "Using cached GL program");
     240                 :            :     } else {
     241                 :            :         pl_clock_t start = pl_clock_now();
     242                 :        331 :         pass_gl->program = gl_compile_program(gpu, params);
     243                 :        331 :         pl_log_cpu_time(gpu->log, start, pl_clock_now(), "compiling shader");
     244                 :            :     }
     245                 :            : 
     246         [ -  + ]:        332 :     if (!pass_gl->program)
     247                 :          0 :         goto error;
     248                 :            : 
     249                 :            :     // Update program cache if possible
     250   [ +  +  +  - ]:        332 :     if (cache && gl_test_ext(gpu, "GL_ARB_get_program_binary", 41, 30)) {
     251                 :          2 :         GLint buf_size = 0;
     252                 :          2 :         gl->GetProgramiv(pass_gl->program, GL_PROGRAM_BINARY_LENGTH, &buf_size);
     253         [ +  - ]:          2 :         if (buf_size > 0) {
     254                 :          2 :             buf_size += sizeof(struct gl_cache_header);
     255                 :          2 :             pl_cache_obj_resize(NULL, &obj, buf_size);
     256                 :          2 :             struct gl_cache_header *header = obj.data;
     257                 :          2 :             void *buffer = &header[1];
     258                 :          2 :             GLsizei binary_size = 0;
     259                 :          2 :             gl->GetProgramBinary(pass_gl->program, buf_size, &binary_size,
     260                 :            :                                  &header->format, buffer);
     261                 :          2 :             bool ok = gl_check_err(gpu, "gl_pass_create: get program binary");
     262         [ +  - ]:          2 :             if (ok) {
     263                 :          2 :                 obj.size = sizeof(*header) + binary_size;
     264         [ -  + ]:          2 :                 pl_assert(obj.size <= buf_size);
     265                 :          2 :                 pl_cache_set(cache, &obj);
     266                 :            :             }
     267                 :            :         }
     268                 :            :     }
     269                 :            : 
     270                 :        332 :     gl->UseProgram(pass_gl->program);
     271                 :        332 :     pass_gl->var_locs = pl_calloc(pass, params->num_variables, sizeof(GLint));
     272                 :            : 
     273         [ +  + ]:        858 :     for (int i = 0; i < params->num_variables; i++) {
     274                 :       1052 :         pass_gl->var_locs[i] = gl->GetUniformLocation(pass_gl->program,
     275                 :        526 :                                                       params->variables[i].name);
     276                 :            : 
     277                 :            :         // Due to OpenGL API restrictions, we need to ensure that this is a
     278                 :            :         // variable type we can actually *update*. Fortunately, this is easily
     279                 :            :         // checked by virtue of the fact that all legal combinations of
     280                 :            :         // parameters will have a valid GLSL type name
     281         [ -  + ]:        526 :         if (!pl_var_glsl_type_name(params->variables[i])) {
     282                 :          0 :             gl->UseProgram(0);
     283                 :          0 :             PL_ERR(gpu, "Input variable '%s' does not match any known type!",
     284                 :            :                    params->variables[i].name);
     285                 :          0 :             goto error;
     286                 :            :         }
     287                 :            :     }
     288                 :            : 
     289         [ +  + ]:       1071 :     for (int i = 0; i < params->num_descriptors; i++) {
     290                 :        739 :         const struct pl_desc *desc = &params->descriptors[i];
     291   [ +  +  +  -  :        739 :         switch (desc->type) {
                   -  - ]
     292                 :        631 :         case PL_DESC_SAMPLED_TEX:
     293                 :            :         case PL_DESC_STORAGE_IMG: {
     294                 :            :             // For compatibility with older OpenGL, we need to explicitly
     295                 :            :             // update the texture/image unit bindings after creating the shader
     296                 :            :             // program, since specifying it directly requires GLSL 4.20+
     297                 :        631 :             GLint loc = gl->GetUniformLocation(pass_gl->program, desc->name);
     298                 :        631 :             gl->Uniform1i(loc, desc->binding);
     299                 :        631 :             break;
     300                 :            :         }
     301                 :        101 :         case PL_DESC_BUF_UNIFORM: {
     302                 :        101 :             GLuint idx = gl->GetUniformBlockIndex(pass_gl->program, desc->name);
     303                 :        101 :             gl->UniformBlockBinding(pass_gl->program, idx, desc->binding);
     304                 :        101 :             break;
     305                 :            :         }
     306                 :          7 :         case PL_DESC_BUF_STORAGE: {
     307                 :          7 :             GLuint idx = gl->GetProgramResourceIndex(pass_gl->program,
     308                 :            :                                                      GL_SHADER_STORAGE_BLOCK,
     309                 :          7 :                                                      desc->name);
     310                 :          7 :             gl->ShaderStorageBlockBinding(pass_gl->program, idx, desc->binding);
     311                 :          7 :             break;
     312                 :            :         }
     313                 :            :         case PL_DESC_BUF_TEXEL_UNIFORM:
     314                 :            :         case PL_DESC_BUF_TEXEL_STORAGE:
     315                 :          0 :             assert(!"unimplemented"); // TODO
     316                 :            :         case PL_DESC_INVALID:
     317                 :            :         case PL_DESC_TYPE_COUNT:
     318                 :          0 :             pl_unreachable();
     319                 :            :         }
     320                 :            :     }
     321                 :            : 
     322                 :        332 :     gl->UseProgram(0);
     323                 :            : 
     324                 :            :     // Initialize the VAO and single vertex buffer
     325                 :        332 :     gl->GenBuffers(1, &pass_gl->buffer);
     326         [ +  - ]:        332 :     if (p->has_vao) {
     327                 :        332 :         gl->GenVertexArrays(1, &pass_gl->vao);
     328                 :        332 :         gl->BindBuffer(GL_ARRAY_BUFFER, pass_gl->buffer);
     329                 :        332 :         gl->BindVertexArray(pass_gl->vao);
     330                 :        332 :         gl_update_va(gpu, pass, 0);
     331                 :        332 :         gl->BindVertexArray(0);
     332                 :        332 :         gl->BindBuffer(GL_ARRAY_BUFFER, 0);
     333                 :            :     }
     334                 :            : 
     335         [ -  + ]:        332 :     if (!gl_check_err(gpu, "gl_pass_create"))
     336                 :          0 :         goto error;
     337                 :            : 
     338                 :            :     pl_cache_obj_free(&obj);
     339                 :            :     RELEASE_CURRENT();
     340                 :        332 :     return pass;
     341                 :            : 
     342                 :          0 : error:
     343                 :          0 :     PL_ERR(gpu, "Failed creating pass");
     344                 :            :     pl_cache_obj_free(&obj);
     345                 :          0 :     gl_pass_destroy(gpu, pass);
     346                 :            :     RELEASE_CURRENT();
     347                 :          0 :     return NULL;
     348                 :            : }
     349                 :            : 
     350   [ +  +  +  - ]:       1110 : static void update_var(pl_gpu gpu, pl_pass pass,
     351                 :            :                        const struct pl_var_update *vu)
     352                 :            : {
     353                 :            :     const gl_funcs *gl = gl_funcs_get(gpu);
     354                 :       1110 :     struct pl_pass_gl *pass_gl = PL_PRIV(pass);
     355                 :       1110 :     const struct pl_var *var = &pass->params.variables[vu->index];
     356                 :       1110 :     GLint loc = pass_gl->var_locs[vu->index];
     357                 :            : 
     358   [ +  +  +  - ]:       1110 :     switch (var->type) {
     359                 :         33 :     case PL_VAR_SINT: {
     360                 :         33 :         const int *i = vu->data;
     361         [ -  + ]:         33 :         pl_assert(var->dim_m == 1);
     362   [ +  +  -  -  :         33 :         switch (var->dim_v) {
                      - ]
     363                 :         13 :         case 1: gl->Uniform1iv(loc, var->dim_a, i); break;
     364                 :         20 :         case 2: gl->Uniform2iv(loc, var->dim_a, i); break;
     365                 :          0 :         case 3: gl->Uniform3iv(loc, var->dim_a, i); break;
     366                 :          0 :         case 4: gl->Uniform4iv(loc, var->dim_a, i); break;
     367                 :          0 :         default: pl_unreachable();
     368                 :            :         }
     369                 :            :         return;
     370                 :            :     }
     371                 :         16 :     case PL_VAR_UINT: {
     372                 :         16 :         const unsigned int *u = vu->data;
     373         [ -  + ]:         16 :         pl_assert(var->dim_m == 1);
     374   [ +  -  -  -  :         16 :         switch (var->dim_v) {
                      - ]
     375                 :         16 :         case 1: gl->Uniform1uiv(loc, var->dim_a, u); break;
     376                 :          0 :         case 2: gl->Uniform2uiv(loc, var->dim_a, u); break;
     377                 :          0 :         case 3: gl->Uniform3uiv(loc, var->dim_a, u); break;
     378                 :          0 :         case 4: gl->Uniform4uiv(loc, var->dim_a, u); break;
     379                 :          0 :         default: pl_unreachable();
     380                 :            :         }
     381                 :            :         return;
     382                 :            :     }
     383                 :       1061 :     case PL_VAR_FLOAT: {
     384                 :       1061 :         const float *f = vu->data;
     385         [ +  + ]:       1061 :         if (var->dim_m == 1) {
     386   [ +  +  +  -  :        908 :             switch (var->dim_v) {
                      - ]
     387                 :        683 :             case 1: gl->Uniform1fv(loc, var->dim_a, f); break;
     388                 :        157 :             case 2: gl->Uniform2fv(loc, var->dim_a, f); break;
     389                 :         68 :             case 3: gl->Uniform3fv(loc, var->dim_a, f); break;
     390                 :          0 :             case 4: gl->Uniform4fv(loc, var->dim_a, f); break;
     391                 :          0 :             default: pl_unreachable();
     392                 :            :             }
     393   [ +  +  +  - ]:        153 :         } else if (var->dim_m == 2 && var->dim_v == 2) {
     394                 :         17 :             gl->UniformMatrix2fv(loc, var->dim_a, GL_FALSE, f);
     395   [ +  -  +  - ]:        136 :         } else if (var->dim_m == 3 && var->dim_v == 3) {
     396                 :        136 :             gl->UniformMatrix3fv(loc, var->dim_a, GL_FALSE, f);
     397   [ #  #  #  # ]:          0 :         } else if (var->dim_m == 4 && var->dim_v == 4) {
     398                 :          0 :             gl->UniformMatrix4fv(loc, var->dim_a, GL_FALSE, f);
     399   [ #  #  #  # ]:          0 :         } else if (var->dim_m == 2 && var->dim_v == 3) {
     400                 :          0 :             gl->UniformMatrix2x3fv(loc, var->dim_a, GL_FALSE, f);
     401   [ #  #  #  # ]:          0 :         } else if (var->dim_m == 3 && var->dim_v == 2) {
     402                 :          0 :             gl->UniformMatrix3x2fv(loc, var->dim_a, GL_FALSE, f);
     403   [ #  #  #  # ]:          0 :         } else if (var->dim_m == 2 && var->dim_v == 4) {
     404                 :          0 :             gl->UniformMatrix2x4fv(loc, var->dim_a, GL_FALSE, f);
     405   [ #  #  #  # ]:          0 :         } else if (var->dim_m == 4 && var->dim_v == 2) {
     406                 :          0 :             gl->UniformMatrix4x2fv(loc, var->dim_a, GL_FALSE, f);
     407   [ #  #  #  # ]:          0 :         } else if (var->dim_m == 3 && var->dim_v == 4) {
     408                 :          0 :             gl->UniformMatrix3x4fv(loc, var->dim_a, GL_FALSE, f);
     409   [ #  #  #  # ]:          0 :         } else if (var->dim_m == 4 && var->dim_v == 3) {
     410                 :          0 :             gl->UniformMatrix4x3fv(loc, var->dim_a, GL_FALSE, f);
     411                 :            :         } else {
     412                 :          0 :             pl_unreachable();
     413                 :            :         }
     414                 :            :         return;
     415                 :            :     }
     416                 :            : 
     417                 :            :     case PL_VAR_INVALID:
     418                 :            :     case PL_VAR_TYPE_COUNT:
     419                 :            :         break;
     420                 :            :     }
     421                 :            : 
     422                 :          0 :     pl_unreachable();
     423                 :            : }
     424                 :            : 
     425   [ +  +  +  +  :       2711 : static void update_desc(pl_gpu gpu, pl_pass pass, int index,
                   -  - ]
     426                 :            :                         const struct pl_desc_binding *db)
     427                 :            : {
     428                 :            :     const gl_funcs *gl = gl_funcs_get(gpu);
     429                 :       2711 :     const struct pl_desc *desc = &pass->params.descriptors[index];
     430                 :            : 
     431                 :            :     static const GLenum access[] = {
     432                 :            :         [PL_DESC_ACCESS_READWRITE] = GL_READ_WRITE,
     433                 :            :         [PL_DESC_ACCESS_READONLY]  = GL_READ_ONLY,
     434                 :            :         [PL_DESC_ACCESS_WRITEONLY] = GL_WRITE_ONLY,
     435                 :            :     };
     436                 :            : 
     437                 :            :     static const GLint wraps[PL_TEX_ADDRESS_MODE_COUNT] = {
     438                 :            :         [PL_TEX_ADDRESS_CLAMP]  = GL_CLAMP_TO_EDGE,
     439                 :            :         [PL_TEX_ADDRESS_REPEAT] = GL_REPEAT,
     440                 :            :         [PL_TEX_ADDRESS_MIRROR] = GL_MIRRORED_REPEAT,
     441                 :            :     };
     442                 :            : 
     443                 :            :     static const GLint filters[PL_TEX_SAMPLE_MODE_COUNT] = {
     444                 :            :         [PL_TEX_SAMPLE_NEAREST] = GL_NEAREST,
     445                 :            :         [PL_TEX_SAMPLE_LINEAR]  = GL_LINEAR,
     446                 :            :     };
     447                 :            : 
     448   [ +  +  +  +  :       2711 :     switch (desc->type) {
                   -  - ]
     449                 :       2181 :     case PL_DESC_SAMPLED_TEX: {
     450                 :       2181 :         pl_tex tex = db->object;
     451                 :       2181 :         struct pl_tex_gl *tex_gl = PL_PRIV(tex);
     452                 :       2181 :         gl->ActiveTexture(GL_TEXTURE0 + desc->binding);
     453                 :       2181 :         gl->BindTexture(tex_gl->target, tex_gl->texture);
     454                 :            : 
     455                 :       2181 :         GLint filter = filters[db->sample_mode];
     456                 :       2181 :         GLint wrap = wraps[db->address_mode];
     457                 :       2181 :         gl->TexParameteri(tex_gl->target, GL_TEXTURE_MIN_FILTER, filter);
     458                 :       2181 :         gl->TexParameteri(tex_gl->target, GL_TEXTURE_MAG_FILTER, filter);
     459                 :            :         switch (pl_tex_params_dimension(tex->params)) {
     460                 :         70 :         case 3: gl->TexParameteri(tex_gl->target, GL_TEXTURE_WRAP_R, wrap); // fall through
     461                 :       2063 :         case 2: gl->TexParameteri(tex_gl->target, GL_TEXTURE_WRAP_T, wrap); // fall through
     462                 :       2181 :         case 1: gl->TexParameteri(tex_gl->target, GL_TEXTURE_WRAP_S, wrap); break;
     463                 :            :         }
     464                 :            :         return;
     465                 :            :     }
     466                 :         48 :     case PL_DESC_STORAGE_IMG: {
     467                 :         48 :         pl_tex tex = db->object;
     468                 :         48 :         struct pl_tex_gl *tex_gl = PL_PRIV(tex);
     469                 :         48 :         gl->BindImageTexture(desc->binding, tex_gl->texture, 0, GL_FALSE, 0,
     470                 :         48 :                              access[desc->access], tex_gl->iformat);
     471                 :         48 :         return;
     472                 :            :     }
     473                 :        471 :     case PL_DESC_BUF_UNIFORM: {
     474                 :        471 :         pl_buf buf = db->object;
     475                 :        471 :         struct pl_buf_gl *buf_gl = PL_PRIV(buf);
     476                 :        471 :         gl->BindBufferRange(GL_UNIFORM_BUFFER, desc->binding, buf_gl->buffer,
     477                 :        471 :                             buf_gl->offset, buf->params.size);
     478                 :        471 :         return;
     479                 :            :     }
     480                 :         11 :     case PL_DESC_BUF_STORAGE: {
     481                 :         11 :         pl_buf buf = db->object;
     482                 :         11 :         struct pl_buf_gl *buf_gl = PL_PRIV(buf);
     483                 :         11 :         gl->BindBufferRange(GL_SHADER_STORAGE_BUFFER, desc->binding, buf_gl->buffer,
     484                 :         11 :                             buf_gl->offset, buf->params.size);
     485                 :         11 :         return;
     486                 :            :     }
     487                 :            :     case PL_DESC_BUF_TEXEL_UNIFORM:
     488                 :            :     case PL_DESC_BUF_TEXEL_STORAGE:
     489                 :          0 :         assert(!"unimplemented"); // TODO
     490                 :            : 
     491                 :            :     case PL_DESC_INVALID:
     492                 :            :     case PL_DESC_TYPE_COUNT:
     493                 :            :         break;
     494                 :            :     }
     495                 :            : 
     496                 :          0 :     pl_unreachable();
     497                 :            : }
     498                 :            : 
     499   [ +  +  +  +  :       2711 : static void unbind_desc(pl_gpu gpu, pl_pass pass, int index,
                   -  - ]
     500                 :            :                         const struct pl_desc_binding *db)
     501                 :            : {
     502                 :            :     const gl_funcs *gl = gl_funcs_get(gpu);
     503                 :       2711 :     const struct pl_desc *desc = &pass->params.descriptors[index];
     504                 :            : 
     505   [ +  +  +  +  :       2711 :     switch (desc->type) {
                   -  - ]
     506                 :       2181 :     case PL_DESC_SAMPLED_TEX: {
     507                 :       2181 :         pl_tex tex = db->object;
     508                 :       2181 :         struct pl_tex_gl *tex_gl = PL_PRIV(tex);
     509                 :       2181 :         gl->ActiveTexture(GL_TEXTURE0 + desc->binding);
     510                 :       2181 :         gl->BindTexture(tex_gl->target, 0);
     511                 :       2181 :         return;
     512                 :            :     }
     513                 :         48 :     case PL_DESC_STORAGE_IMG: {
     514                 :         48 :         pl_tex tex = db->object;
     515                 :         48 :         struct pl_tex_gl *tex_gl = PL_PRIV(tex);
     516                 :         48 :         gl->BindImageTexture(desc->binding, 0, 0, GL_FALSE, 0,
     517                 :            :                              GL_WRITE_ONLY, GL_R32F);
     518         [ +  + ]:         48 :         if (desc->access != PL_DESC_ACCESS_READONLY)
     519                 :         46 :             gl->MemoryBarrier(tex_gl->barrier);
     520                 :            :         return;
     521                 :            :     }
     522                 :        471 :     case PL_DESC_BUF_UNIFORM:
     523                 :        471 :         gl->BindBufferBase(GL_UNIFORM_BUFFER, desc->binding, 0);
     524                 :        471 :         return;
     525                 :         11 :     case PL_DESC_BUF_STORAGE: {
     526                 :         11 :         pl_buf buf = db->object;
     527                 :         11 :         struct pl_buf_gl *buf_gl = PL_PRIV(buf);
     528                 :         11 :         gl->BindBufferBase(GL_SHADER_STORAGE_BUFFER, desc->binding, 0);
     529         [ +  + ]:         11 :         if (desc->access != PL_DESC_ACCESS_READONLY)
     530                 :         10 :             gl->MemoryBarrier(buf_gl->barrier);
     531                 :            :         return;
     532                 :            :     }
     533                 :            :     case PL_DESC_BUF_TEXEL_UNIFORM:
     534                 :            :     case PL_DESC_BUF_TEXEL_STORAGE:
     535                 :          0 :         assert(!"unimplemented"); // TODO
     536                 :            :     case PL_DESC_INVALID:
     537                 :            :     case PL_DESC_TYPE_COUNT:
     538                 :            :         break;
     539                 :            :     }
     540                 :            : 
     541                 :          0 :     pl_unreachable();
     542                 :            : }
     543                 :            : 
     544                 :       1415 : void gl_pass_run(pl_gpu gpu, const struct pl_pass_run_params *params)
     545                 :            : {
     546                 :            :     const gl_funcs *gl = gl_funcs_get(gpu);
     547                 :            :     if (!MAKE_CURRENT())
     548                 :          0 :         return;
     549                 :            : 
     550                 :       1415 :     pl_pass pass = params->pass;
     551                 :       1415 :     struct pl_pass_gl *pass_gl = PL_PRIV(pass);
     552                 :            :     struct pl_gl *p = PL_PRIV(gpu);
     553                 :            : 
     554                 :       1415 :     gl->UseProgram(pass_gl->program);
     555                 :            : 
     556         [ +  + ]:       2525 :     for (int i = 0; i < params->num_var_updates; i++)
     557                 :       1110 :         update_var(gpu, pass, &params->var_updates[i]);
     558         [ +  + ]:       4126 :     for (int i = 0; i < pass->params.num_descriptors; i++)
     559                 :       2711 :         update_desc(gpu, pass, i, &params->desc_bindings[i]);
     560                 :       1415 :     gl->ActiveTexture(GL_TEXTURE0);
     561                 :            : 
     562         [ -  + ]:       1415 :     if (!gl_check_err(gpu, "gl_pass_run: updating uniforms")) {
     563                 :            :         RELEASE_CURRENT();
     564                 :          0 :         return;
     565                 :            :     }
     566                 :            : 
     567   [ +  +  -  - ]:       1415 :     switch (pass->params.type) {
     568                 :       1367 :     case PL_PASS_RASTER: {
     569                 :       1367 :         struct pl_tex_gl *target_gl = PL_PRIV(params->target);
     570                 :       1367 :         gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, target_gl->fbo);
     571   [ +  +  +  - ]:       1367 :         if (!pass->params.load_target && p->has_invalidate_fb) {
     572         [ -  + ]:       1275 :             GLenum fb = target_gl->fbo ? GL_COLOR_ATTACHMENT0 : GL_COLOR;
     573                 :       1275 :             gl->InvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, &fb);
     574                 :            :         }
     575                 :            : 
     576                 :       1367 :         gl->Viewport(params->viewport.x0, params->viewport.y0,
     577                 :       1367 :                      pl_rect_w(params->viewport), pl_rect_h(params->viewport));
     578                 :       1367 :         gl->Scissor(params->scissors.x0, params->scissors.y0,
     579                 :       1367 :                     pl_rect_w(params->scissors), pl_rect_h(params->scissors));
     580                 :       1367 :         gl->Enable(GL_SCISSOR_TEST);
     581                 :       1367 :         gl->Disable(GL_DEPTH_TEST);
     582                 :       1367 :         gl->Disable(GL_CULL_FACE);
     583                 :       1367 :         gl_check_err(gpu, "gl_pass_run: enabling viewport/scissor");
     584                 :            : 
     585                 :       1367 :         const struct pl_blend_params *blend = pass->params.blend_params;
     586         [ +  + ]:       1367 :         if (blend) {
     587                 :            :             static const GLenum map_blend[] = {
     588                 :            :                 [PL_BLEND_ZERO]                 = GL_ZERO,
     589                 :            :                 [PL_BLEND_ONE]                  = GL_ONE,
     590                 :            :                 [PL_BLEND_SRC_ALPHA]            = GL_SRC_ALPHA,
     591                 :            :                 [PL_BLEND_ONE_MINUS_SRC_ALPHA]  = GL_ONE_MINUS_SRC_ALPHA,
     592                 :            :             };
     593                 :            : 
     594                 :         12 :             gl->BlendFuncSeparate(map_blend[blend->src_rgb],
     595                 :         12 :                                   map_blend[blend->dst_rgb],
     596                 :         12 :                                   map_blend[blend->src_alpha],
     597                 :         12 :                                   map_blend[blend->dst_alpha]);
     598                 :         12 :             gl->Enable(GL_BLEND);
     599                 :         12 :             gl_check_err(gpu, "gl_pass_run: enabling blend");
     600                 :            :         }
     601                 :            : 
     602                 :            :         // Update VBO and VAO
     603                 :       1367 :         pl_buf vert = params->vertex_buf;
     604         [ +  + ]:       1367 :         struct pl_buf_gl *vert_gl = vert ? PL_PRIV(vert) : NULL;
     605         [ +  + ]:       1367 :         gl->BindBuffer(GL_ARRAY_BUFFER, vert ? vert_gl->buffer : pass_gl->buffer);
     606                 :            : 
     607         [ +  + ]:       1367 :         if (!vert) {
     608                 :            :             // Update the buffer directly. In theory we could also do a memcmp
     609                 :            :             // cache here to avoid unnecessary updates.
     610                 :       1366 :             gl->BufferData(GL_ARRAY_BUFFER, pl_vertex_buf_size(params),
     611                 :       1366 :                            params->vertex_data, GL_STREAM_DRAW);
     612                 :            :         }
     613                 :            : 
     614         [ +  - ]:       1367 :         if (pass_gl->vao)
     615                 :       1367 :             gl->BindVertexArray(pass_gl->vao);
     616                 :            : 
     617         [ +  + ]:       1367 :         uint64_t vert_id = vert ? vert_gl->id : 0;
     618                 :          1 :         size_t vert_offset = vert ? params->buf_offset : 0;
     619   [ +  -  +  + ]:       1367 :         if (!pass_gl->vao || pass_gl->vao_id != vert_id ||
     620         [ -  + ]:       1365 :              pass_gl->vao_offset != vert_offset)
     621                 :            :         {
     622                 :            :             // We need to update the VAO when the buffer ID or offset changes
     623                 :          2 :             gl_update_va(gpu, pass, vert_offset);
     624                 :          2 :             pass_gl->vao_id = vert_id;
     625                 :          2 :             pass_gl->vao_offset = vert_offset;
     626                 :            :         }
     627                 :            : 
     628                 :       1367 :         gl_check_err(gpu, "gl_pass_run: update/bind vertex buffer");
     629                 :            : 
     630                 :            :         static const GLenum map_prim[PL_PRIM_TYPE_COUNT] = {
     631                 :            :             [PL_PRIM_TRIANGLE_LIST]     = GL_TRIANGLES,
     632                 :            :             [PL_PRIM_TRIANGLE_STRIP]    = GL_TRIANGLE_STRIP,
     633                 :            :         };
     634                 :       1367 :         GLenum mode = map_prim[pass->params.vertex_type];
     635                 :            : 
     636                 :       1367 :         gl_timer_begin(gpu, params->timer);
     637                 :            : 
     638         [ +  + ]:       1367 :         if (params->index_data) {
     639                 :            : 
     640                 :            :             static const GLenum index_fmts[PL_INDEX_FORMAT_COUNT] = {
     641                 :            :                 [PL_INDEX_UINT16] = GL_UNSIGNED_SHORT,
     642                 :            :                 [PL_INDEX_UINT32] = GL_UNSIGNED_INT,
     643                 :            :             };
     644                 :            : 
     645                 :            :             // Upload indices to temporary buffer object
     646         [ +  + ]:         13 :             if (!pass_gl->index_buffer)
     647                 :          7 :                 gl->GenBuffers(1, &pass_gl->index_buffer); // lazily allocated
     648                 :         13 :             gl->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, pass_gl->index_buffer);
     649                 :         13 :             gl->BufferData(GL_ELEMENT_ARRAY_BUFFER, pl_index_buf_size(params),
     650                 :         13 :                            params->index_data, GL_STREAM_DRAW);
     651                 :         13 :             gl->DrawElements(mode, params->vertex_count,
     652                 :         13 :                              index_fmts[params->index_fmt], 0);
     653                 :         13 :             gl->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
     654                 :            : 
     655         [ -  + ]:       1354 :         } else if (params->index_buf) {
     656                 :            : 
     657                 :            :             // The pointer argument becomes the index buffer offset
     658                 :          0 :             struct pl_buf_gl *index_gl = PL_PRIV(params->index_buf);
     659                 :          0 :             gl->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_gl->buffer);
     660                 :          0 :             gl->DrawElements(mode, params->vertex_count, GL_UNSIGNED_SHORT,
     661                 :          0 :                              (void *) params->index_offset);
     662                 :          0 :             gl->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
     663                 :            : 
     664                 :            :         } else {
     665                 :            : 
     666                 :            :             // Note: the VBO offset is handled in the VAO
     667                 :       1354 :             gl->DrawArrays(mode, 0, params->vertex_count);
     668                 :            :         }
     669                 :            : 
     670                 :       1367 :         gl_timer_end(gpu, params->timer);
     671                 :       1367 :         gl_check_err(gpu, "gl_pass_run: drawing");
     672                 :            : 
     673         [ +  - ]:       1367 :         if (pass_gl->vao) {
     674                 :       1367 :             gl->BindVertexArray(0);
     675                 :            :         } else {
     676         [ #  # ]:          0 :             for (int i = 0; i < pass->params.num_vertex_attribs; i++)
     677                 :          0 :                 gl->DisableVertexAttribArray(i);
     678                 :            :         }
     679                 :            : 
     680                 :       1367 :         gl->BindBuffer(GL_ARRAY_BUFFER, 0);
     681                 :       1367 :         gl->Disable(GL_SCISSOR_TEST);
     682                 :       1367 :         gl->Disable(GL_BLEND);
     683                 :       1367 :         gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
     684                 :       1367 :         break;
     685                 :            :     }
     686                 :            : 
     687                 :         48 :     case PL_PASS_COMPUTE:
     688                 :         48 :         gl_timer_begin(gpu, params->timer);
     689                 :         48 :         gl->DispatchCompute(params->compute_groups[0],
     690                 :         48 :                             params->compute_groups[1],
     691                 :         48 :                             params->compute_groups[2]);
     692                 :         48 :         gl_timer_end(gpu, params->timer);
     693                 :         48 :         break;
     694                 :            : 
     695                 :            :     case PL_PASS_INVALID:
     696                 :            :     case PL_PASS_TYPE_COUNT:
     697                 :          0 :         pl_unreachable();
     698                 :            :     }
     699                 :            : 
     700         [ +  + ]:       4126 :     for (int i = 0; i < pass->params.num_descriptors; i++)
     701                 :       2711 :         unbind_desc(gpu, pass, i, &params->desc_bindings[i]);
     702                 :       1415 :     gl->ActiveTexture(GL_TEXTURE0);
     703                 :            : 
     704                 :       1415 :     gl->UseProgram(0);
     705                 :       1415 :     gl_check_err(gpu, "gl_pass_run");
     706                 :            :     RELEASE_CURRENT();
     707                 :            : }

Generated by: LCOV version 1.16