LCOV - code coverage report
Current view: top level - src - shader.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 39.3 % 84 33
Test Date: 2025-06-27 11:12:05 Functions: 75.0 % 4 3

            Line data    Source code
       1              : // Copyright (c) 2025 Milton McDonald
       2              : // This source code is licensed under the MIT License. See LICENSE file in the
       3              : // project root for details.
       4              : 
       5              : #include "shader.h"
       6              : 
       7              : #include <algorithm>
       8              : #include <cassert>
       9              : #include <format>
      10              : #include <iostream>
      11              : #include <ranges>
      12              : #include <unordered_map>
      13              : #include <utility>
      14              : 
      15              : #include "error.h"
      16              : #include "glad/glad.h"
      17              : #include "graphics-engine/i-shader.h"
      18              : 
      19              : using enum graphics_engine::gl_types::GLShaderObjectParameter;
      20              : using enum graphics_engine::gl_types::GLShaderType;
      21              : using enum graphics_engine::types::ErrorCode;
      22              : 
      23              : using graphics_engine::error::CheckGLError;
      24              : using graphics_engine::error::MakeErrorCode;
      25              : using graphics_engine::gl_types::GLShaderType;
      26              : using graphics_engine::gl_wrappers::AttachShader;
      27              : using graphics_engine::gl_wrappers::CompileShader;
      28              : using graphics_engine::gl_wrappers::CreateProgram;
      29              : using graphics_engine::gl_wrappers::CreateShader;
      30              : using graphics_engine::gl_wrappers::GetShaderInfoLog;
      31              : using graphics_engine::gl_wrappers::GetShaderiv;
      32              : using graphics_engine::gl_wrappers::LinkProgram;
      33              : using graphics_engine::gl_wrappers::ShaderSource;
      34              : using graphics_engine::shader::IShaderPtr;
      35              : using graphics_engine::types::Expected;
      36              : using graphics_engine::types::ShaderSourceMap;
      37              : 
      38              : using std::cerr;
      39              : using std::exception;
      40              : using std::format;
      41              : using std::is_same_v;
      42              : using std::runtime_error;
      43              : using std::string;
      44              : using std::to_underlying;
      45              : using std::unexpected;
      46              : using std::unordered_map;
      47              : using std::vector;
      48              : using std::ranges::contains;
      49              : using std::ranges::for_each;
      50              : using std::views::keys;
      51              : 
      52              : static_assert(is_same_v<GLchar, char>,
      53              :               "GLchar and char are not the same type!");
      54              : static_assert(is_same_v<GLint, int>, "GLint and int are not the same type!");
      55              : static_assert(is_same_v<GLsizei, int>,
      56              :               "GLsizei and int are not the same type!");
      57              : static_assert(is_same_v<GLuint, unsigned int>,
      58              :               "GLuint and unsigned int are not the same type!");
      59              : 
      60              : namespace graphics_engine::shader {
      61              : 
      62            0 : auto DeleteShader(unsigned int shader_id)
      63              :     -> ::graphics_engine::types::Expected<void> {
      64            0 :   glDeleteShader(shader_id);
      65            0 :   if (GLenum error = glGetError(); error != GL_NO_ERROR) {
      66            0 :     cerr << "glDeleteShader failed with error code " << error << '\n';
      67            0 :     switch (error) {
      68            0 :       default:
      69            0 :         assert(false);  // If we get here, add a new case to the switch
      70            0 :         [[fallthrough]];
      71            0 :       case GL_INVALID_VALUE:
      72            0 :         return unexpected(MakeErrorCode(kGLErrorInvalidValue));
      73              :     }
      74              :   }
      75              : 
      76            0 :   return {};
      77              : }
      78              : 
      79            1 : auto CreateIShader(const ShaderSourceMap& sources) -> IShaderPtr {
      80            1 :   Shader shader;
      81            1 :   Expected<void> result = shader.Initialize(sources);
      82            1 :   if (!result.has_value()) {
      83            0 :     cerr << "Shader initialization failed with error code "
      84            0 :          << result.error().value() << ": " << result.error().message() << '\n';
      85            0 :     return nullptr;
      86              :   }
      87              : 
      88            1 :   return std::make_unique<Shader>(shader);
      89            1 : }
      90              : 
      91            1 : auto Shader::GetProgramId() const -> unsigned int { return program_id_; }
      92              : 
      93            1 : auto Shader::Initialize(const types::ShaderSourceMap& sources)
      94              :     -> types::Expected<void> {
      95            1 :   std::vector<GLuint> shader_ids;
      96              : 
      97              :   // Compile each of the shaders in the shader source map.
      98            5 :   for (const auto& [shader_type, source_code] : sources) {
      99            2 :     Expected<GLuint> shader_id = CreateShader(shader_type);
     100            2 :     if (!shader_id) {
     101            0 :       cerr << "CreateShader failed for shader type "
     102            0 :            << to_underlying(shader_type) << " with error code "
     103            0 :            << shader_id.error().value() << ": " << shader_id.error().message()
     104            0 :            << '\n';
     105            0 :       return unexpected(shader_id.error());
     106              :     }
     107              : 
     108            2 :     shader_ids.push_back(*shader_id);
     109              : 
     110            2 :     const GLchar* source_code_cstr = source_code.c_str();
     111            2 :     Expected<void> result =
     112            2 :         ShaderSource(*shader_id, 1, &source_code_cstr, nullptr);
     113            2 :     if (!result.has_value()) {
     114            0 :       cerr << "ShaderSource failed with error code " << result.error().value()
     115            0 :            << ": " << result.error().message() << '\n';
     116            0 :       return unexpected(result.error());
     117              :     }
     118              : 
     119            2 :     result = CompileShader(*shader_id);
     120            2 :     if (!result.has_value()) {
     121            0 :       cerr << "CompileShader failed with error code " << result.error().value()
     122            0 :            << ": " << result.error().message() << '\n';
     123            0 :       return unexpected(result.error());
     124              :     }
     125              : 
     126            2 :     int params{};
     127            2 :     result = GetShaderiv(*shader_id, kCompileStatus, &params);
     128            2 :     if (!result.has_value()) {
     129            0 :       cerr << "GetShaderiv failed with error code " << result.error().value()
     130            0 :            << ": " << result.error().message() << '\n';
     131            0 :       return unexpected(result.error());
     132              :     }
     133              : 
     134              :     // If compilation failed...
     135            2 :     if (params == GL_FALSE) {
     136            0 :       result = GetShaderiv(*shader_id, kInfoLogLength, &params);
     137            0 :       if (!result.has_value()) {
     138            0 :         cerr << "GetShaderiv failed with error code " << result.error().value()
     139            0 :              << ": " << result.error().message() << '\n';
     140            0 :         return unexpected(result.error());
     141              :       }
     142              : 
     143            0 :       string info_log(params, '\0');
     144            0 :       result = GetShaderInfoLog(*shader_id, params, nullptr, info_log.data());
     145            0 :       if (!result.has_value()) {
     146            0 :         cerr << "GetShaderInfoLog failed with error code "
     147            0 :              << result.error().value() << ": " << result.error().message()
     148            0 :              << '\n';
     149            0 :         return unexpected(result.error());
     150              :       }
     151            0 :     }
     152              :   }
     153              : 
     154              :   // Compilation succeeded. Time to link.
     155            1 :   Expected<GLuint> program_id = CreateProgram();
     156            1 :   if (!program_id) {
     157            0 :     cerr << "CreateProgram failed with error code "
     158            0 :          << program_id.error().value() << ": " << program_id.error().message()
     159            0 :          << '\n';
     160            0 :     return unexpected(program_id.error());
     161              :   }
     162              : 
     163            3 :   for (const auto& shader_id : shader_ids) {
     164            2 :     Expected<void> result = AttachShader(*program_id, shader_id);
     165            2 :     if (!result) {
     166            0 :       cerr << "AttachShader failed with error code: " << result.error().value()
     167            0 :            << ": " << result.error().message() << '\n';
     168            0 :       return unexpected(result.error());
     169              :     }
     170              :   }
     171              : 
     172            1 :   Expected<void> result = LinkProgram(*program_id);
     173            1 :   if (!result) {
     174            0 :     cerr << "LinkProgram failed with error code: " << result.error().value()
     175            0 :          << ": " << result.error().message() << '\n';
     176            0 :     return unexpected(result.error());
     177              :   }
     178              : 
     179            1 :   program_id_ = *program_id;
     180              : 
     181            1 :   return {};
     182            1 : }
     183              : 
     184              : }  // namespace graphics_engine::shader
        

Generated by: LCOV version 2.0-1