diff options
author | Ali Mohammad Pur <ali.mpfard@gmail.com> | 2021-05-09 08:25:15 +0430 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2021-05-11 14:09:17 +0100 |
commit | 720d21411ba2187d2cc45f34f2471fb07c12ce97 (patch) | |
tree | 38c5556a2803aae37b7532326f79a2b2e4427320 /Userland/Libraries/LibGL | |
parent | 02de813950fc7c6858f645f39e38c7aeee5058fe (diff) | |
download | serenity-720d21411ba2187d2cc45f34f2471fb07c12ce97.zip |
LibGL: Implement glGenLists and a few friends
This commit implements glGenLists(), glNewList(), glDeleteLists(), and
glCallList().
The 'compiled' records are implemented as a vector of member function
pointers and tuples containing their arguments, and a mechanism is
implemented to allow the recorded calls to copy-capture values from the
time of the call; this is currently only used with glLoadMatrix.
Diffstat (limited to 'Userland/Libraries/LibGL')
-rw-r--r-- | Userland/Libraries/LibGL/CMakeLists.txt | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibGL/GL/gl.h | 9 | ||||
-rw-r--r-- | Userland/Libraries/LibGL/GLContext.h | 5 | ||||
-rw-r--r-- | Userland/Libraries/LibGL/GLLists.cpp | 35 | ||||
-rw-r--r-- | Userland/Libraries/LibGL/SoftwareGLContext.cpp | 152 | ||||
-rw-r--r-- | Userland/Libraries/LibGL/SoftwareGLContext.h | 90 |
6 files changed, 292 insertions, 2 deletions
diff --git a/Userland/Libraries/LibGL/CMakeLists.txt b/Userland/Libraries/LibGL/CMakeLists.txt index 637658c73d..4a86aba3e6 100644 --- a/Userland/Libraries/LibGL/CMakeLists.txt +++ b/Userland/Libraries/LibGL/CMakeLists.txt @@ -1,8 +1,9 @@ set(SOURCES Clipper.cpp GLColor.cpp - GLMat.cpp GLContext.cpp + GLLists.cpp + GLMat.cpp GLUtils.cpp GLVert.cpp SoftwareGLContext.cpp diff --git a/Userland/Libraries/LibGL/GL/gl.h b/Userland/Libraries/LibGL/GL/gl.h index 05d861c999..1896caaa35 100644 --- a/Userland/Libraries/LibGL/GL/gl.h +++ b/Userland/Libraries/LibGL/GL/gl.h @@ -61,6 +61,10 @@ extern "C" { #define GL_CW 0x0900 #define GL_CCW 0x0901 +// Listing enums +#define GL_COMPILE 0x1300 +#define GL_COMPILE_AND_EXECUTE 0x1301 + // // OpenGL typedefs // @@ -115,6 +119,11 @@ GLAPI void glEnable(GLenum cap); GLAPI void glDisable(GLenum cap); GLAPI void glCullFace(GLenum mode); GLAPI void glFrontFace(GLenum mode); +GLuint glGenLists(GLsizei range); +void glCallList(GLuint list); +void glDeleteLists(GLuint list, GLsizei range); +void glEndList(void); +void glNewList(GLuint list, GLenum mode); #ifdef __cplusplus } diff --git a/Userland/Libraries/LibGL/GLContext.h b/Userland/Libraries/LibGL/GLContext.h index 4d7ec88cd2..3c2b830ad8 100644 --- a/Userland/Libraries/LibGL/GLContext.h +++ b/Userland/Libraries/LibGL/GLContext.h @@ -42,6 +42,11 @@ public: virtual void gl_disable(GLenum) = 0; virtual void gl_front_face(GLenum) = 0; virtual void gl_cull_face(GLenum) = 0; + virtual GLuint gl_gen_lists(GLsizei range) = 0; + virtual void gl_call_list(GLuint list) = 0; + virtual void gl_delete_lists(GLuint list, GLsizei range) = 0; + virtual void gl_end_list(void) = 0; + virtual void gl_new_list(GLuint list, GLenum mode) = 0; virtual void present() = 0; }; diff --git a/Userland/Libraries/LibGL/GLLists.cpp b/Userland/Libraries/LibGL/GLLists.cpp new file mode 100644 index 0000000000..06ff3cc863 --- /dev/null +++ b/Userland/Libraries/LibGL/GLLists.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "GL/gl.h" +#include "GLContext.h" + +extern GL::GLContext* g_gl_context; + +GLuint glGenLists(GLsizei range) +{ + return g_gl_context->gl_gen_lists(range); +} + +void glCallList(GLuint list) +{ + return g_gl_context->gl_call_list(list); +} + +void glDeleteLists(GLuint list, GLsizei range) +{ + return g_gl_context->gl_delete_lists(list, range); +} + +void glEndList(void) +{ + return g_gl_context->gl_end_list(); +} + +void glNewList(GLuint list, GLenum mode) +{ + return g_gl_context->gl_new_list(list, mode); +} diff --git a/Userland/Libraries/LibGL/SoftwareGLContext.cpp b/Userland/Libraries/LibGL/SoftwareGLContext.cpp index 283b7391c5..7c739c473c 100644 --- a/Userland/Libraries/LibGL/SoftwareGLContext.cpp +++ b/Userland/Libraries/LibGL/SoftwareGLContext.cpp @@ -12,6 +12,8 @@ #include <AK/Debug.h> #include <AK/Format.h> #include <AK/QuickSort.h> +#include <AK/TemporaryChange.h> +#include <AK/Variant.h> #include <AK/Vector.h> #include <LibGfx/Bitmap.h> #include <LibGfx/Painter.h> @@ -25,6 +27,13 @@ namespace GL { // FIXME: We should set this up when we create the context! static constexpr size_t MATRIX_STACK_LIMIT = 1024; +#define APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(name, ...) \ + if (should_append_to_listing()) { \ + append_to_listing<&SoftwareGLContext::name>(__VA_ARGS__); \ + if (!should_execute_after_appending_to_listing()) \ + return; \ + } + SoftwareGLContext::SoftwareGLContext(Gfx::Bitmap& frontbuffer) : m_frontbuffer(frontbuffer) , m_rasterizer(frontbuffer.size()) @@ -33,6 +42,8 @@ SoftwareGLContext::SoftwareGLContext(Gfx::Bitmap& frontbuffer) void SoftwareGLContext::gl_begin(GLenum mode) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_begin, mode); + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -50,6 +61,8 @@ void SoftwareGLContext::gl_begin(GLenum mode) void SoftwareGLContext::gl_clear(GLbitfield mask) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear, mask); + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -71,6 +84,8 @@ void SoftwareGLContext::gl_clear(GLbitfield mask) void SoftwareGLContext::gl_clear_color(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear_color, red, green, blue, alpha); + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -82,6 +97,8 @@ void SoftwareGLContext::gl_clear_color(GLclampf red, GLclampf green, GLclampf bl void SoftwareGLContext::gl_clear_depth(GLdouble depth) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear_depth, depth); + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -93,12 +110,16 @@ void SoftwareGLContext::gl_clear_depth(GLdouble depth) void SoftwareGLContext::gl_color(GLdouble r, GLdouble g, GLdouble b, GLdouble a) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_color, r, g, b, a); + m_current_vertex_color = { (float)r, (float)g, (float)b, (float)a }; m_error = GL_NO_ERROR; } void SoftwareGLContext::gl_end() { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_end); + // At this point, the user has effectively specified that they are done with defining the geometry // of what they want to draw. We now need to do a few things (https://www.khronos.org/opengl/wiki/Rendering_Pipeline_Overview): // @@ -313,6 +334,8 @@ void SoftwareGLContext::gl_end() void SoftwareGLContext::gl_frustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_frustum, left, right, bottom, top, near_val, far_val); + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -344,6 +367,8 @@ void SoftwareGLContext::gl_frustum(GLdouble left, GLdouble right, GLdouble botto void SoftwareGLContext::gl_ortho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_ortho, left, right, bottom, top, near_val, far_val); + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -411,6 +436,8 @@ GLubyte* SoftwareGLContext::gl_get_string(GLenum name) void SoftwareGLContext::gl_load_identity() { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_load_identity); + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -428,6 +455,13 @@ void SoftwareGLContext::gl_load_identity() void SoftwareGLContext::gl_load_matrix(const FloatMatrix4x4& matrix) { + if (should_append_to_listing()) { + auto ptr = store_in_listing(matrix); + append_to_listing<&SoftwareGLContext::gl_load_matrix>(*ptr); + if (!should_execute_after_appending_to_listing()) + return; + } + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -445,6 +479,8 @@ void SoftwareGLContext::gl_load_matrix(const FloatMatrix4x4& matrix) void SoftwareGLContext::gl_matrix_mode(GLenum mode) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_matrix_mode, mode); + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -461,6 +497,8 @@ void SoftwareGLContext::gl_matrix_mode(GLenum mode) void SoftwareGLContext::gl_push_matrix() { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_push_matrix); + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -493,6 +531,8 @@ void SoftwareGLContext::gl_push_matrix() void SoftwareGLContext::gl_pop_matrix() { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_pop_matrix); + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -526,6 +566,8 @@ void SoftwareGLContext::gl_pop_matrix() void SoftwareGLContext::gl_rotate(GLdouble angle, GLdouble x, GLdouble y, GLdouble z) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_rotate, angle, x, y, z); + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -545,6 +587,8 @@ void SoftwareGLContext::gl_rotate(GLdouble angle, GLdouble x, GLdouble y, GLdoub void SoftwareGLContext::gl_scale(GLdouble x, GLdouble y, GLdouble z) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_scale, x, y, z); + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -561,6 +605,8 @@ void SoftwareGLContext::gl_scale(GLdouble x, GLdouble y, GLdouble z) void SoftwareGLContext::gl_translate(GLdouble x, GLdouble y, GLdouble z) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_translate, x, y, z); + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -577,6 +623,8 @@ void SoftwareGLContext::gl_translate(GLdouble x, GLdouble y, GLdouble z) void SoftwareGLContext::gl_vertex(GLdouble x, GLdouble y, GLdouble z, GLdouble w) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_vertex, x, y, z, w); + GLVertex vertex; vertex.x = x; @@ -599,6 +647,8 @@ void SoftwareGLContext::gl_vertex(GLdouble x, GLdouble y, GLdouble z, GLdouble w void SoftwareGLContext::gl_viewport(GLint x, GLint y, GLsizei width, GLsizei height) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_viewport, x, y, width, height); + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -613,6 +663,8 @@ void SoftwareGLContext::gl_viewport(GLint x, GLint y, GLsizei width, GLsizei hei void SoftwareGLContext::gl_enable(GLenum capability) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_enable, capability); + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -641,6 +693,8 @@ void SoftwareGLContext::gl_enable(GLenum capability) void SoftwareGLContext::gl_disable(GLenum capability) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_disable, capability); + if (m_in_draw_state) { m_error = GL_INVALID_OPERATION; return; @@ -669,6 +723,8 @@ void SoftwareGLContext::gl_disable(GLenum capability) void SoftwareGLContext::gl_front_face(GLenum face) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_front_face, face); + if (face < GL_CW || face > GL_CCW) { m_error = GL_INVALID_ENUM; return; @@ -679,6 +735,8 @@ void SoftwareGLContext::gl_front_face(GLenum face) void SoftwareGLContext::gl_cull_face(GLenum cull_mode) { + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_cull_face, cull_mode); + if (cull_mode < GL_FRONT || cull_mode > GL_FRONT_AND_BACK) { m_error = GL_INVALID_ENUM; return; @@ -687,9 +745,101 @@ void SoftwareGLContext::gl_cull_face(GLenum cull_mode) m_culled_sides = cull_mode; } +GLuint SoftwareGLContext::gl_gen_lists(GLsizei range) +{ + if (range <= 0) { + m_error = GL_INVALID_VALUE; + return 0; + } + if (m_in_draw_state) { + m_error = GL_INVALID_OPERATION; + return 0; + } + + auto initial_entry = m_listings.size(); + m_listings.resize(range + initial_entry); + return initial_entry + 1; +} + +void SoftwareGLContext::gl_call_list(GLuint list) +{ + if (m_gl_call_depth > max_allowed_gl_call_depth) + return; + + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_call_list, list); + + if (m_listings.size() < list) + return; + + TemporaryChange change { m_gl_call_depth, m_gl_call_depth + 1 }; + + auto& listing = m_listings[list - 1]; + for (auto& entry : listing.entries) { + entry.function.visit([&](auto& function) { + entry.arguments.visit([&](auto& arguments) { + auto apply = [&]<typename... Args>(Args && ... args) + { + if constexpr (requires { (this->*function)(forward<Args>(args)...); }) + (this->*function)(forward<Args>(args)...); + }; + + arguments.apply_as_args(apply); + }); + }); + } +} + +void SoftwareGLContext::gl_delete_lists(GLuint list, GLsizei range) +{ + if (m_listings.size() < list || m_listings.size() <= list + range) + return; + + for (auto& entry : m_listings.span().slice(list - 1, range)) + entry.entries.clear(); +} + +void SoftwareGLContext::gl_end_list() +{ + if (m_in_draw_state) { + m_error = GL_INVALID_OPERATION; + return; + } + if (!m_current_listing_index.has_value()) { + m_error = GL_INVALID_OPERATION; + return; + } + + m_listings[m_current_listing_index->index] = move(m_current_listing_index->listing); + m_current_listing_index.clear(); +} + +void SoftwareGLContext::gl_new_list(GLuint list, GLenum mode) +{ + if (list == 0) { + m_error = GL_INVALID_VALUE; + return; + } + if (mode != GL_COMPILE && mode != GL_COMPILE_AND_EXECUTE) { + m_error = GL_INVALID_ENUM; + return; + } + if (m_in_draw_state) { + m_error = GL_INVALID_OPERATION; + return; + } + if (m_current_listing_index.has_value()) { + m_error = GL_INVALID_OPERATION; + return; + } + + if (m_listings.size() < list) + return; + + m_current_listing_index = CurrentListing { {}, static_cast<size_t>(list - 1), mode }; +} + void SoftwareGLContext::present() { m_rasterizer.blit_to(*m_frontbuffer); } - } diff --git a/Userland/Libraries/LibGL/SoftwareGLContext.h b/Userland/Libraries/LibGL/SoftwareGLContext.h index 350415382b..04982769f2 100644 --- a/Userland/Libraries/LibGL/SoftwareGLContext.h +++ b/Userland/Libraries/LibGL/SoftwareGLContext.h @@ -11,6 +11,8 @@ #include "GLStruct.h" #include "SoftwareRasterizer.h" #include <AK/RefPtr.h> +#include <AK/Tuple.h> +#include <AK/Variant.h> #include <AK/Vector.h> #include <LibGfx/Bitmap.h> #include <LibGfx/Matrix4x4.h> @@ -46,10 +48,34 @@ public: virtual void gl_disable(GLenum) override; virtual void gl_front_face(GLenum) override; virtual void gl_cull_face(GLenum) override; + virtual GLuint gl_gen_lists(GLsizei range) override; + virtual void gl_call_list(GLuint list) override; + virtual void gl_delete_lists(GLuint list, GLsizei range) override; + virtual void gl_end_list(void) override; + virtual void gl_new_list(GLuint list, GLenum mode) override; virtual void present() override; private: + template<typename T> + T* store_in_listing(T value) + { + VERIFY(m_current_listing_index.has_value()); + auto& listing = m_current_listing_index->listing; + listing.saved_arguments.empend(make<Listing::ExtraSavedArguments>(move(value))); + return listing.saved_arguments.last()->template get_pointer<T>(); + } + + template<auto member, typename... Args> + void append_to_listing(Args&&... args) + { + VERIFY(m_current_listing_index.has_value()); + m_current_listing_index->listing.entries.empend(member, Listing::ArgumentsFor<member> { forward<Args>(args)... }); + } + + [[nodiscard]] bool should_append_to_listing() const { return m_current_listing_index.has_value(); } + [[nodiscard]] bool should_execute_after_appending_to_listing() const { return m_current_listing_index.has_value() && m_current_listing_index->mode == GL_COMPILE_AND_EXECUTE; } + GLenum m_current_draw_mode; GLenum m_current_matrix_mode; FloatMatrix4x4 m_projection_matrix; @@ -82,6 +108,70 @@ private: Clipper m_clipper; SoftwareRasterizer m_rasterizer; + + struct Listing { + + template<typename F> + struct TupleTypeForArgumentListOf_; + + template<typename Ret, typename C, typename... Args> + struct TupleTypeForArgumentListOf_<Ret (C::*)(Args...)> { + using Type = Tuple<Args...>; + }; + + template<typename F> + using TupleTypeForArgumentListOf = typename TupleTypeForArgumentListOf_<F>::Type; + + template<auto member> + using ArgumentsFor = TupleTypeForArgumentListOf<decltype(member)>; + + template<typename... Fns> + struct FunctionAndArgs { + Variant<Fns...> function; + Variant<TupleTypeForArgumentListOf<Fns>...> arguments; + }; + + using FunctionsAndArgs = FunctionAndArgs< + decltype(&SoftwareGLContext::gl_begin), + decltype(&SoftwareGLContext::gl_clear), + decltype(&SoftwareGLContext::gl_clear_color), + decltype(&SoftwareGLContext::gl_clear_depth), + decltype(&SoftwareGLContext::gl_color), + decltype(&SoftwareGLContext::gl_end), + decltype(&SoftwareGLContext::gl_frustum), + decltype(&SoftwareGLContext::gl_load_identity), + decltype(&SoftwareGLContext::gl_load_matrix), + decltype(&SoftwareGLContext::gl_matrix_mode), + decltype(&SoftwareGLContext::gl_ortho), + decltype(&SoftwareGLContext::gl_push_matrix), + decltype(&SoftwareGLContext::gl_pop_matrix), + decltype(&SoftwareGLContext::gl_rotate), + decltype(&SoftwareGLContext::gl_scale), + decltype(&SoftwareGLContext::gl_translate), + decltype(&SoftwareGLContext::gl_vertex), + decltype(&SoftwareGLContext::gl_viewport), + decltype(&SoftwareGLContext::gl_enable), + decltype(&SoftwareGLContext::gl_disable), + decltype(&SoftwareGLContext::gl_front_face), + decltype(&SoftwareGLContext::gl_cull_face), + decltype(&SoftwareGLContext::gl_call_list)>; + + using ExtraSavedArguments = Variant< + FloatMatrix4x4>; + + Vector<NonnullOwnPtr<ExtraSavedArguments>> saved_arguments; + Vector<FunctionsAndArgs> entries; + }; + + static constexpr size_t max_allowed_gl_call_depth { 128 }; + size_t m_gl_call_depth { 0 }; + Vector<Listing> m_listings; + struct CurrentListing { + Listing listing; + size_t index { 0 }; + GLenum mode { GL_COMPILE }; + }; + Optional<CurrentListing> m_current_listing_index; }; } |