From 9a436a9406d5eb7fb01ada465a84034343e0c398 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Wed, 22 Feb 2023 23:35:50 +0100 Subject: [PATCH] Compile shaders into the library. This was long overdue; I was reluctant for a while since it's easier to develop or debug shaders this way, but the solution is of course to give priority to the filesystem. It is now allowed to give "" as the data directory, which will only ever look in the bundle. Most users should probably just do that. Shaders are no longer installed by make install. There is no API or ABI break, but of course, you cannot give "" as directory to older versions (it would mean essentially /). --- .gitignore | 2 ++ Makefile.in | 13 ++++++-- bundled_shaders.h | 18 +++++++++++ init.h | 4 ++- make_bundled_shaders.cpp | 65 ++++++++++++++++++++++++++++++++++++++++ util.cpp | 44 +++++++++++++++++++++++++++ version.h | 2 +- 7 files changed, 143 insertions(+), 5 deletions(-) create mode 100644 bundled_shaders.h create mode 100644 make_bundled_shaders.cpp diff --git a/.gitignore b/.gitignore index e9f545e..a918e00 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ perf.data *.dot demo +make_bundled_shaders +bundled_shaders.cpp effect_chain_test compute_shader_test gamma_compression_effect_test diff --git a/Makefile.in b/Makefile.in index b021ded..1d874e9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -90,7 +90,7 @@ EFFECTS = $(TESTED_EFFECTS) $(UNTESTED_EFFECTS) # Unit tests. TESTS=effect_chain_test fp16_test $(TESTED_INPUTS:=_test) $(TESTED_EFFECTS:=_test) -LIB_OBJS=effect_util.o util.o effect.o effect_chain.o init.o resource_pool.o ycbcr.o $(INPUTS:=.o) $(EFFECTS:=.o) +LIB_OBJS=effect_util.o util.o effect.o effect_chain.o init.o resource_pool.o ycbcr.o bundled_shaders.o $(INPUTS:=.o) $(EFFECTS:=.o) # Default target: all: libmovit.la $(TESTS) @@ -135,7 +135,8 @@ DEPS=$(OBJS:.o=.d) $(OBJS:.o=.ld) clean: $(LIBTOOL) --mode=clean $(RM) demo $(TESTS) libmovit.la $(OBJS) $(OBJS:.o=.lo) - $(RM) $(OBJS:.o=.gcno) $(OBJS:.o=.gcda) $(DEPS) step*.dot chain*.frag + $(LIBTOOL) --mode=clean $(RM) $(MAKE_BUNDLE_OBJS) $(MAKE_BUNDLE_OBJS:.o=.lo) make_bundled_shaders bundled_shaders.cpp + $(RM) $(OBJS:.o=.gcno) $(OBJS:.o=.gcda) $(MAKE_BUNDLE_OBJS:.o=.gcno) $(MAKE_BUNDLE_OBJS:.o=.gcda) $(DEPS) step*.dot chain*.frag $(RM) -r movit.info coverage/ .libs/ distclean: clean @@ -180,6 +181,13 @@ MISSING_SHADERS = diffusion_effect.frag glow_effect.frag unsharp_mask_effect.fra MISSING_SHADERS += fft_convolution_effect.frag fft_input.frag SHADERS := $(filter-out $(MISSING_SHADERS),$(SHADERS)) +# A program to compile all the shaders into one bundle that we can link into the library. +MAKE_BUNDLE_OBJS=make_bundled_shaders.o util.o init.o resource_pool.o +make_bundled_shaders: $(MAKE_BUNDLE_OBJS) + $(LIBTOOL) --mode=link $(CXX) $(LDFLAGS) -o make_bundled_shaders $(MAKE_BUNDLE_OBJS) -lepoxy +bundled_shaders.cpp: make_bundled_shaders $(SHADERS) + ./make_bundled_shaders $(SHADERS) > $@ + install: libmovit.la $(MKDIR) -p $(DESTDIR)$(libdir)/ $(LIBTOOL) --mode=install $(INSTALL) -m 0644 libmovit.la $(DESTDIR)$(libdir)/ @@ -197,7 +205,6 @@ dist: $(MKDIR) $(DISTDIR) cp $(OWN_OBJS:.o=.cpp) $(DISTDIR)/ cp $(HDRS) $(DISTDIR)/ - cp $(SHADERS) $(DISTDIR)/ cp $(OTHER_DIST_FILES) $(DISTDIR)/ ( cd $(DISTDIR) && aclocal && libtoolize --install --copy && autoconf && $(RM) -r autom4te.cache/ ) tar zcvvf ../$(DISTDIR).tar.gz $(DISTDIR) diff --git a/bundled_shaders.h b/bundled_shaders.h new file mode 100644 index 0000000..26d6e06 --- /dev/null +++ b/bundled_shaders.h @@ -0,0 +1,18 @@ +#ifndef _MOVIT_BUNDLED_SHADERS_H +#define _MOVIT_BUNDLED_SHADERS_H 1 + +// Shader files that are compiled into the library. + +namespace movit { + +struct BundledShader { + const char *filename; // nullptr for end. + size_t offset; // Into shader_bundle. + size_t length; +}; +extern BundledShader bundled_shaders[]; +extern const char *shader_bundle; + +} // namespace movit + +#endif // _MOVIT_BUNDLED_SHADERS_H diff --git a/init.h b/init.h index 2305522..2c7638a 100644 --- a/init.h +++ b/init.h @@ -17,7 +17,9 @@ enum MovitDebugLevel { // succeeded. // // The first parameter gives which directory to read .frag files from. -// This is a temporary hack until we add something more solid. +// If you use "", or the file isn't found, a compiled-in version will +// be used instead (if it exists). Most users should probably use "" +// unless you need backwards compatibility with Movit 1.6.3 or older. // // The second parameter specifies whether debugging is on or off. // If it is on, Movit will write intermediate graphs and the final diff --git a/make_bundled_shaders.cpp b/make_bundled_shaders.cpp new file mode 100644 index 0000000..53ce13f --- /dev/null +++ b/make_bundled_shaders.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include "util.h" +#include "bundled_shaders.h" + +using namespace std; +using namespace movit; + +namespace movit { + +// We need a fake (empty) list of shaders, since we reuse read_file(). +BundledShader bundled_shaders[] = { + { nullptr, 0, 0 } +}; +const char *shader_bundle = ""; +extern string *movit_data_directory; + +} // namespace movit + +int main(int argc, char **argv) +{ + std::vector shaders; + std::string bundle; + + movit_data_directory = new string("."); + + for (int i = 1; i < argc; ++i) { + string contents = read_file(argv[i]); + shaders.push_back(BundledShader{ argv[i], /*offset=*/bundle.size(), /*length=*/contents.size() }); + bundle += contents; + } + + printf("// Autogenerated by make_bundled_shaders.cpp. Do not edit by hand!\n"); + printf("#include \n"); + printf("#include \"bundled_shaders.h\"\n"); + printf("\n"); + printf("namespace movit {\n"); + printf("\n"); + printf("BundledShader bundled_shaders[] = {\n"); + for (const BundledShader &shader : shaders) { + printf("\t{ \"%s\", %zu, %zu },\n", shader.filename, shader.offset, shader.length); + } + printf("\t{ nullptr, 0, 0 }\n"); + printf("};\n"); + printf("const char *shader_bundle = \""); + for (unsigned char ch : bundle) { + if (ch == '\n') { + printf("\\n"); + } else if (ch == '\t') { + printf("\\t"); + } else if (ch == '"') { + printf("\\\""); + } else if (ch == '\\') { + printf("\\\\"); + } else if (!isprint(ch)) { + printf("\\0%o", ch); + } else { + printf("%c", ch); + } + } + printf("\";\n"); + printf("\n"); + printf("} // namespace movit\n"); +} diff --git a/util.cpp b/util.cpp index 9b01882..0854619 100644 --- a/util.cpp +++ b/util.cpp @@ -9,6 +9,7 @@ #include #include +#include "bundled_shaders.h" #include "fp16.h" #include "init.h" #include "util.h" @@ -84,18 +85,49 @@ void hsv2rgb_normalized(float h, float s, float v, float *r, float *g, float *b) } } +string read_file_from_bundle(const string &filename) +{ + for (const BundledShader *shader = bundled_shaders; shader->filename != nullptr; ++shader) { + if (shader->filename == filename) { + return string(shader_bundle + shader->offset, shader->length); + } + } + return ""; // Not found. +} + string read_file(const string &filename) { + string contents_from_bundle = read_file_from_bundle(filename); + + // If no data directory has been given, we read only from the bundle. + if (*movit_data_directory == "") { + if (contents_from_bundle.empty()) { + fprintf(stderr, "%s: Shader not compiled in, and no data directory has been given.\n", filename.c_str()); + exit(1); + } else { + return contents_from_bundle; + } + } + + // If we're given a data directory, we still support reading from the bundle, + // but a successful read from the file system takes priority. const string full_pathname = *movit_data_directory + "/" + filename; FILE *fp = fopen(full_pathname.c_str(), "r"); if (fp == nullptr) { + if (!contents_from_bundle.empty()) { + return contents_from_bundle; + } perror(full_pathname.c_str()); exit(1); } int ret = fseek(fp, 0, SEEK_END); if (ret == -1) { + if (!contents_from_bundle.empty()) { + fclose(fp); + return contents_from_bundle; + } perror("fseek(SEEK_END)"); exit(1); } @@ -104,6 +136,10 @@ string read_file(const string &filename) ret = fseek(fp, 0, SEEK_SET); if (ret == -1) { + if (!contents_from_bundle.empty()) { + fclose(fp); + return contents_from_bundle; + } perror("fseek(SEEK_SET)"); exit(1); } @@ -112,10 +148,18 @@ string read_file(const string &filename) str.resize(size); ret = fread(&str[0], size, 1, fp); if (ret == -1) { + if (!contents_from_bundle.empty()) { + fclose(fp); + return contents_from_bundle; + } perror("fread"); exit(1); } if (ret == 0) { + if (!contents_from_bundle.empty()) { + fclose(fp); + return contents_from_bundle; + } fprintf(stderr, "Short read when trying to read %d bytes from %s\n", size, full_pathname.c_str()); exit(1); diff --git a/version.h b/version.h index 9c08728..b85acce 100644 --- a/version.h +++ b/version.h @@ -5,6 +5,6 @@ // changes, even within git versions. There is no specific version // documentation outside the regular changelogs, though. -#define MOVIT_VERSION 37 +#define MOVIT_VERSION 38 #endif // !defined(_MOVIT_VERSION_H) -- 2.39.2