[colobot] 379/390: Shader and buffer optimizations

Didier Raboud odyx at moszumanska.debian.org
Fri Jun 12 14:22:07 UTC 2015


This is an automated email from the git hooks/post-receive script.

odyx pushed a commit to branch upstream/latest
in repository colobot.

commit a0c56f54cb3bc1c3d29b37daa8fdbeda6e52bbaa
Author: Tomasz Kapuściński <tomaszkax86 at gmail.com>
Date:   Mon Jun 1 17:21:10 2015 +0200

    Shader and buffer optimizations
---
 src/graphics/opengl/gl21device.cpp | 189 +++++++++++-----------------------
 src/graphics/opengl/gl21device.h   |   9 +-
 src/graphics/opengl/gl33device.cpp | 202 ++++++++++---------------------------
 src/graphics/opengl/gl33device.h   |   9 ++
 src/graphics/opengl/glutil.cpp     |  78 ++++++++++++++
 src/graphics/opengl/glutil.h       |   4 +
 6 files changed, 211 insertions(+), 280 deletions(-)

diff --git a/src/graphics/opengl/gl21device.cpp b/src/graphics/opengl/gl21device.cpp
index c4a6067..528d781 100644
--- a/src/graphics/opengl/gl21device.cpp
+++ b/src/graphics/opengl/gl21device.cpp
@@ -261,10 +261,9 @@ bool CGL21Device::Create()
     else
         CLogger::GetInstance().Info("Using per-vertex lighting\n");
 
-    // Create shader program
-    GLchar source[65536];
-    const GLchar *sources[] = { source };
 
+    // Create normal shader program
+    GLint shaders[2];
     char filename[128];
 
     if (m_perPixelLighting)
@@ -272,147 +271,65 @@ bool CGL21Device::Create()
     else
         sprintf(filename, "shaders/vertex_shader_21_pervertex.glsl");
 
-    PHYSFS_file *file = PHYSFS_openRead(filename);
-    if (file == nullptr)
-    {
-        CLogger::GetInstance().Error("Cannot read vertex shader code file!\n");
-        CLogger::GetInstance().Error("Missing file \"%s\"\n", filename);
-        return false;
-    }
-
-    int length = PHYSFS_read(file, source, 1, 65536);
-    source[length] = '\0';
-
-    PHYSFS_close(file);
-
-    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
-    glShaderSource(vertexShader, 1, sources, nullptr);
-    glCompileShader(vertexShader);
-
-    GLint status;
-    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
-
-    if (status != GL_TRUE)
-    {
-        GLint len;
-        glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &len);
-
-        GLchar *message = new GLchar[len + 1];
-        glGetShaderInfoLog(vertexShader, len + 1, nullptr, message);
-
-        GetLogger()->Error("Vertex shader compilation error occured!\n%s\n", message);
-
-        delete[] message;
-        return false;
-    }
+    shaders[0] = LoadShader(GL_VERTEX_SHADER, filename);
+    if (shaders[0] == 0) return false;
 
     if (m_perPixelLighting)
         sprintf(filename, "shaders/fragment_shader_21_perpixel.glsl");
     else
         sprintf(filename, "shaders/fragment_shader_21_pervertex.glsl");
 
-    file = PHYSFS_openRead(filename);
-    if (file == nullptr)
-    {
-        CLogger::GetInstance().Error("Cannot read fragment shader code file!\n");
-        CLogger::GetInstance().Error("Missing file \"%s\"\n", filename);
-        return false;
-    }
-
-    length = PHYSFS_read(file, source, 1, 65536);
-    source[length] = '\0';
-
-    PHYSFS_close(file);
-
-    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
-    glShaderSource(fragmentShader, 1, sources, nullptr);
-    glCompileShader(fragmentShader);
-
-    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status);
-
-    if (status != GL_TRUE)
-    {
-        GLint len;
-        glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &len);
-
-        GLchar *message = new GLchar[len + 1];
-        glGetShaderInfoLog(fragmentShader, len + 1, nullptr, message);
-
-        GetLogger()->Error("Fragment shader compilation error occured!\n%s\n", message);
-
-        delete[] message;
-        return false;
-    }
-
-    m_shaderProgram = glCreateProgram();
-    glAttachShader(m_shaderProgram, vertexShader);
-    glAttachShader(m_shaderProgram, fragmentShader);
+    shaders[1] = LoadShader(GL_FRAGMENT_SHADER, filename);
+    if (shaders[1] == 0) return false;
 
