summaryrefslogtreecommitdiff
path: root/src/gl/buffer.h
blob: 439533bb0ef3e49f350a7cb44415a467b56a803e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
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_