[escher] Specify runtime deps

The specification of runtime deps on a linux/mac test is needed for
portable testing so that it may be run outside of the tree.

Moreover, this change removes the dependency of these tests on tree
source.

See test_spec.gni in
https://fuchsia-review.googlesource.com/c/fuchsia/+/249798 for how this
information will be aggregated.

Bug: IN-819
Test: No change to production; correct test metadata produced.

Change-Id: I79fe2697a4b96bbea6a2667e79791da8c398d663
diff --git a/garnet/examples/escher/common/BUILD.gn b/garnet/examples/escher/common/BUILD.gn
index 7f63ff9..81cfaac 100644
--- a/garnet/examples/escher/common/BUILD.gn
+++ b/garnet/examples/escher/common/BUILD.gn
@@ -31,7 +31,10 @@
     deps += [ ":demo_harness_fuchsia" ]
   }
   if (is_linux) {
-    deps += [ ":demo_harness_linux" ]
+    deps += [
+      ":demo_harness_linux",
+      "//garnet/public/lib/escher/shaders:linux_shader_data",
+    ]
   }
 }
 
diff --git a/garnet/examples/escher/waterfall2/waterfall_demo.cc b/garnet/examples/escher/waterfall2/waterfall_demo.cc
index 0761ea2..4b11a33 100644
--- a/garnet/examples/escher/waterfall2/waterfall_demo.cc
+++ b/garnet/examples/escher/waterfall2/waterfall_demo.cc
@@ -30,7 +30,8 @@
   // Initialize filesystem with files before creating renderer; it will use them
   // to generate the necessary ShaderPrograms.
   escher()->shader_program_factory()->filesystem()->InitializeWithRealFiles(
-      {"shaders/model_renderer/main.frag", "shaders/model_renderer/main.vert",
+      {"shaders/model_renderer/main.frag",
+       "shaders/model_renderer/main.vert",
        "shaders/model_renderer/default_position.vert",
        "shaders/model_renderer/shadow_map_generation.frag",
        "shaders/model_renderer/shadow_map_lighting.frag",
diff --git a/garnet/public/lib/escher/fs/fuchsia_data_source.cc b/garnet/public/lib/escher/fs/fuchsia_data_source.cc
index 1f7d375..82c1deb 100644
--- a/garnet/public/lib/escher/fs/fuchsia_data_source.cc
+++ b/garnet/public/lib/escher/fs/fuchsia_data_source.cc
@@ -38,11 +38,11 @@
     : root_dir_(fbl::MakeRefCounted<fs::PseudoDir>()) {}
 
 bool FuchsiaDataSource::InitializeWithRealFiles(
-    const std::vector<HackFilePath>& paths, const char* prefix) {
-  const std::string kPrefix(prefix);
+    const std::vector<HackFilePath>& paths, const char* root) {
+  const std::string kRoot(root);
   bool success = true;
   for (const auto& path : paths) {
-    success &= LoadFile(this, kPrefix, path);
+    success &= LoadFile(this, kRoot, path);
 
     auto segs = StrSplit(path, "/");
     FXL_DCHECK(segs.size() > 0);
diff --git a/garnet/public/lib/escher/fs/fuchsia_data_source.h b/garnet/public/lib/escher/fs/fuchsia_data_source.h
index 94e1fe5..d436a2b 100644
--- a/garnet/public/lib/escher/fs/fuchsia_data_source.h
+++ b/garnet/public/lib/escher/fs/fuchsia_data_source.h
@@ -18,7 +18,7 @@
 
   // |HackFilesystem|
   bool InitializeWithRealFiles(const std::vector<HackFilePath>& paths,
-                               const char* prefix) override;
+                               const char* root) override;
 
  private:
   fbl::RefPtr<fs::PseudoDir> root_dir_;
diff --git a/garnet/public/lib/escher/fs/hack_filesystem.cc b/garnet/public/lib/escher/fs/hack_filesystem.cc
index 597d7f4..1178efb 100644
--- a/garnet/public/lib/escher/fs/hack_filesystem.cc
+++ b/garnet/public/lib/escher/fs/hack_filesystem.cc
@@ -6,6 +6,7 @@
 
 #include "lib/fxl/files/directory.h"
 #include "lib/fxl/files/file.h"
+#include "lib/fxl/files/path.h"
 
 #ifdef __Fuchsia__
 #include "lib/escher/fs/fuchsia_data_source.h"
@@ -67,14 +68,15 @@
   FXL_DCHECK(erased == 1);
 }
 
-bool HackFilesystem::LoadFile(HackFilesystem* fs, const HackFilePath& prefix,
+bool HackFilesystem::LoadFile(HackFilesystem* fs, const HackFilePath& root,
                               const HackFilePath& path) {
   std::string contents;
-  if (files::ReadFileToString(prefix + path, &contents)) {
+  std::string fullpath = files::JoinPath(root, path);
+  if (files::ReadFileToString(fullpath, &contents)) {
     fs->WriteFile(path, contents);
     return true;
   }
-  FXL_LOG(WARNING) << "Failed to read file: " << prefix + path;
+  FXL_LOG(WARNING) << "Failed to read file: " << fullpath;
   return false;
 }
 
diff --git a/garnet/public/lib/escher/fs/hack_filesystem.h b/garnet/public/lib/escher/fs/hack_filesystem.h
index 4576516..cd8e8e1 100644
--- a/garnet/public/lib/escher/fs/hack_filesystem.h
+++ b/garnet/public/lib/escher/fs/hack_filesystem.h
@@ -54,22 +54,22 @@
   std::unique_ptr<HackFilesystemWatcher> RegisterWatcher(
       HackFilesystemWatcherFunc func);
 
-  // Load the specified files from the real filesystem.  A prefix will be
-  // prepended to each path. On Fuchsia the default prefix is "/pkg/data/". On
-  // Linux, the default prefix is "garnet/public/lib/escher/", assuming $PWD is
-  // $FUCHSIA_DIR.
+  // Load the specified files from the real filesystem, given a root directory.
+  // On Fuchsia the default root is "/pkg/data/"; on Linux, the default is
+  // "../test_data/escher", which points to a directory of escher test data
+  // relative to the test binary itself.
   virtual bool InitializeWithRealFiles(const std::vector<HackFilePath>& paths,
-                                       const char* prefix =
+                                       const char* root =
 #ifdef __Fuchsia__
-                                           "/pkg/data/"
+                                           "/pkg/data"
 #else
-                                           "garnet/public/lib/escher/"
+                                           "../test_data/escher"
 #endif
                                        ) = 0;
 
  protected:
   HackFilesystem() = default;
-  static bool LoadFile(HackFilesystem* fs, const HackFilePath& prefix,
+  static bool LoadFile(HackFilesystem* fs, const HackFilePath& root,
                        const HackFilePath& path);
 
  private:
diff --git a/garnet/public/lib/escher/fs/linux_data_source.cc b/garnet/public/lib/escher/fs/linux_data_source.cc
index 64ca5e1..38aac46 100644
--- a/garnet/public/lib/escher/fs/linux_data_source.cc
+++ b/garnet/public/lib/escher/fs/linux_data_source.cc
@@ -4,21 +4,30 @@
 
 #include "lib/escher/fs/linux_data_source.h"
 
+#include <limits.h>
+#include <unistd.h>
+
 #include "lib/fxl/files/directory.h"
+#include "lib/fxl/files/path.h"
 
 namespace escher {
 
 bool LinuxDataSource::InitializeWithRealFiles(
-    const std::vector<HackFilePath>& paths, const char* prefix) {
-  const std::string kPrefix(prefix);
-  if (!files::IsDirectory(kPrefix)) {
-    FXL_LOG(ERROR) << "Cannot find garnet/public/lib/escher/.  Are you running "
-                      "from $FUCHSIA_DIR?";
-    return false;
+    const std::vector<HackFilePath>& paths, const char* root) {
+
+  if (root == nullptr) {
+    FXL_LOG(ERROR) << "root not provided";
+  } else if (root[0] != '.') {
+    FXL_LOG(ERROR) << "root must be a relative path: " << root;
   }
+  char test_path[PATH_MAX];
+  const char exe_link[] = "/proc/self/exe";
+  realpath(exe_link, test_path);
+  const std::string kRoot = files::SimplifyPath(files::JoinPath(test_path, root));
+
   bool success = true;
   for (const auto& path : paths) {
-    success &= LoadFile(this, kPrefix, path);
+    success &= LoadFile(this, kRoot, path);
   }
   return success;
 }
diff --git a/garnet/public/lib/escher/fs/linux_data_source.h b/garnet/public/lib/escher/fs/linux_data_source.h
index 892258fc..c45be10 100644
--- a/garnet/public/lib/escher/fs/linux_data_source.h
+++ b/garnet/public/lib/escher/fs/linux_data_source.h
@@ -14,7 +14,7 @@
  public:
   // |HackFilesystem|
   bool InitializeWithRealFiles(const std::vector<HackFilePath>& paths,
-                               const char* prefix) override;
+                               const char* root) override;
 };
 
 }  // namespace escher
diff --git a/garnet/public/lib/escher/shaders/BUILD.gn b/garnet/public/lib/escher/shaders/BUILD.gn
new file mode 100644
index 0000000..6faad16
--- /dev/null
+++ b/garnet/public/lib/escher/shaders/BUILD.gn
@@ -0,0 +1,61 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+assert(is_linux,
+       "shaders need only be copied to the build directory for linux tests")
+
+shaders = [
+  "model_renderer/default_position.vert",
+  "model_renderer/main.frag",
+  "model_renderer/main.vert",
+  "model_renderer/shadow_map_generation.frag",
+  "model_renderer/shadow_map_lighting.frag",
+  "model_renderer/wobble_position.vert",
+  "paper/common/use.glsl",
+  "paper/frag/main_ambient_light.frag",
+  "paper/frag/main_point_light.frag",
+  "paper/vert/compute_model_space_position.vert",
+  "paper/vert/compute_world_space_position.vert",
+  "paper/vert/main_shadow_volume_extrude.vert",
+  "paper/vert/vertex_attributes.vert",
+]
+
+# Copies shaders needed for escher linux tests to a specific test data
+# directory near the test binary.
+group_deps = []
+test_data = []
+foreach(shader, shaders) {
+  name = get_path_info(shader, "file")
+  copy_name = "copy_$name"
+  copy(copy_name) {
+    sources = [
+      shader,
+    ]
+    outputs = [
+      "$root_out_dir/test_data/escher/shaders/$shader",
+    ]
+  }
+  group_deps += [ ":$copy_name" ]
+  test_data += get_target_outputs(":$copy_name")
+
+  # TODO(IN-819): Delete once tests are no longer being run out of
+  # $root_build_dir/host_tests/.
+  deprecated_copy_name = "${copy_name}_deprecated"
+  copy(deprecated_copy_name) {
+    sources = [
+      shader,
+    ]
+    outputs = [
+      "$root_build_dir/host_tests/test_data/escher/shaders/$shader",
+    ]
+  }
+  group_deps += [ ":$deprecated_copy_name" ]
+}
+
+group("linux_shader_data") {
+  deps = group_deps
+  metadata = {
+    test_runtime_deps = test_data
+  }
+}
diff --git a/garnet/public/lib/escher/test/BUILD.gn b/garnet/public/lib/escher/test/BUILD.gn
index 76caecf..2cc5729 100644
--- a/garnet/public/lib/escher/test/BUILD.gn
+++ b/garnet/public/lib/escher/test/BUILD.gn
@@ -83,6 +83,10 @@
       "//third_party/shaderc/third_party/glslang:glslang-default-resource-limits",
     ]
 
+    if (is_linux) {
+      deps += ["//garnet/public/lib/escher/shaders:linux_shader_data"]
+    }
+
     if (is_fuchsia) {
       sources += [
         "flib/fence_listener_unittest.cc",