-    glLinkProgram(m_shaderProgram);
+    m_program = LinkProgram(2, shaders);
+    if (m_program == 0) return false;
 
-    glDetachShader(m_shaderProgram, vertexShader);
-    glDetachShader(m_shaderProgram, fragmentShader);
+    glDeleteShader(shaders[0]);
+    glDeleteShader(shaders[1]);
 
-    glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, &status);
-
-    if (status != GL_TRUE)
-    {
-        GLint len;
-        glGetProgramiv(m_shaderProgram, GL_INFO_LOG_LENGTH, &len);
-
-        GLchar *message = new GLchar[len + 1];
-        glGetProgramInfoLog(m_shaderProgram, len + 1, nullptr, message);
-
-        GetLogger()->Error("Shader program linking error occured!\n%s\n", message);
-
-        delete[] message;
-        return false;
-    }
-
-    glDeleteShader(vertexShader);
-    glDeleteShader(fragmentShader);
-
-    glUseProgram(m_shaderProgram);
 
     // Obtain uniform locations
-    uni_ProjectionMatrix = glGetUniformLocation(m_shaderProgram, "uni_ProjectionMatrix");
-    uni_ViewMatrix = glGetUniformLocation(m_shaderProgram, "uni_ViewMatrix");
-    uni_ModelMatrix = glGetUniformLocation(m_shaderProgram, "uni_ModelMatrix");
-    uni_NormalMatrix = glGetUniformLocation(m_shaderProgram, "uni_NormalMatrix");
-    uni_ShadowMatrix = glGetUniformLocation(m_shaderProgram, "uni_ShadowMatrix");
+    uni_ProjectionMatrix = glGetUniformLocation(m_program, "uni_ProjectionMatrix");
+    uni_ViewMatrix = glGetUniformLocation(m_program, "uni_ViewMatrix");
+    uni_ModelMatrix = glGetUniformLocation(m_program, "uni_ModelMatrix");
+    uni_NormalMatrix = glGetUniformLocation(m_program, "uni_NormalMatrix");
+    uni_ShadowMatrix = glGetUniformLocation(m_program, "uni_ShadowMatrix");
 
-    uni_PrimaryTexture = glGetUniformLocation(m_shaderProgram, "uni_PrimaryTexture");
-    uni_SecondaryTexture = glGetUniformLocation(m_shaderProgram, "uni_SecondaryTexture");
-    uni_ShadowTexture = glGetUniformLocation(m_shaderProgram, "uni_ShadowTexture");
+    uni_PrimaryTexture = glGetUniformLocation(m_program, "uni_PrimaryTexture");
+    uni_SecondaryTexture = glGetUniformLocation(m_program, "uni_SecondaryTexture");
+    uni_ShadowTexture = glGetUniformLocation(m_program, "uni_ShadowTexture");
 
     for (int i = 0; i < 3; i++)
     {
         char name[64];
         sprintf(name, "uni_TextureEnabled[%d]", i);
-        uni_TextureEnabled[i] = glGetUniformLocation(m_shaderProgram, name);
+        uni_TextureEnabled[i] = glGetUniformLocation(m_program, name);
     }
 
-    uni_AlphaTestEnabled = glGetUniformLocation(m_shaderProgram, "uni_AlphaTestEnabled");
-    uni_AlphaReference = glGetUniformLocation(m_shaderProgram, "uni_AlphaReference");
+    uni_AlphaTestEnabled = glGetUniformLocation(m_program, "uni_AlphaTestEnabled");
+    uni_AlphaReference = glGetUniformLocation(m_program, "uni_AlphaReference");
 
-    uni_FogEnabled = glGetUniformLocation(m_shaderProgram, "uni_FogEnabled");
-    uni_FogRange = glGetUniformLocation(m_shaderProgram, "uni_FogRange");
-    uni_FogColor = glGetUniformLocation(m_shaderProgram, "uni_FogColor");
+    uni_FogEnabled = glGetUniformLocation(m_program, "uni_FogEnabled");
+    uni_FogRange = glGetUniformLocation(m_program, "uni_FogRange");
+    uni_FogColor = glGetUniformLocation(m_program, "uni_FogColor");
 
