]> git.sesse.net Git - movit/blobdiff - resource_pool.cpp
Fix compiling without C++11.
[movit] / resource_pool.cpp
index 6939fe01d50a61131d4357858c6d82a4d9361da2..5b0499972121934a643c5351f8b62cf4a94bc1d1 100644 (file)
@@ -89,14 +89,24 @@ void ResourcePool::delete_program(GLuint glsl_program_num)
                }
        }
        assert(found_program);
-       glDeleteProgram(glsl_program_num);
 
-       map<GLuint, pair<GLuint, GLuint> >::iterator shader_it =
+       map<GLuint, stack<GLuint> >::iterator instance_list_it = program_instances.find(glsl_program_num);
+       assert(instance_list_it != program_instances.end());
+
+       while (!instance_list_it->second.empty()) {
+               GLuint instance_program_num = instance_list_it->second.top();
+               instance_list_it->second.pop();
+               glDeleteProgram(instance_program_num);
+               program_masters.erase(instance_program_num);
+       }
+       program_instances.erase(instance_list_it);
+
+       map<GLuint, ShaderSpec>::iterator shader_it =
                program_shaders.find(glsl_program_num);
        assert(shader_it != program_shaders.end());
 
-       glDeleteShader(shader_it->second.first);
-       glDeleteShader(shader_it->second.second);
+       glDeleteShader(shader_it->second.vs_obj);
+       glDeleteShader(shader_it->second.fs_obj);
        program_shaders.erase(shader_it);
 }
 
