Serenity Operating System
at master 316 lines 12 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/Assertions.h> 10#include <AK/NumericLimits.h> 11#include <LibGL/GLContext.h> 12 13namespace GL { 14 15// General helper function to read arbitrary vertex attribute data into a float array 16static void read_from_vertex_attribute_pointer(VertexAttribPointer const& attrib, int index, float* elements) 17{ 18 auto const* byte_ptr = reinterpret_cast<char const*>(attrib.pointer); 19 20 auto read_values = [&]<typename T>() { 21 auto const stride = (attrib.stride == 0) ? sizeof(T) * attrib.size : attrib.stride; 22 for (int i = 0; i < attrib.size; ++i) { 23 elements[i] = *(reinterpret_cast<T const*>(byte_ptr + stride * index) + i); 24 if constexpr (IsIntegral<T>) { 25 if (attrib.normalize) 26 elements[i] /= NumericLimits<T>::max(); 27 } 28 } 29 }; 30 31 switch (attrib.type) { 32 case GL_BYTE: 33 read_values.operator()<GLbyte>(); 34 break; 35 case GL_UNSIGNED_BYTE: 36 read_values.operator()<GLubyte>(); 37 break; 38 case GL_SHORT: 39 read_values.operator()<GLshort>(); 40 break; 41 case GL_UNSIGNED_SHORT: 42 read_values.operator()<GLushort>(); 43 break; 44 case GL_INT: 45 read_values.operator()<GLint>(); 46 break; 47 case GL_UNSIGNED_INT: 48 read_values.operator()<GLuint>(); 49 break; 50 case GL_FLOAT: 51 read_values.operator()<GLfloat>(); 52 break; 53 case GL_DOUBLE: 54 read_values.operator()<GLdouble>(); 55 break; 56 } 57} 58 59void GLContext::gl_array_element(GLint i) 60{ 61 // NOTE: This always dereferences data; display list support is deferred to the 62 // individual vertex attribute calls such as `gl_color`, `gl_normal` etc. 63 RETURN_WITH_ERROR_IF(i < 0, GL_INVALID_VALUE); 64 65 if (m_client_side_color_array_enabled) { 66 float color[4] { 0.f, 0.f, 0.f, 1.f }; 67 read_from_vertex_attribute_pointer(m_client_color_pointer, i, color); 68 gl_color(color[0], color[1], color[2], color[3]); 69 } 70 71 for (size_t t = 0; t < m_client_tex_coord_pointer.size(); ++t) { 72 if (m_client_side_texture_coord_array_enabled[t]) { 73 float tex_coords[4] { 0.f, 0.f, 0.f, 1.f }; 74 read_from_vertex_attribute_pointer(m_client_tex_coord_pointer[t], i, tex_coords); 75 gl_multi_tex_coord(GL_TEXTURE0 + t, tex_coords[0], tex_coords[1], tex_coords[2], tex_coords[3]); 76 } 77 } 78 79 if (m_client_side_normal_array_enabled) { 80 float normal[3]; 81 read_from_vertex_attribute_pointer(m_client_normal_pointer, i, normal); 82 gl_normal(normal[0], normal[1], normal[2]); 83 } 84 85 if (m_client_side_vertex_array_enabled) { 86 float vertex[4] { 0.f, 0.f, 0.f, 1.f }; 87 read_from_vertex_attribute_pointer(m_client_vertex_pointer, i, vertex); 88 gl_vertex(vertex[0], vertex[1], vertex[2], vertex[3]); 89 } 90} 91 92void GLContext::gl_color(GLfloat r, GLfloat g, GLfloat b, GLfloat a) 93{ 94 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_color, r, g, b, a); 95 96 m_current_vertex_color = { r, g, b, a }; 97} 98 99void GLContext::gl_color_pointer(GLint size, GLenum type, GLsizei stride, void const* pointer) 100{ 101 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 102 RETURN_WITH_ERROR_IF(!(size == 3 || size == 4), GL_INVALID_VALUE); 103 RETURN_WITH_ERROR_IF(type != GL_BYTE 104 && type != GL_UNSIGNED_BYTE 105 && type != GL_SHORT 106 && type != GL_UNSIGNED_SHORT 107 && type != GL_INT 108 && type != GL_UNSIGNED_INT 109 && type != GL_FLOAT 110 && type != GL_DOUBLE, 111 GL_INVALID_ENUM); 112 RETURN_WITH_ERROR_IF(stride < 0, GL_INVALID_VALUE); 113 114 void const* data_pointer = pointer; 115 if (m_array_buffer) { 116 size_t data_offset = reinterpret_cast<size_t>(pointer); 117 data_pointer = m_array_buffer->offset_data(data_offset); 118 } 119 m_client_color_pointer = { .size = size, .type = type, .normalize = true, .stride = stride, .pointer = data_pointer }; 120} 121 122void GLContext::gl_draw_arrays(GLenum mode, GLint first, GLsizei count) 123{ 124 // NOTE: This always dereferences data; display list support is deferred to the 125 // individual vertex attribute calls such as `gl_color`, `gl_normal` etc. 126 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 127 128 // FIXME: Some modes are still missing (GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES) 129 RETURN_WITH_ERROR_IF(!(mode == GL_TRIANGLE_STRIP 130 || mode == GL_TRIANGLE_FAN 131 || mode == GL_TRIANGLES 132 || mode == GL_QUADS 133 || mode == GL_QUAD_STRIP 134 || mode == GL_POLYGON), 135 GL_INVALID_ENUM); 136 137 RETURN_WITH_ERROR_IF(count < 0, GL_INVALID_VALUE); 138 139 auto last = first + count; 140 gl_begin(mode); 141 for (int i = first; i < last; i++) { 142 if (m_client_side_color_array_enabled) { 143 float color[4] { 0.f, 0.f, 0.f, 1.f }; 144 read_from_vertex_attribute_pointer(m_client_color_pointer, i, color); 145 gl_color(color[0], color[1], color[2], color[3]); 146 } 147 148 for (size_t t = 0; t < m_client_tex_coord_pointer.size(); ++t) { 149 if (m_client_side_texture_coord_array_enabled[t]) { 150 float tex_coords[4] { 0.f, 0.f, 0.f, 1.f }; 151 read_from_vertex_attribute_pointer(m_client_tex_coord_pointer[t], i, tex_coords); 152 gl_multi_tex_coord(GL_TEXTURE0 + t, tex_coords[0], tex_coords[1], tex_coords[2], tex_coords[3]); 153 } 154 } 155 156 if (m_client_side_normal_array_enabled) { 157 float normal[3]; 158 read_from_vertex_attribute_pointer(m_client_normal_pointer, i, normal); 159 gl_normal(normal[0], normal[1], normal[2]); 160 } 161 162 if (m_client_side_vertex_array_enabled) { 163 float vertex[4] { 0.f, 0.f, 0.f, 1.f }; 164 read_from_vertex_attribute_pointer(m_client_vertex_pointer, i, vertex); 165 gl_vertex(vertex[0], vertex[1], vertex[2], vertex[3]); 166 } 167 } 168 gl_end(); 169} 170 171void GLContext::gl_draw_elements(GLenum mode, GLsizei count, GLenum type, void const* indices) 172{ 173 // NOTE: This always dereferences data; display list support is deferred to the 174 // individual vertex attribute calls such as `gl_color`, `gl_normal` etc. 175 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 176 177 // FIXME: Some modes are still missing (GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES) 178 RETURN_WITH_ERROR_IF(!(mode == GL_TRIANGLE_STRIP 179 || mode == GL_TRIANGLE_FAN 180 || mode == GL_TRIANGLES 181 || mode == GL_QUADS 182 || mode == GL_QUAD_STRIP 183 || mode == GL_POLYGON), 184 GL_INVALID_ENUM); 185 186 RETURN_WITH_ERROR_IF(!(type == GL_UNSIGNED_BYTE 187 || type == GL_UNSIGNED_SHORT 188 || type == GL_UNSIGNED_INT), 189 GL_INVALID_ENUM); 190 191 RETURN_WITH_ERROR_IF(count < 0, GL_INVALID_VALUE); 192 193 void const* index_data = indices; 194 if (m_element_array_buffer) { 195 size_t data_offset = reinterpret_cast<size_t>(indices); 196 index_data = m_element_array_buffer->offset_data(data_offset); 197 } 198 199 gl_begin(mode); 200 for (int index = 0; index < count; index++) { 201 int i = 0; 202 switch (type) { 203 case GL_UNSIGNED_BYTE: 204 i = reinterpret_cast<GLubyte const*>(index_data)[index]; 205 break; 206 case GL_UNSIGNED_SHORT: 207 i = reinterpret_cast<GLushort const*>(index_data)[index]; 208 break; 209 case GL_UNSIGNED_INT: 210 i = reinterpret_cast<GLuint const*>(index_data)[index]; 211 break; 212 } 213 214 if (m_client_side_color_array_enabled) { 215 float color[4] { 0.f, 0.f, 0.f, 1.f }; 216 read_from_vertex_attribute_pointer(m_client_color_pointer, i, color); 217 gl_color(color[0], color[1], color[2], color[3]); 218 } 219 220 for (size_t t = 0; t < m_client_tex_coord_pointer.size(); ++t) { 221 if (m_client_side_texture_coord_array_enabled[t]) { 222 float tex_coords[4] { 0.f, 0.f, 0.f, 1.f }; 223 read_from_vertex_attribute_pointer(m_client_tex_coord_pointer[t], i, tex_coords); 224 gl_multi_tex_coord(GL_TEXTURE0 + t, tex_coords[0], tex_coords[1], tex_coords[2], tex_coords[3]); 225 } 226 } 227 228 if (m_client_side_normal_array_enabled) { 229 float normal[3]; 230 read_from_vertex_attribute_pointer(m_client_normal_pointer, i, normal); 231 gl_normal(normal[0], normal[1], normal[2]); 232 } 233 234 if (m_client_side_vertex_array_enabled) { 235 float vertex[4] { 0.f, 0.f, 0.f, 1.f }; 236 read_from_vertex_attribute_pointer(m_client_vertex_pointer, i, vertex); 237 gl_vertex(vertex[0], vertex[1], vertex[2], vertex[3]); 238 } 239 } 240 gl_end(); 241} 242 243void GLContext::gl_normal(GLfloat nx, GLfloat ny, GLfloat nz) 244{ 245 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_normal, nx, ny, nz); 246 247 m_current_vertex_normal = { nx, ny, nz }; 248} 249 250void GLContext::gl_normal_pointer(GLenum type, GLsizei stride, void const* pointer) 251{ 252 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 253 RETURN_WITH_ERROR_IF(type != GL_BYTE 254 && type != GL_SHORT 255 && type != GL_INT 256 && type != GL_FLOAT 257 && type != GL_DOUBLE, 258 GL_INVALID_ENUM); 259 RETURN_WITH_ERROR_IF(stride < 0, GL_INVALID_VALUE); 260 261 void const* data_pointer = pointer; 262 if (m_array_buffer) { 263 size_t data_offset = reinterpret_cast<size_t>(pointer); 264 data_pointer = m_array_buffer->offset_data(data_offset); 265 } 266 m_client_normal_pointer = { .size = 3, .type = type, .normalize = true, .stride = stride, .pointer = data_pointer }; 267} 268 269void GLContext::gl_tex_coord_pointer(GLint size, GLenum type, GLsizei stride, void const* pointer) 270{ 271 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 272 RETURN_WITH_ERROR_IF(!(size == 1 || size == 2 || size == 3 || size == 4), GL_INVALID_VALUE); 273 RETURN_WITH_ERROR_IF(!(type == GL_SHORT || type == GL_INT || type == GL_FLOAT || type == GL_DOUBLE), GL_INVALID_ENUM); 274 RETURN_WITH_ERROR_IF(stride < 0, GL_INVALID_VALUE); 275 276 auto& tex_coord_pointer = m_client_tex_coord_pointer[m_client_active_texture]; 277 278 void const* data_pointer = pointer; 279 if (m_array_buffer) { 280 size_t data_offset = reinterpret_cast<size_t>(pointer); 281 data_pointer = m_array_buffer->offset_data(data_offset); 282 } 283 tex_coord_pointer = { .size = size, .type = type, .normalize = false, .stride = stride, .pointer = data_pointer }; 284} 285 286void GLContext::gl_vertex(GLfloat x, GLfloat y, GLfloat z, GLfloat w) 287{ 288 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_vertex, x, y, z, w); 289 290 GPU::Vertex vertex; 291 292 vertex.position = { x, y, z, w }; 293 vertex.color = m_current_vertex_color; 294 for (size_t i = 0; i < m_device_info.num_texture_units; ++i) 295 vertex.tex_coords[i] = m_current_vertex_tex_coord[i]; 296 vertex.normal = m_current_vertex_normal; 297 298 m_vertex_list.append(vertex); 299} 300 301void GLContext::gl_vertex_pointer(GLint size, GLenum type, GLsizei stride, void const* pointer) 302{ 303 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 304 RETURN_WITH_ERROR_IF(!(size == 2 || size == 3 || size == 4), GL_INVALID_VALUE); 305 RETURN_WITH_ERROR_IF(!(type == GL_SHORT || type == GL_INT || type == GL_FLOAT || type == GL_DOUBLE), GL_INVALID_ENUM); 306 RETURN_WITH_ERROR_IF(stride < 0, GL_INVALID_VALUE); 307 308 void const* data_pointer = pointer; 309 if (m_array_buffer) { 310 size_t data_offset = reinterpret_cast<size_t>(pointer); 311 data_pointer = m_array_buffer->offset_data(data_offset); 312 } 313 m_client_vertex_pointer = { .size = size, .type = type, .normalize = false, .stride = stride, .pointer = data_pointer }; 314} 315 316}