From e18da092ef9a81202c9ec941bcb9876f257eed5b Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Thu, 19 Nov 2015 17:18:55 +0000 Subject: slideshow: Batch primitive display as much as possible We now set the state and upload all vertices data at once, before each batch, in order to minimize GL calls during drawing. The next step will be to move to shaders, in order to use per-primitive uniforms instead of changing the global modelview matrix and issuing another draw call. Change-Id: I8c7cf29047047b9cad575cc6264485ae77d6ba10 --- .../OGLTrans/generic/OGLTrans_TransitionImpl.cxx | 120 ++++++++++++--------- .../OGLTrans/generic/OGLTrans_TransitionImpl.hxx | 39 +++++-- 2 files changed, 100 insertions(+), 59 deletions(-) (limited to 'slideshow') diff --git a/slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionImpl.cxx b/slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionImpl.cxx index 11e6c4e92093..a7fa892decd1 100644 --- a/slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionImpl.cxx +++ b/slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionImpl.cxx @@ -192,6 +192,58 @@ void OGLTransitionImpl::applyOverallOperations( double nTime, double SlideWidthS rOverallOperations[i]->interpolate(nTime,SlideWidthScale,SlideHeightScale); } +static void display_primitives(const Primitives_t& primitives, double nTime, double WidthScale, double HeightScale) +{ + CHECK_GL_ERROR(); + GLuint buffer; + glGenBuffers(1, &buffer); + CHECK_GL_ERROR(); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + + int size = 0; + for (const Primitive& primitive: primitives) + size += primitive.getVerticesSize(); + + CHECK_GL_ERROR(); + glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_STREAM_DRAW); + CHECK_GL_ERROR(); + Vertex *buf = reinterpret_cast(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY)); + + std::vector first_elements; + int last_pos = 0; + for (const Primitive& primitive: primitives) { + first_elements.push_back(last_pos); + int num = primitive.writeVertices(buf); + buf += num; + last_pos += num; + } + auto first = first_elements.begin(); + + CHECK_GL_ERROR(); + glUnmapBuffer(GL_ARRAY_BUFFER); + + // State initialization + // TODO: move that elsewhere. + CHECK_GL_ERROR(); + glEnableClientState( GL_VERTEX_ARRAY ); + CHECK_GL_ERROR(); + glVertexPointer( 3, GL_FLOAT, sizeof(Vertex), reinterpret_cast(offsetof(Vertex, position)) ); + CHECK_GL_ERROR(); + glEnableClientState( GL_NORMAL_ARRAY ); + CHECK_GL_ERROR(); + glNormalPointer( GL_FLOAT , sizeof(Vertex) , reinterpret_cast(offsetof(Vertex, normal)) ); + CHECK_GL_ERROR(); + glEnableClientState( GL_TEXTURE_COORD_ARRAY ); + CHECK_GL_ERROR(); + glTexCoordPointer( 2, GL_FLOAT, sizeof(Vertex), reinterpret_cast(offsetof(Vertex, texcoord)) ); + + for (const Primitive& primitive: primitives) + primitive.display(nTime, WidthScale, HeightScale, *first++); + + CHECK_GL_ERROR(); + glDeleteBuffers(1, &buffer); +} + void OGLTransitionImpl::displaySlide( const double nTime, @@ -216,8 +268,7 @@ OGLTransitionImpl::displaySlide( glTranslated( 0, 2 - surfaceLevel, 0 ); glCullFace(GL_FRONT); - for(size_t i(0); i < primitives.size(); ++i) - primitives[i].display(nTime, SlideWidthScale, SlideHeightScale); + display_primitives(primitives, nTime, SlideWidthScale, SlideHeightScale); glCullFace(GL_BACK); slideShadow( nTime, primitives[0], SlideWidthScale, SlideHeightScale ); @@ -225,8 +276,7 @@ OGLTransitionImpl::displaySlide( glPopMatrix(); } - for(size_t i(0); i < primitives.size(); ++i) - primitives[i].display(nTime, SlideWidthScale, SlideHeightScale); + display_primitives(primitives, nTime, SlideWidthScale, SlideHeightScale); CHECK_GL_ERROR(); } @@ -240,7 +290,7 @@ void OGLTransitionImpl::displayScene( double nTime, double SlideWidth, double Sl CHECK_GL_ERROR(); } -void Primitive::display(double nTime, double WidthScale, double HeightScale) const +void Primitive::display(double nTime, double WidthScale, double HeightScale, int first) const { CHECK_GL_ERROR(); glPushMatrix(); @@ -249,19 +299,8 @@ void Primitive::display(double nTime, double WidthScale, double HeightScale) con applyOperations( nTime, WidthScale, HeightScale ); CHECK_GL_ERROR(); - glEnableClientState( GL_VERTEX_ARRAY ); - CHECK_GL_ERROR(); - glNormalPointer( GL_FLOAT , 0 , &Normals[0] ); - CHECK_GL_ERROR(); - glEnableClientState( GL_NORMAL_ARRAY ); - CHECK_GL_ERROR(); - glEnableClientState( GL_TEXTURE_COORD_ARRAY ); - CHECK_GL_ERROR(); - glTexCoordPointer( 2, GL_FLOAT, 0, &TexCoords[0] ); - CHECK_GL_ERROR(); - glVertexPointer( 3, GL_FLOAT, 0, &Vertices[0] ); - CHECK_GL_ERROR(); - glDrawArrays( GL_TRIANGLES, 0, Vertices.size() ); + glDrawArrays( GL_TRIANGLES, first, Vertices.size() ); + CHECK_GL_ERROR(); glPopMatrix(); CHECK_GL_ERROR(); @@ -278,22 +317,19 @@ void Primitive::applyOperations(double nTime, double WidthScale, double HeightSc void SceneObject::display(double nTime, double /* SlideWidth */, double /* SlideHeight */, double DispWidth, double DispHeight ) const { + // fixme: allow various model spaces, now we make it so that + // it is regular -1,-1 to 1,1, where the whole display fits in CHECK_GL_ERROR(); - for(size_t i(0); i < maPrimitives.size(); ++i) { - // fixme: allow various model spaces, now we make it so that - // it is regular -1,-1 to 1,1, where the whole display fits in - CHECK_GL_ERROR(); - glPushMatrix(); - CHECK_GL_ERROR(); - if (DispHeight > DispWidth) - glScaled(DispHeight/DispWidth, 1, 1); - else - glScaled(1, DispWidth/DispHeight, 1); - maPrimitives[i].display(nTime, 1, 1); - CHECK_GL_ERROR(); - glPopMatrix(); - CHECK_GL_ERROR(); - } + glPushMatrix(); + CHECK_GL_ERROR(); + if (DispHeight > DispWidth) + glScaled(DispHeight/DispWidth, 1, 1); + else + glScaled(1, DispWidth/DispHeight, 1); + CHECK_GL_ERROR(); + display_primitives(maPrimitives, nTime, 1, 1); + CHECK_GL_ERROR(); + glPopMatrix(); CHECK_GL_ERROR(); } @@ -1063,8 +1099,6 @@ Primitive& Primitive::operator=(const Primitive& rvalue) Primitive::Primitive(const Primitive& rvalue) : Operations(rvalue.Operations) , Vertices(rvalue.Vertices) - , Normals(rvalue.Normals) - , TexCoords(rvalue.TexCoords) { } @@ -1074,8 +1108,6 @@ void Primitive::swap(Primitive& rOther) swap(Operations, rOther.Operations); swap(Vertices, rOther.Vertices); - swap(Normals, rOther.Normals); - swap(TexCoords, rOther.TexCoords); } void Primitive::pushTriangle(const glm::vec2& SlideLocation0,const glm::vec2& SlideLocation1,const glm::vec2& SlideLocation2) @@ -1108,17 +1140,9 @@ void Primitive::pushTriangle(const glm::vec2& SlideLocation0,const glm::vec2& Sl Verts.push_back(glm::vec3( 2*SlideLocation1.x - 1, -2*SlideLocation1.y + 1 , 0.0 )); } - Vertices.push_back(Verts[0]); - Vertices.push_back(Verts[1]); - Vertices.push_back(Verts[2]); - - TexCoords.push_back(Texs[0]); - TexCoords.push_back(Texs[1]); - TexCoords.push_back(Texs[2]); - - Normals.push_back(glm::vec3(0,0,1));//all normals always face the screen when untransformed. - Normals.push_back(glm::vec3(0,0,1));//all normals always face the screen when untransformed. - Normals.push_back(glm::vec3(0,0,1));//all normals always face the screen when untransformed. + Vertices.push_back({Verts[0], glm::vec3(0, 0, 1), Texs[0]}); //all normals always face the screen when untransformed. + Vertices.push_back({Verts[1], glm::vec3(0, 0, 1), Texs[1]}); //all normals always face the screen when untransformed. + Vertices.push_back({Verts[2], glm::vec3(0, 0, 1), Texs[2]}); //all normals always face the screen when untransformed. } namespace diff --git a/slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionImpl.hxx b/slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionImpl.hxx index 37df57e86e56..972cb83a61e5 100644 --- a/slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionImpl.hxx +++ b/slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionImpl.hxx @@ -277,6 +277,14 @@ private: GLuint maTexture; }; +struct Vertex +{ + glm::vec3 position; + glm::vec3 normal; + glm::vec2 texcoord; +}; +static_assert(sizeof(Vertex) == (3 + 3 + 2) * 4, "Vertex struct has wrong size/alignment"); + /** This class is a list of Triangles that will share Operations, and could possibly share */ class Primitive @@ -290,7 +298,7 @@ public: void swap(Primitive& rOther); void applyOperations(double nTime, double SlideWidthScale, double SlideHeightScale) const; - void display(double nTime, double SlideWidthScale, double SlideHeightScale) const; + void display(double nTime, double SlideWidthScale, double SlideHeightScale, int first) const; /** PushBack a vertex,normal, and tex coord. Each SlideLocation is where on the slide is mapped to this location ( from (0,0) to (1,1) ). This will make sure the correct aspect ratio is used, and helps to make slides begin and end at the correct position. (0,0) is the top left of the slide, and (1,1) is the bottom right. @@ -311,7 +319,24 @@ public: @return the list of vertices */ - const glm::vec3& getVertex(int n) const {return Vertices[n];} + const glm::vec3& getVertex(int n) const {return Vertices[n].position;} + + /** accessor for the size of the vertices data + + @return + the size in bytes of the Vertices data + */ + int getVerticesSize() const {return Vertices.size() * sizeof(Vertex);} + + /** copies all vertices to the C array passed + + @return + the number of written vertices + */ + int writeVertices(Vertex *location) const { + std::copy(Vertices.begin(), Vertices.end(), location); + return Vertices.size(); + } /** list of Operations to be performed on this primitive.These operations will be called in the order they were pushed back in. In OpenGL this effectively uses the operations in the opposite order they were pushed back. @@ -324,15 +349,7 @@ public: private: /** list of vertices */ - std::vector Vertices; - - /** list of Normals - */ - std::vector Normals; - - /** list of Texture Coordinates - */ - std::vector TexCoords; + std::vector Vertices; }; /** This class is to be derived to make any operation (transform) you may need in order to construct your transitions -- cgit