From: Steinar H. Gunderson Date: Tue, 13 Nov 2018 23:27:44 +0000 (+0100) Subject: Embed shaders into the binary. X-Git-Tag: 1.8.0~76^2~12 X-Git-Url: https://git.sesse.net/?p=nageru;a=commitdiff_plain;h=92cca212dad5e4b968c052d8200a534473929674 Embed shaders into the binary. --- diff --git a/bin2h.cpp b/bin2h.cpp new file mode 100644 index 0000000..a396afe --- /dev/null +++ b/bin2h.cpp @@ -0,0 +1,51 @@ +#include +#include + +using namespace std; + +int main(int argc, char **argv) +{ + if (argc != 4) { + fprintf(stderr, "Usage: bin2h INFILE BASENAME OUTFILE\n"); + return 1; + } + + string basename = argv[2]; + for (char &ch : basename) { + if (!isalpha(ch) && !isdigit(ch)) { + ch = '_'; + } + } + + FILE *infp = fopen(argv[1], "rb"); + if (infp == nullptr) { + perror(argv[1]); + exit(1); + } + + FILE *outfp = fopen(argv[3], "w"); + if (outfp == nullptr) { + perror(argv[3]); + exit(1); + } + + fprintf(outfp, "// Generated by bin2h.cpp from %s. Do not edit by hand.\n", argv[1]); + fprintf(outfp, "#include \n"); + fprintf(outfp, "unsigned char _binary_%s[] = {", basename.c_str()); + + size_t num_bytes = 0; + while (!feof(infp)) { + if (num_bytes++ % 16 == 0) { + fprintf(outfp, "\n\t"); + } + int ch = getc(infp); + if (ch == -1) { + break; + } + fprintf(outfp, "0x%02x, ", ch); + } + fprintf(outfp, "\n};\n"); + fprintf(outfp, "unsigned char *_binary_%s_data = _binary_%s;\n", basename.c_str(), basename.c_str()); + fprintf(outfp, "size_t _binary_%s_size = sizeof(_binary_%s);\n", basename.c_str(), basename.c_str()); + return 0; +} diff --git a/chroma_subsampler.cpp b/chroma_subsampler.cpp index 04fd594..d064bc7 100644 --- a/chroma_subsampler.cpp +++ b/chroma_subsampler.cpp @@ -3,11 +3,13 @@ #include #include +#include "embedded_files.h" + #define BUFFER_OFFSET(i) ((char *)nullptr + (i)) using namespace std; -string read_file(const string &filename); +string read_file(const string &filename, const unsigned char *start = nullptr, const size_t size = 0); GLuint compile_shader(const string &shader_src, GLenum type); GLuint link_program(GLuint vs_obj, GLuint fs_obj); void bind_sampler(GLuint program, GLint location, GLuint texture_unit, GLuint tex, GLuint sampler); @@ -69,8 +71,8 @@ ChromaSubsampler::ChromaSubsampler() // // See also http://www.poynton.com/PDFs/Merging_RGB_and_422.pdf, pages 6–7. - cbcr_vs_obj = compile_shader(read_file("chroma_subsample.vert"), GL_VERTEX_SHADER); - cbcr_fs_obj = compile_shader(read_file("chroma_subsample.frag"), GL_FRAGMENT_SHADER); + cbcr_vs_obj = compile_shader(read_file("chroma_subsample.vert", _binary_chroma_subsample_vert_data, _binary_chroma_subsample_vert_size), GL_VERTEX_SHADER); + cbcr_fs_obj = compile_shader(read_file("chroma_subsample.frag", _binary_chroma_subsample_frag_data, _binary_chroma_subsample_frag_size), GL_FRAGMENT_SHADER); cbcr_program = link_program(cbcr_vs_obj, cbcr_fs_obj); // Set up the VAO containing all the required position data. diff --git a/embedded_files.h b/embedded_files.h new file mode 100644 index 0000000..83cf0fc --- /dev/null +++ b/embedded_files.h @@ -0,0 +1,60 @@ +#ifndef _EMBEDDED_FILES_H +#define _EMBEDDED_FILES_H 1 + +// Files that are embedded into the binary as part of the build process. +// They are used as a backup if the files are not available on disk +// (which is typically the case if the program is installed, as opposed to +// being run during development). + +#include + +extern const unsigned char *_binary_add_base_flow_frag_data; +extern const size_t _binary_add_base_flow_frag_size; +extern const unsigned char *_binary_blend_frag_data; +extern const size_t _binary_blend_frag_size; +extern const unsigned char *_binary_chroma_subsample_frag_data; +extern const size_t _binary_chroma_subsample_frag_size; +extern const unsigned char *_binary_chroma_subsample_vert_data; +extern const size_t _binary_chroma_subsample_vert_size; +extern const unsigned char *_binary_densify_frag_data; +extern const size_t _binary_densify_frag_size; +extern const unsigned char *_binary_densify_vert_data; +extern const size_t _binary_densify_vert_size; +extern const unsigned char *_binary_derivatives_frag_data; +extern const size_t _binary_derivatives_frag_size; +extern const unsigned char *_binary_diffusivity_frag_data; +extern const size_t _binary_diffusivity_frag_size; +extern const unsigned char *_binary_equations_frag_data; +extern const size_t _binary_equations_frag_size; +extern const unsigned char *_binary_equations_vert_data; +extern const size_t _binary_equations_vert_size; +extern const unsigned char *_binary_gray_frag_data; +extern const size_t _binary_gray_frag_size; +extern const unsigned char *_binary_hole_blend_frag_data; +extern const size_t _binary_hole_blend_frag_size; +extern const unsigned char *_binary_hole_fill_frag_data; +extern const size_t _binary_hole_fill_frag_size; +extern const unsigned char *_binary_hole_fill_vert_data; +extern const size_t _binary_hole_fill_vert_size; +extern const unsigned char *_binary_motion_search_frag_data; +extern const size_t _binary_motion_search_frag_size; +extern const unsigned char *_binary_motion_search_vert_data; +extern const size_t _binary_motion_search_vert_size; +extern const unsigned char *_binary_prewarp_frag_data; +extern const size_t _binary_prewarp_frag_size; +extern const unsigned char *_binary_resize_flow_frag_data; +extern const size_t _binary_resize_flow_frag_size; +extern const unsigned char *_binary_sobel_frag_data; +extern const size_t _binary_sobel_frag_size; +extern const unsigned char *_binary_sor_frag_data; +extern const size_t _binary_sor_frag_size; +extern const unsigned char *_binary_sor_vert_data; +extern const size_t _binary_sor_vert_size; +extern const unsigned char *_binary_splat_frag_data; +extern const size_t _binary_splat_frag_size; +extern const unsigned char *_binary_splat_vert_data; +extern const size_t _binary_splat_vert_size; +extern const unsigned char *_binary_vs_vert_data; +extern const size_t _binary_vs_vert_size; + +#endif // !defined(_EMBEDDED_FILES_H) diff --git a/flow.cpp b/flow.cpp index e672fe6..5125d26 100644 --- a/flow.cpp +++ b/flow.cpp @@ -2,12 +2,14 @@ #include "flow.h" +#include "embedded_files.h" #include "gpu_timers.h" #include "util.h" #include #include #include +#include #include #include #include @@ -48,10 +50,18 @@ int find_num_levels(int width, int height) return levels; } -string read_file(const string &filename) +string read_file(const string &filename, const unsigned char *start = nullptr, const size_t size = 0) { FILE *fp = fopen(filename.c_str(), "r"); if (fp == nullptr) { + // Fall back to the version we compiled in. (We prefer disk if we can, + // since that makes it possible to work on shaders without recompiling + // all the time.) + if (start != nullptr) { + return string(reinterpret_cast(start), + reinterpret_cast(start) + size); + } + perror(filename.c_str()); exit(1); } @@ -62,7 +72,7 @@ string read_file(const string &filename) exit(1); } - int size = ftell(fp); + int disk_size = ftell(fp); ret = fseek(fp, 0, SEEK_SET); if (ret == -1) { @@ -71,15 +81,15 @@ string read_file(const string &filename) } string str; - str.resize(size); - ret = fread(&str[0], size, 1, fp); + str.resize(disk_size); + ret = fread(&str[0], disk_size, 1, fp); if (ret == -1) { perror("fread"); exit(1); } if (ret == 0) { fprintf(stderr, "Short read when trying to read %d bytes from %s\n", - size, filename.c_str()); + disk_size, filename.c_str()); exit(1); } fclose(fp); @@ -202,8 +212,8 @@ void PersistentFBOSetWithDepth::render_to(GLuint depth_rb, const a GrayscaleConversion::GrayscaleConversion() { - gray_vs_obj = compile_shader(read_file("vs.vert"), GL_VERTEX_SHADER); - gray_fs_obj = compile_shader(read_file("gray.frag"), GL_FRAGMENT_SHADER); + gray_vs_obj = compile_shader(read_file("vs.vert", _binary_vs_vert_data, _binary_vs_vert_size), GL_VERTEX_SHADER); + gray_fs_obj = compile_shader(read_file("gray.frag", _binary_gray_frag_data, _binary_gray_frag_size), GL_FRAGMENT_SHADER); gray_program = link_program(gray_vs_obj, gray_fs_obj); // Set up the VAO containing all the required position/texcoord data. @@ -231,8 +241,8 @@ void GrayscaleConversion::exec(GLint tex, GLint gray_tex, int width, int height, Sobel::Sobel() { - sobel_vs_obj = compile_shader(read_file("vs.vert"), GL_VERTEX_SHADER); - sobel_fs_obj = compile_shader(read_file("sobel.frag"), GL_FRAGMENT_SHADER); + sobel_vs_obj = compile_shader(read_file("vs.vert", _binary_vs_vert_data, _binary_vs_vert_size), GL_VERTEX_SHADER); + sobel_fs_obj = compile_shader(read_file("sobel.frag", _binary_sobel_frag_data, _binary_sobel_frag_size), GL_FRAGMENT_SHADER); sobel_program = link_program(sobel_vs_obj, sobel_fs_obj); uniform_tex = glGetUniformLocation(sobel_program, "tex"); @@ -252,8 +262,8 @@ void Sobel::exec(GLint tex_view, GLint grad_tex, int level_width, int level_heig MotionSearch::MotionSearch(const OperatingPoint &op) : op(op) { - motion_vs_obj = compile_shader(read_file("motion_search.vert"), GL_VERTEX_SHADER); - motion_fs_obj = compile_shader(read_file("motion_search.frag"), GL_FRAGMENT_SHADER); + motion_vs_obj = compile_shader(read_file("motion_search.vert", _binary_motion_search_vert_data, _binary_motion_search_vert_size), GL_VERTEX_SHADER); + motion_fs_obj = compile_shader(read_file("motion_search.frag", _binary_motion_search_frag_data, _binary_motion_search_frag_size), GL_FRAGMENT_SHADER); motion_search_program = link_program(motion_vs_obj, motion_fs_obj); uniform_inv_image_size = glGetUniformLocation(motion_search_program, "inv_image_size"); @@ -288,8 +298,8 @@ void MotionSearch::exec(GLuint tex_view, GLuint grad_tex, GLuint flow_tex, GLuin Densify::Densify(const OperatingPoint &op) : op(op) { - densify_vs_obj = compile_shader(read_file("densify.vert"), GL_VERTEX_SHADER); - densify_fs_obj = compile_shader(read_file("densify.frag"), GL_FRAGMENT_SHADER); + densify_vs_obj = compile_shader(read_file("densify.vert", _binary_densify_vert_data, _binary_densify_vert_size), GL_VERTEX_SHADER); + densify_fs_obj = compile_shader(read_file("densify.frag", _binary_densify_frag_data, _binary_densify_frag_size), GL_FRAGMENT_SHADER); densify_program = link_program(densify_vs_obj, densify_fs_obj); uniform_patch_size = glGetUniformLocation(densify_program, "patch_size"); @@ -319,8 +329,8 @@ void Densify::exec(GLuint tex_view, GLuint flow_tex, GLuint dense_flow_tex, int Prewarp::Prewarp() { - prewarp_vs_obj = compile_shader(read_file("vs.vert"), GL_VERTEX_SHADER); - prewarp_fs_obj = compile_shader(read_file("prewarp.frag"), GL_FRAGMENT_SHADER); + prewarp_vs_obj = compile_shader(read_file("vs.vert", _binary_vs_vert_data, _binary_vs_vert_size), GL_VERTEX_SHADER); + prewarp_fs_obj = compile_shader(read_file("prewarp.frag", _binary_prewarp_frag_data, _binary_prewarp_frag_size), GL_FRAGMENT_SHADER); prewarp_program = link_program(prewarp_vs_obj, prewarp_fs_obj); uniform_image_tex = glGetUniformLocation(prewarp_program, "image_tex"); @@ -342,8 +352,8 @@ void Prewarp::exec(GLuint tex_view, GLuint flow_tex, GLuint I_tex, GLuint I_t_te Derivatives::Derivatives() { - derivatives_vs_obj = compile_shader(read_file("vs.vert"), GL_VERTEX_SHADER); - derivatives_fs_obj = compile_shader(read_file("derivatives.frag"), GL_FRAGMENT_SHADER); + derivatives_vs_obj = compile_shader(read_file("vs.vert", _binary_vs_vert_data, _binary_vs_vert_size), GL_VERTEX_SHADER); + derivatives_fs_obj = compile_shader(read_file("derivatives.frag", _binary_derivatives_frag_data, _binary_derivatives_frag_size), GL_FRAGMENT_SHADER); derivatives_program = link_program(derivatives_vs_obj, derivatives_fs_obj); uniform_tex = glGetUniformLocation(derivatives_program, "tex"); @@ -363,8 +373,8 @@ void Derivatives::exec(GLuint input_tex, GLuint I_x_y_tex, GLuint beta_0_tex, in ComputeDiffusivity::ComputeDiffusivity() { - diffusivity_vs_obj = compile_shader(read_file("vs.vert"), GL_VERTEX_SHADER); - diffusivity_fs_obj = compile_shader(read_file("diffusivity.frag"), GL_FRAGMENT_SHADER); + diffusivity_vs_obj = compile_shader(read_file("vs.vert", _binary_vs_vert_data, _binary_vs_vert_size), GL_VERTEX_SHADER); + diffusivity_fs_obj = compile_shader(read_file("diffusivity.frag", _binary_diffusivity_frag_data, _binary_diffusivity_frag_size), GL_FRAGMENT_SHADER); diffusivity_program = link_program(diffusivity_vs_obj, diffusivity_fs_obj); uniform_flow_tex = glGetUniformLocation(diffusivity_program, "flow_tex"); @@ -391,8 +401,8 @@ void ComputeDiffusivity::exec(GLuint flow_tex, GLuint diff_flow_tex, GLuint diff SetupEquations::SetupEquations() { - equations_vs_obj = compile_shader(read_file("equations.vert"), GL_VERTEX_SHADER); - equations_fs_obj = compile_shader(read_file("equations.frag"), GL_FRAGMENT_SHADER); + equations_vs_obj = compile_shader(read_file("equations.vert", _binary_equations_vert_data, _binary_equations_vert_size), GL_VERTEX_SHADER); + equations_fs_obj = compile_shader(read_file("equations.frag", _binary_equations_frag_data, _binary_equations_frag_size), GL_FRAGMENT_SHADER); equations_program = link_program(equations_vs_obj, equations_fs_obj); uniform_I_x_y_tex = glGetUniformLocation(equations_program, "I_x_y_tex"); @@ -428,8 +438,8 @@ void SetupEquations::exec(GLuint I_x_y_tex, GLuint I_t_tex, GLuint diff_flow_tex SOR::SOR() { - sor_vs_obj = compile_shader(read_file("sor.vert"), GL_VERTEX_SHADER); - sor_fs_obj = compile_shader(read_file("sor.frag"), GL_FRAGMENT_SHADER); + sor_vs_obj = compile_shader(read_file("sor.vert", _binary_sor_vert_data, _binary_sor_vert_size), GL_VERTEX_SHADER); + sor_fs_obj = compile_shader(read_file("sor.frag", _binary_sor_frag_data, _binary_sor_frag_size), GL_FRAGMENT_SHADER); sor_program = link_program(sor_vs_obj, sor_fs_obj); uniform_diff_flow_tex = glGetUniformLocation(sor_program, "diff_flow_tex"); @@ -490,8 +500,8 @@ void SOR::exec(GLuint diff_flow_tex, GLuint equation_red_tex, GLuint equation_bl AddBaseFlow::AddBaseFlow() { - add_flow_vs_obj = compile_shader(read_file("vs.vert"), GL_VERTEX_SHADER); - add_flow_fs_obj = compile_shader(read_file("add_base_flow.frag"), GL_FRAGMENT_SHADER); + add_flow_vs_obj = compile_shader(read_file("vs.vert", _binary_vs_vert_data, _binary_vs_vert_size), GL_VERTEX_SHADER); + add_flow_fs_obj = compile_shader(read_file("add_base_flow.frag", _binary_add_base_flow_frag_data, _binary_add_base_flow_frag_size), GL_FRAGMENT_SHADER); add_flow_program = link_program(add_flow_vs_obj, add_flow_fs_obj); uniform_diff_flow_tex = glGetUniformLocation(add_flow_program, "diff_flow_tex"); @@ -513,8 +523,8 @@ void AddBaseFlow::exec(GLuint base_flow_tex, GLuint diff_flow_tex, int level_wid ResizeFlow::ResizeFlow() { - resize_flow_vs_obj = compile_shader(read_file("vs.vert"), GL_VERTEX_SHADER); - resize_flow_fs_obj = compile_shader(read_file("resize_flow.frag"), GL_FRAGMENT_SHADER); + resize_flow_vs_obj = compile_shader(read_file("vs.vert", _binary_vs_vert_data, _binary_vs_vert_size), GL_VERTEX_SHADER); + resize_flow_fs_obj = compile_shader(read_file("resize_flow.frag", _binary_resize_flow_frag_data, _binary_resize_flow_frag_size), GL_FRAGMENT_SHADER); resize_flow_program = link_program(resize_flow_vs_obj, resize_flow_fs_obj); uniform_flow_tex = glGetUniformLocation(resize_flow_program, "flow_tex"); @@ -770,8 +780,8 @@ GLuint DISComputeFlow::exec(GLuint tex, FlowDirection flow_direction, ResizeStra Splat::Splat(const OperatingPoint &op) : op(op) { - splat_vs_obj = compile_shader(read_file("splat.vert"), GL_VERTEX_SHADER); - splat_fs_obj = compile_shader(read_file("splat.frag"), GL_FRAGMENT_SHADER); + splat_vs_obj = compile_shader(read_file("splat.vert", _binary_splat_vert_data, _binary_splat_vert_size), GL_VERTEX_SHADER); + splat_fs_obj = compile_shader(read_file("splat.frag", _binary_splat_frag_data, _binary_splat_frag_size), GL_FRAGMENT_SHADER); splat_program = link_program(splat_vs_obj, splat_fs_obj); uniform_splat_size = glGetUniformLocation(splat_program, "splat_size"); @@ -813,8 +823,8 @@ void Splat::exec(GLuint gray_tex, GLuint bidirectional_flow_tex, GLuint flow_tex HoleFill::HoleFill() { - fill_vs_obj = compile_shader(read_file("hole_fill.vert"), GL_VERTEX_SHADER); - fill_fs_obj = compile_shader(read_file("hole_fill.frag"), GL_FRAGMENT_SHADER); + fill_vs_obj = compile_shader(read_file("hole_fill.vert", _binary_hole_fill_vert_data, _binary_hole_fill_vert_size), GL_VERTEX_SHADER); + fill_fs_obj = compile_shader(read_file("hole_fill.frag", _binary_hole_fill_frag_data, _binary_hole_fill_frag_size), GL_FRAGMENT_SHADER); fill_program = link_program(fill_vs_obj, fill_fs_obj); uniform_tex = glGetUniformLocation(fill_program, "tex"); @@ -877,8 +887,8 @@ void HoleFill::exec(GLuint flow_tex, GLuint depth_rb, GLuint temp_tex[3], int wi HoleBlend::HoleBlend() { - blend_vs_obj = compile_shader(read_file("hole_fill.vert"), GL_VERTEX_SHADER); // Reuse the vertex shader from the fill. - blend_fs_obj = compile_shader(read_file("hole_blend.frag"), GL_FRAGMENT_SHADER); + blend_vs_obj = compile_shader(read_file("hole_fill.vert", _binary_hole_fill_vert_data, _binary_hole_fill_vert_size), GL_VERTEX_SHADER); // Reuse the vertex shader from the fill. + blend_fs_obj = compile_shader(read_file("hole_blend.frag", _binary_hole_blend_frag_data, _binary_hole_blend_frag_size), GL_FRAGMENT_SHADER); blend_program = link_program(blend_vs_obj, blend_fs_obj); uniform_left_tex = glGetUniformLocation(blend_program, "left_tex"); @@ -916,7 +926,7 @@ void HoleBlend::exec(GLuint flow_tex, GLuint depth_rb, GLuint temp_tex[3], int w Blend::Blend(bool split_ycbcr_output) : split_ycbcr_output(split_ycbcr_output) { - string frag_shader = read_file("blend.frag"); + string frag_shader = read_file("blend.frag", _binary_blend_frag_data, _binary_blend_frag_size); if (split_ycbcr_output) { // Insert after the first #version line. size_t offset = frag_shader.find('\n'); @@ -924,7 +934,7 @@ Blend::Blend(bool split_ycbcr_output) 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_vs_obj = compile_shader(read_file("vs.vert", _binary_vs_vert_data, _binary_vs_vert_size), GL_VERTEX_SHADER); blend_fs_obj = compile_shader(frag_shader, GL_FRAGMENT_SHADER); blend_program = link_program(blend_vs_obj, blend_fs_obj); diff --git a/meson.build b/meson.build index 8308335..18f9272 100644 --- a/meson.build +++ b/meson.build @@ -48,7 +48,24 @@ srcs += ['mainwindow.cpp', 'jpeg_frame_view.cpp', 'clip_list.cpp'] srcs += moc_files srcs += proto_generated +# Shaders needed at runtime. +shaders = ['chroma_subsample.vert', 'densify.vert', 'equations.vert', 'hole_fill.vert', 'motion_search.vert', 'sor.vert', 'splat.vert', 'vs.vert'] +shaders += ['add_base_flow.frag', 'blend.frag', 'chroma_subsample.frag', 'densify.frag', 'derivatives.frag', 'diffusivity.frag', + 'equations.frag', 'gray.frag', 'hole_blend.frag', 'hole_fill.frag', 'motion_search.frag', 'prewarp.frag', 'resize_flow.frag', + 'sobel.frag', 'sor.frag', 'splat.frag'] + +foreach shader : shaders + run_command('ln', '-s', join_paths(meson.current_source_dir(), shader), meson.current_build_dir()) +endforeach + +bin2h = executable('bin2h', 'bin2h.cpp') +bin2h_gen = generator(bin2h, \ + output : ['@PLAINNAME@.cpp'], + arguments : ['@INPUT@', '@PLAINNAME@', '@OUTPUT@']) +shader_srcs = bin2h_gen.process(shaders) +srcs += shader_srcs + executable('futatabi', srcs, dependencies: [qt5deps, libjpegdep, movitdep, libmicrohttpddep, protobufdep, sqlite3dep, vax11dep, vadrmdep, x11dep, libavformatdep, libavcodecdep, libavutildep, libswscaledep]) -executable('flow', 'flow_main.cpp', 'flow.cpp', 'gpu_timers.cpp', dependencies: [epoxydep, sdl2dep, sdl2_imagedep]) +executable('flow', 'flow_main.cpp', 'flow.cpp', 'gpu_timers.cpp', shader_srcs, dependencies: [epoxydep, sdl2dep, sdl2_imagedep]) executable('eval', 'eval.cpp', 'util.cpp') executable('vis', 'vis.cpp', 'util.cpp')