Blender V5.0
gl_batch.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2016 by Mike Erwin. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
12
13#include "BLI_assert.h"
14
15#include "GPU_batch.hh"
16#include "gpu_shader_private.hh"
17
18#include "gl_context.hh"
19#include "gl_debug.hh"
20#include "gl_index_buffer.hh"
21#include "gl_primitive.hh"
22#include "gl_storage_buffer.hh"
23#include "gl_vertex_array.hh"
24
25#include "gl_batch.hh"
26
27using namespace blender::gpu;
28
29/* -------------------------------------------------------------------- */
35
40
42{
43 this->clear();
44}
45
46void GLVaoCache::init()
47{
48 context_ = nullptr;
49 interface_ = nullptr;
50 is_dynamic_vao_count = false;
51 for (int i = 0; i < GPU_VAO_STATIC_LEN; i++) {
52 static_vaos.interfaces[i] = nullptr;
53 static_vaos.vao_ids[i] = 0;
54 }
55 vao_base_instance_ = 0;
56 base_instance_ = 0;
57 vao_id_ = 0;
58}
59
61{
62 /* Now insert the cache. */
63 if (!is_dynamic_vao_count) {
64 int i; /* find first unused slot */
65 for (i = 0; i < GPU_VAO_STATIC_LEN; i++) {
66 if (static_vaos.vao_ids[i] == 0) {
67 break;
68 }
69 }
70
71 if (i < GPU_VAO_STATIC_LEN) {
72 static_vaos.interfaces[i] = interface;
73 static_vaos.vao_ids[i] = vao;
74 }
75 else {
76 /* Erase previous entries, they will be added back if drawn again. */
77 for (int i = 0; i < GPU_VAO_STATIC_LEN; i++) {
78 if (static_vaos.interfaces[i] != nullptr) {
79 const_cast<GLShaderInterface *>(static_vaos.interfaces[i])->ref_remove(this);
80 context_->vao_free(static_vaos.vao_ids[i]);
81 }
82 }
83 /* Not enough place switch to dynamic. */
84 is_dynamic_vao_count = true;
85 /* Init dynamic arrays and let the branch below set the values. */
87 dynamic_vaos.interfaces = (const GLShaderInterface **)MEM_callocN(
88 dynamic_vaos.count * sizeof(GLShaderInterface *), "dyn vaos interfaces");
89 dynamic_vaos.vao_ids = MEM_calloc_arrayN<GLuint>(dynamic_vaos.count, "dyn vaos ids");
90 }
91 }
92
93 if (is_dynamic_vao_count) {
94 int i; /* find first unused slot */
95 for (i = 0; i < dynamic_vaos.count; i++) {
96 if (dynamic_vaos.vao_ids[i] == 0) {
97 break;
98 }
99 }
100
101 if (i == dynamic_vaos.count) {
102 /* Not enough place, realloc the array. */
103 i = dynamic_vaos.count;
105 dynamic_vaos.interfaces = (const GLShaderInterface **)MEM_recallocN(
106 (void *)dynamic_vaos.interfaces, sizeof(GLShaderInterface *) * dynamic_vaos.count);
107 dynamic_vaos.vao_ids = (GLuint *)MEM_recallocN(dynamic_vaos.vao_ids,
108 sizeof(GLuint) * dynamic_vaos.count);
109 }
110 dynamic_vaos.interfaces[i] = interface;
111 dynamic_vaos.vao_ids[i] = vao;
112 }
113
114 const_cast<GLShaderInterface *>(interface)->ref_add(this);
115}
116
118{
119 const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN;
120 GLuint *vaos = (is_dynamic_vao_count) ? dynamic_vaos.vao_ids : static_vaos.vao_ids;
121 const GLShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces :
122 static_vaos.interfaces;
123 for (int i = 0; i < count; i++) {
124 if (interfaces[i] == interface) {
125 context_->vao_free(vaos[i]);
126 vaos[i] = 0;
127 interfaces[i] = nullptr;
128 break; /* cannot have duplicates */
129 }
130 }
131
132 if (interface_ == interface) {
133 interface_ = nullptr;
134 vao_id_ = 0;
135 }
136}
137
139{
140 GLContext *ctx = GLContext::get();
141 const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN;
142 GLuint *vaos = (is_dynamic_vao_count) ? dynamic_vaos.vao_ids : static_vaos.vao_ids;
143 const GLShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces :
144 static_vaos.interfaces;
145 /* Early out, nothing to free. */
146 if (context_ == nullptr) {
147 return;
148 }
149
150 if (context_ == ctx) {
151 glDeleteVertexArrays(count, vaos);
152 glDeleteVertexArrays(1, &vao_base_instance_);
153 }
154 else {
155 /* TODO(fclem): Slow way. Could avoid multiple mutex lock here */
156 for (int i = 0; i < count; i++) {
157 context_->vao_free(vaos[i]);
158 }
159 context_->vao_free(vao_base_instance_);
160 }
161
162 for (int i = 0; i < count; i++) {
163 if (interfaces[i] != nullptr) {
164 const_cast<GLShaderInterface *>(interfaces[i])->ref_remove(this);
165 }
166 }
167
168 if (is_dynamic_vao_count) {
169 MEM_freeN(dynamic_vaos.interfaces);
170 MEM_freeN(dynamic_vaos.vao_ids);
171 }
172
173 if (context_) {
174 context_->vao_cache_unregister(this);
175 }
176 /* Reinitialize. */
177 this->init();
178}
179
181{
182 const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN;
183 const GLShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces :
184 static_vaos.interfaces;
185 for (int i = 0; i < count; i++) {
186 if (interfaces[i] == interface) {
187 return (is_dynamic_vao_count) ? dynamic_vaos.vao_ids[i] : static_vaos.vao_ids[i];
188 }
189 }
190 return 0;
191}
192
193void GLVaoCache::context_check()
194{
195 GLContext *ctx = GLContext::get();
196 BLI_assert(ctx);
197
198 if (context_ != ctx) {
199 if (context_ != nullptr) {
200 /* IMPORTANT: Trying to draw a batch in multiple different context will trash the VAO cache.
201 * This has major performance impact and should be avoided in most cases. */
202 context_->vao_cache_unregister(this);
203 }
204 this->clear();
205 context_ = ctx;
206 context_->vao_cache_register(this);
207 }
208}
209
211{
212 this->context_check();
213
215 GLShaderInterface *interface = static_cast<GLShaderInterface *>(shader->interface);
216 if (interface_ != interface) {
217 interface_ = interface;
218 vao_id_ = this->lookup(interface_);
219
220 if (vao_id_ == 0) {
221 /* Cache miss, create a new VAO. */
222 glGenVertexArrays(1, &vao_id_);
223 this->insert(interface_, vao_id_);
224 GLVertArray::update_bindings(vao_id_, batch, interface_);
225 }
226 }
227
228 return vao_id_;
229}
230
232
233/* -------------------------------------------------------------------- */
236
238{
240
241 if (flag & GPU_BATCH_DIRTY) {
243 vao_cache_.clear();
244 }
245
246 glBindVertexArray(vao_cache_.vao_get(this));
247}
248
249void GLBatch::draw(int v_first, int v_count, int i_first, int i_count)
250{
251 GL_CHECK_RESOURCES("Batch");
252
253 this->bind();
254
255 BLI_assert(v_count > 0 && i_count > 0);
256
257 GLenum gl_type = to_gl(prim_type);
258
259 if (elem) {
260 const GLIndexBuf *el = this->elem_();
261 GLenum index_type = to_gl(el->index_type_);
262 GLint base_index = el->index_base_;
263 void *v_first_ofs = el->offset_ptr(v_first);
264
265 glDrawElementsInstancedBaseVertexBaseInstance(
266 gl_type, v_count, index_type, v_first_ofs, i_count, base_index, i_first);
267 }
268 else {
269 glDrawArraysInstancedBaseInstance(gl_type, v_first, v_count, i_count, i_first);
270 }
271}
272
273void GLBatch::draw_indirect(blender::gpu::StorageBuf *indirect_buf, intptr_t offset)
274{
275 GL_CHECK_RESOURCES("Batch");
276
277 this->bind();
278 dynamic_cast<GLStorageBuf *>(indirect_buf)->bind_as(GL_DRAW_INDIRECT_BUFFER);
279
280 GLenum gl_type = to_gl(prim_type);
281 if (elem) {
282 const GLIndexBuf *el = this->elem_();
283 GLenum index_type = to_gl(el->index_type_);
284 glDrawElementsIndirect(gl_type, index_type, (GLvoid *)offset);
285 }
286 else {
287 glDrawArraysIndirect(gl_type, (GLvoid *)offset);
288 }
289 /* Unbind. */
290 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
291}
292
294 int count,
295 intptr_t offset,
296 intptr_t stride)
297{
298 GL_CHECK_RESOURCES("Batch");
299
300 this->bind();
301 dynamic_cast<GLStorageBuf *>(indirect_buf)->bind_as(GL_DRAW_INDIRECT_BUFFER);
302
303 GLenum gl_type = to_gl(prim_type);
304 if (elem) {
305 const GLIndexBuf *el = this->elem_();
306 GLenum index_type = to_gl(el->index_type_);
307 glMultiDrawElementsIndirect(gl_type, index_type, (GLvoid *)offset, count, stride);
308 }
309 else {
310 glMultiDrawArraysIndirect(gl_type, (GLvoid *)offset, count, stride);
311 }
312 /* Unbind. */
313 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
314}
315
#define BLI_assert(a)
Definition BLI_assert.h:46
static constexpr int GPU_BATCH_VAO_DYN_ALLOC_COUNT
Definition GPU_batch.hh:35
@ GPU_BATCH_DIRTY
Definition GPU_batch.hh:53
#define MEM_recallocN(vmemh, len)
void init()
GLIndexBuf * elem_() const
Definition gl_batch.hh:103
void draw(int v_first, int v_count, int i_first, int i_count) override
Definition gl_batch.cc:249
void multi_draw_indirect(StorageBuf *indirect_buf, int count, intptr_t offset, intptr_t stride) override
Definition gl_batch.cc:293
void draw_indirect(StorageBuf *indirect_buf, intptr_t offset) override
Definition gl_batch.cc:273
GLVaoCache vao_cache_
Definition gl_batch.hh:90
void vao_cache_unregister(GLVaoCache *cache)
static GLContext * get()
void vao_cache_register(GLVaoCache *cache)
void * offset_ptr(uint additional_vertex_offset) const
GLuint lookup(const GLShaderInterface *interface)
Definition gl_batch.cc:180
const GLShaderInterface * interfaces[GPU_VAO_STATIC_LEN]
Definition gl_batch.hh:50
GLuint vao_get(Batch *batch)
Definition gl_batch.cc:210
void insert(const GLShaderInterface *interface, GLuint vao_id)
Definition gl_batch.cc:60
struct blender::gpu::GLVaoCache::@157236110271242160153365376064020364322222010350::@314007012112177177054114203301226370061215216002 static_vaos
struct blender::gpu::GLVaoCache::@157236110271242160153365376064020364322222010350::@162033253374111303027310313277133152141252374306 dynamic_vaos
void remove(const GLShaderInterface *interface)
Definition gl_batch.cc:117
GPUIndexBufType index_type_
virtual void apply_state()=0
#define GL_CHECK_RESOURCES(info)
Definition gl_debug.hh:14
struct @021025263243242147216143265077100330027142264337::@225245033123204053237120173316075113304004012000 batch
int count
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define GPU_VAO_STATIC_LEN
Definition mtl_batch.hh:26
void update_bindings(const GLuint vao, const Batch *batch, const ShaderInterface *interface)
static GLenum to_gl(const GPUAttachmentType type)
i
Definition text_draw.cc:230
uint8_t flag
Definition wm_window.cc:145