-    uni_ShadowColor =  glGetUniformLocation(m_shaderProgram, "uni_ShadowColor");
-    uni_LightingEnabled = glGetUniformLocation(m_shaderProgram, "uni_LightingEnabled");
+    uni_ShadowColor = glGetUniformLocation(m_program, "uni_ShadowColor");
+    uni_LightingEnabled = glGetUniformLocation(m_program, "uni_LightingEnabled");
 
     for (int i = 0; i < 8; i++)
     {
         char name[64];
         sprintf(name, "uni_LightEnabled[%d]", i);
-        uni_LightEnabled[i] = glGetUniformLocation(m_shaderProgram, name);
+        uni_LightEnabled[i] = glGetUniformLocation(m_program, name);
     }
 
     // Set default uniform values
     Math::Matrix matrix;
     matrix.LoadIdentity();
 
+    glUseProgram(m_program);
+
     glUniformMatrix4fv(uni_ProjectionMatrix, 1, GL_FALSE, matrix.Array());
     glUniformMatrix4fv(uni_ViewMatrix, 1, GL_FALSE, matrix.Array());
     glUniformMatrix4fv(uni_ModelMatrix, 1, GL_FALSE, matrix.Array());
@@ -447,7 +364,7 @@ void CGL21Device::Destroy()
     // Delete the remaining textures
     // Should not be strictly necessary, but just in case
     glUseProgram(0);
-    glDeleteProgram(m_shaderProgram);
+    glDeleteProgram(m_program);
 
     DestroyAllTextures();
 
@@ -489,6 +406,7 @@ void CGL21Device::SetTransform(TransformType type, const Math::Matrix &matrix)
     if (type == TRANSFORM_WORLD)
     {
         m_worldMat = matrix;
+
         glUniformMatrix4fv(uni_ModelMatrix, 1, GL_FALSE, m_worldMat.Array());
 
         // normal transform
@@ -503,11 +421,13 @@ void CGL21Device::SetTransform(TransformType type, const Math::Matrix &matrix)
         Math::Matrix scale;
         Math::LoadScaleMatrix(scale, Math::Vector(1.0f, 1.0f, -1.0f));
         Math::Matrix temp = Math::MultiplyMatrices(scale, matrix);
+
         glUniformMatrix4fv(uni_ViewMatrix, 1, GL_FALSE, temp.Array());
     }
     else if (type == TRANSFORM_PROJECTION)
     {
         m_projectionMat = matrix;
+
         glUniformMatrix4fv(uni_ProjectionMatrix, 1, GL_FALSE, m_projectionMat.Array());
     }
     else if (type == TRANSFORM_SHADOW)
@@ -967,6 +887,14 @@ void CGL21Device::UpdateTextureStatus()
     */
 }
 
