diff options
Diffstat (limited to 'src/gl/buffer.h')
-rw-r--r-- | src/gl/buffer.h | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/src/gl/buffer.h b/src/gl/buffer.h new file mode 100644 index 0000000..439533b --- /dev/null +++ b/src/gl/buffer.h @@ -0,0 +1,206 @@ +// Copyright 2021 Benjamin Barenblat +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +// Buffer objects. + +#ifndef GLPLANET_SRC_GL_BUFFER_H_ +#define GLPLANET_SRC_GL_BUFFER_H_ + +#include <assert.h> +#include <stdint.h> + +#include <concepts> +#include <type_traits> +#include <utility> + +#include "src/gl/error.h" +#include "third_party/abseil/absl/types/span.h" +#include "third_party/glew/include/GL/glew.h" + +namespace gl { + +// A byte buffer in GPU memory. +class Buffer final { + public: + // The frequency with which data in the buffer will be accessed. + enum class AccessFrequency : uint8_t { kStatic, kStream, kDynamic }; + + // The type of that access. + enum class AccessNature : uint8_t { kDraw, kRead, kCopy }; + + explicit Buffer() noexcept(!(gl_internal::kThreadSafetyChecks || + gl_internal::kAggressiveErrorChecking)) + : size_bytes_(0), + frequency_(AccessFrequency::kStatic), + nature_(AccessNature::kDraw) { + gl_internal::CheckThreadSafety(); + glCreateBuffers(1, &buffer_); + gl_internal::UnnecessaryErrorCheck(); + } + + Buffer(const Buffer&); + + Buffer& operator=(const Buffer& other) { + if (this != &other) { + Buffer other2(other); + swap(*this, other2); + } + return *this; + } + + Buffer(Buffer&& other) noexcept + : buffer_(0), + size_bytes_(0), + frequency_(AccessFrequency::kStatic), + nature_(AccessNature::kDraw) { + *this = std::move(other); + } + + Buffer& operator=(Buffer&& other) noexcept { + swap(*this, other); + return *this; + } + + ~Buffer() noexcept(!(gl_internal::kThreadSafetyChecks || + gl_internal::kAggressiveErrorChecking)) { + gl_internal::CheckThreadSafety(); + glDeleteBuffers(1, &buffer_); + gl_internal::UnnecessaryErrorCheck(); + } + + friend void swap(Buffer& left, Buffer& right) noexcept { + using ::std::swap; + swap(left.buffer_, right.buffer_); + swap(left.size_bytes_, right.size_bytes_); + swap(left.frequency_, right.frequency_); + swap(left.nature_, right.nature_); + } + + // Loads data into the buffer. + void SetData(const void*, int size_bytes, AccessFrequency, AccessNature); + + int size() const noexcept { return size_bytes_; } + + // The GL identifier for this buffer. + unsigned int id() const noexcept { return buffer_; } + + private: + GLuint buffer_; + int size_bytes_; + AccessFrequency frequency_; + AccessNature nature_; +}; + +// A vertex buffer object. +class VertexBuffer final { + public: + explicit VertexBuffer() noexcept(!(gl_internal::kThreadSafetyChecks || + gl_internal::kAggressiveErrorChecking)) = + default; + + // A shorthand to construct the buffer and load data into it in one step. + template <typename T> + explicit VertexBuffer(absl::Span<const T> data, + Buffer::AccessFrequency frequency, + Buffer::AccessNature nature) { + SetData(data, frequency, nature); + } + + VertexBuffer(const VertexBuffer&) = default; + VertexBuffer& operator=(const VertexBuffer&) = default; + VertexBuffer(VertexBuffer&&) = default; + VertexBuffer& operator=(VertexBuffer&&) = default; + + // Loads data into the buffer. + template <typename T> + void SetData(absl::Span<const T> data, Buffer::AccessFrequency frequency, + Buffer::AccessNature nature) { + buffer_.SetData(data.data(), data.size() * sizeof(T), frequency, nature); + element_size_ = sizeof(T); + } + + // The number of vertices in this buffer. + int size() const noexcept { + assert(buffer_.size() % element_size() == 0); + return buffer_.size() / element_size(); + } + + // The size, in bytes, of an individual vertex. + int element_size() const noexcept { return element_size_; } + + // The GL identifier for this buffer. + unsigned int id() const noexcept { return buffer_.id(); } + + private: + Buffer buffer_; + int element_size_; +}; + +// The types that can go in an element buffer. +template <typename T> +concept IsElement = std::same_as<T, uint8_t> || std::same_as<T, uint16_t> || + std::same_as<T, uint32_t>; + +// An element buffer. +class ElementBuffer final { + public: + explicit ElementBuffer() noexcept(!(gl_internal::kThreadSafetyChecks || + gl_internal::kAggressiveErrorChecking)) = + default; + + // Constructs an element buffer containing the specified data. + template <IsElement T> + explicit ElementBuffer(absl::Span<const T> data, + Buffer::AccessFrequency frequency, + Buffer::AccessNature nature) { + SetData(data, frequency, nature); + } + + ElementBuffer(const ElementBuffer&) = default; + ElementBuffer& operator=(const ElementBuffer&) = default; + ElementBuffer(ElementBuffer&&) noexcept = default; + ElementBuffer& operator=(ElementBuffer&&) noexcept = default; + + // Loads data into the buffer. + template <IsElement T> + void SetData(absl::Span<const T> data, Buffer::AccessFrequency frequency, + Buffer::AccessNature nature) { + buffer_.SetData(data.data(), data.size() * sizeof(T), frequency, nature); + element_size_ = sizeof(T); + } + + // The number of elements in this buffer. + int size() const noexcept { + assert(buffer_.size() % element_size() == 0); + return buffer_.size() / element_size(); + } + + // The size, in bytes, of an individual element. This will always be 1, 2, + // or 4. + int element_size() const noexcept { + assert(element_size_ == 1 || element_size_ == 2 || element_size_ == 4); + return element_size_; + } + + // The GL identifier for this buffer. + unsigned int id() const noexcept { return buffer_.id(); } + + private: + Buffer buffer_; + int element_size_; +}; + +} // namespace gl + +#endif // GLPLANET_SRC_GL_BUFFER_H_ |