Skip to content

File shader_util.hpp

File List > illixr > shader_util.hpp

Go to the documentation of this file

#pragma once
#if defined(_WIN32) || defined(_WIN64)
#    include 
#endif

#include "error_util.hpp"

#ifdef __ANDROID__
#    include "EGL/egl.h"

#    include 
#    define SHADER_TYPE GLuint
#else
// clang-format off
#  include 
#  include 
// clang-format on
#    define SHADER_TYPE GLint
#endif

#include 
#include 
#include 
#include 
#include 

using namespace ILLIXR;

static constexpr std::size_t GL_MAX_LOG_LENGTH = 4096U;

#ifndef __ANDROID__
static void GLAPIENTRY message_callback([[maybe_unused]] GLenum source, [[maybe_unused]] GLenum type,
                                        [[maybe_unused]] GLuint id, [[maybe_unused]] GLenum severity,
                                        [[maybe_unused]] GLsizei length, [[maybe_unused]] const GLchar* message,
                                        [[maybe_unused]] const void* user_param) {
#    ifndef NDEBUG
    if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) {
        return;
    }
    std::string type_error = (type == GL_DEBUG_TYPE_ERROR) ? "** GL ERROR **" : "";
    spdlog::get("illixr")->warn("[shader_util] GL CALLBACK: {} type = {:x}, severity = {:x}, message = {}", type_error, type,
                                severity, message);
    // https://www.khronos.org/opengl/wiki/Debug_Output#Message_Components
    if (severity == GL_DEBUG_SEVERITY_HIGH) {
        ILLIXR::abort();
    } 
#    endif
}
#endif

static GLuint init_and_link(const char* vertex_shader, const char* fragment_shader) {
    // GL handles for intermediary objects.
    GLint       result;
    SHADER_TYPE vertex_shader_handle, fragment_shader_handle, shader_program;
    vertex_shader_handle = glCreateShader(GL_VERTEX_SHADER);
    auto vert_shader_len = static_cast<GLint>(strlen(vertex_shader));
    glShaderSource(vertex_shader_handle, 1, &vertex_shader, &vert_shader_len);
    glCompileShader(vertex_shader_handle);
    glGetShaderiv(vertex_shader_handle, GL_COMPILE_STATUS, &result);
    if (result == GL_FALSE) {
        GLsizei             length = 0;
        std::vector<GLchar> gl_buf_log;
        gl_buf_log.resize(GL_MAX_LOG_LENGTH);

        glGetShaderInfoLog(vertex_shader_handle, GL_MAX_LOG_LENGTH * sizeof(GLchar), &length, gl_buf_log.data());
        const std::string msg{gl_buf_log.begin(), gl_buf_log.end()};
        // assert(length == static_cast(msg.size()) && "Length of log should match GLchar vector contents");
        ILLIXR::abort("[shader_util] Failed to get vertex_shader_handle: " + msg);
    }

    GLint frag_result      = GL_FALSE;
    fragment_shader_handle = glCreateShader(GL_FRAGMENT_SHADER);
    auto frag_shader_len   = static_cast<GLint>(strlen(fragment_shader));
    glShaderSource(fragment_shader_handle, 1, &fragment_shader, &frag_shader_len);
    glCompileShader(fragment_shader_handle);
    glGetShaderiv(fragment_shader_handle, GL_COMPILE_STATUS, &frag_result);
    if (frag_result == GL_FALSE) {
        GLsizei             length = 0;
        std::vector<GLchar> gl_buf_log;
        gl_buf_log.resize(GL_MAX_LOG_LENGTH);

        glGetShaderInfoLog(fragment_shader_handle, GL_MAX_LOG_LENGTH * sizeof(GLchar), &length, gl_buf_log.data());
        const std::string msg{gl_buf_log.begin(), gl_buf_log.end()};
        assert(length == static_cast<GLsizei>(msg.size()) && "Length of log should match GLchar vector contents");
        ILLIXR::abort("[shader_util] Failed to get fragment_shader_handle: " + msg);
    }

    // Create program and link shaders
    shader_program = glCreateProgram();
    glAttachShader(shader_program, vertex_shader_handle);
    glAttachShader(shader_program, fragment_shader_handle);
    const GLenum gl_err_attach = glGetError();
    if (gl_err_attach != GL_NO_ERROR) {
        ILLIXR::abort("[shader_util] AttachShader or createProgram failed");
    }

    // Link and verify

    glLinkProgram(shader_program);

    const GLenum gl_err_link = glGetError();
    if (gl_err_link != GL_NO_ERROR) {
        ILLIXR::abort("[shader_util] Linking failed");
    }

    glGetProgramiv(shader_program, GL_LINK_STATUS, &result);
    if (result == GL_FALSE) {
        GLsizei             length = 0;
        std::vector<GLchar> gl_buf_log;
        gl_buf_log.resize(GL_MAX_LOG_LENGTH);

        glGetProgramInfoLog(shader_program, GL_MAX_LOG_LENGTH * sizeof(GLchar), &length, gl_buf_log.data());
        const std::string msg{gl_buf_log.begin(), gl_buf_log.end()};
        assert(length == static_cast<GLsizei>(msg.size()) && "Length of log should match GLchar vector contents");
        ILLIXR::abort("[shader_util] Failed to get shader program: " + msg);
    }

    // After successful link, detach shaders from shader program
    glDetachShader(shader_program, vertex_shader_handle);
    glDetachShader(shader_program, fragment_shader_handle);

    return shader_program;
}