Browse Source

LibGL: Add simple implementation of buffer objects

For now, buffers are only implemented on the LibGL side, however in the
future buffer objects should be stored in LibGPU.
cflip 2 years ago
parent
commit
59df2e62ee

+ 78 - 10
Userland/Libraries/LibGL/Buffer.cpp

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl>
+ * Copyright (c) 2022, cflip <cflip@cflip.net>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -11,32 +12,99 @@ namespace GL {
 
 void GLContext::gl_bind_buffer(GLenum target, GLuint buffer)
 {
-    // FIXME: implement me
-    dbgln_if(GL_DEBUG, "{}({:#x}, {})): unimplemented", __FUNCTION__, target, buffer);
+    RETURN_WITH_ERROR_IF(target != GL_ARRAY_BUFFER && target != GL_ELEMENT_ARRAY_BUFFER, GL_INVALID_ENUM);
+    RETURN_WITH_ERROR_IF(!m_buffer_name_allocator.has_allocated_name(buffer), GL_INVALID_VALUE);
+
+    auto& target_buffer = target == GL_ELEMENT_ARRAY_BUFFER ? m_element_array_buffer : m_array_buffer;
+    target_buffer = nullptr;
+
+    if (buffer != 0) {
+        auto it = m_allocated_buffers.find(buffer);
+        if (it != m_allocated_buffers.end()) {
+            auto buffer_object = it->value;
+            if (!buffer_object.is_null()) {
+                target_buffer = buffer_object;
+            }
+        }
+
+        if (!target_buffer) {
+            target_buffer = adopt_ref(*new Buffer());
+            m_allocated_buffers.set(buffer, target_buffer);
+        }
+    }
 }
 
 void GLContext::gl_buffer_data(GLenum target, GLsizeiptr size, void const* data, GLenum usage)
 {
-    // FIXME: implement me
-    dbgln_if(GL_DEBUG, "{}({:#x}, {}, {:p}, {:#x}): unimplemented", __FUNCTION__, target, size, data, usage);
+    RETURN_WITH_ERROR_IF(usage != GL_STREAM_DRAW
+            && usage != GL_STREAM_READ
+            && usage != GL_STREAM_COPY
+            && usage != GL_STATIC_DRAW
+            && usage != GL_STATIC_READ
+            && usage != GL_STATIC_COPY
+            && usage != GL_DYNAMIC_DRAW
+            && usage != GL_DYNAMIC_READ
+            && usage != GL_DYNAMIC_COPY,
+        GL_INVALID_ENUM);
+    RETURN_WITH_ERROR_IF(target != GL_ARRAY_BUFFER && target != GL_ELEMENT_ARRAY_BUFFER, GL_INVALID_ENUM);
+
+    auto& target_buffer = target == GL_ELEMENT_ARRAY_BUFFER ? m_element_array_buffer : m_array_buffer;
+    RETURN_WITH_ERROR_IF(!target_buffer, GL_INVALID_OPERATION);
+
+    // FIXME: Report GL_OUT_OF_MEMORY or other errors as needed here
+    MUST(target_buffer->set_data(data, size));
 }
 
 void GLContext::gl_buffer_sub_data(GLenum target, GLintptr offset, GLsizeiptr size, void const* data)
 {
-    // FIXME: implement me
-    dbgln_if(GL_DEBUG, "{}({:#x}, {}, {}, {:p}): unimplemented", __FUNCTION__, target, offset, size, data);
+    RETURN_WITH_ERROR_IF(target != GL_ARRAY_BUFFER && target != GL_ELEMENT_ARRAY_BUFFER, GL_INVALID_ENUM);
+    RETURN_WITH_ERROR_IF(offset < 0, GL_INVALID_VALUE);
+    // FIXME: Support buffer storage mutability flags.
+
+    auto& target_buffer = target == GL_ELEMENT_ARRAY_BUFFER ? m_element_array_buffer : m_array_buffer;
+    RETURN_WITH_ERROR_IF(!target_buffer, GL_INVALID_OPERATION);
+    RETURN_WITH_ERROR_IF((offset + size) > target_buffer->size(), GL_INVALID_VALUE);
+
+    target_buffer->replace_data(data, offset, size);
 }
 
 void GLContext::gl_delete_buffers(GLsizei n, GLuint const* buffers)
 {
-    // FIXME: implement me
-    dbgln_if(GL_DEBUG, "{}({}, {:p}): unimplemented", __FUNCTION__, n, buffers);
+    RETURN_WITH_ERROR_IF(n < 0, GL_INVALID_VALUE);
+
+    for (auto i = 0; i < n; i++) {
+        GLuint name = buffers[i];
+        if (name == 0)
+            continue;
+
+        auto buffer_object = m_allocated_buffers.find(name);
+        if (buffer_object == m_allocated_buffers.end() || buffer_object->value.is_null())
+            continue;
+
+        Buffer* buffer = buffer_object->value;
+
+        if (m_array_buffer == buffer)
+            m_array_buffer = nullptr;
+
+        if (m_element_array_buffer == buffer)
+            m_element_array_buffer = nullptr;
+
+        m_buffer_name_allocator.free(name);
+        m_allocated_buffers.remove(name);
+    }
 }
 
 void GLContext::gl_gen_buffers(GLsizei n, GLuint* buffers)
 {
-    // FIXME: implement me
-    dbgln_if(GL_DEBUG, "{}({}, {:p}): unimplemented", __FUNCTION__, n, buffers);
+    RETURN_WITH_ERROR_IF(n < 0, GL_INVALID_VALUE);
+
+    m_buffer_name_allocator.allocate(n, buffers);
+
+    // Initialize all buffer names with a nullptr
+    for (auto i = 0; i < n; ++i) {
+        GLuint name = buffers[i];
+        m_allocated_buffers.set(name, nullptr);
+    }
 }
 
 }

