From 1804eb57fd27fceb0ed113e3ef2f4a55db0d03c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 31 Aug 2020 15:14:47 +0200 Subject: GPUImmediate: GL backend isolation This is part of the Vulkan backend task T68990. This is mostly a cleanup, however, there is a small change: We don't use a special Vertex Array binding function for Immediate anymore and just reuse the one for batches. This might create a bit more state changes but this could be fixed easily if it causes perf regression. # Conflicts: # source/blender/gpu/intern/gpu_context.cc --- source/blender/gpu/opengl/gl_context.cc | 2 + source/blender/gpu/opengl/gl_immediate.cc | 183 +++++++++++++++++++++++++++ source/blender/gpu/opengl/gl_immediate.hh | 81 ++++++++++++ source/blender/gpu/opengl/gl_primitive.hh | 65 ++++++++++ source/blender/gpu/opengl/gl_vertex_array.cc | 11 ++ source/blender/gpu/opengl/gl_vertex_array.hh | 5 + 6 files changed, 347 insertions(+) create mode 100644 source/blender/gpu/opengl/gl_immediate.cc create mode 100644 source/blender/gpu/opengl/gl_immediate.hh create mode 100644 source/blender/gpu/opengl/gl_primitive.hh (limited to 'source/blender/gpu/opengl') diff --git a/source/blender/gpu/opengl/gl_context.cc b/source/blender/gpu/opengl/gl_context.cc index 6bfbac72301..e5373777894 100644 --- a/source/blender/gpu/opengl/gl_context.cc +++ b/source/blender/gpu/opengl/gl_context.cc @@ -31,6 +31,7 @@ #include "gpu_context_private.hh" +#include "gl_immediate.hh" #include "gl_state.hh" #include "gl_backend.hh" /* TODO remove */ @@ -55,6 +56,7 @@ GLContext::GLContext(void *ghost_window, GLSharedOrphanLists &shared_orphan_list glBindBuffer(GL_ARRAY_BUFFER, 0); state_manager = new GLStateManager(); + imm = new GLImmediate(); ghost_window_ = ghost_window; if (ghost_window) { diff --git a/source/blender/gpu/opengl/gl_immediate.cc b/source/blender/gpu/opengl/gl_immediate.cc new file mode 100644 index 00000000000..ff598f79b3f --- /dev/null +++ b/source/blender/gpu/opengl/gl_immediate.cc @@ -0,0 +1,183 @@ +/* + * 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 + * + * Mimics old style opengl immediate mode drawing. + */ + +#include "BKE_global.h" + +#include "gpu_context_private.hh" +#include "gpu_shader_private.hh" +#include "gpu_vertex_format_private.h" + +#include "gl_context.hh" +#include "gl_primitive.hh" +#include "gl_vertex_array.hh" + +#include "gl_immediate.hh" + +namespace blender::gpu { + +/* -------------------------------------------------------------------- */ +/** \name Creation & Deletion + * \{ */ + +GLImmediate::GLImmediate() +{ + glGenVertexArrays(1, &vao_id_); + + buffer.buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE; + glGenBuffers(1, &buffer.vbo_id); + glBindBuffer(GL_ARRAY_BUFFER, buffer.vbo_id); + glBufferData(GL_ARRAY_BUFFER, buffer.buffer_size, NULL, GL_DYNAMIC_DRAW); + + buffer_strict.buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE; + glGenBuffers(1, &buffer_strict.vbo_id); + glBindBuffer(GL_ARRAY_BUFFER, buffer_strict.vbo_id); + glBufferData(GL_ARRAY_BUFFER, buffer_strict.buffer_size, NULL, GL_DYNAMIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + +#ifndef __APPLE__ + if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) { + glObjectLabel(GL_VERTEX_ARRAY, vao_id_, -1, "VAO-Immediate"); + glObjectLabel(GL_BUFFER, buffer.vbo_id, -1, "VBO-ImmediateBuffer"); + glObjectLabel(GL_BUFFER, buffer_strict.vbo_id, -1, "VBO-ImmediateBufferStrict"); + } +#endif +} + +GLImmediate::~GLImmediate() +{ + glDeleteVertexArrays(1, &vao_id_); + + glDeleteBuffers(1, &buffer.vbo_id); + glDeleteBuffers(1, &buffer_strict.vbo_id); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Buffer management + * \{ */ + +uchar *GLImmediate::begin() +{ + /* How many bytes do we need for this draw call? */ + const size_t bytes_needed = vertex_buffer_size(&vertex_format, vertex_len); + /* Does the current buffer have enough room? */ + const size_t available_bytes = buffer_size() - buffer_offset(); + + glBindBuffer(GL_ARRAY_BUFFER, vbo_id()); + + bool recreate_buffer = false; + if (bytes_needed > buffer_size()) { + /* expand the internal buffer */ + buffer_size() = bytes_needed; + recreate_buffer = true; + } + else if (bytes_needed < DEFAULT_INTERNAL_BUFFER_SIZE && + buffer_size() > DEFAULT_INTERNAL_BUFFER_SIZE) { + /* shrink the internal buffer */ + buffer_size() = DEFAULT_INTERNAL_BUFFER_SIZE; + recreate_buffer = true; + } + + /* ensure vertex data is aligned */ + /* Might waste a little space, but it's safe. */ + const uint pre_padding = padding(buffer_offset(), vertex_format.stride); + + if (!recreate_buffer && ((bytes_needed + pre_padding) <= available_bytes)) { + buffer_offset() += pre_padding; + } + else { + /* orphan this buffer & start with a fresh one */ + glBufferData(GL_ARRAY_BUFFER, buffer_size(), NULL, GL_DYNAMIC_DRAW); + buffer_offset() = 0; + } + +#ifndef NDEBUG + { + GLint bufsize; + glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &bufsize); + BLI_assert(buffer_offset() + bytes_needed <= bufsize); + } +#endif + + GLbitfield access = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT; + if (!strict_vertex_len) { + access |= GL_MAP_FLUSH_EXPLICIT_BIT; + } + void *data = glMapBufferRange(GL_ARRAY_BUFFER, buffer_offset(), bytes_needed, access); + BLI_assert(data != NULL); + + bytes_mapped_ = bytes_needed; + return (uchar *)data; +} + +void GLImmediate::end(void) +{ + BLI_assert(prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */ + + uint buffer_bytes_used = bytes_mapped_; + if (!strict_vertex_len) { + if (vertex_idx != vertex_len) { + vertex_len = vertex_idx; + buffer_bytes_used = vertex_buffer_size(&vertex_format, vertex_len); + /* unused buffer bytes are available to the next immBegin */ + } + /* tell OpenGL what range was modified so it doesn't copy the whole mapped range */ + glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, buffer_bytes_used); + } + glUnmapBuffer(GL_ARRAY_BUFFER); + + if (vertex_len > 0) { + GPU_context_active_get()->state_manager->apply_state(); + + /* We convert the offset in vertex offset from the buffer's start. + * This works because we added some padding to align the first vertex vertex. */ + uint v_first = buffer_offset() / vertex_format.stride; + GLVertArray::update_bindings( + vao_id_, v_first, &vertex_format, reinterpret_cast(shader)->interface); + + /* Update matrices. */ + GPU_shader_bind(shader); + +#ifdef __APPLE__ + glDisable(GL_PRIMITIVE_RESTART); +#endif + glDrawArrays(to_gl(prim_type), 0, vertex_len); +#ifdef __APPLE__ + glEnable(GL_PRIMITIVE_RESTART); +#endif + /* These lines are causing crash on startup on some old GPU + drivers. + * They are not required so just comment them. (T55722) */ + // glBindBuffer(GL_ARRAY_BUFFER, 0); + // glBindVertexArray(0); + } + + buffer_offset() += buffer_bytes_used; +} + +/** \} */ + +} // namespace blender::gpu \ No newline at end of file diff --git a/source/blender/gpu/opengl/gl_immediate.hh b/source/blender/gpu/opengl/gl_immediate.hh new file mode 100644 index 00000000000..2b9b90d692b --- /dev/null +++ b/source/blender/gpu/opengl/gl_immediate.hh @@ -0,0 +1,81 @@ +/* + * 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 + * + * Mimics old style opengl immediate mode drawing. + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +#include "glew-mx.h" + +#include "gpu_immediate_private.hh" + +namespace blender::gpu { + +/* size of internal buffer */ +#define DEFAULT_INTERNAL_BUFFER_SIZE (4 * 1024 * 1024) + +class GLImmediate : public Immediate { + private: + /* Use two buffers for strict and unstrict vertex count to + * avoid some huge driver slowdown (see T70922). + * Use accessor functions to get / modify. */ + struct { + /** Opengl Handle for this buffer. */ + GLuint vbo_id = 0; + /** Offset of the mapped data in data. */ + size_t buffer_offset = 0; + /** Size of the whole buffer in bytes. */ + size_t buffer_size = 0; + } buffer, buffer_strict; + /** Size in bytes of the mapped region. */ + size_t bytes_mapped_ = 0; + /** Vertex array for this immediate mode instance. */ + GLuint vao_id_ = 0; + + public: + GLImmediate(); + ~GLImmediate(); + + uchar *begin(void) override; + void end(void) override; + + private: + GLuint &vbo_id(void) + { + return strict_vertex_len ? buffer_strict.vbo_id : buffer.vbo_id; + }; + + size_t &buffer_offset(void) + { + return strict_vertex_len ? buffer_strict.buffer_offset : buffer.buffer_offset; + }; + + size_t &buffer_size(void) + { + return strict_vertex_len ? buffer_strict.buffer_size : buffer.buffer_size; + }; +}; + +} // namespace blender::gpu \ No newline at end of file diff --git a/source/blender/gpu/opengl/gl_primitive.hh b/source/blender/gpu/opengl/gl_primitive.hh new file mode 100644 index 00000000000..7cd0654bc2c --- /dev/null +++ b/source/blender/gpu/opengl/gl_primitive.hh @@ -0,0 +1,65 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Encapsulation of Framebuffer states (attached textures, viewport, scissors). + */ + +#pragma once + +#include "BLI_assert.h" + +#include "GPU_primitive.h" + +#include "glew-mx.h" + +namespace blender::gpu { + +static inline GLenum to_gl(GPUPrimType prim_type) +{ + BLI_assert(prim_type != GPU_PRIM_NONE); + switch (prim_type) { + default: + case GPU_PRIM_POINTS: + return GL_POINTS; + case GPU_PRIM_LINES: + return GL_LINES; + case GPU_PRIM_LINE_STRIP: + return GL_LINE_STRIP; + case GPU_PRIM_LINE_LOOP: + return GL_LINE_LOOP; + case GPU_PRIM_TRIS: + return GL_TRIANGLES; + case GPU_PRIM_TRI_STRIP: + return GL_TRIANGLE_STRIP; + case GPU_PRIM_TRI_FAN: + return GL_TRIANGLE_FAN; + + case GPU_PRIM_LINES_ADJ: + return GL_LINES_ADJACENCY; + case GPU_PRIM_LINE_STRIP_ADJ: + return GL_LINE_STRIP_ADJACENCY; + case GPU_PRIM_TRIS_ADJ: + return GL_TRIANGLES_ADJACENCY; + }; +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc index b2d2445f113..64d44c39587 100644 --- a/source/blender/gpu/opengl/gl_vertex_array.cc +++ b/source/blender/gpu/opengl/gl_vertex_array.cc @@ -155,6 +155,17 @@ void GLVertArray::update_bindings(const GLuint vao, } } +/* 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 diff --git a/source/blender/gpu/opengl/gl_vertex_array.hh b/source/blender/gpu/opengl/gl_vertex_array.hh index 59cd50ad7b8..7037986e31e 100644 --- a/source/blender/gpu/opengl/gl_vertex_array.hh +++ b/source/blender/gpu/opengl/gl_vertex_array.hh @@ -38,6 +38,11 @@ void update_bindings(const GLuint vao, const ShaderInterface *interface, const int base_instance); +void update_bindings(const GLuint vao, + const uint v_first, + const GPUVertFormat *format, + const ShaderInterface *interface); + } // namespace GLVertArray } // namespace gpu -- cgit v1.2.3