1 #include "resource_pool.h"
16 ResourcePool::ResourcePool(size_t program_freelist_max_length)
17 : program_freelist_max_length(program_freelist_max_length) {
18 pthread_mutex_init(&lock, NULL);
21 ResourcePool::~ResourcePool()
23 assert(program_refcount.empty());
25 for (list<GLuint>::const_iterator freelist_it = program_freelist.begin();
26 freelist_it != program_freelist.end();
28 delete_program(*freelist_it);
30 assert(programs.empty());
31 assert(program_shaders.empty());
34 void ResourcePool::delete_program(GLuint glsl_program_num)
36 bool found_program = false;
37 for (std::map<std::pair<std::string, std::string>, GLuint>::iterator program_it = programs.begin();
38 program_it != programs.end();
40 if (program_it->second == glsl_program_num) {
41 programs.erase(program_it);
46 assert(found_program);
47 glDeleteProgram(glsl_program_num);
49 std::map<GLuint, std::pair<GLuint, GLuint> >::iterator shader_it =
50 program_shaders.find(glsl_program_num);
51 assert(shader_it != program_shaders.end());
53 glDeleteShader(shader_it->second.first);
54 glDeleteShader(shader_it->second.second);
55 program_shaders.erase(shader_it);
58 GLuint ResourcePool::compile_glsl_program(const string& vertex_shader, const string& fragment_shader)
60 GLuint glsl_program_num;
61 pthread_mutex_lock(&lock);
62 const pair<string, string> key(vertex_shader, fragment_shader);
63 if (programs.count(key)) {
64 // Already in the cache. Increment the refcount, or take it off the freelist
66 glsl_program_num = programs[key];
67 map<GLuint, int>::iterator refcount_it = program_refcount.find(glsl_program_num);
68 if (refcount_it != program_refcount.end()) {
69 ++refcount_it->second;
71 list<GLuint>::iterator freelist_it =
72 find(program_freelist.begin(), program_freelist.end(), glsl_program_num);
73 assert(freelist_it != program_freelist.end());
74 program_freelist.erase(freelist_it);
75 program_refcount.insert(make_pair(glsl_program_num, 1));
78 // Not in the cache. Compile the shaders.
79 glsl_program_num = glCreateProgram();
80 GLuint vs_obj = compile_shader(vertex_shader, GL_VERTEX_SHADER);
81 GLuint fs_obj = compile_shader(fragment_shader, GL_FRAGMENT_SHADER);
82 glAttachShader(glsl_program_num, vs_obj);
84 glAttachShader(glsl_program_num, fs_obj);
86 glLinkProgram(glsl_program_num);
89 if (movit_debug_level == MOVIT_DEBUG_ON) {
90 // Output shader to a temporary file, for easier debugging.
91 static int compiled_shader_num = 0;
93 sprintf(filename, "chain-%03d.frag", compiled_shader_num++);
94 FILE *fp = fopen(filename, "w");
99 fprintf(fp, "%s\n", fragment_shader.c_str());
103 programs.insert(make_pair(key, glsl_program_num));
104 program_refcount.insert(make_pair(glsl_program_num, 1));
105 program_shaders.insert(make_pair(glsl_program_num, make_pair(vs_obj, fs_obj)));
107 pthread_mutex_unlock(&lock);
108 return glsl_program_num;
111 void ResourcePool::release_glsl_program(GLuint glsl_program_num)
113 pthread_mutex_lock(&lock);
114 map<GLuint, int>::iterator refcount_it = program_refcount.find(glsl_program_num);
115 assert(refcount_it != program_refcount.end());
117 if (--refcount_it->second == 0) {
118 program_refcount.erase(refcount_it);
119 assert(find(program_freelist.begin(), program_freelist.end(), glsl_program_num)
120 == program_freelist.end());
121 program_freelist.push_front(glsl_program_num);
122 if (program_freelist.size() > program_freelist_max_length) {
123 delete_program(program_freelist.back());
124 program_freelist.pop_back();
128 pthread_mutex_unlock(&lock);