@@ -133,36 +143,11 @@ GLuint ResourcePool::compile_glsl_program(const string& vertex_shader,
                }
        } else {
                // Not in the cache. Compile the shaders.
-               glsl_program_num = glCreateProgram();
-               check_error();
                GLuint vs_obj = compile_shader(vertex_shader, GL_VERTEX_SHADER);
                check_error();
                GLuint fs_obj = compile_shader(fragment_shader_processed, GL_FRAGMENT_SHADER);
                check_error();
-               glAttachShader(glsl_program_num, vs_obj);
-               check_error();
-               glAttachShader(glsl_program_num, fs_obj);
-               check_error();
-
-               // Bind the outputs, if we have multiple ones.
-               if (fragment_shader_outputs.size() > 1) {
-                       for (unsigned output_index = 0; output_index < fragment_shader_outputs.size(); ++output_index) {
-                               glBindFragDataLocation(glsl_program_num, output_index,
-                                                      fragment_shader_outputs[output_index].c_str());
-                       }
-               }
-
-               glLinkProgram(glsl_program_num);
-               check_error();
-
-               GLint success;
-               glGetProgramiv(glsl_program_num, GL_LINK_STATUS, &success);
-               if (success == GL_FALSE) {
-                       GLchar error_log[1024] = {0};
-                       glGetProgramInfoLog(glsl_program_num, 1024, NULL, error_log);
-                       fprintf(stderr, "Error linking program: %s\n", error_log);
-                       exit(1);
-               }
+               glsl_program_num = link_program(vs_obj, fs_obj, fragment_shader_outputs);
 
                if (movit_debug_level == MOVIT_DEBUG_ON) {
                        // Output shader to a temporary file, for easier debugging.
@@ -180,12 +165,54 @@ GLuint ResourcePool::compile_glsl_program(const string& vertex_shader,
 
                programs.insert(make_pair(key, glsl_program_num));
                program_refcount.insert(make_pair(glsl_program_num, 1));
-               program_shaders.insert(make_pair(glsl_program_num, make_pair(vs_obj, fs_obj)));
+               ShaderSpec spec;
+               spec.vs_obj = vs_obj;
+               spec.fs_obj = fs_obj;
+               spec.fragment_shader_outputs = fragment_shader_outputs;
+               program_shaders.insert(make_pair(glsl_program_num, spec));
+               stack<GLuint> instances;
+               instances.push(glsl_program_num);
+               program_instances.insert(make_pair(glsl_program_num, instances));
+               program_masters.insert(make_pair(glsl_program_num, glsl_program_num));
        }
        pthread_mutex_unlock(&lock);
        return glsl_program_num;
 }
 
+GLuint ResourcePool::link_program(GLuint vs_obj,
+                                  GLuint fs_obj,
+                                  const vector<string>& fragment_shader_outputs)
+{
+       GLuint glsl_program_num = glCreateProgram();
+       check_error();
+       glAttachShader(glsl_program_num, vs_obj);
+       check_error();
+       glAttachShader(glsl_program_num, fs_obj);
+       check_error();
+
+       // Bind the outputs, if we have multiple ones.
+       if (fragment_shader_outputs.size() > 1) {
+               for (unsigned output_index = 0; output_index < fragment_shader_outputs.size(); ++output_index) {
+                       glBindFragDataLocation(glsl_program_num, output_index,
+                                              fragment_shader_outputs[output_index].c_str());
+               }
+       }
+
+       glLinkProgram(glsl_program_num);
+       check_error();
+
+       GLint success;
+       glGetProgramiv(glsl_program_num, GL_LINK_STATUS, &success);
+       if (success == GL_FALSE) {
+               GLchar error_log[1024] = {0};
+               glGetProgramInfoLog(glsl_program_num, 1024, NULL, error_log);
+               fprintf(stderr, "Error linking program: %s\n", error_log);
+               exit(1);
+       }
+
+       return glsl_program_num;
+}
+
 void ResourcePool::release_glsl_program(GLuint glsl_program_num)
 {
        pthread_mutex_lock(&lock);
@@ -206,6 +233,51 @@ void ResourcePool::release_glsl_program(GLuint glsl_program_num)
        pthread_mutex_unlock(&lock);
 }
 
+GLuint ResourcePool::use_glsl_program(GLuint glsl_program_num)
+{
+       pthread_mutex_lock(&lock);
+       assert(program_instances.count(glsl_program_num));
+       stack<GLuint> &instances = program_instances[glsl_program_num];
+
+       GLuint instance_program_num;
+       if (!instances.empty()) {
+               // There's an unused instance of this program; just return it.
+               instance_program_num = instances.top();
+               instances.pop();
+       } else {
+               // We need to clone this program. (unuse_glsl_program()
+               // will later put it onto the list.)
+               map<GLuint, ShaderSpec>::iterator shader_it =
+                       program_shaders.find(glsl_program_num);
+               assert(shader_it != program_shaders.end());
+
+               instance_program_num = link_program(
+                       shader_it->second.vs_obj,
+                       shader_it->second.fs_obj,
+                       shader_it->second.fragment_shader_outputs);
+               program_masters.insert(make_pair(instance_program_num, glsl_program_num));
+       }
+       pthread_mutex_unlock(&lock);
+
+       glUseProgram(instance_program_num);
+       return instance_program_num;
+}
+
+void ResourcePool::unuse_glsl_program(GLuint instance_program_num)
+{
+       pthread_mutex_lock(&lock);
+
+       map<GLuint, GLuint>::const_iterator master_it = program_masters.find(instance_program_num);
+       assert(master_it != program_masters.end());
+
+       assert(program_instances.count(master_it->second));
+       stack<GLuint> &instances = program_instances[master_it->second];
+
+       instances.push(instance_program_num);
+
+       pthread_mutex_unlock(&lock);
+}
+
 GLuint ResourcePool::create_2d_texture(GLint internal_format, GLsizei width, GLsizei height)
 {
        assert(width > 0);
@@ -235,6 +307,7 @@ GLuint ResourcePool::create_2d_texture(GLint internal_format, GLsizei width, GLs
        switch (internal_format) {
        case GL_RGBA32F_ARB:
        case GL_RGBA16F_ARB:
+       case GL_RGBA16:
        case GL_RGBA8:
        case GL_RGB10_A2:
        case GL_SRGB8_ALPHA8:
@@ -242,6 +315,7 @@ GLuint ResourcePool::create_2d_texture(GLint internal_format, GLsizei width, GLs
                break;
        case GL_RGB32F:
        case GL_RGB16F:
+       case GL_RGB16:
        case GL_R11F_G11F_B10F:
        case GL_RGB8:
        case GL_RGB10:
@@ -252,11 +326,13 @@ GLuint ResourcePool::create_2d_texture(GLint internal_format, GLsizei width, GLs
                break;
        case GL_RG32F:
        case GL_RG16F:
+       case GL_RG16:
        case GL_RG8:
                format = GL_RG;
                break;
        case GL_R32F:
        case GL_R16F:
+       case GL_R16:
        case GL_R8:
                format = GL_RED;
                break;
@@ -280,6 +356,12 @@ GLuint ResourcePool::create_2d_texture(GLint internal_format, GLsizei width, GLs
        case GL_R16F:
                type = GL_FLOAT;
                break;
+       case GL_RGBA16:
+       case GL_RGB16:
+       case GL_RG16:
+       case GL_R16:
+               type = GL_UNSIGNED_SHORT;
+               break;
        case GL_SRGB8_ALPHA8:
        case GL_SRGB8:
        case GL_RGBA8:
@@ -546,6 +628,18 @@ size_t ResourcePool::estimate_texture_size(const Texture2D &texture_format)
        case GL_RGB565:
                bytes_per_pixel = 2;
                break;
+       case GL_RGBA16:
+               bytes_per_pixel = 8;
+               break;
+       case GL_RGB16:
+               bytes_per_pixel = 6;
+               break;
+       case GL_RG16:
+               bytes_per_pixel = 4;
+               break;
+       case GL_R16:
+               bytes_per_pixel = 2;
+               break;
        default:
                // TODO: Add more here as needed.
                assert(false);