Serenity Operating System
at master 214 lines 8.6 kB view raw
1/* 2 * Copyright (c) 2022, Stephan Unverwerth <s.unverwerth@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/StringBuilder.h> 8#include <LibGL/GLContext.h> 9 10namespace GL { 11 12GLuint GLContext::gl_create_shader(GLenum shader_type) 13{ 14 // FIXME: Add support for GL_COMPUTE_SHADER, GL_TESS_CONTROL_SHADER, GL_TESS_EVALUATION_SHADER and GL_GEOMETRY_SHADER. 15 RETURN_VALUE_WITH_ERROR_IF(shader_type != GL_VERTEX_SHADER 16 && shader_type != GL_FRAGMENT_SHADER, 17 GL_INVALID_ENUM, 18 0); 19 20 GLuint shader_name; 21 m_shader_name_allocator.allocate(1, &shader_name); 22 auto shader = Shader::create(shader_type); 23 m_allocated_shaders.set(shader_name, shader); 24 return shader_name; 25} 26 27void GLContext::gl_delete_shader(GLuint shader) 28{ 29 // "A value of 0 for shader will be silently ignored." (https://registry.khronos.org/OpenGL-Refpages/gl4/html/glDeleteShader.xhtml) 30 if (shader == 0) 31 return; 32 33 auto it = m_allocated_shaders.find(shader); 34 RETURN_WITH_ERROR_IF(it == m_allocated_shaders.end(), GL_INVALID_VALUE); 35 36 // FIXME: According to the spec, we should only flag the shader for deletion here and delete it once it is detached from all programs. 37 m_allocated_shaders.remove(it); 38 m_shader_name_allocator.free(shader); 39} 40 41void GLContext::gl_shader_source(GLuint shader, GLsizei count, GLchar const** string, GLint const* length) 42{ 43 auto it = m_allocated_shaders.find(shader); 44 // FIXME: implement check "GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL." 45 RETURN_WITH_ERROR_IF(it == m_allocated_shaders.end(), GL_INVALID_OPERATION); 46 RETURN_WITH_ERROR_IF(count < 0, GL_INVALID_VALUE); 47 48 it->value->clear_sources(); 49 for (int i = 0; i < count; i++) { 50 if (length == nullptr || length[i] < 0) { 51 auto result = it->value->add_source(StringView(string[i], strlen(string[i]))); 52 RETURN_WITH_ERROR_IF(result.is_error() && result.error().is_errno() && result.error().code() == ENOMEM, GL_OUT_OF_MEMORY); 53 RETURN_WITH_ERROR_IF(result.is_error(), GL_INVALID_OPERATION); 54 } else { 55 auto result = it->value->add_source(StringView(string[i], length[i])); 56 RETURN_WITH_ERROR_IF(result.is_error() && result.error().is_errno() && result.error().code() == ENOMEM, GL_OUT_OF_MEMORY); 57 RETURN_WITH_ERROR_IF(result.is_error(), GL_INVALID_OPERATION); 58 } 59 } 60} 61 62void GLContext::gl_compile_shader(GLuint shader) 63{ 64 auto it = m_allocated_shaders.find(shader); 65 // FIXME: implement check "GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL." 66 RETURN_WITH_ERROR_IF(it == m_allocated_shaders.end(), GL_INVALID_OPERATION); 67 68 // NOTE: We are ignoring the compilation result here since it is tracked inside the shader object 69 (void)it->value->compile(); 70} 71 72void GLContext::gl_get_shader(GLuint shader, GLenum pname, GLint* params) 73{ 74 RETURN_WITH_ERROR_IF(pname != GL_SHADER_TYPE 75 && pname != GL_DELETE_STATUS 76 && pname != GL_COMPILE_STATUS 77 && pname != GL_INFO_LOG_LENGTH 78 && pname != GL_SHADER_SOURCE_LENGTH, 79 GL_INVALID_ENUM); 80 81 // FIXME: implement check "GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL." 82 // FIXME: implement check "GL_INVALID_OPERATION is generated if pname is GL_COMPILE_STATUS, GL_INFO_LOG_LENGTH, or GL_SHADER_SOURCE_LENGTH but a shader compiler is not supported." 83 84 auto it = m_allocated_shaders.find(shader); 85 RETURN_WITH_ERROR_IF(it == m_allocated_shaders.end(), GL_INVALID_OPERATION); 86 87 switch (pname) { 88 case GL_SHADER_TYPE: 89 *params = it->value->type(); 90 break; 91 92 case GL_DELETE_STATUS: 93 // FIXME: Return the actual delete status once we implement this missing feature 94 *params = GL_FALSE; 95 break; 96 97 case GL_COMPILE_STATUS: 98 *params = it->value->compile_status() ? GL_TRUE : GL_FALSE; 99 break; 100 101 case GL_INFO_LOG_LENGTH: 102 *params = it->value->info_log_length(); 103 break; 104 105 case GL_SHADER_SOURCE_LENGTH: 106 *params = it->value->combined_source_length(); 107 break; 108 109 default: 110 VERIFY_NOT_REACHED(); 111 } 112} 113 114GLuint GLContext::gl_create_program() 115{ 116 GLuint program_name; 117 m_program_name_allocator.allocate(1, &program_name); 118 auto program = Program::create(); 119 m_allocated_programs.set(program_name, program); 120 return program_name; 121} 122 123void GLContext::gl_delete_program(GLuint program) 124{ 125 // "A value of 0 for program will be silently ignored." (https://registry.khronos.org/OpenGL-Refpages/gl4/html/glDeleteProgram.xhtml) 126 if (program == 0) 127 return; 128 129 auto it = m_allocated_programs.find(program); 130 RETURN_WITH_ERROR_IF(it == m_allocated_programs.end(), GL_INVALID_VALUE); 131 132 // FIXME: According to the spec, we should only flag the program for deletion here and delete it once it is not used anymore. 133 m_allocated_programs.remove(it); 134 m_program_name_allocator.free(program); 135} 136 137void GLContext::gl_attach_shader(GLuint program, GLuint shader) 138{ 139 auto program_it = m_allocated_programs.find(program); 140 auto shader_it = m_allocated_shaders.find(shader); 141 // FIXME: implement check "GL_INVALID_VALUE is generated if either program or shader is not a value generated by OpenGL." 142 RETURN_WITH_ERROR_IF(program_it == m_allocated_programs.end(), GL_INVALID_OPERATION); 143 RETURN_WITH_ERROR_IF(shader_it == m_allocated_shaders.end(), GL_INVALID_OPERATION); 144 145 // NOTE: attach_result is Error if the shader is already attached to this program 146 auto attach_result = program_it->value->attach_shader(*shader_it->value); 147 RETURN_WITH_ERROR_IF(attach_result.is_error() && attach_result.error().is_errno() && attach_result.error().code() == ENOMEM, GL_OUT_OF_MEMORY); 148 RETURN_WITH_ERROR_IF(attach_result.is_error(), GL_INVALID_OPERATION); 149} 150 151void GLContext::gl_link_program(GLuint program) 152{ 153 auto program_it = m_allocated_programs.find(program); 154 // FIXME: implement check "GL_INVALID_VALUE is generated if program is not a value generated by OpenGL." 155 RETURN_WITH_ERROR_IF(program_it == m_allocated_programs.end(), GL_INVALID_OPERATION); 156 // FIXME: implement check "GL_INVALID_OPERATION is generated if program is the currently active program object and transform feedback mode is active." 157 158 // NOTE: We are ignoring the link result since this is tracked inside the program object 159 (void)program_it->value->link(*m_rasterizer); 160} 161 162void GLContext::gl_use_program(GLuint program) 163{ 164 if (program == 0) { 165 m_current_program = nullptr; 166 return; 167 } 168 169 auto it = m_allocated_programs.find(program); 170 171 // FIXME: implement check "GL_INVALID_VALUE is generated if program is not a value generated by OpenGL." 172 RETURN_WITH_ERROR_IF(it == m_allocated_programs.end(), GL_INVALID_OPERATION); 173 // FIXME: implement check "GL_INVALID_OPERATION is generated if transform feedback mode is active." 174 RETURN_WITH_ERROR_IF(it->value->link_status() != true, GL_INVALID_OPERATION); 175 176 m_current_program = it->value; 177} 178 179void GLContext::gl_get_program(GLuint program, GLenum pname, GLint* params) 180{ 181 auto it = m_allocated_programs.find(program); 182 183 // FIXME: implement check "GL_INVALID_VALUE is generated if program is not a value generated by OpenGL." 184 RETURN_WITH_ERROR_IF(it == m_allocated_programs.end(), GL_INVALID_OPERATION); 185 // FIXME: implement check "GL_INVALID_OPERATION is generated if pname is GL_GEOMETRY_VERTICES_OUT, GL_GEOMETRY_INPUT_TYPE, or GL_GEOMETRY_OUTPUT_TYPE, and program does not contain a geometry shader." 186 187 // FIXME: implement all the other allowed pname values (https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetProgram.xhtml) 188 RETURN_WITH_ERROR_IF(pname != GL_DELETE_STATUS 189 && pname != GL_LINK_STATUS 190 && pname != GL_INFO_LOG_LENGTH, 191 GL_INVALID_ENUM); 192 193 // FIXME: implement check "GL_INVALID_OPERATION is generated if pname is GL_COMPUTE_WORK_GROUP_SIZE and program does not contain a binary for the compute shader stage." 194 195 switch (pname) { 196 case GL_DELETE_STATUS: 197 // FIXME: Return the actual delete status once we implement this missing feature 198 *params = GL_FALSE; 199 break; 200 201 case GL_LINK_STATUS: 202 *params = it->value->link_status() ? GL_TRUE : GL_FALSE; 203 break; 204 205 case GL_INFO_LOG_LENGTH: 206 *params = it->value->info_log_length(); 207 break; 208 209 default: 210 VERIFY_NOT_REACHED(); 211 } 212} 213 214}