+inline void CGL21Device::BindVBO(GLint vbo)
+{
+    if (m_currentVBO == vbo) return;
+
+    glBindBuffer(GL_ARRAY_BUFFER, vbo);
+    m_currentVBO = vbo;
+}
+
 /**
   Sets the texture parameters for the given texture stage.
   If the given texture was not set (bound) yet, nothing happens.
@@ -1222,6 +1150,8 @@ void CGL21Device::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode
 void CGL21Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount,
                               Color color)
 {
+    BindVBO(0);
+
     Vertex* vs = const_cast<Vertex*>(vertices);
 
     glEnableClientState(GL_VERTEX_ARRAY);
@@ -1247,6 +1177,8 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int
 void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount,
                               Color color)
 {
+    BindVBO(0);
+
     VertexTex2* vs = const_cast<VertexTex2*>(vertices);
 
     glEnableClientState(GL_VERTEX_ARRAY);
@@ -1278,6 +1210,8 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices,
 
 void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount)
 {
+    BindVBO(0);
+
     VertexCol* vs = const_cast<VertexCol*>(vertices);
 
     glEnableClientState(GL_VERTEX_ARRAY);
@@ -1304,9 +1238,8 @@ unsigned int CGL21Device::CreateStaticBuffer(PrimitiveType primitiveType, const
     info.size = vertexCount * sizeof(Vertex);
 
     glGenBuffers(1, &info.bufferId);
-    glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
+    BindVBO(info.bufferId);
     glBufferData(GL_ARRAY_BUFFER, info.size, vertices, GL_STATIC_DRAW);
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
 
     m_vboObjects[id] = info;
 
@@ -1325,9 +1258,8 @@ unsigned int CGL21Device::CreateStaticBuffer(PrimitiveType primitiveType, const
     info.size = vertexCount * sizeof(VertexTex2);
 
     glGenBuffers(1, &info.bufferId);
-    glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
+    BindVBO(info.bufferId);
     glBufferData(GL_ARRAY_BUFFER, info.size, vertices, GL_STATIC_DRAW);
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
 
     m_vboObjects[id] = info;
 
@@ -1346,9 +1278,8 @@ unsigned int CGL21Device::CreateStaticBuffer(PrimitiveType primitiveType, const
     info.size = vertexCount * sizeof(VertexCol);
 
     glGenBuffers(1, &info.bufferId);
-    glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
+    BindVBO(info.bufferId);
     glBufferData(GL_ARRAY_BUFFER, info.size, vertices, GL_STATIC_DRAW);
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
 
     m_vboObjects[id] = info;
 
@@ -1368,7 +1299,7 @@ void CGL21Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
     info.vertexType = VERTEX_TYPE_NORMAL;
     info.vertexCount = vertexCount;
 
-    glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
+    BindVBO(info.bufferId);
 
     if (info.size < newSize)
     {
@@ -1379,8 +1310,6 @@ void CGL21Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
     {
         glBufferSubData(GL_ARRAY_BUFFER, 0, newSize, vertices);
     }
-    
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
 }
 
 void CGL21Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount)
@@ -1395,8 +1324,8 @@ void CGL21Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
     info.vertexCount = vertexCount;
 
     int newSize = vertexCount * sizeof(VertexTex2);
-    
-    glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
+
+    BindVBO(info.bufferId);
 
     if (info.size < newSize)
     {
@@ -1407,8 +1336,6 @@ void CGL21Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
     {
         glBufferSubData(GL_ARRAY_BUFFER, 0, newSize, vertices);
     }
-
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
 }
 
 void CGL21Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount)
@@ -1424,7 +1351,7 @@ void CGL21Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
 
     int newSize = vertexCount * sizeof(VertexCol);
 
-    glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
+    BindVBO(info.bufferId);
 
     if (info.size < newSize)
     {
@@ -1435,8 +1362,6 @@ void CGL21Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
     {
         glBufferSubData(GL_ARRAY_BUFFER, 0, newSize, vertices);
     }
-
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
 }
 
 void CGL21Device::DrawStaticBuffer(unsigned int bufferId)
@@ -1446,7 +1371,7 @@ void CGL21Device::DrawStaticBuffer(unsigned int bufferId)
         return;
 
     glEnable(GL_VERTEX_ARRAY);
-    glBindBuffer(GL_ARRAY_BUFFER, (*it).second.bufferId);
+    BindVBO((*it).second.bufferId);
 
     if ((*it).second.vertexType == VERTEX_TYPE_NORMAL)
     {
@@ -1510,7 +1435,6 @@ void CGL21Device::DrawStaticBuffer(unsigned int bufferId)
         glDisableClientState(GL_COLOR_ARRAY);
     }
 
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
     glDisable(GL_VERTEX_ARRAY);
 }
 
@@ -1520,6 +1444,9 @@ void CGL21Device::DestroyStaticBuffer(unsigned int bufferId)
     if (it == m_vboObjects.end())
         return;
 
+    if (m_currentVBO == (*it).second.bufferId)
+        BindVBO(0);
+
     glDeleteBuffers(1, &(*it).second.bufferId);
 
     m_vboObjects.erase(it);
diff --git a/src/graphics/opengl/gl21device.h b/src/graphics/opengl/gl21device.h
index 2f3dfa1..36d8c7b 100644
--- a/src/graphics/opengl/gl21device.h
+++ b/src/graphics/opengl/gl21device.h
@@ -152,6 +152,8 @@ private:
     void UpdateTextureParams(int index);
     //! Updates texture status
     void UpdateTextureStatus();
+    //! Binds VBO
+    inline void BindVBO(GLint vbo);
 
 private:
     //! Current config
@@ -217,6 +219,8 @@ private:
     std::map<unsigned int, VboObjectInfo> m_vboObjects;
     //! Last ID of VBO object
     unsigned int m_lastVboId;
+    //! Currently bound VBO
+    GLint m_currentVBO;
 
     // Offscreen buffer
     //! Framebuffer object
@@ -230,11 +234,12 @@ private:
     //! true if offscreen rendering enabled
     bool m_offscreenRenderingEnabled;
 
-    //! Shader program
-    GLuint m_shaderProgram;
     //! true enables per-pixel lighting
     bool m_perPixelLighting;
 
+    //! Shader program
+    GLuint m_program;
+
     // Uniforms
     //! Projection matrix
     GLint uni_ProjectionMatrix;
diff --git a/src/graphics/opengl/gl33device.cpp b/src/graphics/opengl/gl33device.cpp
index a4f31b6..bd31808 100644
--- a/src/graphics/opengl/gl33device.cpp
+++ b/src/graphics/opengl/gl33device.cpp
@@ -263,9 +263,7 @@ bool CGL33Device::Create()
         CLogger::GetInstance().Info("Using per-vertex lighting\n");
 
     // Create shader program
-    GLchar source[65536];
-    const GLchar *sources[] = { source };
-
+    GLint shaders[2];
     char filename[64];
 
     if (m_perPixelLighting)
@@ -273,105 +271,22 @@ bool CGL33Device::Create()
     else
         sprintf(filename, "shaders/vertex_shader_33_pervertex.glsl");
 
-    PHYSFS_file *file = PHYSFS_openRead(filename);
-    if (file == nullptr)
-    {
-        CLogger::GetInstance().Error("Cannot read vertex shader code file!\n");
-        CLogger::GetInstance().Error("Missing file \"%s\"\n", filename);
-        return false;
-    }
-
-    int length = PHYSFS_read(file, source, 1, 65536);
-    source[length] = '\0';
-
-    PHYSFS_close(file);
-    
-    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
-    glShaderSource(vertexShader, 1, sources, nullptr);
-    glCompileShader(vertexShader);
-
-    GLint status;
-    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
-
-    if (status != GL_TRUE)
-    {
-        GLint len;
-        glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &len);
-
-        GLchar *message = new GLchar[len + 1];
-        glGetShaderInfoLog(vertexShader, len + 1, nullptr, message);
-
-        GetLogger()->Error("Vertex shader compilation error occured!\n%s\n", message);
-
-        delete[] message;
-        return false;
-    }
+    shaders[0] = LoadShader(GL_VERTEX_SHADER, filename);
+    if (shaders[0] == 0) return false;
 
     if (m_perPixelLighting)
         sprintf(filename, "shaders/fragment_shader_33_perpixel.glsl");
     else
         sprintf(filename, "shaders/fragment_shader_33_pervertex.glsl");
 
-    file = PHYSFS_openRead(filename);
-    if (file == nullptr)
-    {
-        CLogger::GetInstance().Error("Cannot read fragment shader code file!\n");
-        CLogger::GetInstance().Error("Missing file \"%s\"\n", filename);
-        return false;
-    }
-
-    length = PHYSFS_read(file, source, 1, 65536);
-    source[length] = '\0';
-
-    PHYSFS_close(file);
-
-    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
-    glShaderSource(fragmentShader, 1, sources, nullptr);
-    glCompileShader(fragmentShader);
-
-    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status);
-
-    if (status != GL_TRUE)
-    {
-        GLint len;
-        glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &len);
-
-        GLchar *message = new GLchar[len + 1];
-        glGetShaderInfoLog(fragmentShader, len + 1, nullptr, message);
-
-        GetLogger()->Error("Fragment shader compilation error occured!\n%s\n", message);
+    shaders[1] = LoadShader(GL_FRAGMENT_SHADER, filename);
+    if (shaders[1] == 0) return false;
 
-        delete[] message;
-        return false;
-    }
-
-    m_shaderProgram = glCreateProgram();
-    glAttachShader(m_shaderProgram, vertexShader);
-    glAttachShader(m_shaderProgram, fragmentShader);
-    
-    glLinkProgram(m_shaderProgram);
-    
-    glDetachShader(m_shaderProgram, vertexShader);
-    glDetachShader(m_shaderProgram, fragmentShader);
-
-    glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, &status);
-
-    if (status != GL_TRUE)
-    {
-        GLint len;
-        glGetProgramiv(m_shaderProgram, GL_INFO_LOG_LENGTH, &len);
+    m_shaderProgram = LinkProgram(2, shaders);
+    if (m_shaderProgram == 0) return false;
 
-        GLchar *message = new GLchar[len + 1];
-        glGetProgramInfoLog(m_shaderProgram, len + 1, nullptr, message);
-
-        GetLogger()->Error("Shader program linking error occured!\n%s\n", message);
-
-        delete[] message;
-        return false;
-    }
-
-    glDeleteShader(vertexShader);
-    glDeleteShader(fragmentShader);
+    glDeleteShader(shaders[0]);
+    glDeleteShader(shaders[1]);
 
     glUseProgram(m_shaderProgram);
 
@@ -1245,8 +1160,8 @@ void CGL33Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int
 
     unsigned int size = vertexCount * sizeof(Vertex);
 
-    glBindVertexArray(info.vao);
-    glBindBuffer(GL_ARRAY_BUFFER, info.vbo);
+    BindVAO(info.vao);
+    BindVBO(info.vbo);
 
     // If needed vertex data is too large, increase the size of buffer
     if (info.size >= size)
@@ -1285,9 +1200,6 @@ void CGL33Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int
     UpdateRenderingMode();
 
     glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
-
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glBindVertexArray(0);
 }
 
 void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, Color color)
@@ -1297,8 +1209,8 @@ void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices,
 
     unsigned int size = vertexCount * sizeof(VertexTex2);
 
-    glBindVertexArray(info.vao);
-    glBindBuffer(GL_ARRAY_BUFFER, info.vbo);
+    BindVAO(info.vao);
+    BindVBO(info.vbo);
 
     // If needed vertex data is too large, increase the size of buffer
     if (info.size >= size)
@@ -1337,9 +1249,6 @@ void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices,
     UpdateRenderingMode();
 
     glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
-
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glBindVertexArray(0);
 }
 
 void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount)
@@ -1349,8 +1258,8 @@ void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i
 
     unsigned int size = vertexCount * sizeof(VertexCol);
 
-    glBindVertexArray(info.vao);
-    glBindBuffer(GL_ARRAY_BUFFER, info.vbo);
+    BindVAO(info.vao);
+    BindVBO(info.vbo);
 
     // If needed vertex data is too large, increase the size of buffer
     if (info.size >= size)
@@ -1387,9 +1296,6 @@ void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i
     UpdateRenderingMode();
 
     glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
-
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glBindVertexArray(0);
 }
 
 unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount)
@@ -1405,10 +1311,11 @@ unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const
     info.size = vertexCount * sizeof(Vertex);
 
     glGenVertexArrays(1, &info.vao);
-    glBindVertexArray(info.vao);
+    BindVAO(info.vao);
 
     glGenBuffers(1, &info.vbo);
-    glBindBuffer(GL_ARRAY_BUFFER, info.vbo);
+    BindVBO(info.vbo);
+
     glBufferData(GL_ARRAY_BUFFER, info.size, vertices, GL_STATIC_DRAW);
 
     // Vertex coordinate
@@ -1431,9 +1338,6 @@ unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const
     glDisableVertexAttribArray(4);
     glVertexAttrib2f(4, 0.0f, 0.0f);
 
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glBindVertexArray(0);
-
     m_vboObjects[id] = info;
 
     return id;
@@ -1452,10 +1356,11 @@ unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const
     info.size = vertexCount * sizeof(VertexTex2);
 
     glGenVertexArrays(1, &info.vao);
-    glBindVertexArray(info.vao);
+    BindVAO(info.vao);
 
     glGenBuffers(1, &info.vbo);
-    glBindBuffer(GL_ARRAY_BUFFER, info.vbo);
+    BindVBO(info.vbo);
+
     glBufferData(GL_ARRAY_BUFFER, info.size, vertices, GL_STATIC_DRAW);
 
     // Vertex coordinate
@@ -1478,9 +1383,6 @@ unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const
     glEnableVertexAttribArray(4);
     glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), reinterpret_cast<void*>(offsetof(VertexTex2, texCoord2)));
 
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glBindVertexArray(0);
-
     m_vboObjects[id] = info;
 
     return id;
@@ -1497,10 +1399,11 @@ unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const
     info.size = vertexCount * sizeof(VertexCol);
 
     glGenVertexArrays(1, &info.vao);
-    glBindVertexArray(info.vao);
+    BindVAO(info.vao);
 
     glGenBuffers(1, &info.vbo);
-    glBindBuffer(GL_ARRAY_BUFFER, info.vbo);
+    BindVBO(info.vbo);
+
     glBufferData(GL_ARRAY_BUFFER, info.size, vertices, GL_STATIC_DRAW);
 
     // Vertex coordinate
@@ -1523,9 +1426,6 @@ unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const
     glDisableVertexAttribArray(4);
     glVertexAttrib2f(4, 0.0f, 0.0f);
 
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glBindVertexArray(0);
-
     m_vboObjects[id] = info;
 
     return id;
@@ -1547,7 +1447,7 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
     info.vertexType = VERTEX_TYPE_NORMAL;
     info.vertexCount = vertexCount;
 
-    glBindBuffer(GL_ARRAY_BUFFER, info.vbo);
+    BindVBO(info.vbo);
 
     if (info.size < size)
     {
@@ -1562,7 +1462,7 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
 
     if (changed)        // Update vertex array bindings
     {
-        glBindVertexArray(info.vao);
+        BindVAO(info.vao);
 
         // Vertex coordinate
         glEnableVertexAttribArray(0);
@@ -1583,11 +1483,7 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
         // Texture coordinate 1
         glDisableVertexAttribArray(4);
         glVertexAttrib2f(4, 0.0f, 0.0f);
-
-        glBindVertexArray(0);
     }
-
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
 }
 
 void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount)
@@ -1605,7 +1501,8 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
     info.primitiveType = primitiveType;
     info.vertexType = VERTEX_TYPE_TEX2;
     info.vertexCount = vertexCount;
-    glBindBuffer(GL_ARRAY_BUFFER, info.vbo);
+
+    BindVBO(info.vbo);
 
     if (info.size < size)
     {
@@ -1620,7 +1517,7 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
 
     if (changed)        // Update vertex array bindings
     {
-        glBindVertexArray(info.vao);
+        BindVAO(info.vao);
 
         // Vertex coordinate
         glEnableVertexAttribArray(0);
@@ -1641,11 +1538,7 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
         // Texture coordinate 1
         glEnableVertexAttribArray(4);
         glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), reinterpret_cast<void*>(offsetof(VertexTex2, texCoord2)));
-        
-        glBindVertexArray(0);
     }
-
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
 }
 
 void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount)
@@ -1664,7 +1557,7 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
     info.vertexType = VERTEX_TYPE_COL;
     info.vertexCount = vertexCount;
 
-    glBindBuffer(GL_ARRAY_BUFFER, info.vbo);
+    BindVBO(info.vbo);
 
     if (info.size < size)
     {
@@ -1679,7 +1572,7 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
 
     if (changed)        // Update vertex array bindings
     {
-        glBindVertexArray(info.vao);
+        BindVAO(info.vao);
 
         // Vertex coordinate
         glEnableVertexAttribArray(0);
@@ -1700,11 +1593,7 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
         // Texture coordinate 1
         glDisableVertexAttribArray(4);
         glVertexAttrib2f(4, 0.0f, 0.0f);
-
-        glBindVertexArray(0);
     }
-
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
 }
 
 void CGL33Device::DrawStaticBuffer(unsigned int bufferId)
@@ -1717,12 +1606,10 @@ void CGL33Device::DrawStaticBuffer(unsigned int bufferId)
 
     UpdateRenderingMode();
 
-    glBindVertexArray(info.vao);
+    BindVAO(info.vao);
 
     GLenum mode = TranslateGfxPrimitive(info.primitiveType);
     glDrawArrays(mode, 0, info.vertexCount);
-
-    glBindVertexArray(0);
 }
 
 void CGL33Device::DestroyStaticBuffer(unsigned int bufferId)
@@ -1733,6 +1620,11 @@ void CGL33Device::DestroyStaticBuffer(unsigned int bufferId)
 
     VertexBufferInfo &info = (*it).second;
 
+    if (m_currentVAO == info.vao)
+        BindVAO(0);
+    if (m_currentVBO == info.vbo)
+        BindVBO(0);
+
     glDeleteBuffers(1, &info.vbo);
     glDeleteVertexArrays(1, &info.vao);
 
@@ -1846,9 +1738,9 @@ void CGL33Device::SetRenderState(RenderState state, bool enabled)
     else if (state == RENDER_STATE_OFFSCREEN_RENDERING)
     {
         if (m_framebuffer == 0)
-            InitOffscreenBuffer(2048, 2048);
+            InitOffscreenBuffer(1024, 1024);
 
-        m_offscreenRenderingEnabled = true;
+        m_offscreenRenderingEnabled = enabled;
 
         GLuint toBind = (enabled ? m_framebuffer : 0);
 
@@ -2077,4 +1969,20 @@ void CGL33Device::UpdateRenderingMode()
     glUniform1i(uni_ShadowTextureEnabled, enabled ? 1 : 0);
 }
 
+inline void CGL33Device::BindVBO(GLint vbo)
+{
+    if (m_currentVBO == vbo) return;
+
+    glBindBuffer(GL_ARRAY_BUFFER, vbo);
+    m_currentVBO = vbo;
+}
+
+inline void CGL33Device::BindVAO(GLint vao)
+{
+    if (m_currentVAO == vao) return;
+
+    glBindVertexArray(vao);
+    m_currentVAO = vao;
+}
+
 } // namespace Gfx
diff --git a/src/graphics/opengl/gl33device.h b/src/graphics/opengl/gl33device.h
index 2d0f8ab..479b5bb 100644
--- a/src/graphics/opengl/gl33device.h
+++ b/src/graphics/opengl/gl33device.h
@@ -151,6 +151,11 @@ private:
     //! Updates rendering mode
     void UpdateRenderingMode();
 
+    //! Binds VBO
+    inline void BindVBO(GLint vbo);
+    //! Binds VAO
+    inline void BindVAO(GLint vao);
+
 private:
     //! Current config
     GLDeviceConfig m_config;
@@ -214,6 +219,10 @@ private:
     std::map<unsigned int, VertexBufferInfo> m_vboObjects;
     //! Last ID of VBO object
     unsigned int m_lastVboId;
+    //! Currently bound VBO
+    GLint m_currentVBO;
+    //! Currently bound VAO
+    GLint m_currentVAO;
 
     // Offscreen buffer
     //! Framebuffer object
diff --git a/src/graphics/opengl/glutil.cpp b/src/graphics/opengl/glutil.cpp
index fd03b33..2465c5c 100644
--- a/src/graphics/opengl/glutil.cpp
+++ b/src/graphics/opengl/glutil.cpp
@@ -18,6 +18,8 @@
  */
 
 #include "graphics/opengl/glutil.h"
