#define NO_SDL_GLEXT 1
-#include <epoxy/gl.h>
-
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
#include "flow.h"
+
#include "gpu_timers.h"
#include "util.h"
#include <algorithm>
+#include <assert.h>
#include <deque>
-#include <memory>
+#include <epoxy/gl.h>
#include <map>
+#include <memory>
#include <stack>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
#include <vector>
#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
}
if (ret == 0) {
fprintf(stderr, "Short read when trying to read %d bytes from %s\n",
- size, filename.c_str());
+ size, filename.c_str());
exit(1);
}
fclose(fp);
return str;
}
-
GLuint compile_shader(const string &shader_src, GLenum type)
{
GLuint obj = glCreateShader(type);
- const GLchar* source[] = { shader_src.data() };
+ const GLchar *source[] = { shader_src.data() };
const GLint length[] = { (GLint)shader_src.size() };
glShaderSource(obj, 1, source, length);
glCompileShader(obj);
uniform_splat_size = glGetUniformLocation(splat_program, "splat_size");
uniform_alpha = glGetUniformLocation(splat_program, "alpha");
- uniform_image_tex = glGetUniformLocation(splat_program, "image_tex");
+ uniform_gray_tex = glGetUniformLocation(splat_program, "gray_tex");
uniform_flow_tex = glGetUniformLocation(splat_program, "flow_tex");
uniform_inv_flow_size = glGetUniformLocation(splat_program, "inv_flow_size");
}
-void Splat::exec(GLuint image_tex, GLuint bidirectional_flow_tex, GLuint flow_tex, GLuint depth_rb, int width, int height, float alpha)
+void Splat::exec(GLuint gray_tex, GLuint bidirectional_flow_tex, GLuint flow_tex, GLuint depth_rb, int width, int height, float alpha)
{
glUseProgram(splat_program);
- bind_sampler(splat_program, uniform_image_tex, 0, image_tex, linear_sampler);
+ bind_sampler(splat_program, uniform_gray_tex, 0, gray_tex, linear_sampler);
bind_sampler(splat_program, uniform_flow_tex, 1, bidirectional_flow_tex, nearest_sampler);
glProgramUniform2f(splat_program, uniform_splat_size, op.splat_size / width, op.splat_size / height);
glDisable(GL_DEPTH_TEST);
}
-Blend::Blend()
+Blend::Blend(bool split_ycbcr_output)
+ : split_ycbcr_output(split_ycbcr_output)
{
+ string frag_shader = read_file("blend.frag");
+ if (split_ycbcr_output) {
+ // Insert after the first #version line.
+ size_t offset = frag_shader.find('\n');
+ assert(offset != string::npos);
+ frag_shader = frag_shader.substr(0, offset + 1) + "#define SPLIT_YCBCR_OUTPUT 1\n" + frag_shader.substr(offset + 1);
+ }
+
blend_vs_obj = compile_shader(read_file("vs.vert"), GL_VERTEX_SHADER);
- blend_fs_obj = compile_shader(read_file("blend.frag"), GL_FRAGMENT_SHADER);
+ blend_fs_obj = compile_shader(frag_shader, GL_FRAGMENT_SHADER);
blend_program = link_program(blend_vs_obj, blend_fs_obj);
uniform_image_tex = glGetUniformLocation(blend_program, "image_tex");
uniform_flow_consistency_tolerance = glGetUniformLocation(blend_program, "flow_consistency_tolerance");
}
-void Blend::exec(GLuint image_tex, GLuint flow_tex, GLuint output_tex, int level_width, int level_height, float alpha)
+void Blend::exec(GLuint image_tex, GLuint flow_tex, GLuint output_tex, GLuint output2_tex, int level_width, int level_height, float alpha)
{
glUseProgram(blend_program);
bind_sampler(blend_program, uniform_image_tex, 0, image_tex, linear_sampler);
glProgramUniform1f(blend_program, uniform_alpha, alpha);
glViewport(0, 0, level_width, level_height);
- fbos.render_to(output_tex);
+ if (split_ycbcr_output) {
+ fbos_split.render_to(output_tex, output2_tex);
+ } else {
+ fbos.render_to(output_tex);
+ }
glDisable(GL_BLEND); // A bit ironic, perhaps.
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
-Interpolate::Interpolate(int width, int height, const OperatingPoint &op)
- : width(width), height(height), flow_level(op.finest_level), op(op), splat(op) {
+Interpolate::Interpolate(const OperatingPoint &op, bool split_ycbcr_output)
+ : flow_level(op.finest_level),
+ split_ycbcr_output(split_ycbcr_output),
+ splat(op),
+ blend(split_ycbcr_output) {
// Set up the vertex data that will be shared between all passes.
float vertices[] = {
0.0f, 1.0f,
glVertexAttribPointer(position_attrib, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
}
-GLuint Interpolate::exec(GLuint image_tex, GLuint bidirectional_flow_tex, GLuint width, GLuint height, float alpha)
+pair<GLuint, GLuint> Interpolate::exec(GLuint image_tex, GLuint gray_tex, GLuint bidirectional_flow_tex, GLuint width, GLuint height, float alpha)
{
GPUTimers timers;
// Pick out the right level to test splatting results on.
GLuint tex_view;
glGenTextures(1, &tex_view);
- glTextureView(tex_view, GL_TEXTURE_2D_ARRAY, image_tex, GL_RGBA8, flow_level, 1, 0, 2);
+ glTextureView(tex_view, GL_TEXTURE_2D_ARRAY, gray_tex, GL_R8, flow_level, 1, 0, 2);
int flow_width = width >> flow_level;
int flow_height = height >> flow_level;
pool.release_texture(temp_tex[2]);
pool.release_renderbuffer(depth_rb);
- GLuint output_tex = pool.get_texture(GL_RGBA8, width, height);
- {
- ScopedTimer timer("Blend", &total_timer);
- blend.exec(image_tex, flow_tex, output_tex, width, height, alpha);
+ GLuint output_tex, output2_tex = 0;
+ if (split_ycbcr_output) {
+ output_tex = pool.get_texture(GL_R8, width, height);
+ output2_tex = pool.get_texture(GL_RG8, width, height);
+ {
+ ScopedTimer timer("Blend", &total_timer);
+ blend.exec(image_tex, flow_tex, output_tex, output2_tex, width, height, alpha);
+ }
+ } else {
+ output_tex = pool.get_texture(GL_RGBA8, width, height);
+ {
+ ScopedTimer timer("Blend", &total_timer);
+ blend.exec(image_tex, flow_tex, output_tex, 0, width, height, alpha);
+ }
}
pool.release_texture(flow_tex);
total_timer.end();
timers.print();
}
- return output_tex;
+ return make_pair(output_tex, output2_tex);
}
GLuint TexturePool::get_texture(GLenum format, GLuint width, GLuint height, GLuint num_layers)