diff --git a/Userland/Libraries/LibGL/Buffer.cpp b/Userland/Libraries/LibGL/Buffer.cpp index c088830eea..2cd15423ec 100644 --- a/Userland/Libraries/LibGL/Buffer.cpp +++ b/Userland/Libraries/LibGL/Buffer.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, Jelle Raaijmakers + * Copyright (c) 2022, cflip * * 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); + } } } diff --git a/Userland/Libraries/LibGL/Buffer/Buffer.cpp b/Userland/Libraries/LibGL/Buffer/Buffer.cpp new file mode 100644 index 0000000000..dbfa844415 --- /dev/null +++ b/Userland/Libraries/LibGL/Buffer/Buffer.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022, cflip + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "Buffer.h" + +namespace GL { + +ErrorOr 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); +} + +} diff --git a/Userland/Libraries/LibGL/Buffer/Buffer.h b/Userland/Libraries/LibGL/Buffer/Buffer.h new file mode 100644 index 0000000000..ba3d1af334 --- /dev/null +++ b/Userland/Libraries/LibGL/Buffer/Buffer.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022, cflip + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +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 { +public: + ErrorOr 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; +}; + +} diff --git a/Userland/Libraries/LibGL/CMakeLists.txt b/Userland/Libraries/LibGL/CMakeLists.txt index 3c9bb66725..4c76ad7854 100644 --- a/Userland/Libraries/LibGL/CMakeLists.txt +++ b/Userland/Libraries/LibGL/CMakeLists.txt @@ -1,4 +1,5 @@ set(SOURCES + Buffer/Buffer.cpp Buffer.cpp ClipPlane.cpp ContextParameter.cpp diff --git a/Userland/Libraries/LibGL/GL/gl.h b/Userland/Libraries/LibGL/GL/gl.h index 74938b6c99..0acd40852d 100644 --- a/Userland/Libraries/LibGL/GL/gl.h +++ b/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); diff --git a/Userland/Libraries/LibGL/GLContext.h b/Userland/Libraries/LibGL/GLContext.h index f76ed24ef5..31d3badf39 100644 --- a/Userland/Libraries/LibGL/GLContext.h +++ b/Userland/Libraries/LibGL/GLContext.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -543,6 +544,12 @@ private: // GL Extension string String m_extensions; + + // Buffer objects + NameAllocator m_buffer_name_allocator; + HashMap> m_allocated_buffers; + RefPtr m_array_buffer; + RefPtr m_element_array_buffer; }; ErrorOr> create_context(Gfx::Bitmap&);