+ 41 - 0
Userland/Libraries/LibGL/Buffer/Buffer.cpp

@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2022, cflip <cflip@cflip.net>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "Buffer.h"
+
+namespace GL {
+
+ErrorOr<void> Buffer::set_data(void const* data, size_t size)
+{
+    if (!data) {
+        m_data = TRY(ByteBuffer::create_uninitialized(size));
+        return {};
+    }
+    m_data = TRY(ByteBuffer::copy(data, size));
+    return {};
+}
+
+void Buffer::replace_data(void const* data, size_t offset, size_t size)
+{
+    m_data.overwrite(offset, data, size);
+}
+
+size_t Buffer::size()
+{
+    return m_data.size();
+}
+
+void* Buffer::data()
+{
+    return m_data.data();
+}
+
+void* Buffer::offset_data(size_t offset)
+{
+    return m_data.offset_pointer(offset);
+}
+
+}

+ 29 - 0
Userland/Libraries/LibGL/Buffer/Buffer.h

@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2022, cflip <cflip@cflip.net>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/ByteBuffer.h>
+#include <AK/RefCounted.h>
+
+namespace GL {
+
+// FIXME: For now, this is basically just a wrapper around ByteBuffer, but in
+//        the future buffer data should be stored in LibGPU.
+class Buffer : public RefCounted<Buffer> {
+public:
+    ErrorOr<void> set_data(void const*, size_t);
+    void replace_data(void const*, size_t offset, size_t size);
+
+    size_t size();
+    void* data();
+    void* offset_data(size_t);
+
+private:
+    ByteBuffer m_data;
+};
+
+}

+ 1 - 0
Userland/Libraries/LibGL/CMakeLists.txt

@@ -1,4 +1,5 @@
 set(SOURCES
+    Buffer/Buffer.cpp
     Buffer.cpp
     ClipPlane.cpp
     ContextParameter.cpp

+ 14 - 0
Userland/Libraries/LibGL/GL/gl.h

@@ -587,6 +587,20 @@ extern "C" {
 #define GL_CLIP_PLANE4 0x3004
 #define GL_CLIP_PLANE5 0x3005
 
+// Buffer objects
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+
+#define GL_STREAM_DRAW 0x88e0
+#define GL_STREAM_READ 0x88e1
+#define GL_STREAM_COPY 0x88e2
+#define GL_STATIC_DRAW 0x88e4
+#define GL_STATIC_READ 0x88e5
+#define GL_STATIC_COPY 0x88e6
+#define GL_DYNAMIC_DRAW 0x88e8
+#define GL_DYNAMIC_READ 0x88e9
+#define GL_DYNAMIC_COPY 0x88ea
+
 GLAPI void glBegin(GLenum mode);
 GLAPI void glClear(GLbitfield mask);
 GLAPI void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);

+ 7 - 0
Userland/Libraries/LibGL/GLContext.h

@@ -15,6 +15,7 @@
 #include <AK/Tuple.h>
 #include <AK/Variant.h>
 #include <AK/Vector.h>
+#include <LibGL/Buffer/Buffer.h>
 #include <LibGL/NameAllocator.h>
 #include <LibGL/Tex/Texture.h>
 #include <LibGL/Tex/TextureUnit.h>
@@ -543,6 +544,12 @@ private:
 
     // GL Extension string
     String m_extensions;
+
+    // Buffer objects
+    NameAllocator m_buffer_name_allocator;
+    HashMap<GLuint, RefPtr<Buffer>> m_allocated_buffers;
+    RefPtr<Buffer> m_array_buffer;
+    RefPtr<Buffer> m_element_array_buffer;
 };
 
 ErrorOr<NonnullOwnPtr<GLContext>> create_context(Gfx::Bitmap&);