changeset 20541:6e216d3bc4df draft

-Codechange: [OpenGL] Use a vertex array object to store the vertex state for the video buffer.
author Michael Lutz <michi@icosahedron.de>
date Sat, 01 Jun 2013 21:48:34 +0200
parents adbcc8c10688
children b6097f4fe3be
files src/video/opengl.cpp src/video/opengl.h
diffstat 2 files changed, 40 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/video/opengl.cpp
+++ b/src/video/opengl.cpp
@@ -42,6 +42,10 @@
 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;
@@ -169,6 +173,25 @@
 	return _glGenBuffers != NULL && _glDeleteBuffers != NULL && _glBindBuffer != NULL && _glBufferData != NULL && _glMapBuffer != NULL && _glUnmapBuffer != NULL;
 }
 
+/** 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 {
+		_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)GetOGLProcAddress("glGenVertexArraysAPPLE");
+		_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)GetOGLProcAddress("glDeleteVertexArraysAPPLE");
+		_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)GetOGLProcAddress("glBindVertexArrayAPPLE");
+	}
+
+	return _glGenVertexArrays != NULL && _glDeleteVertexArrays != NULL && _glBindVertexArray != NULL;
+}
+
 
 /**
  * Construct OpenGL back-end class.
@@ -182,6 +205,7 @@
  */
 OpenGLBackend::~OpenGLBackend()
 {
+	_glDeleteVertexArrays(1, &this->vao_quad);
 	_glDeleteBuffers(1, &this->vbo_quad);
 	glDeleteTextures(1, &this->vid_texture);
 	free(this->vid_buffer);
@@ -208,6 +232,9 @@
 	/* 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);
@@ -220,7 +247,8 @@
 	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 },
@@ -229,13 +257,21 @@
 		{ -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);
@@ -291,9 +327,7 @@
 	}
 
 	/* 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);
 
 	glFlush();
--- a/src/video/opengl.h
+++ b/src/video/opengl.h
@@ -23,6 +23,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.
 
 public: