diff options
Diffstat (limited to 'source/blender/gpu/opengl/gl_vertex_array.cc')
-rw-r--r-- | source/blender/gpu/opengl/gl_vertex_array.cc | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc new file mode 100644 index 00000000000..64d44c39587 --- /dev/null +++ b/source/blender/gpu/opengl/gl_vertex_array.cc @@ -0,0 +1,171 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#include "GPU_glew.h" + +#include "GPU_vertex_buffer.h" + +#include "gpu_shader_interface.hh" +#include "gpu_vertex_format_private.h" + +#include "gl_batch.hh" +#include "gl_context.hh" + +#include "gl_vertex_array.hh" + +namespace blender::gpu { + +/* -------------------------------------------------------------------- */ +/** \name Vertex Array Bindings + * \{ */ + +/* Returns enabled vertex pointers as a bitflag (one bit per attrib). */ +static uint16_t vbo_bind(const ShaderInterface *interface, + const GPUVertFormat *format, + uint v_first, + uint v_len, + const bool use_instancing) +{ + uint16_t enabled_attrib = 0; + const uint attr_len = format->attr_len; + uint stride = format->stride; + uint offset = 0; + GLuint divisor = (use_instancing) ? 1 : 0; + + for (uint a_idx = 0; a_idx < attr_len; a_idx++) { + const GPUVertAttr *a = &format->attrs[a_idx]; + + if (format->deinterleaved) { + offset += ((a_idx == 0) ? 0 : format->attrs[a_idx - 1].sz) * v_len; + stride = a->sz; + } + else { + offset = a->offset; + } + + const GLvoid *pointer = (const GLubyte *)0 + offset + v_first * stride; + const GLenum type = convert_comp_type_to_gl(static_cast<GPUVertCompType>(a->comp_type)); + + for (uint n_idx = 0; n_idx < a->name_len; n_idx++) { + const char *name = GPU_vertformat_attr_name_get(format, a, n_idx); + const ShaderInput *input = interface->attr_get(name); + + if (input == NULL) { + continue; + } + + enabled_attrib |= (1 << input->location); + + if (a->comp_len == 16 || a->comp_len == 12 || a->comp_len == 8) { + BLI_assert(a->fetch_mode == GPU_FETCH_FLOAT); + BLI_assert(a->comp_type == GPU_COMP_F32); + for (int i = 0; i < a->comp_len / 4; i++) { + glEnableVertexAttribArray(input->location + i); + glVertexAttribDivisor(input->location + i, divisor); + glVertexAttribPointer( + input->location + i, 4, type, GL_FALSE, stride, (const GLubyte *)pointer + i * 16); + } + } + else { + glEnableVertexAttribArray(input->location); + glVertexAttribDivisor(input->location, divisor); + + switch (a->fetch_mode) { + case GPU_FETCH_FLOAT: + case GPU_FETCH_INT_TO_FLOAT: + glVertexAttribPointer(input->location, a->comp_len, type, GL_FALSE, stride, pointer); + break; + case GPU_FETCH_INT_TO_FLOAT_UNIT: + glVertexAttribPointer(input->location, a->comp_len, type, GL_TRUE, stride, pointer); + break; + case GPU_FETCH_INT: + glVertexAttribIPointer(input->location, a->comp_len, type, stride, pointer); + break; + } + } + } + } + return enabled_attrib; +} + +/* Update the Attrib Binding of the currently bound VAO. */ +void GLVertArray::update_bindings(const GLuint vao, + const GPUBatch *batch, + const ShaderInterface *interface, + const int base_instance) +{ + uint16_t attr_mask = interface->enabled_attr_mask_; + + glBindVertexArray(vao); + + /* Reverse order so first VBO'S have more prevalence (in term of attribute override). */ + for (int v = GPU_BATCH_VBO_MAX_LEN - 1; v > -1; v--) { + GPUVertBuf *vbo = batch->verts[v]; + if (vbo) { + GPU_vertbuf_use(vbo); + attr_mask &= ~vbo_bind(interface, &vbo->format, 0, vbo->vertex_len, false); + } + } + + for (int v = GPU_BATCH_INST_VBO_MAX_LEN - 1; v > -1; v--) { + GPUVertBuf *vbo = batch->inst[v]; + if (vbo) { + GPU_vertbuf_use(vbo); + attr_mask &= ~vbo_bind(interface, &vbo->format, base_instance, vbo->vertex_len, true); + } + } + + if (attr_mask != 0 && GLEW_ARB_vertex_attrib_binding) { + for (uint16_t mask = 1, a = 0; a < 16; a++, mask <<= 1) { + if (attr_mask & mask) { + GLContext *ctx = static_cast<GLContext *>(GPU_context_active_get()); + /* This replaces glVertexAttrib4f(a, 0.0f, 0.0f, 0.0f, 1.0f); with a more modern style. + * Fix issues for some drivers (see T75069). */ + glBindVertexBuffer(a, ctx->default_attr_vbo_, (intptr_t)0, (intptr_t)0); + glEnableVertexAttribArray(a); + glVertexAttribFormat(a, 4, GL_FLOAT, GL_FALSE, 0); + glVertexAttribBinding(a, a); + } + } + } + + if (batch->elem) { + /* Binds the index buffer. This state is also saved in the VAO. */ + GPU_indexbuf_use(batch->elem); + } +} + +/* Another version of update_bindings for Immediate mode. */ +void GLVertArray::update_bindings(const GLuint vao, + const uint v_first, + const GPUVertFormat *format, + const ShaderInterface *interface) +{ + glBindVertexArray(vao); + + vbo_bind(interface, format, v_first, 0, false); +} + +/** \} */ + +} // namespace blender::gpu
\ No newline at end of file |