X-Git-Url: https://git.sesse.net/?p=movit;a=blobdiff_plain;f=effect_chain.cpp;h=c46e60d20475a70fd3b721fefe3d9f3775f3d792;hp=4d13d3f8d30c6f24c0520f4c4633e864b9d12904;hb=6538edf86b77a7cdb47789816cb19452340ff7d1;hpb=e8499e3e9892a74c7882af4be14ccdc1e3d92c2b diff --git a/effect_chain.cpp b/effect_chain.cpp index 4d13d3f..c46e60d 100644 --- a/effect_chain.cpp +++ b/effect_chain.cpp @@ -36,8 +36,9 @@ EffectChain::EffectChain(float aspect_nom, float aspect_denom, ResourcePool *res : aspect_nom(aspect_nom), aspect_denom(aspect_denom), output_color_rgba(false), - output_color_ycbcr(false), + num_output_color_ycbcr(0), dither_effect(NULL), + ycbcr_conversion_effect_node(NULL), intermediate_format(GL_RGBA16F), intermediate_transformation(NO_FRAMEBUFFER_TRANSFORMATION), num_dither_bits(0), @@ -96,15 +97,27 @@ void EffectChain::add_output(const ImageFormat &format, OutputAlphaFormat alpha_ } void EffectChain::add_ycbcr_output(const ImageFormat &format, OutputAlphaFormat alpha_format, - const YCbCrFormat &ycbcr_format, YCbCrOutputSplitting output_splitting) + const YCbCrFormat &ycbcr_format, YCbCrOutputSplitting output_splitting, + GLenum output_type) { assert(!finalized); - assert(!output_color_ycbcr); + assert(num_output_color_ycbcr < 2); output_format = format; output_alpha_format = alpha_format; - output_color_ycbcr = true; - output_ycbcr_format = ycbcr_format; - output_ycbcr_splitting = output_splitting; + + if (num_output_color_ycbcr == 1) { + // Check that the format is the same. + assert(output_ycbcr_format.luma_coefficients == ycbcr_format.luma_coefficients); + assert(output_ycbcr_format.full_range == ycbcr_format.full_range); + assert(output_ycbcr_format.num_levels == ycbcr_format.num_levels); + assert(output_ycbcr_format.chroma_subsampling_x == 1); + assert(output_ycbcr_format.chroma_subsampling_y == 1); + assert(output_ycbcr_type == output_type); + } else { + output_ycbcr_format = ycbcr_format; + output_ycbcr_type = output_type; + } + output_ycbcr_splitting[num_output_color_ycbcr++] = output_splitting; assert(ycbcr_format.chroma_subsampling_x == 1); assert(ycbcr_format.chroma_subsampling_y == 1); @@ -112,24 +125,14 @@ void EffectChain::add_ycbcr_output(const ImageFormat &format, OutputAlphaFormat void EffectChain::change_ycbcr_output_format(const YCbCrFormat &ycbcr_format) { - assert(output_color_ycbcr); - assert(output_ycbcr_format.chroma_subsampling_x == ycbcr_format.chroma_subsampling_x); - assert(output_ycbcr_format.chroma_subsampling_y == ycbcr_format.chroma_subsampling_y); - assert(fabs(output_ycbcr_format.cb_x_position - ycbcr_format.cb_x_position) < 1e-3); - assert(fabs(output_ycbcr_format.cb_y_position - ycbcr_format.cb_y_position) < 1e-3); - assert(fabs(output_ycbcr_format.cr_x_position - ycbcr_format.cr_x_position) < 1e-3); - assert(fabs(output_ycbcr_format.cr_y_position - ycbcr_format.cr_y_position) < 1e-3); + assert(num_output_color_ycbcr > 0); + assert(output_ycbcr_format.chroma_subsampling_x == 1); + assert(output_ycbcr_format.chroma_subsampling_y == 1); output_ycbcr_format = ycbcr_format; if (finalized) { - // Find the YCbCrConversionEffect node. We don't store it to avoid - // an unneeded ABI break (this can be fixed on next break). - for (Node *node : nodes) { - if (node->effect->effect_type_id() == "YCbCrConversionEffect") { - YCbCrConversionEffect *effect = (YCbCrConversionEffect *)(node->effect); - effect->change_output_format(ycbcr_format); - } - } + YCbCrConversionEffect *effect = (YCbCrConversionEffect *)(ycbcr_conversion_effect_node->effect); + effect->change_output_format(ycbcr_format); } } @@ -417,8 +420,8 @@ void EffectChain::compile_glsl_program(Phase *phase) // If we're the last phase, add the right #defines for Y'CbCr multi-output as needed. vector frag_shader_outputs; // In order. - if (phase->output_node->outgoing_links.empty() && output_color_ycbcr) { - switch (output_ycbcr_splitting) { + if (phase->output_node->outgoing_links.empty() && num_output_color_ycbcr > 0) { + switch (output_ycbcr_splitting[0]) { case YCBCR_OUTPUT_INTERLEAVED: // No #defines set. frag_shader_outputs.push_back("FragColor"); @@ -438,6 +441,28 @@ void EffectChain::compile_glsl_program(Phase *phase) assert(false); } + if (num_output_color_ycbcr > 1) { + switch (output_ycbcr_splitting[1]) { + case YCBCR_OUTPUT_INTERLEAVED: + frag_shader += "#define SECOND_YCBCR_OUTPUT_INTERLEAVED 1\n"; + frag_shader_outputs.push_back("YCbCr2"); + break; + case YCBCR_OUTPUT_SPLIT_Y_AND_CBCR: + frag_shader += "#define SECOND_YCBCR_OUTPUT_SPLIT_Y_AND_CBCR 1\n"; + frag_shader_outputs.push_back("Y2"); + frag_shader_outputs.push_back("Chroma2"); + break; + case YCBCR_OUTPUT_PLANAR: + frag_shader += "#define SECOND_YCBCR_OUTPUT_PLANAR 1\n"; + frag_shader_outputs.push_back("Y2"); + frag_shader_outputs.push_back("Cb2"); + frag_shader_outputs.push_back("Cr2"); + break; + default: + assert(false); + } + } + if (output_color_rgba) { // Note: Needs to come in the header, because not only the // output needs to see it (YCbCrConversionEffect and DitherEffect @@ -1617,13 +1642,13 @@ void EffectChain::fix_output_gamma() // gamma-encoded data. void EffectChain::add_ycbcr_conversion_if_needed() { - assert(output_color_rgba || output_color_ycbcr); - if (!output_color_ycbcr) { + assert(output_color_rgba || num_output_color_ycbcr > 0); + if (num_output_color_ycbcr == 0) { return; } Node *output = find_output_node(); - Node *ycbcr = add_node(new YCbCrConversionEffect(output_ycbcr_format)); - connect_nodes(output, ycbcr); + ycbcr_conversion_effect_node = add_node(new YCbCrConversionEffect(output_ycbcr_format, output_ycbcr_type)); + connect_nodes(output, ycbcr_conversion_effect_node); } // If the user has requested dither, add a DitherEffect right at the end @@ -1738,8 +1763,10 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height check_error(); glDisable(GL_DITHER); check_error(); - glEnable(GL_FRAMEBUFFER_SRGB); + + const bool final_srgb = glIsEnabled(GL_FRAMEBUFFER_SRGB); check_error(); + bool current_srgb = final_srgb; // Save original viewport. GLuint x = 0, y = 0; @@ -1762,17 +1789,6 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height glDepthMask(GL_FALSE); check_error(); - // Generate a VAO that will be used during the entire execution, - // and bind the VBO, since it contains all the data. - GLuint vao; - glGenVertexArrays(1, &vao); - check_error(); - glBindVertexArray(vao); - check_error(); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - check_error(); - set bound_attribute_indices; - set generated_mipmaps; // We choose the simplest option of having one texture per output, @@ -1805,7 +1821,22 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height CHECK(dither_effect->set_int("output_height", height)); } } - execute_phase(phase, phase_num == phases.size() - 1, &bound_attribute_indices, &output_textures, &generated_mipmaps); + bool last_phase = (phase_num == phases.size() - 1); + + // Enable sRGB rendering for intermediates in case we are + // rendering to an sRGB format. + bool needs_srgb = last_phase ? final_srgb : true; + if (needs_srgb && !current_srgb) { + glEnable(GL_FRAMEBUFFER_SRGB); + check_error(); + current_srgb = true; + } else if (!needs_srgb && current_srgb) { + glDisable(GL_FRAMEBUFFER_SRGB); + check_error(); + current_srgb = true; + } + + execute_phase(phase, last_phase, &output_textures, &generated_mipmaps); if (do_phase_timing) { glEndQuery(GL_TIME_ELAPSED); } @@ -1826,8 +1857,6 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height check_error(); glBindVertexArray(0); check_error(); - glDeleteVertexArrays(1, &vao); - check_error(); if (do_phase_timing) { // Get back the timer queries. @@ -1890,7 +1919,6 @@ void EffectChain::print_phase_timing() } void EffectChain::execute_phase(Phase *phase, bool last_phase, - set *bound_attribute_indices, map *output_textures, set *generated_mipmaps) { @@ -1951,30 +1979,9 @@ void EffectChain::execute_phase(Phase *phase, bool last_phase, // from there. setup_uniforms(phase); - // Clean up old attributes if they are no longer needed. - for (set::iterator attr_it = bound_attribute_indices->begin(); - attr_it != bound_attribute_indices->end(); ) { - if (phase->attribute_indexes.count(*attr_it) == 0) { - glDisableVertexAttribArray(*attr_it); - check_error(); - bound_attribute_indices->erase(attr_it++); - } else { - ++attr_it; - } - } - - // Set up the new attributes, if needed. - for (set::iterator attr_it = phase->attribute_indexes.begin(); - attr_it != phase->attribute_indexes.end(); - ++attr_it) { - if (bound_attribute_indices->count(*attr_it) == 0) { - glEnableVertexAttribArray(*attr_it); - check_error(); - glVertexAttribPointer(*attr_it, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); - check_error(); - bound_attribute_indices->insert(*attr_it); - } - } + // Bind the vertex data. + GLuint vao = resource_pool->create_vec2_vao(phase->attribute_indexes, vbo); + glBindVertexArray(vao); glDrawArrays(GL_TRIANGLES, 0, 3); check_error(); @@ -1985,6 +1992,7 @@ void EffectChain::execute_phase(Phase *phase, bool last_phase, } resource_pool->unuse_glsl_program(instance_program_num); + resource_pool->release_vec2_vao(vao); if (!last_phase) { resource_pool->release_fbo(fbo);