Simulant  21.12-574
A portable game engine for Windows, OSX, Linux, Dreamcast, and PSP
vbo_manager.h
1 #pragma once
2 
3 #include <cstdint>
4 #include <array>
5 #include <unordered_map>
6 #include <queue>
7 
8 #include "../../meshes/mesh.h"
9 #include "../../generic/managed.h"
10 #include "../../time_keeper.h"
11 #include "../glad/glad/glad.h"
12 #include "../../utils/gl_error.h"
13 #include "../batching/renderable.h"
14 
15 #include "../../logging.h"
16 
17 #define __LOGGER__ "/smlt/vbo"
18 
19 #define L_DEBUG_VBO(txt) smlt::get_logger(__LOGGER__)->debug(txt, __FILE__, __LINE__)
20 #define L_INFO_VBO(txt) smlt::get_logger(__LOGGER__)->info(txt, __FILE__, __LINE__)
21 #define L_WARN_VBO(txt) smlt::get_logger(__LOGGER__)->warn(txt, __FILE__, __LINE__)
22 #define L_ERROR_VBO(txt) smlt::get_logger(__LOGGER__)->error(txt, __FILE__, __LINE__)
23 
24 namespace smlt {
25 
26 /* The size of VBO to allocate */
27 const uint32_t VBO_SIZE = 1024 * 512;
28 
29 typedef uint32_t VBOSlot;
30 
31 class VBO;
32 
33 struct GPUBuffer {
34  /* Slot into the VBO */
35  VBO* vertex_vbo = nullptr;
36  VBO* index_vbo = nullptr;
37 
38  VBOSlot vertex_vbo_slot;
39  VBOSlot index_vbo_slot;
40 
41  void sync_data_from_renderable(Renderable* renderable);
42  void bind_vbos();
43 };
44 
45 enum VBOSlotSize {
46  VBO_SLOT_SIZE_1K = (1 << 10),
47  VBO_SLOT_SIZE_2K = (1 << 11),
48  VBO_SLOT_SIZE_4K = (1 << 12),
49  VBO_SLOT_SIZE_8K = (1 << 13),
50  VBO_SLOT_SIZE_16K = (1 << 14),
51  VBO_SLOT_SIZE_32K = (1 << 15),
52  VBO_SLOT_SIZE_64K = (1 << 16),
53  VBO_SLOT_SIZE_128K = (1 << 17),
54  VBO_SLOT_SIZE_256K = (1 << 18),
55  VBO_SLOT_SIZE_512K = (1 << 19)
56 };
57 
58 const int VBO_SLOT_SIZE_COUNT = 11;
59 
60 class VBO {
61 public:
62  virtual ~VBO() {}
63 
64  virtual GLenum target() const = 0;
65  virtual void upload(VBOSlot, const VertexData* vertex_data) = 0;
66  virtual void upload(VBOSlot, const IndexData* index_data) = 0;
67  virtual void bind(VBOSlot) = 0;
68  virtual uint64_t slot_last_updated(VBOSlot slot) = 0;
69  virtual uint32_t byte_offset(VBOSlot slot) = 0;
70  virtual uint32_t slot_size_in_bytes() const = 0;
71 
72  virtual VBOSlot allocate_slot() = 0;
73  virtual void release_slot(VBOSlot slot) = 0;
74 
75  virtual uint32_t used_slot_count() const = 0;
76  virtual uint32_t free_slot_count() const = 0;
77 };
78 
80  public RefCounted<DedicatedVBO>,
81  public VBO {
82 
83 public:
84  DedicatedVBO(uint32_t size, VertexSpecification spec):
85  size_in_bytes_(size),
86  spec_(spec),
87  type_(GL_ARRAY_BUFFER) {}
88 
89  DedicatedVBO(uint32_t size, IndexType index_type):
90  size_in_bytes_(size),
91  index_type_(index_type),
92  type_(GL_ELEMENT_ARRAY_BUFFER) {}
93 
94  ~DedicatedVBO() {
95  try {
96  if(gl_id_) glDeleteBuffers(1, &gl_id_);
97  } catch(...) {
98  S_WARN("Exception while deleting GL VBO");
99  }
100  }
101 
102  uint64_t slot_last_updated(VBOSlot slot) { assert(slot == 0); return last_updated_; }
103  GLenum target() const { return type_; }
104 
105  void upload(VBOSlot, const VertexData* vertex_data);
106  void upload(VBOSlot, const IndexData* index_data);
107  void bind(VBOSlot);
108 
109  uint32_t byte_offset(VBOSlot slot) {
110  assert(slot == 0);
111  return 0;
112  }
113 
114  uint32_t slot_size_in_bytes() const {
115  return size_in_bytes_;
116  }
117 
118  VBOSlot allocate_slot();
119  void release_slot(VBOSlot slot);
120 
121  uint32_t used_slot_count() const {
122  return (allocated_) ? 1 : 0;
123  }
124 
125  uint32_t free_slot_count() const {
126  return (allocated_) ? 0 : 1;
127  }
128 private:
129  uint32_t size_in_bytes_;
130  VertexSpecification spec_;
131  IndexType index_type_;
132  GLenum type_;
133 
134  uint64_t last_updated_ = 0;
135  bool allocated_ = false;
136  GLuint gl_id_ = 0;
137 };
138 
139 class SharedVBO:
140  public RefCounted<SharedVBO>,
141  public VBO {
142 
143 public:
144  SharedVBO(VBOSlotSize slot_size, VertexSpecification spec):
145  slot_size_(slot_size),
146  slot_size_in_bytes_(int(slot_size)),
147  spec_(spec),
148  type_(GL_ARRAY_BUFFER) {}
149 
150  SharedVBO(VBOSlotSize slot_size, IndexType type):
151  slot_size_(slot_size),
152  slot_size_in_bytes_(int(slot_size)),
153  index_type_(type),
154  type_(GL_ELEMENT_ARRAY_BUFFER) {}
155 
156  uint64_t slot_last_updated(VBOSlot slot) {
157  assert(slot < metas_.size());
158  return metas_[slot].last_updated;
159  }
160 
161  GLenum target() const { return type_; }
162 
163  VBOSlot allocate_slot();
164 
165  void release_slot(VBOSlot slot);
166 
167  void upload(VBOSlot slot, const VertexData* vertex_data);
168  void upload(VBOSlot slot, const IndexData* index_data);
169  void bind(VBOSlot slot);
170 
171  VBOSlotSize slot_size() const { return slot_size_; }
172  uint32_t slot_size_in_bytes() const { return int(slot_size_); }
173 
174  uint32_t byte_offset(VBOSlot slot) {
175  const int SLOTS_PER_BUFFER = (VBO_SIZE / slot_size_in_bytes_);
176  return (slot % SLOTS_PER_BUFFER) * slot_size_in_bytes_;
177  }
178 
179  uint32_t used_slot_count() const {
180  return metas_.size() - free_slots_.size();
181  }
182 
183  uint32_t free_slot_count() const {
184  return free_slots_.size();
185  }
186 
187 private:
188  void allocate_new_gl_buffer();
189 
190  VBOSlotSize slot_size_;
191  uint32_t slot_size_in_bytes_;
192 
193  VertexSpecification spec_;
194  IndexType index_type_;
195  GLenum type_;
196  std::queue<VBOSlot> free_slots_;
197  std::vector<GLuint> gl_ids_;
198 
199  struct SlotMeta {
200  uint64_t last_updated = 0;
201  uint32_t uploaded_size = 0;
202  };
203 
204  std::vector<SlotMeta> metas_;
205 };
206 
207 class VBOManager : public RefCounted<VBOManager> {
208 public:
209  virtual ~VBOManager();
210  GPUBuffer update_and_fetch_buffers(const Renderable* renderable);
211 
212  uint32_t dedicated_buffer_count() const;
213 
214 private:
215  VBOSlotSize calc_vbo_slot_size(uint32_t required_size_in_bytes);
216 
217  std::pair<VBO*, VBOSlot> allocate_slot(const VertexData* vertex_data);
218  std::pair<VBO*, VBOSlot> allocate_slot(const IndexData* index_data);
219 
220  void release_slot(const VertexData* vertex_data);
221  void release_slot(const IndexData* index_data);
222 
223  /* Buffers for renderables which aren't dynamic and are less than 512k */
224  std::array<
225  std::unordered_map<VertexSpecification, SharedVBO::ptr>,
226  VBO_SLOT_SIZE_COUNT
227  > shared_vertex_vbos_;
228 
229  std::array<
230  std::unordered_map<IndexType, SharedVBO::ptr>,
231  VBO_SLOT_SIZE_COUNT
232  > shared_index_vbos_;
233 
234  typedef std::unordered_map<uuid64, DedicatedVBO::ptr> DedicatedMap;
235  typedef std::unordered_map<uuid64, std::pair<VBO*, VBOSlot>> SlotMap;
236 
237  DedicatedMap dedicated_vertex_vbos_;
238  DedicatedMap dedicated_index_vbos_;
239 
240  SlotMap vertex_data_slots_;
241  SlotMap index_data_slots_;
242 
243  std::unordered_map<uuid64, sig::connection> vdata_destruction_connections_;
244  std::unordered_map<uuid64, sig::connection> idata_destruction_connections_;
245 
246  void connect_destruction_signal(const VertexData *vertex_data);
247  void connect_destruction_signal(const IndexData *vertex_data);
248  void disconnect_destruction_signal(const VertexData *vertex_data);
249  void disconnect_destruction_signal(const IndexData *vertex_data);
250 
251  void on_vertex_data_destroyed(VertexData* vertex_data);
252  void on_index_data_destroyed(IndexData* vertex_data);
253 
254  template<typename Data>
255  std::pair<VBO*, VBOSlot> perform_fetch_or_upload(const Data*, VBOManager::DedicatedMap&, VBOManager::SlotMap&);
256 
257 };
258 
259 }
smlt::VertexData
Definition: vertex_data.h:57
smlt::VertexSpecification
Definition: types.h:121
smlt::RefCounted
Definition: managed.h:65
smlt::VBOManager
Definition: vbo_manager.h:207
smlt
Definition: animation.cpp:25
smlt::SharedVBO
Definition: vbo_manager.h:141
smlt::DedicatedVBO
Definition: vbo_manager.h:81
smlt::VBO
Definition: vbo_manager.h:60
smlt::IndexData
Definition: vertex_data.h:334
smlt::Renderable
Definition: renderable.h:67
smlt::GPUBuffer
Definition: vbo_manager.h:33