}
}
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);
}
}
} 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.
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);
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);
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:
break;
case GL_RGB32F:
case GL_RGB16F:
+ case GL_RGB16:
case GL_R11F_G11F_B10F:
case GL_RGB8:
case GL_RGB10:
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;
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:
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);