Blender V4.3
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
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/* -------------------------------------------------------------------- */
37{
38 init();
39}
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
60void GLVaoCache::insert(const GLShaderInterface *interface, GLuint vao)
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 = (GLuint *)MEM_callocN(dynamic_vaos.count * sizeof(GLuint),
90 "dyn vaos ids");
91 }
92 }
93
94 if (is_dynamic_vao_count) {
95 int i; /* find first unused slot */
96 for (i = 0; i < dynamic_vaos.count; i++) {
97 if (dynamic_vaos.vao_ids[i] == 0) {
98 break;
99 }
100 }
101
102 if (i == dynamic_vaos.count) {
103 /* Not enough place, realloc the array. */
104 i = dynamic_vaos.count;
106 dynamic_vaos.interfaces = (const GLShaderInterface **)MEM_recallocN(
107 (void *)dynamic_vaos.interfaces, sizeof(GLShaderInterface *) * dynamic_vaos.count);
108 dynamic_vaos.vao_ids = (GLuint *)MEM_recallocN(dynamic_vaos.vao_ids,
109 sizeof(GLuint) * dynamic_vaos.count);
110 }
111 dynamic_vaos.interfaces[i] = interface;
112 dynamic_vaos.vao_ids[i] = vao;
113 }
114
115 const_cast<GLShaderInterface *>(interface)->ref_add(this);
116}
117
119{
120 const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN;
121 GLuint *vaos = (is_dynamic_vao_count) ? dynamic_vaos.vao_ids : static_vaos.vao_ids;
122 const GLShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces :
123 static_vaos.interfaces;
124 for (int i = 0; i < count; i++) {
125 if (interfaces[i] == interface) {
126 context_->vao_free(vaos[i]);
127 vaos[i] = 0;
128 interfaces[i] = nullptr;
129 break; /* cannot have duplicates */
130 }
131 }
132
133 if (interface_ == interface) {
134 interface_ = nullptr;
135 vao_id_ = 0;
136 }
137}
138
140{
141 GLContext *ctx = GLContext::get();
142 const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN;
143 GLuint *vaos = (is_dynamic_vao_count) ? dynamic_vaos.vao_ids : static_vaos.vao_ids;
144 const GLShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces :
145 static_vaos.interfaces;
146 /* Early out, nothing to free. */
147 if (context_ == nullptr) {
148 return;
149 }
150
151 if (context_ == ctx) {
152 glDeleteVertexArrays(count, vaos);
153 glDeleteVertexArrays(1, &vao_base_instance_);
154 }
155 else {
156 /* TODO(fclem): Slow way. Could avoid multiple mutex lock here */
157 for (int i = 0; i < count; i++) {
158 context_->vao_free(vaos[i]);
159 }
160 context_->vao_free(vao_base_instance_);
161 }
162
163 for (int i = 0; i < count; i++) {
164 if (interfaces[i] != nullptr) {
165 const_cast<GLShaderInterface *>(interfaces[i])->ref_remove(this);
166 }
167 }
168
169 if (is_dynamic_vao_count) {
170 MEM_freeN((void *)dynamic_vaos.interfaces);
171 MEM_freeN(dynamic_vaos.vao_ids);
172 }
173
174 if (context_) {
175 context_->vao_cache_unregister(this);
176 }
177 /* Reinitialize. */
178 this->init();
179}
180
181GLuint GLVaoCache::lookup(const GLShaderInterface *interface)
182{
183 const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN;
184 const GLShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces :
185 static_vaos.interfaces;
186 for (int i = 0; i < count; i++) {
187 if (interfaces[i] == interface) {
188 return (is_dynamic_vao_count) ? dynamic_vaos.vao_ids[i] : static_vaos.vao_ids[i];
189 }
190 }
191 return 0;
192}
193
194void GLVaoCache::context_check()
195{
196 GLContext *ctx = GLContext::get();
197 BLI_assert(ctx);
198
199 if (context_ != ctx) {
200 if (context_ != nullptr) {
201 /* IMPORTANT: Trying to draw a batch in multiple different context will trash the VAO cache.
202 * This has major performance impact and should be avoided in most cases. */
203 context_->vao_cache_unregister(this);
204 }
205 this->clear();
206 context_ = ctx;
207 context_->vao_cache_register(this);
208 }
209}
210
212{
213 this->context_check();
214
215 Shader *shader = GLContext::get()->shader;
216 GLShaderInterface *interface = static_cast<GLShaderInterface *>(shader->interface);
217 if (interface_ != interface) {
218 interface_ = interface;
219 vao_id_ = this->lookup(interface_);
220
221 if (vao_id_ == 0) {
222 /* Cache miss, create a new VAO. */
223 glGenVertexArrays(1, &vao_id_);
224 this->insert(interface_, vao_id_);
225 GLVertArray::update_bindings(vao_id_, batch, interface_, 0);
226 }
227 }
228
229 return vao_id_;
230}
231
234/* -------------------------------------------------------------------- */
239{
241
242 if (flag & GPU_BATCH_DIRTY) {
243 flag &= ~GPU_BATCH_DIRTY;
245 }
246
247 glBindVertexArray(vao_cache_.vao_get(this));
248}
249
250void GLBatch::draw(int v_first, int v_count, int i_first, int i_count)
251{
252 GL_CHECK_RESOURCES("Batch");
253
254 this->bind();
255
256 BLI_assert(v_count > 0 && i_count > 0);
257
258 GLenum gl_type = to_gl(prim_type);
259
260 if (elem) {
261 const GLIndexBuf *el = this->elem_();
262 GLenum index_type = to_gl(el->index_type_);
263 GLint base_index = el->index_base_;
264 void *v_first_ofs = el->offset_ptr(v_first);
265
266 glDrawElementsInstancedBaseVertexBaseInstance(
267 gl_type, v_count, index_type, v_first_ofs, i_count, base_index, i_first);
268 }
269 else {
270 glDrawArraysInstancedBaseInstance(gl_type, v_first, v_count, i_count, i_first);
271 }
272}
273
274void GLBatch::draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset)
275{
276 GL_CHECK_RESOURCES("Batch");
277
278 this->bind();
279 dynamic_cast<GLStorageBuf *>(unwrap(indirect_buf))->bind_as(GL_DRAW_INDIRECT_BUFFER);
280
281 GLenum gl_type = to_gl(prim_type);
282 if (elem) {
283 const GLIndexBuf *el = this->elem_();
284 GLenum index_type = to_gl(el->index_type_);
285 glDrawElementsIndirect(gl_type, index_type, (GLvoid *)offset);
286 }
287 else {
288 glDrawArraysIndirect(gl_type, (GLvoid *)offset);
289 }
290 /* Unbind. */
291 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
292}
293
294void GLBatch::multi_draw_indirect(GPUStorageBuf *indirect_buf,
295 int count,
296 intptr_t offset,
297 intptr_t stride)
298{
299 GL_CHECK_RESOURCES("Batch");
300
301 this->bind();
302 dynamic_cast<GLStorageBuf *>(unwrap(indirect_buf))->bind_as(GL_DRAW_INDIRECT_BUFFER);
303
304 GLenum gl_type = to_gl(prim_type);
305 if (elem) {
306 const GLIndexBuf *el = this->elem_();
307 GLenum index_type = to_gl(el->index_type_);
308 glMultiDrawElementsIndirect(gl_type, index_type, (GLvoid *)offset, count, stride);
309 }
310 else {
311 glMultiDrawArraysIndirect(gl_type, (GLvoid *)offset, count, stride);
312 }
313 /* Unbind. */
314 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
315}
316
#define BLI_assert(a)
Definition BLI_assert.h:50
@ GPU_BATCH_DIRTY
Definition GPU_batch.hh:58
#define GPU_BATCH_VAO_DYN_ALLOC_COUNT
Definition GPU_batch.hh:35
#define MEM_recallocN(vmemh, len)
void multi_draw_indirect(GPUStorageBuf *indirect_buf, int count, intptr_t offset, intptr_t stride) override
Definition gl_batch.cc:294
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:250
void draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset) override
Definition gl_batch.cc:274
GLVaoCache vao_cache_
Definition gl_batch.hh:90
void vao_cache_unregister(GLVaoCache *cache)
static GLContext * get()
void vao_free(GLuint vao_id)
void vao_cache_register(GLVaoCache *cache)
void * offset_ptr(uint additional_vertex_offset) const
struct blender::gpu::GLVaoCache::@655::@657 static_vaos
GLuint lookup(const GLShaderInterface *interface)
Definition gl_batch.cc:181
struct blender::gpu::GLVaoCache::@655::@658 dynamic_vaos
const GLShaderInterface * interfaces[GPU_VAO_STATIC_LEN]
Definition gl_batch.hh:50
GLuint vao_get(Batch *batch)
Definition gl_batch.cc:211
void insert(const GLShaderInterface *interface, GLuint vao_id)
Definition gl_batch.cc:60
void remove(const GLShaderInterface *interface)
Definition gl_batch.cc:118
GPUIndexBufType index_type_
virtual void apply_state()=0
#define GL_CHECK_RESOURCES(info)
Definition gl_debug.hh:65
struct @620::@622 batch
int count
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define GPU_VAO_STATIC_LEN
Definition mtl_batch.hh:26
void update_bindings(const GLuint vao, const Batch *batch, const ShaderInterface *interface, int base_instance)
static Context * unwrap(GPUContext *ctx)
static GLenum to_gl(const GPUAttachmentType type)
_W64 int intptr_t
Definition stdint.h:118
uint8_t flag
Definition wm_window.cc:138