From 5af0cfd902e71d1d3ed5d20649b44f5c0125b4cd Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Sat, 16 Jan 2021 16:43:14 +0100 Subject: [PATCH] Codechange: [OpenGL] Use a vertex array object to store the vertex state for the video buffer. --- src/video/opengl.cpp | 44 +++++++++++++++++++++++++++++++++++++++----- src/video/opengl.h | 1 + 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/video/opengl.cpp b/src/video/opengl.cpp index ff4689b94e..6f329994fb 100644 --- a/src/video/opengl.cpp +++ b/src/video/opengl.cpp @@ -41,6 +41,10 @@ static PFNGLBUFFERDATAPROC _glBufferData; static PFNGLMAPBUFFERPROC _glMapBuffer; static PFNGLUNMAPBUFFERPROC _glUnmapBuffer; +static PFNGLGENVERTEXARRAYSPROC _glGenVertexArrays; +static PFNGLDELETEVERTEXARRAYSPROC _glDeleteVertexArrays; +static PFNGLBINDVERTEXARRAYPROC _glBindVertexArray; + /** A simple 2D vertex with just position and texture. */ struct Simple2DVertex { float x, y; @@ -148,6 +152,25 @@ static bool BindVBOExtension() return _glGenBuffers != nullptr && _glDeleteBuffers != nullptr && _glBindBuffer != nullptr && _glBufferData != nullptr && _glMapBuffer != nullptr && _glUnmapBuffer != nullptr; } +/** Bind vertex array object extension functions. */ +static bool BindVBAExtension() +{ + /* The APPLE and ARB variants have different semantics (that don't matter for us). + * Successfully getting pointers to one variant doesn't mean it is supported for + * the current context. Always check the extension strings as well. */ + if (IsOpenGLVersionAtLeast(3, 0) || IsOpenGLExtensionSupported("GL_ARB_vertex_array_object")) { + _glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)GetOGLProcAddress("glGenVertexArrays"); + _glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)GetOGLProcAddress("glDeleteVertexArrays"); + _glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)GetOGLProcAddress("glBindVertexArray"); + } else if (IsOpenGLExtensionSupported("GL_APPLE_vertex_array_object")) { + _glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)GetOGLProcAddress("glGenVertexArraysAPPLE"); + _glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)GetOGLProcAddress("glDeleteVertexArraysAPPLE"); + _glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)GetOGLProcAddress("glBindVertexArrayAPPLE"); + } + + return _glGenVertexArrays != nullptr && _glDeleteVertexArrays != nullptr && _glBindVertexArray != nullptr; +} + /** Callback to receive OpenGL debug messages. */ void APIENTRY DebugOutputCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) { @@ -238,6 +261,7 @@ OpenGLBackend::OpenGLBackend() */ OpenGLBackend::~OpenGLBackend() { + if (_glDeleteVertexArrays != nullptr) _glDeleteVertexArrays(1, &this->vao_quad); if (_glDeleteBuffers != nullptr) { _glDeleteBuffers(1, &this->vbo_quad); } @@ -273,6 +297,9 @@ const char *OpenGLBackend::Init() /* Check for vertex buffer objects. */ if (!IsOpenGLVersionAtLeast(1, 5) && !IsOpenGLExtensionSupported("ARB_vertex_buffer_object")) return "Vertex buffer objects not supported"; if (!BindVBOExtension()) return "Failed to bind VBO extension functions"; + /* Check for vertex array objects. */ + if (!IsOpenGLVersionAtLeast(3, 0) && (!IsOpenGLExtensionSupported("GL_ARB_vertex_array_object") || !IsOpenGLExtensionSupported("GL_APPLE_vertex_array_object"))) return "Vertex array objects not supported"; + if (!BindVBAExtension()) return "Failed to bind VBA extension functions"; /* Setup video buffer texture. */ glGenTextures(1, &this->vid_texture); @@ -285,7 +312,8 @@ const char *OpenGLBackend::Init() glBindTexture(GL_TEXTURE_2D, 0); if (glGetError() != GL_NO_ERROR) return "Can't generate video buffer texture"; - /* Prime vertex buffer with a full-screen quad. */ + /* Prime vertex buffer with a full-screen quad and store + * the corresponding state in a vertex array object. */ static const Simple2DVertex vert_array[] = { // x y u v { 1.f, -1.f, 1.f, 1.f }, @@ -294,13 +322,21 @@ const char *OpenGLBackend::Init() { -1.f, 1.f, 0.f, 0.f }, }; + /* Create VAO. */ + _glGenVertexArrays(1, &this->vao_quad); + _glBindVertexArray(this->vao_quad); + + /* Create and fill VBO. */ _glGenBuffers(1, &this->vbo_quad); _glBindBuffer(GL_ARRAY_BUFFER, this->vbo_quad); _glBufferData(GL_ARRAY_BUFFER, sizeof(vert_array), vert_array, GL_STATIC_DRAW); if (glGetError() != GL_NO_ERROR) return "Can't generate VBO for fullscreen quad"; - + /* Set vertex state. */ glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(2, GL_FLOAT, sizeof(Simple2DVertex), (GLvoid *)offsetof(Simple2DVertex, x)); + glTexCoordPointer(2, GL_FLOAT, sizeof(Simple2DVertex), (GLvoid *)offsetof(Simple2DVertex, u)); + _glBindVertexArray(0); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glDisable(GL_DEPTH_TEST); @@ -358,9 +394,7 @@ void OpenGLBackend::Paint(Rect update_rect) } /* Blit video buffer to screen. */ - _glBindBuffer(GL_ARRAY_BUFFER, this->vbo_quad); - glVertexPointer(2, GL_FLOAT, sizeof(Simple2DVertex), (GLvoid *)offsetof(Simple2DVertex, x)); - glTexCoordPointer(2, GL_FLOAT, sizeof(Simple2DVertex), (GLvoid *)offsetof(Simple2DVertex, u)); + _glBindVertexArray(this->vao_quad); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } diff --git a/src/video/opengl.h b/src/video/opengl.h index 15dc390b79..dfc71b5f7e 100644 --- a/src/video/opengl.h +++ b/src/video/opengl.h @@ -27,6 +27,7 @@ private: void *vid_buffer; ///< Pointer to the memory used for the video driver to draw to. GLuint vid_texture; ///< Texture handle for the video buffer texture. + GLuint vao_quad; ///< Vertex array object storing the rendering state for the fullscreen quad. GLuint vbo_quad; ///< Vertex buffer with a fullscreen quad. OpenGLBackend();