]> git.sesse.net Git - movit/blobdiff - resource_pool.cpp
Explicitly bind fragment shader outputs in order.
[movit] / resource_pool.cpp
index 240c3b2c58b332d3b2a02b7fbff8cde5bfe206b2..944910bde3829320abcbdd859b861c3995b3da4f 100644 (file)
@@ -55,7 +55,7 @@ ResourcePool::~ResourcePool()
        void *context = get_gl_context_identifier();
        cleanup_unlinked_fbos(context);
 
-       for (map<void *, std::list<GLuint> >::iterator context_it = fbo_freelist.begin();
+       for (map<void *, std::list<FBOFormatIterator> >::iterator context_it = fbo_freelist.begin();
             context_it != fbo_freelist.end();
             ++context_it) {
                if (context_it->first != context) {
@@ -63,15 +63,13 @@ ResourcePool::~ResourcePool()
                        assert(context_it->second.empty());
                        continue;
                }
-               for (list<GLuint>::const_iterator freelist_it = context_it->second.begin();
+               for (list<FBOFormatIterator>::const_iterator freelist_it = context_it->second.begin();
                     freelist_it != context_it->second.end();
                     ++freelist_it) {
-                       pair<void *, GLuint> key(context, *freelist_it);
-                       GLuint free_fbo_num = *freelist_it;
-                       assert(fbo_formats.count(key) != 0);
-                       fbo_formats.erase(key);
-                       glDeleteFramebuffers(1, &free_fbo_num);
+                       FBOFormatIterator fbo_it = *freelist_it;
+                       glDeleteFramebuffers(1, &fbo_it->second.fbo_num);
                        check_error();
+                       fbo_formats.erase(fbo_it);
                }
        }
 
@@ -102,11 +100,23 @@ void ResourcePool::delete_program(GLuint glsl_program_num)
        program_shaders.erase(shader_it);
 }
 
-GLuint ResourcePool::compile_glsl_program(const string& vertex_shader, const string& fragment_shader)
+GLuint ResourcePool::compile_glsl_program(const string& vertex_shader,
+                                          const string& fragment_shader,
+                                          const vector<string>& fragment_shader_outputs)
 {
        GLuint glsl_program_num;
        pthread_mutex_lock(&lock);
-       const pair<string, string> key(vertex_shader, fragment_shader);
+
+       // Augment the fragment shader program text with the outputs, so that they become
+       // part of the key. Also potentially useful for debugging.
+       string fragment_shader_processed = fragment_shader;
+       for (unsigned output_index = 0; output_index < fragment_shader_outputs.size(); ++output_index) {
+               char buf[256];
+               snprintf(buf, sizeof(buf), "// Bound output: %s\n", fragment_shader_outputs[output_index].c_str());
+               fragment_shader_processed += buf;
+       }
+
+       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.
@@ -127,12 +137,21 @@ GLuint ResourcePool::compile_glsl_program(const string& vertex_shader, const str
                check_error();
                GLuint vs_obj = compile_shader(vertex_shader, GL_VERTEX_SHADER);
                check_error();
-               GLuint fs_obj = compile_shader(fragment_shader, GL_FRAGMENT_SHADER);
+               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();
 
@@ -155,7 +174,7 @@ GLuint ResourcePool::compile_glsl_program(const string& vertex_shader, const str
                                perror(filename);
                                exit(1);
                        }
-                       fprintf(fp, "%s\n", fragment_shader.c_str());
+                       fprintf(fp, "%s\n", fragment_shader_processed.c_str());
                        fclose(fp);
                }
 
@@ -342,20 +361,17 @@ GLuint ResourcePool::create_fbo(GLuint texture0_num, GLuint texture1_num, GLuint
        pthread_mutex_lock(&lock);
        if (fbo_freelist.count(context) != 0) {
                // See if there's an FBO on the freelist we can use.
-               for (list<GLuint>::iterator freelist_it = fbo_freelist[context].begin();
-                    freelist_it != fbo_freelist[context].end();
-                    ++freelist_it) {
-                       GLuint fbo_num = *freelist_it;
-                       map<pair<void *, GLuint>, FBO>::const_iterator format_it =
-                               fbo_formats.find(make_pair(context, fbo_num));
-                       assert(format_it != fbo_formats.end());
-                       if (format_it->second.texture_num[0] == texture0_num &&
-                           format_it->second.texture_num[1] == texture1_num &&
-                           format_it->second.texture_num[2] == texture2_num &&
-                           format_it->second.texture_num[3] == texture3_num) {
+               list<FBOFormatIterator>::iterator end = fbo_freelist[context].end();
+               for (list<FBOFormatIterator>::iterator freelist_it = fbo_freelist[context].begin();
+                    freelist_it != end; ++freelist_it) {
+                       FBOFormatIterator fbo_it = *freelist_it;
+                       if (fbo_it->second.texture_num[0] == texture0_num &&
+                           fbo_it->second.texture_num[1] == texture1_num &&
+                           fbo_it->second.texture_num[2] == texture2_num &&
+                           fbo_it->second.texture_num[3] == texture3_num) {
                                fbo_freelist[context].erase(freelist_it);
                                pthread_mutex_unlock(&lock);
-                               return fbo_num;
+                               return fbo_it->second.fbo_num;
                        }
                }
        }
@@ -367,10 +383,9 @@ GLuint ResourcePool::create_fbo(GLuint texture0_num, GLuint texture1_num, GLuint
        fbo_format.texture_num[2] = texture2_num;
        fbo_format.texture_num[3] = texture3_num;
 
-       GLuint fbo_num;
-       glGenFramebuffers(1, &fbo_num);
+       glGenFramebuffers(1, &fbo_format.fbo_num);
        check_error();
-       glBindFramebuffer(GL_FRAMEBUFFER, fbo_num);
+       glBindFramebuffer(GL_FRAMEBUFFER, fbo_format.fbo_num);
        check_error();
 
        GLenum bufs[num_fbo_attachments];
@@ -397,12 +412,12 @@ GLuint ResourcePool::create_fbo(GLuint texture0_num, GLuint texture1_num, GLuint
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        check_error();
 
-       pair<void *, GLuint> key(context, fbo_num);
+       pair<void *, GLuint> key(context, fbo_format.fbo_num);
        assert(fbo_formats.count(key) == 0);
        fbo_formats.insert(make_pair(key, fbo_format));
 
        pthread_mutex_unlock(&lock);
-       return fbo_num;
+       return fbo_format.fbo_num;
 }
 
 void ResourcePool::release_fbo(GLuint fbo_num)
@@ -410,8 +425,9 @@ void ResourcePool::release_fbo(GLuint fbo_num)
        void *context = get_gl_context_identifier();
 
        pthread_mutex_lock(&lock);
-       fbo_freelist[context].push_front(fbo_num);
-       assert(fbo_formats.count(make_pair(context, fbo_num)) != 0);
+       FBOFormatIterator fbo_it = fbo_formats.find(make_pair(context, fbo_num));
+       assert(fbo_it != fbo_formats.end());
+       fbo_freelist[context].push_front(fbo_it);
 
        // Now that we're in this context, free up any FBOs that are connected
        // to deleted textures (in release_2d_texture).
@@ -433,24 +449,22 @@ void ResourcePool::clean_context()
 
 void ResourcePool::cleanup_unlinked_fbos(void *context)
 {
-       for (list<GLuint>::iterator freelist_it = fbo_freelist[context].begin();
-            freelist_it != fbo_freelist[context].end(); ) {
-               GLuint fbo_num = *freelist_it;
-               pair<void *, GLuint> key(context, fbo_num);
-               assert(fbo_formats.count(key) != 0);
+       list<FBOFormatIterator>::iterator end = fbo_freelist[context].end();
+       for (list<FBOFormatIterator>::iterator freelist_it = fbo_freelist[context].begin(); freelist_it != end; ) {
+               FBOFormatIterator fbo_it = *freelist_it;
 
                bool all_unlinked = true;
                for (unsigned i = 0; i < num_fbo_attachments; ++i) {
-                       if (fbo_formats[key].texture_num[i] != 0 &&
-                           fbo_formats[key].texture_num[i] != GL_INVALID_INDEX) {
+                       if (fbo_it->second.texture_num[i] != 0 &&
+                           fbo_it->second.texture_num[i] != GL_INVALID_INDEX) {
                                all_unlinked = false;
                                break;
                        }
                }
                if (all_unlinked) {
-                       fbo_formats.erase(key);
-                       glDeleteFramebuffers(1, &fbo_num);
+                       glDeleteFramebuffers(1, &fbo_it->second.fbo_num);
                        check_error();
+                       fbo_formats.erase(fbo_it);
                        fbo_freelist[context].erase(freelist_it++);
                } else {
                        freelist_it++;
@@ -460,14 +474,13 @@ void ResourcePool::cleanup_unlinked_fbos(void *context)
 
 void ResourcePool::shrink_fbo_freelist(void *context, size_t max_length)
 {
-       while (fbo_freelist[context].size() > max_length) {
-               GLuint free_fbo_num = fbo_freelist[context].back();
-               pair<void *, GLuint> key(context, free_fbo_num);
-               fbo_freelist[context].pop_back();
-               assert(fbo_formats.count(key) != 0);
-               fbo_formats.erase(key);
-               glDeleteFramebuffers(1, &free_fbo_num);
+       list<FBOFormatIterator> &freelist = fbo_freelist[context];
+       while (freelist.size() > max_length) {
+               FBOFormatIterator free_fbo_it = freelist.back();
+               glDeleteFramebuffers(1, &free_fbo_it->second.fbo_num);
                check_error();
+               fbo_formats.erase(free_fbo_it);
+               freelist.pop_back();
        }
 }