]> git.sesse.net Git - movit/blobdiff - resource_pool.cpp
Some refactoring in ResourcePool.
[movit] / resource_pool.cpp
index b560f1530bf4599692fdb1f63e026cc3cfa07994..46592d09917d12fa171fb3c5167431501bb4189b 100644 (file)
@@ -18,10 +18,12 @@ namespace movit {
 
 ResourcePool::ResourcePool(size_t program_freelist_max_length,
                            size_t texture_freelist_max_bytes,
-                           size_t fbo_freelist_max_length)
+                           size_t fbo_freelist_max_length,
+                           size_t vao_freelist_max_length)
        : program_freelist_max_length(program_freelist_max_length),
          texture_freelist_max_bytes(texture_freelist_max_bytes),
          fbo_freelist_max_length(fbo_freelist_max_length),
+         vao_freelist_max_length(vao_freelist_max_length),
          texture_freelist_bytes(0)
 {
        pthread_mutex_init(&lock, NULL);
@@ -128,19 +130,9 @@ GLuint ResourcePool::compile_glsl_program(const string& vertex_shader,
 
        const pair<string, string> key(vertex_shader, fragment_shader_processed);
        if (programs.count(key)) {
-               // Already in the cache. Increment the refcount, or take it off the freelist
-               // if it's zero.
+               // Already in the cache.
                glsl_program_num = programs[key];
-               map<GLuint, int>::iterator refcount_it = program_refcount.find(glsl_program_num);
-               if (refcount_it != program_refcount.end()) {
-                       ++refcount_it->second;
-               } else {
-                       list<GLuint>::iterator freelist_it =
-                               find(program_freelist.begin(), program_freelist.end(), glsl_program_num);
-                       assert(freelist_it != program_freelist.end());
-                       program_freelist.erase(freelist_it);
-                       program_refcount.insert(make_pair(glsl_program_num, 1));
-               }
+               increment_program_refcount(glsl_program_num);
        } else {
                // Not in the cache. Compile the shaders.
                GLuint vs_obj = compile_shader(vertex_shader, GL_VERTEX_SHADER);
@@ -149,31 +141,16 @@ GLuint ResourcePool::compile_glsl_program(const string& vertex_shader,
                check_error();
                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.
-                       static int compiled_shader_num = 0;
-                       char filename[256];
-                       sprintf(filename, "chain-%03d.frag", compiled_shader_num++);
-                       FILE *fp = fopen(filename, "w");
-                       if (fp == NULL) {
-                               perror(filename);
-                               exit(1);
-                       }
-                       fprintf(fp, "%s\n", fragment_shader_processed.c_str());
-                       fclose(fp);
-               }
+               output_debug_shader(fragment_shader_processed, "frag");
 
                programs.insert(make_pair(key, glsl_program_num));
-               program_refcount.insert(make_pair(glsl_program_num, 1));
+               add_master_program(glsl_program_num);
+
                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;
@@ -307,6 +284,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:
@@ -314,6 +292,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:
@@ -324,11 +303,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;
@@ -352,6 +333,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:
@@ -517,14 +504,82 @@ void ResourcePool::release_fbo(GLuint fbo_num)
        pthread_mutex_unlock(&lock);
 }
 
+GLuint ResourcePool::create_vec2_vao(const set<GLint> &attribute_indices, GLuint vbo_num)
+{
+       void *context = get_gl_context_identifier();
+
+       pthread_mutex_lock(&lock);
+       if (vao_freelist.count(context) != 0) {
+               // See if there's a VAO the freelist we can use.
+               list<VAOFormatIterator>::iterator end = vao_freelist[context].end();
+               for (list<VAOFormatIterator>::iterator freelist_it = vao_freelist[context].begin();
+                    freelist_it != end; ++freelist_it) {
+                       VAOFormatIterator vao_it = *freelist_it;
+                       if (vao_it->second.vbo_num == vbo_num &&
+                           vao_it->second.attribute_indices == attribute_indices) {
+                               vao_freelist[context].erase(freelist_it);
+                               pthread_mutex_unlock(&lock);
+                               return vao_it->second.vao_num;
+                       }
+               }
+       }
+
+       // Create a new one.
+       VAO vao_format;
+       vao_format.attribute_indices = attribute_indices;
+       vao_format.vbo_num = vbo_num;
+
+       glGenVertexArrays(1, &vao_format.vao_num);
+       check_error();
+       glBindVertexArray(vao_format.vao_num);
+       check_error();
+       glBindBuffer(GL_ARRAY_BUFFER, vbo_num);
+       check_error();
+
+       for (set<GLint>::const_iterator attr_it = attribute_indices.begin(); attr_it != attribute_indices.end(); ++attr_it) {
+               glEnableVertexAttribArray(*attr_it);
+               check_error();
+               glVertexAttribPointer(*attr_it, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
+               check_error();
+       }
+
+       glBindVertexArray(0);
+       check_error();
+       glBindBuffer(GL_ARRAY_BUFFER, 0);
+       check_error();
+
+       pair<void *, GLuint> key(context, vao_format.vao_num);
+       assert(vao_formats.count(key) == 0);
+       vao_formats.insert(make_pair(key, vao_format));
+
+       pthread_mutex_unlock(&lock);
+       return vao_format.vao_num;
+}
+
+void ResourcePool::release_vec2_vao(GLuint vao_num)
+{
+       void *context = get_gl_context_identifier();
+
+       pthread_mutex_lock(&lock);
+       VAOFormatIterator vao_it = vao_formats.find(make_pair(context, vao_num));
+       assert(vao_it != vao_formats.end());
+       vao_freelist[context].push_front(vao_it);
+
+       shrink_vao_freelist(context, vao_freelist_max_length);
+       pthread_mutex_unlock(&lock);
+}
+
 void ResourcePool::clean_context()
 {
        void *context = get_gl_context_identifier();
 
-       // Currently, we only need to worry about FBOs, as they are the only
-       // non-shareable resource we hold.
+       // Currently, we only need to worry about FBOs and VAOs, as they are the only
+       // non-shareable resources we hold.
        shrink_fbo_freelist(context, 0);
        fbo_freelist.erase(context);
+
+       shrink_vao_freelist(context, 0);
+       vao_freelist.erase(context);
 }
 
 void ResourcePool::cleanup_unlinked_fbos(void *context)
@@ -564,6 +619,58 @@ void ResourcePool::shrink_fbo_freelist(void *context, size_t max_length)
        }
 }
 
+void ResourcePool::shrink_vao_freelist(void *context, size_t max_length)
+{
+       list<VAOFormatIterator> &freelist = vao_freelist[context];
+       while (freelist.size() > max_length) {
+               VAOFormatIterator free_vao_it = freelist.back();
+               glDeleteVertexArrays(1, &free_vao_it->second.vao_num);
+               check_error();
+               vao_formats.erase(free_vao_it);
+               freelist.pop_back();
+       }
+}
+
+void ResourcePool::increment_program_refcount(GLuint program_num)
+{
+       map<GLuint, int>::iterator refcount_it = program_refcount.find(program_num);
+       if (refcount_it != program_refcount.end()) {
+               ++refcount_it->second;
+       } else {
+               list<GLuint>::iterator freelist_it =
+                       find(program_freelist.begin(), program_freelist.end(), program_num);
+               assert(freelist_it != program_freelist.end());
+               program_freelist.erase(freelist_it);
+               program_refcount.insert(make_pair(program_num, 1));
+       }
+}
+
+void ResourcePool::output_debug_shader(const string &shader_src, const string &suffix)
+{
+       if (movit_debug_level == MOVIT_DEBUG_ON) {
+               // Output shader to a temporary file, for easier debugging.
+               static int compiled_shader_num = 0;
+               char filename[256];
+               sprintf(filename, "chain-%03d.%s", compiled_shader_num++, suffix.c_str());
+               FILE *fp = fopen(filename, "w");
+               if (fp == NULL) {
+                       perror(filename);
+                       exit(1);
+               }
+               fprintf(fp, "%s\n", shader_src.c_str());
+               fclose(fp);
+       }
+}
+
+void ResourcePool::add_master_program(GLuint program_num)
+{
+       program_refcount.insert(make_pair(program_num, 1));
+       stack<GLuint> instances;
+       instances.push(program_num);
+       program_instances.insert(make_pair(program_num, instances));
+       program_masters.insert(make_pair(program_num, program_num));
+}
+
 size_t ResourcePool::estimate_texture_size(const Texture2D &texture_format)
 {
        size_t bytes_per_pixel;
@@ -618,6 +725,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);