/* * Copyright (c) 2022, Stephan Unverwerth * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include namespace GL { NonnullRefPtr Program::create() { return adopt_ref(*new Program()); } bool Program::is_shader_attached(Shader const& shader) const { switch (shader.type()) { case GL_VERTEX_SHADER: return m_vertex_shaders.contains_slow(shader); case GL_FRAGMENT_SHADER: return m_fragment_shaders.contains_slow(shader); default: VERIFY_NOT_REACHED(); } } ErrorOr Program::attach_shader(Shader& shader) { if (is_shader_attached(shader)) return Error::from_string_literal("Trying to attach a shader that is already attached"); switch (shader.type()) { case GL_VERTEX_SHADER: TRY(m_vertex_shaders.try_append(shader)); break; case GL_FRAGMENT_SHADER: TRY(m_fragment_shaders.try_append(shader)); break; default: VERIFY_NOT_REACHED(); } return {}; } ErrorOr Program::link() { m_info_log = TRY(String::from_utf8(""sv)); GLSL::Linker linker; // Link vertex shader objects Vector vertex_shader_object_files; for (auto vertex_shader : m_vertex_shaders) vertex_shader_object_files.append(vertex_shader->object_file()); auto linked_vertex_shader_or_error = linker.link(vertex_shader_object_files); if (linked_vertex_shader_or_error.is_error()) { m_link_status = false; m_info_log = linker.messages(); return linked_vertex_shader_or_error.error(); } m_linked_vertex_shader = linked_vertex_shader_or_error.release_value(); // Link fragment shader objects Vector fragment_shader_object_files; for (auto fragment_shader : m_fragment_shaders) fragment_shader_object_files.append(fragment_shader->object_file()); auto linked_fragment_shader_or_error = linker.link(fragment_shader_object_files); if (linked_fragment_shader_or_error.is_error()) { m_link_status = false; m_info_log = linker.messages(); return linked_fragment_shader_or_error.error(); } m_linked_fragment_shader = linked_fragment_shader_or_error.release_value(); m_link_status = true; return {}; } size_t Program::info_log_length() const { if (!m_info_log.has_value()) return 0; // Per the spec we return the size including the null terminator return m_info_log.value().bytes().size() + 1; } }