Blender V5.0
gl_immediate.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
10
11#include "GPU_capabilities.hh"
12
14#include "gpu_shader_private.hh"
16
17#include "gl_context.hh"
18#include "gl_debug.hh"
19#include "gl_primitive.hh"
20#include "gl_vertex_array.hh"
21
22#include "gl_immediate.hh"
23
24namespace blender::gpu {
25
26/* -------------------------------------------------------------------- */
29
31{
32 glGenVertexArrays(1, &vao_id_);
33 glBindVertexArray(vao_id_); /* Necessary for glObjectLabel. */
34
35 buffer.buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE;
36 glGenBuffers(1, &buffer.vbo_id);
37 glBindBuffer(GL_ARRAY_BUFFER, buffer.vbo_id);
38 glBufferData(GL_ARRAY_BUFFER, buffer.buffer_size, nullptr, GL_DYNAMIC_DRAW);
39
40 buffer_strict.buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE;
41 glGenBuffers(1, &buffer_strict.vbo_id);
42 glBindBuffer(GL_ARRAY_BUFFER, buffer_strict.vbo_id);
43 glBufferData(GL_ARRAY_BUFFER, buffer_strict.buffer_size, nullptr, GL_DYNAMIC_DRAW);
44
45 glBindBuffer(GL_ARRAY_BUFFER, 0);
46 glBindVertexArray(0);
47
48 debug::object_label(GL_VERTEX_ARRAY, vao_id_, "Immediate");
49 debug::object_label(GL_BUFFER, buffer.vbo_id, "ImmediateVbo");
50 debug::object_label(GL_BUFFER, buffer_strict.vbo_id, "ImmediateVboStrict");
51}
52
54{
55 glDeleteVertexArrays(1, &vao_id_);
56
57 glDeleteBuffers(1, &buffer.vbo_id);
58 glDeleteBuffers(1, &buffer_strict.vbo_id);
59}
60
62
63/* -------------------------------------------------------------------- */
66
68{
69 /* How many bytes do we need for this draw call? */
70 const size_t bytes_needed = vertex_buffer_size(&vertex_format, vertex_len);
71 /* Does the current buffer have enough room? */
72 const size_t available_bytes = buffer_size() - buffer_offset();
73
74#ifndef NDEBUG
75 if (this->shader->is_polyline) {
76 /* Silence error. These are bound inside `immEnd()`. */
80 }
81#endif
82
83 GL_CHECK_RESOURCES("Immediate");
84
85 glBindBuffer(GL_ARRAY_BUFFER, vbo_id());
86
87 bool recreate_buffer = false;
88 if (bytes_needed > buffer_size()) {
89 /* expand the internal buffer */
90 buffer_size() = bytes_needed;
91 recreate_buffer = true;
92 }
93 else if (bytes_needed < DEFAULT_INTERNAL_BUFFER_SIZE &&
95 {
96 /* shrink the internal buffer */
98 recreate_buffer = true;
99 }
100
101 uint vert_alignment = vertex_format.stride;
102 if (this->shader->is_polyline) {
103 /* Polyline needs to bind the buffer as SSBO.
104 * The start of the range needs to match the SSBO alignment requirements. */
105 vert_alignment = ceil_to_multiple_u(vert_alignment, GPU_storage_buffer_alignment());
106 }
107 /* Ensure vertex data is aligned. Might waste a little space, but it's safe. */
108 const uint pre_padding = padding(buffer_offset(), vert_alignment);
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) {
155 /* NOOP. Nothing to draw. */
156 }
157 else if (this->shader->is_polyline) {
158 GLintptr offset = buffer_offset();
159 GLenum target = GL_SHADER_STORAGE_BUFFER;
160 glBindBufferRange(target, GPU_SSBO_POLYLINE_POS_BUF_SLOT, vbo_id(), offset, buffer_bytes_used);
161 glBindBufferRange(target, GPU_SSBO_POLYLINE_COL_BUF_SLOT, vbo_id(), offset, buffer_bytes_used);
162 /* Not used. Satisfy the binding. */
163 glBindBufferRange(target, GPU_SSBO_INDEX_BUF_SLOT, vbo_id(), offset, buffer_bytes_used);
164
166
167#ifndef NDEBUG
171#endif
172 }
173 else {
175
176 /* We convert the offset in vertex offset from the buffer's start.
177 * This works because we added some padding to align the first vertex. */
178 uint v_first = buffer_offset() / vertex_format.stride;
180 vao_id_, v_first, &vertex_format, reinterpret_cast<Shader *>(shader)->interface);
181
182 /* Update matrices. */
184
185 glDrawArrays(to_gl(prim_type), 0, vertex_len);
186
187 /* These lines are causing crash on startup on some old GPU + drivers.
188 * They are not required so just comment them. (#55722) */
189 // glBindBuffer(GL_ARRAY_BUFFER, 0);
190 // glBindVertexArray(0);
191 }
192
193 buffer_offset() += buffer_bytes_used;
194}
195
197
198} // namespace blender::gpu
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE uint ceil_to_multiple_u(uint a, uint b)
unsigned char uchar
unsigned int uint
size_t GPU_storage_buffer_alignment()
@ GPU_PRIM_NONE
void GPU_shader_bind(blender::gpu::Shader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
BMesh const char void * data
static GLContext * get()
uchar * begin() override
void polyline_draw_workaround(uint64_t offset)
virtual void apply_state()=0
#define GL_CHECK_RESOURCES(info)
Definition gl_debug.hh:14
#define GPU_SSBO_POLYLINE_POS_BUF_SLOT
#define GPU_SSBO_POLYLINE_COL_BUF_SLOT
#define GPU_SSBO_INDEX_BUF_SLOT
uint vertex_buffer_size(const GPUVertFormat *format, uint vertex_len)
uint padding(uint offset, uint alignment)
void update_bindings(const GLuint vao, const Batch *batch, const ShaderInterface *interface)
void object_label(GLenum type, GLuint object, const char *name)
Definition gl_debug.cc:329
constexpr size_t DEFAULT_INTERNAL_BUFFER_SIZE
static GLenum to_gl(const GPUAttachmentType type)