Blender  V2.93
gl_immediate.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2016 by Mike Erwin.
17  * All rights reserved.
18  */
19 
26 #include "BKE_global.h"
27 
28 #include "gpu_context_private.hh"
29 #include "gpu_shader_private.hh"
31 
32 #include "gl_context.hh"
33 #include "gl_debug.hh"
34 #include "gl_primitive.hh"
35 #include "gl_vertex_array.hh"
36 
37 #include "gl_immediate.hh"
38 
39 namespace blender::gpu {
40 
41 /* -------------------------------------------------------------------- */
46 {
47  glGenVertexArrays(1, &vao_id_);
48  glBindVertexArray(vao_id_); /* Necessary for glObjectLabel. */
49 
50  buffer.buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE;
51  glGenBuffers(1, &buffer.vbo_id);
52  glBindBuffer(GL_ARRAY_BUFFER, buffer.vbo_id);
53  glBufferData(GL_ARRAY_BUFFER, buffer.buffer_size, nullptr, GL_DYNAMIC_DRAW);
54 
55  buffer_strict.buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE;
56  glGenBuffers(1, &buffer_strict.vbo_id);
57  glBindBuffer(GL_ARRAY_BUFFER, buffer_strict.vbo_id);
58  glBufferData(GL_ARRAY_BUFFER, buffer_strict.buffer_size, nullptr, GL_DYNAMIC_DRAW);
59 
60  glBindBuffer(GL_ARRAY_BUFFER, 0);
61  glBindVertexArray(0);
62 
63  debug::object_label(GL_VERTEX_ARRAY, vao_id_, "Immediate");
64  debug::object_label(GL_BUFFER, buffer.vbo_id, "ImmediateVbo");
65  debug::object_label(GL_BUFFER, buffer_strict.vbo_id, "ImmediateVboStrict");
66 }
67 
69 {
70  glDeleteVertexArrays(1, &vao_id_);
71 
72  glDeleteBuffers(1, &buffer.vbo_id);
73  glDeleteBuffers(1, &buffer_strict.vbo_id);
74 }
75 
78 /* -------------------------------------------------------------------- */
83 {
84  /* How many bytes do we need for this draw call? */
85  const size_t bytes_needed = vertex_buffer_size(&vertex_format, vertex_len);
86  /* Does the current buffer have enough room? */
87  const size_t available_bytes = buffer_size() - buffer_offset();
88 
89  GL_CHECK_RESOURCES("Immediate");
90 
91  glBindBuffer(GL_ARRAY_BUFFER, vbo_id());
92 
93  bool recreate_buffer = false;
94  if (bytes_needed > buffer_size()) {
95  /* expand the internal buffer */
96  buffer_size() = bytes_needed;
97  recreate_buffer = true;
98  }
99  else if (bytes_needed < DEFAULT_INTERNAL_BUFFER_SIZE &&
101  /* shrink the internal buffer */
103  recreate_buffer = true;
104  }
105 
106  /* ensure vertex data is aligned */
107  /* Might waste a little space, but it's safe. */
108  const uint pre_padding = padding(buffer_offset(), vertex_format.stride);
109 
110  if (!recreate_buffer && ((bytes_needed + pre_padding) <= available_bytes)) {
111  buffer_offset() += pre_padding;
112  }
113  else {
114  /* orphan this buffer & start with a fresh one */
115  glBufferData(GL_ARRAY_BUFFER, buffer_size(), nullptr, GL_DYNAMIC_DRAW);
116  buffer_offset() = 0;
117  }
118 
119 #ifndef NDEBUG
120  {
121  GLint bufsize;
122  glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &bufsize);
123  BLI_assert(buffer_offset() + bytes_needed <= bufsize);
124  }
125 #endif
126 
127  GLbitfield access = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
128  if (!strict_vertex_len) {
129  access |= GL_MAP_FLUSH_EXPLICIT_BIT;
130  }
131  void *data = glMapBufferRange(GL_ARRAY_BUFFER, buffer_offset(), bytes_needed, access);
132  BLI_assert(data != nullptr);
133 
134  bytes_mapped_ = bytes_needed;
135  return (uchar *)data;
136 }
137 
139 {
140  BLI_assert(prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
141 
142  uint buffer_bytes_used = bytes_mapped_;
143  if (!strict_vertex_len) {
144  if (vertex_idx != vertex_len) {
146  buffer_bytes_used = vertex_buffer_size(&vertex_format, vertex_len);
147  /* unused buffer bytes are available to the next immBegin */
148  }
149  /* tell OpenGL what range was modified so it doesn't copy the whole mapped range */
150  glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, buffer_bytes_used);
151  }
152  glUnmapBuffer(GL_ARRAY_BUFFER);
153 
154  if (vertex_len > 0) {
156 
157  /* We convert the offset in vertex offset from the buffer's start.
158  * This works because we added some padding to align the first vertex vertex. */
159  uint v_first = buffer_offset() / vertex_format.stride;
161  vao_id_, v_first, &vertex_format, reinterpret_cast<Shader *>(shader)->interface);
162 
163  /* Update matrices. */
165 
166 #ifdef __APPLE__
167  glDisable(GL_PRIMITIVE_RESTART);
168 #endif
169  glDrawArrays(to_gl(prim_type), 0, vertex_len);
170 #ifdef __APPLE__
171  glEnable(GL_PRIMITIVE_RESTART);
172 #endif
173  /* These lines are causing crash on startup on some old GPU + drivers.
174  * They are not required so just comment them. (T55722) */
175  // glBindBuffer(GL_ARRAY_BUFFER, 0);
176  // glBindVertexArray(0);
177  }
178 
179  buffer_offset() += buffer_bytes_used;
180 }
181 
184 } // namespace blender::gpu
#define BLI_assert(a)
Definition: BLI_assert.h:58
unsigned char uchar
Definition: BLI_sys_types.h:86
unsigned int uint
Definition: BLI_sys_types.h:83
#define glEnable
#define glDisable
@ GPU_PRIM_NONE
Definition: GPU_primitive.h:47
void GPU_shader_bind(GPUShader *shader)
Definition: gpu_shader.cc:494
static GLContext * get()
Definition: gl_context.hh:118
void end(void) override
uchar * begin(void) override
Definition: gl_immediate.cc:82
virtual void apply_state(void)=0
#define GL_CHECK_RESOURCES(info)
Definition: gl_debug.hh:81
#define DEFAULT_INTERNAL_BUFFER_SIZE
Definition: gl_immediate.hh:37
uint vertex_buffer_size(const GPUVertFormat *format, uint vertex_len)
uint padding(uint offset, uint alignment)
void update_bindings(const GLuint vao, const GPUBatch *batch, const ShaderInterface *interface, const int base_instance)
void object_label(GLenum type, GLuint object, const char *name)
Definition: gl_debug.cc:335
static GLenum to_gl(const GPUAttachmentType type)