X-Git-Url: https://git.sesse.net/?p=movit;a=blobdiff_plain;f=effect_chain.cpp;h=f800d1ea40ce62e8dadab19940a5b3a228c1afd2;hp=9b77ef032f49f5359df6fb1925852b1b9b6bc610;hb=refs%2Fheads%2Fubo;hpb=c1bd648471212ae960a26c1fb518223416a83f4b diff --git a/effect_chain.cpp b/effect_chain.cpp index 9b77ef0..f800d1e 100644 --- a/effect_chain.cpp +++ b/effect_chain.cpp @@ -1,5 +1,3 @@ -#define GL_GLEXT_PROTOTYPES 1 - #include #include #include @@ -34,12 +32,13 @@ using namespace std; namespace movit { -EffectChain::EffectChain(float aspect_nom, float aspect_denom, ResourcePool *resource_pool) +EffectChain::EffectChain(float aspect_nom, float aspect_denom, ResourcePool *resource_pool, GLenum intermediate_format) : aspect_nom(aspect_nom), aspect_denom(aspect_denom), output_color_rgba(false), output_color_ycbcr(false), dither_effect(NULL), + intermediate_format(intermediate_format), num_dither_bits(0), output_origin(OUTPUT_ORIGIN_BOTTOM_LEFT), finalized(false), @@ -276,6 +275,7 @@ template void extract_uniform_declarations(const vector > &effect_uniforms, const string &type_specifier, const string &effect_id, + bool in_ubo_block, vector > *phase_uniforms, string *glsl_string) { @@ -283,8 +283,10 @@ void extract_uniform_declarations(const vector > &effect_uniforms, phase_uniforms->push_back(effect_uniforms[i]); phase_uniforms->back().prefix = effect_id; - *glsl_string += string("uniform ") + type_specifier + " " + effect_id - + "_" + effect_uniforms[i].name + ";\n"; + if (!in_ubo_block) { + *glsl_string += "uniform "; + } + *glsl_string += type_specifier + " " + effect_id + "_" + effect_uniforms[i].name + ";\n"; } } @@ -292,6 +294,7 @@ template void extract_uniform_array_declarations(const vector > &effect_uniforms, const string &type_specifier, const string &effect_id, + bool in_ubo_block, vector > *phase_uniforms, string *glsl_string) { @@ -299,8 +302,12 @@ void extract_uniform_array_declarations(const vector > &effect_unifor phase_uniforms->push_back(effect_uniforms[i]); phase_uniforms->back().prefix = effect_id; + if (!in_ubo_block) { + *glsl_string += "uniform "; + } + char buf[256]; - snprintf(buf, sizeof(buf), "uniform %s %s_%s[%d];\n", + snprintf(buf, sizeof(buf), "%s %s_%s[%d];\n", type_specifier.c_str(), effect_id.c_str(), effect_uniforms[i].name.c_str(), int(effect_uniforms[i].num_values)); @@ -314,6 +321,7 @@ void collect_uniform_locations(GLuint glsl_program_num, vector > *pha for (unsigned i = 0; i < phase_uniforms->size(); ++i) { Uniform &uniform = (*phase_uniforms)[i]; uniform.location = get_uniform_location(glsl_program_num, uniform.prefix, uniform.name); + get_uniform_offset_and_size(glsl_program_num, uniform.prefix, uniform.name, &uniform.ubo_offset, &uniform.ubo_num_elem); } } @@ -423,24 +431,34 @@ void EffectChain::compile_glsl_program(Phase *phase) // before in the output source, since output_fragment_shader() is allowed // to register new uniforms (e.g. arrays that are of unknown length until // finalization time). - // TODO: Make a uniform block for platforms that support it. string frag_shader_uniforms = ""; for (unsigned i = 0; i < phase->effects.size(); ++i) { + const bool in_ubo_block = true; // TODO: Check for the extension. Node *node = phase->effects[i]; Effect *effect = node->effect; const string effect_id = phase->effect_ids[node]; - extract_uniform_declarations(effect->uniforms_sampler2d, "sampler2D", effect_id, &phase->uniforms_sampler2d, &frag_shader_uniforms); - extract_uniform_declarations(effect->uniforms_bool, "bool", effect_id, &phase->uniforms_bool, &frag_shader_uniforms); - extract_uniform_declarations(effect->uniforms_int, "int", effect_id, &phase->uniforms_int, &frag_shader_uniforms); - extract_uniform_declarations(effect->uniforms_float, "float", effect_id, &phase->uniforms_float, &frag_shader_uniforms); - extract_uniform_declarations(effect->uniforms_vec2, "vec2", effect_id, &phase->uniforms_vec2, &frag_shader_uniforms); - extract_uniform_declarations(effect->uniforms_vec3, "vec3", effect_id, &phase->uniforms_vec3, &frag_shader_uniforms); - extract_uniform_declarations(effect->uniforms_vec4, "vec4", effect_id, &phase->uniforms_vec4, &frag_shader_uniforms); - extract_uniform_array_declarations(effect->uniforms_float_array, "float", effect_id, &phase->uniforms_float, &frag_shader_uniforms); - extract_uniform_array_declarations(effect->uniforms_vec2_array, "vec2", effect_id, &phase->uniforms_vec2, &frag_shader_uniforms); - extract_uniform_array_declarations(effect->uniforms_vec3_array, "vec3", effect_id, &phase->uniforms_vec3, &frag_shader_uniforms); - extract_uniform_array_declarations(effect->uniforms_vec4_array, "vec4", effect_id, &phase->uniforms_vec4, &frag_shader_uniforms); - extract_uniform_declarations(effect->uniforms_mat3, "mat3", effect_id, &phase->uniforms_mat3, &frag_shader_uniforms); + extract_uniform_declarations(effect->uniforms_bool, "bool", effect_id, in_ubo_block, &phase->uniforms_bool, &frag_shader_uniforms); + extract_uniform_declarations(effect->uniforms_int, "int", effect_id, in_ubo_block, &phase->uniforms_int, &frag_shader_uniforms); + extract_uniform_declarations(effect->uniforms_float, "float", effect_id, in_ubo_block, &phase->uniforms_float, &frag_shader_uniforms); + extract_uniform_declarations(effect->uniforms_vec2, "vec2", effect_id, in_ubo_block, &phase->uniforms_vec2, &frag_shader_uniforms); + extract_uniform_declarations(effect->uniforms_vec3, "vec3", effect_id, in_ubo_block, &phase->uniforms_vec3, &frag_shader_uniforms); + extract_uniform_declarations(effect->uniforms_vec4, "vec4", effect_id, in_ubo_block, &phase->uniforms_vec4, &frag_shader_uniforms); + extract_uniform_array_declarations(effect->uniforms_float_array, "float", effect_id, in_ubo_block, &phase->uniforms_float, &frag_shader_uniforms); + extract_uniform_array_declarations(effect->uniforms_vec2_array, "vec2", effect_id, in_ubo_block, &phase->uniforms_vec2, &frag_shader_uniforms); + extract_uniform_array_declarations(effect->uniforms_vec3_array, "vec3", effect_id, in_ubo_block, &phase->uniforms_vec3, &frag_shader_uniforms); + extract_uniform_array_declarations(effect->uniforms_vec4_array, "vec4", effect_id, in_ubo_block, &phase->uniforms_vec4, &frag_shader_uniforms); + extract_uniform_declarations(effect->uniforms_mat3, "mat3", effect_id, in_ubo_block, &phase->uniforms_mat3, &frag_shader_uniforms); + } + if (!frag_shader_uniforms.empty()) { + frag_shader_uniforms = "layout(packed) uniform MovitUniforms {\n" + frag_shader_uniforms + "};\n"; + } + + // Samplers must be outside the UBO block. + for (unsigned i = 0; i < phase->effects.size(); ++i) { + Node *node = phase->effects[i]; + Effect *effect = node->effect; + const string effect_id = phase->effect_ids[node]; + extract_uniform_declarations(effect->uniforms_sampler2d, "sampler2D", effect_id, /*in_ubo_block=*/false, &phase->uniforms_sampler2d, &frag_shader_uniforms); } frag_shader = frag_shader_header + frag_shader_uniforms + frag_shader; @@ -467,6 +485,34 @@ void EffectChain::compile_glsl_program(Phase *phase) phase->attribute_indexes.insert(texcoord_attribute_index); } + // Create an UBO for holding the uniforms. This UBO will be updated each frame. + // TODO: Delete the block on destruction. + phase->uniform_block_index = glGetUniformBlockIndex(phase->glsl_program_num, "MovitUniforms"); + if (phase->uniform_block_index != GL_INVALID_INDEX) { + glGenBuffers(1, &phase->ubo); + check_error(); + GLsizei block_size; + glGetActiveUniformBlockiv( + phase->glsl_program_num, phase->uniform_block_index, + GL_UNIFORM_BLOCK_DATA_SIZE, &block_size); + check_error(); + phase->ubo_data.resize(block_size); + + glBindBuffer(GL_UNIFORM_BUFFER, phase->ubo); + check_error(); + glBufferData(GL_UNIFORM_BUFFER, block_size, NULL, GL_DYNAMIC_DRAW); + check_error(); + + // Associate the uniform block with binding point 0, + // and attach the UBO to that binding point. + glUniformBlockBinding(phase->glsl_program_num, phase->uniform_block_index, 0); + check_error(); + glBindBufferBase(GL_UNIFORM_BUFFER, 0, phase->ubo); + check_error(); + } else { + phase->ubo = GL_INVALID_INDEX; + } + // Collect the resulting location numbers for each uniform. collect_uniform_locations(phase->glsl_program_num, &phase->uniforms_sampler2d); collect_uniform_locations(phase->glsl_program_num, &phase->uniforms_bool); @@ -476,6 +522,9 @@ void EffectChain::compile_glsl_program(Phase *phase) collect_uniform_locations(phase->glsl_program_num, &phase->uniforms_vec3); collect_uniform_locations(phase->glsl_program_num, &phase->uniforms_vec4); collect_uniform_locations(phase->glsl_program_num, &phase->uniforms_mat3); + + glBindBuffer(GL_UNIFORM_BUFFER, 0); + check_error(); } // Construct GLSL programs, starting at the given effect and following @@ -652,9 +701,8 @@ Phase *EffectChain::construct_phase(Node *output, map *complete // Actually make the shader for this phase. compile_glsl_program(phase); - // Initialize timer objects. + // Initialize timers. if (movit_timer_queries_supported) { - glGenQueries(1, &phase->timer_query_object); phase->time_elapsed_ns = 0; phase->num_measured_iterations = 0; } @@ -1695,6 +1743,8 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height check_error(); glDisable(GL_DITHER); check_error(); + glEnable(GL_FRAMEBUFFER_SRGB); + check_error(); // Save original viewport. GLuint x = 0, y = 0; @@ -1738,7 +1788,15 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height Phase *phase = phases[phase_num]; if (do_phase_timing) { - glBeginQuery(GL_TIME_ELAPSED, phase->timer_query_object); + GLuint timer_query_object; + if (phase->timer_query_objects_free.empty()) { + glGenQueries(1, &timer_query_object); + } else { + timer_query_object = phase->timer_query_objects_free.front(); + phase->timer_query_objects_free.pop_front(); + } + glBeginQuery(GL_TIME_ELAPSED, timer_query_object); + phase->timer_query_objects_running.push_back(timer_query_object); } if (phase_num == phases.size() - 1) { // Last phase goes to the output the user specified. @@ -1758,13 +1816,6 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height } } - for (set::iterator attr_it = bound_attribute_indices.begin(); - attr_it != bound_attribute_indices.end(); - ++attr_it) { - glDisableVertexAttribArray(*attr_it); - check_error(); - } - for (map::const_iterator texture_it = output_textures.begin(); texture_it != output_textures.end(); ++texture_it) { @@ -1787,14 +1838,22 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height // Get back the timer queries. for (unsigned phase_num = 0; phase_num < phases.size(); ++phase_num) { Phase *phase = phases[phase_num]; - GLint available = 0; - while (!available) { - glGetQueryObjectiv(phase->timer_query_object, GL_QUERY_RESULT_AVAILABLE, &available); + for (std::list::iterator timer_it = phase->timer_query_objects_running.begin(); + timer_it != phase->timer_query_objects_running.end(); ) { + GLint timer_query_object = *timer_it; + GLint available; + glGetQueryObjectiv(timer_query_object, GL_QUERY_RESULT_AVAILABLE, &available); + if (available) { + GLuint64 time_elapsed; + glGetQueryObjectui64v(timer_query_object, GL_QUERY_RESULT, &time_elapsed); + phase->time_elapsed_ns += time_elapsed; + ++phase->num_measured_iterations; + phase->timer_query_objects_free.push_back(timer_query_object); + phase->timer_query_objects_running.erase(timer_it++); + } else { + ++timer_it; + } } - GLuint64 time_elapsed; - glGetQueryObjectui64v(phase->timer_query_object, GL_QUERY_RESULT, &time_elapsed); - phase->time_elapsed_ns += time_elapsed; - ++phase->num_measured_iterations; } } } @@ -1847,7 +1906,7 @@ void EffectChain::execute_phase(Phase *phase, bool last_phase, if (!last_phase) { find_output_size(phase); - GLuint tex_num = resource_pool->create_2d_texture(GL_RGBA16F, phase->output_width, phase->output_height); + GLuint tex_num = resource_pool->create_2d_texture(intermediate_format, phase->output_width, phase->output_height); output_textures->insert(make_pair(phase, tex_num)); } @@ -1937,54 +1996,75 @@ void EffectChain::execute_phase(Phase *phase, bool last_phase, void EffectChain::setup_uniforms(Phase *phase) { - // TODO: Use UBO blocks. + char *ubo_data = phase->ubo_data.empty() ? NULL : &phase->ubo_data[0]; + for (size_t i = 0; i < phase->uniforms_sampler2d.size(); ++i) { const Uniform &uniform = phase->uniforms_sampler2d[i]; - if (uniform.location != -1) { + if (uniform.location != GL_INVALID_INDEX) { glUniform1iv(uniform.location, uniform.num_values, uniform.value); } + assert(uniform.ubo_offset == -1); // Samplers don't go into UBOs. } for (size_t i = 0; i < phase->uniforms_bool.size(); ++i) { const Uniform &uniform = phase->uniforms_bool[i]; assert(uniform.num_values == 1); - if (uniform.location != -1) { + if (uniform.location != GL_INVALID_INDEX) { glUniform1i(uniform.location, *uniform.value); } + if (uniform.ubo_offset != -1) { + GLint int_val = *uniform.value; + memcpy(ubo_data + uniform.ubo_offset, &int_val, sizeof(int_val)); + } } for (size_t i = 0; i < phase->uniforms_int.size(); ++i) { const Uniform &uniform = phase->uniforms_int[i]; - if (uniform.location != -1) { + if (uniform.location != GL_INVALID_INDEX) { glUniform1iv(uniform.location, uniform.num_values, uniform.value); } + if (uniform.ubo_offset != -1) { + memcpy(ubo_data + uniform.ubo_offset, uniform.value, uniform.ubo_num_elem * sizeof(*uniform.value)); + } } for (size_t i = 0; i < phase->uniforms_float.size(); ++i) { const Uniform &uniform = phase->uniforms_float[i]; - if (uniform.location != -1) { + if (uniform.location != GL_INVALID_INDEX) { glUniform1fv(uniform.location, uniform.num_values, uniform.value); } + if (uniform.ubo_offset != -1) { + memcpy(ubo_data + uniform.ubo_offset, uniform.value, uniform.ubo_num_elem * sizeof(*uniform.value)); + } } for (size_t i = 0; i < phase->uniforms_vec2.size(); ++i) { const Uniform &uniform = phase->uniforms_vec2[i]; - if (uniform.location != -1) { - glUniform2fv(uniform.location, uniform.num_values, uniform.value); + if (uniform.location != GL_INVALID_INDEX) { + glUniform2fv(uniform.location, uniform.ubo_num_elem, uniform.value); + } + if (uniform.ubo_offset != -1) { + memcpy(ubo_data + uniform.ubo_offset, uniform.value, uniform.ubo_num_elem * 2 * sizeof(*uniform.value)); } } for (size_t i = 0; i < phase->uniforms_vec3.size(); ++i) { const Uniform &uniform = phase->uniforms_vec3[i]; - if (uniform.location != -1) { - glUniform3fv(uniform.location, uniform.num_values, uniform.value); + if (uniform.location != GL_INVALID_INDEX) { + glUniform3fv(uniform.location, uniform.ubo_num_elem, uniform.value); + } + if (uniform.ubo_offset != -1) { + memcpy(ubo_data + uniform.ubo_offset, uniform.value, uniform.ubo_num_elem * 3 * sizeof(*uniform.value)); } } for (size_t i = 0; i < phase->uniforms_vec4.size(); ++i) { const Uniform &uniform = phase->uniforms_vec4[i]; - if (uniform.location != -1) { - glUniform4fv(uniform.location, uniform.num_values, uniform.value); + if (uniform.location != GL_INVALID_INDEX) { + glUniform4fv(uniform.location, uniform.ubo_num_elem, uniform.value); + } + if (uniform.ubo_offset != -1) { + memcpy(ubo_data + uniform.ubo_offset, uniform.value, uniform.ubo_num_elem * 4 * sizeof(*uniform.value)); } } for (size_t i = 0; i < phase->uniforms_mat3.size(); ++i) { const Uniform &uniform = phase->uniforms_mat3[i]; - assert(uniform.num_values == 1); - if (uniform.location != -1) { + assert(uniform.ubo_num_elem == 1); + if (uniform.location != GL_INVALID_INDEX) { // Convert to float (GLSL has no double matrices). float matrixf[9]; for (unsigned y = 0; y < 3; ++y) { @@ -1994,6 +2074,16 @@ void EffectChain::setup_uniforms(Phase *phase) } glUniformMatrix3fv(uniform.location, 1, GL_FALSE, matrixf); } + if (uniform.ubo_offset != -1) { + // TODO + assert(false); + } + } + + if (phase->ubo != GL_INVALID_INDEX) { + // TODO: Do we want to demand DSA for this? + glNamedBufferSubData(phase->ubo, 0, phase->ubo_data.size(), ubo_data); + return; } }