+#include "common/logger.h"
+#include <physfs.h>
 
 // Graphics module namespace
 namespace Gfx {
@@ -159,4 +161,80 @@ GLenum TranslateTextureCoordinateGen(int index)
     return textureCoordGen[index];
 }
 
+GLint LoadShader(GLint type, const char* filename)
+{
+    PHYSFS_file *file = PHYSFS_openRead(filename);
+    if (file == nullptr)
+    {
+        CLogger::GetInstance().Error("Cannot read shader source file\n");
+        CLogger::GetInstance().Error("Missing file \"%s\"\n", filename);
+        return 0;
+    }
+
+    char source[65536];
+    char *sources[] = { source };
+    int length = PHYSFS_read(file, source, 1, 65536);
+    source[length] = '\0';
+
+    PHYSFS_close(file);
+
+    GLuint shader = glCreateShader(type);
+    glShaderSource(shader, 1, sources, nullptr);
+    glCompileShader(shader);
+
+    GLint status;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+
+    if (status != GL_TRUE)
+    {
+        GLint len;
+        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
+
+        GLchar *message = new GLchar[len + 1];
+        glGetShaderInfoLog(shader, len + 1, nullptr, message);
+
+        GetLogger()->Error("Shader compilation error occured!\n%s\n", message);
+
+        delete[] message;
+        glDeleteShader(shader);
+        return 0;
+    }
+
+    return shader;
+}
+
+GLint LinkProgram(int count, GLint shaders[])
+{
+    GLint program = glCreateProgram();
+
+    for (int i = 0; i < count; i++)
+        glAttachShader(program, shaders[i]);
+
+    glLinkProgram(program);
+
+    for (int i = 0; i < count; i++)
+        glDetachShader(program, shaders[i]);
+
+    GLint status;
+    glGetProgramiv(program, GL_LINK_STATUS, &status);
+
+    if (status != GL_TRUE)
+    {
+        GLint len;
+        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len);
+
+        GLchar *message = new GLchar[len + 1];
+        glGetProgramInfoLog(program, len + 1, nullptr, message);
+
+        GetLogger()->Error("Shader program linking error occured!\n%s\n", message);
+
+        delete[] message;
+        glDeleteProgram(program);
+
+        return 0;
+    }
+
+    return program;
+}
+
 }
diff --git a/src/graphics/opengl/glutil.h b/src/graphics/opengl/glutil.h
index b0f0606..54086ec 100644
--- a/src/graphics/opengl/glutil.h
+++ b/src/graphics/opengl/glutil.h
@@ -88,4 +88,8 @@ GLenum TranslateTextureCoordinate(int index);
 
 GLenum TranslateTextureCoordinateGen(int index);
 
+GLint LoadShader(GLint type, const char* filename);
+
+GLint LinkProgram(int count, GLint shaders[]);
+
 } // namespace Gfx

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/colobot.git



More information about the Pkg-games-commits mailing list