summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibGL
diff options
context:
space:
mode:
authorAli Mohammad Pur <ali.mpfard@gmail.com>2021-05-09 08:25:15 +0430
committerLinus Groh <mail@linusgroh.de>2021-05-11 14:09:17 +0100
commit720d21411ba2187d2cc45f34f2471fb07c12ce97 (patch)
tree38c5556a2803aae37b7532326f79a2b2e4427320 /Userland/Libraries/LibGL
parent02de813950fc7c6858f645f39e38c7aeee5058fe (diff)
downloadserenity-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.txt3
-rw-r--r--Userland/Libraries/LibGL/GL/gl.h9
-rw-r--r--Userland/Libraries/LibGL/GLContext.h5
-rw-r--r--Userland/Libraries/LibGL/GLLists.cpp35
-rw-r--r--Userland/Libraries/LibGL/SoftwareGLContext.cpp152
-rw-r--r--Userland/Libraries/LibGL/SoftwareGLContext.h90
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;
};
}