Serenity Operating System
at master 166 lines 5.2 kB view raw
1/* 2 * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com> 3 * Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org> 4 * Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl> 5 * 6 * SPDX-License-Identifier: BSD-2-Clause 7 */ 8 9#include <AK/TemporaryChange.h> 10#include <LibGL/GLContext.h> 11 12namespace GL { 13 14void GLContext::gl_call_list(GLuint list) 15{ 16 if (m_gl_call_depth > max_allowed_gl_call_depth) 17 return; 18 19 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_call_list, list); 20 21 if (m_listings.size() < list) 22 return; 23 24 TemporaryChange change { m_gl_call_depth, m_gl_call_depth + 1 }; 25 26 invoke_list(list); 27} 28 29void GLContext::gl_call_lists(GLsizei n, GLenum type, void const* lists) 30{ 31 if (m_gl_call_depth > max_allowed_gl_call_depth) 32 return; 33 34 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_call_lists, n, type, lists); 35 36 RETURN_WITH_ERROR_IF(n < 0, GL_INVALID_VALUE); 37 RETURN_WITH_ERROR_IF(!(type == GL_BYTE 38 || type == GL_UNSIGNED_BYTE 39 || type == GL_SHORT 40 || type == GL_UNSIGNED_SHORT 41 || type == GL_INT 42 || type == GL_UNSIGNED_INT 43 || type == GL_FLOAT 44 || type == GL_2_BYTES 45 || type == GL_3_BYTES 46 || type == GL_4_BYTES), 47 GL_INVALID_ENUM); 48 49 TemporaryChange change { m_gl_call_depth, m_gl_call_depth + 1 }; 50 51 auto invoke_all_lists = [&]<typename T>(T const* lists) { 52 for (int i = 0; i < n; ++i) { 53 auto list = static_cast<size_t>(lists[i]); 54 invoke_list(m_list_base + list); 55 } 56 }; 57 switch (type) { 58 case GL_BYTE: 59 invoke_all_lists(static_cast<GLbyte const*>(lists)); 60 break; 61 case GL_UNSIGNED_BYTE: 62 invoke_all_lists(static_cast<GLubyte const*>(lists)); 63 break; 64 case GL_SHORT: 65 invoke_all_lists(static_cast<GLshort const*>(lists)); 66 break; 67 case GL_UNSIGNED_SHORT: 68 invoke_all_lists(static_cast<GLushort const*>(lists)); 69 break; 70 case GL_INT: 71 invoke_all_lists(static_cast<GLint const*>(lists)); 72 break; 73 case GL_UNSIGNED_INT: 74 invoke_all_lists(static_cast<GLuint const*>(lists)); 75 break; 76 case GL_FLOAT: 77 invoke_all_lists(static_cast<GLfloat const*>(lists)); 78 break; 79 case GL_2_BYTES: 80 case GL_3_BYTES: 81 case GL_4_BYTES: 82 dbgln("GLContext FIXME: unimplemented glCallLists() with type {}", type); 83 break; 84 default: 85 VERIFY_NOT_REACHED(); 86 } 87} 88 89void GLContext::gl_delete_lists(GLuint list, GLsizei range) 90{ 91 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 92 RETURN_WITH_ERROR_IF(range < 0, GL_INVALID_VALUE); 93 94 if (m_listings.size() < list || m_listings.size() <= list + range) 95 return; 96 97 for (auto& entry : m_listings.span().slice(list - 1, range)) 98 entry.entries.clear_with_capacity(); 99} 100 101void GLContext::gl_end_list() 102{ 103 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 104 RETURN_WITH_ERROR_IF(!m_current_listing_index.has_value(), GL_INVALID_OPERATION); 105 106 m_listings[m_current_listing_index->index] = move(m_current_listing_index->listing); 107 m_current_listing_index.clear(); 108} 109 110GLuint GLContext::gl_gen_lists(GLsizei range) 111{ 112 RETURN_VALUE_WITH_ERROR_IF(range <= 0, GL_INVALID_VALUE, 0); 113 RETURN_VALUE_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION, 0); 114 115 auto initial_entry = m_listings.size(); 116 m_listings.resize(range + initial_entry); 117 return initial_entry + 1; 118} 119 120GLboolean GLContext::gl_is_list(GLuint list) 121{ 122 RETURN_VALUE_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION, GL_FALSE); 123 124 return list < m_listings.size() ? GL_TRUE : GL_FALSE; 125} 126 127void GLContext::gl_list_base(GLuint base) 128{ 129 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_list_base, base); 130 131 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 132 133 m_list_base = base; 134} 135 136void GLContext::gl_new_list(GLuint list, GLenum mode) 137{ 138 RETURN_WITH_ERROR_IF(list == 0, GL_INVALID_VALUE); 139 RETURN_WITH_ERROR_IF(mode != GL_COMPILE && mode != GL_COMPILE_AND_EXECUTE, GL_INVALID_ENUM); 140 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 141 RETURN_WITH_ERROR_IF(m_current_listing_index.has_value(), GL_INVALID_OPERATION); 142 143 if (m_listings.size() < list) 144 return; 145 146 m_current_listing_index = CurrentListing { {}, static_cast<size_t>(list - 1), mode }; 147} 148 149void GLContext::invoke_list(size_t list_index) 150{ 151 auto& listing = m_listings[list_index - 1]; 152 for (auto& entry : listing.entries) { 153 entry.function.visit([&](auto& function) { 154 entry.arguments.visit([&](auto& arguments) { 155 auto apply = [&]<typename... Args>(Args&&... args) { 156 if constexpr (requires { (this->*function)(forward<Args>(args)...); }) 157 (this->*function)(forward<Args>(args)...); 158 }; 159 160 arguments.apply_as_args(apply); 161 }); 162 }); 163 } 164} 165 166}