Generate SkSL golden output files from test inputs during the build.
Golden SkSL outputs are intended to eventually replace the majority of
our unit tests, since they can automatically update themselves when we
change implementation details of the compiler.
If you change the compiler output without updating the Golden files, the
CheckGeneratedFiles housekeeper will be triggered. Set
`skia_compile_processors` or `skia_compile_sksl_tests` to true in your
GN args to regenerate them.
Almost all of the tests from SkSLFPTests.cpp and SkSLGLSLTests.cpp can
be migrated into separate unit-test .fp/.sksl files in a followup CL.
hcm@ has signed off on removing the copyright boilerplate preamble from
our unit test files.
Change-Id: I9e24a944bbac8f8efd62c92481b022a0b1ecdd0b
Bug: skia:10694
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/316336
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index d4b30b2..d2ee891 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -548,7 +548,8 @@
}
}
-if (skia_compile_processors) {
+# `Compile Processors` and `Compile SkSL Tests` both rely on skslc.
+if (skia_compile_processors || skia_compile_sksl_tests) {
executable("skslc") {
defines = [ "SKSL_STANDALONE" ]
sources = [ "src/sksl/SkSLMain.cpp" ]
@@ -561,21 +562,6 @@
]
}
- skia_gpu_processor_outputs = []
- foreach(src, skia_gpu_processor_sources) {
- dir = get_path_info(src, "dir")
- name = get_path_info(src, "name")
-
- # GN insists its outputs should go somewhere underneath target_out_dir, so we trick it with a
- # path that starts with target_out_dir and then uses ".." to back up into the src dir.
- skia_gpu_processor_outputs += [
- "$target_out_dir/" +
- rebase_path("$dir/generated/$name.h", target_out_dir),
- # the script also modifies the corresponding .cpp file, but if we tell GN that it gets
- # confused due to the same file being named by two different paths
- ]
- }
-
skslc_path = "$root_out_dir/"
if (host_toolchain != default_toolchain_name) {
skslc_path += "$host_toolchain/"
@@ -640,6 +626,26 @@
]
args += rebase_path(dehydrate_sksl_sources)
}
+} else {
+ group("dehydrate_sksl") {
+ }
+}
+
+skia_gpu_processor_outputs = []
+if (skia_compile_processors) {
+ foreach(src, skia_gpu_processor_sources) {
+ dir = get_path_info(src, "dir")
+ name = get_path_info(src, "name")
+
+ # GN insists its outputs should go somewhere underneath target_out_dir, so we trick it with a
+ # path that starts with target_out_dir and then uses ".." to back up into the src dir.
+ skia_gpu_processor_outputs += [
+ "$target_out_dir/" +
+ rebase_path("$dir/generated/$name.h", target_out_dir),
+ # the script also modifies the corresponding .cpp file, but if we tell GN that it gets
+ # confused due to the same file being named by two different paths
+ ]
+ }
action("compile_processors") {
script = "gn/compile_processors.py"
@@ -658,10 +664,46 @@
args += rebase_path(skia_gpu_processor_sources)
}
} else {
- skia_gpu_processor_outputs = []
group("compile_processors") {
}
- group("dehydrate_sksl") {
+}
+
+if (skia_compile_sksl_tests) {
+ import("gn/sksl_tests.gni")
+ sksl_fp_tests_outputs = []
+ foreach(src, sksl_fp_tests_sources) {
+ dir = get_path_info(src, "dir")
+ name = get_path_info(src, "name")
+ sksl_fp_tests_outputs += [
+ "$target_out_dir/" + rebase_path("$dir/golden/$name.cpp", target_out_dir),
+ "$target_out_dir/" + rebase_path("$dir/golden/$name.h", target_out_dir),
+ ]
+ }
+
+ sksl_glsl_tests_outputs = []
+ foreach(src, sksl_glsl_tests_sources) {
+ dir = get_path_info(src, "dir")
+ name = get_path_info(src, "name")
+ sksl_glsl_tests_outputs +=
+ [ "$target_out_dir/" +
+ rebase_path("$dir/golden/$name.glsl", target_out_dir) ]
+ }
+
+ action("compile_sksl_tests") {
+ script = "gn/compile_sksl_tests.py"
+ deps = [
+ ":create_sksl_fp",
+ ":sksl_pre_includes",
+ ":skslc(//gn/toolchain:$host_toolchain)",
+ ]
+ sources = sksl_fp_tests_sources + sksl_glsl_tests_sources
+ outputs = sksl_fp_tests_outputs + sksl_glsl_tests_outputs
+ args = [ rebase_path(skslc_path) ]
+ args += rebase_path(sksl_fp_tests_sources)
+ args += rebase_path(sksl_glsl_tests_sources)
+ }
+} else {
+ group("compile_sksl_tests") {
}
}
@@ -669,6 +711,7 @@
enabled = skia_enable_gpu
deps = [
":compile_processors",
+ ":compile_sksl_tests",
":dehydrate_sksl",
":run_sksllex",
]
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index dbdec90..399f583 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -135,7 +135,8 @@
r'Copyright (\([cC]\) )?%s \w+' % years_pattern)
for affected_file in input_api.AffectedSourceFiles(source_file_filter):
- if 'third_party' in affected_file.LocalPath():
+ if ('third_party/' in affected_file.LocalPath() or
+ 'tests/sksl/' in affected_file.LocalPath()):
continue
contents = input_api.ReadFile(affected_file, 'rb')
if not re.search(copyright_pattern, contents):
diff --git a/gn/compile_sksl_tests.py b/gn/compile_sksl_tests.py
new file mode 100755
index 0000000..8b92efa
--- /dev/null
+++ b/gn/compile_sksl_tests.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+#
+# Copyright 2020 Google LLC
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import subprocess
+import sys
+
+skslc = sys.argv[1]
+inputs = sys.argv[2:]
+
+for input in inputs:
+ try:
+ noExt, ext = os.path.splitext(input)
+ head, tail = os.path.split(noExt)
+ targetDir = os.path.join(head, "golden")
+ if not os.path.isdir(targetDir):
+ os.mkdir(targetDir)
+ target = os.path.join(targetDir, tail)
+ if ext == ".fp":
+ subprocess.check_output([skslc, input, target + ".h"],
+ stderr=subprocess.STDOUT)
+ subprocess.check_output([skslc, input, target + ".cpp"],
+ stderr=subprocess.STDOUT)
+ elif ext == ".sksl":
+ subprocess.check_output([skslc, input, target + ".glsl"],
+ stderr=subprocess.STDOUT)
+ else:
+ print("### Unrecognized file type for " + input + ", skipped")
+
+ except subprocess.CalledProcessError as err:
+ print("### Error compiling " + input + ":")
+ print(err.output)
+ exit(1)
diff --git a/gn/skia.gni b/gn/skia.gni
index 92c1e14..8a9740b 100644
--- a/gn/skia.gni
+++ b/gn/skia.gni
@@ -96,6 +96,7 @@
}
declare_args() {
+ skia_compile_sksl_tests = skia_compile_processors
skia_enable_fontmgr_android = skia_use_expat && skia_use_freetype
skia_enable_fontmgr_custom_directory = skia_use_freetype && !is_fuchsia
skia_enable_fontmgr_custom_embedded = skia_use_freetype && !is_fuchsia
diff --git a/gn/sksl_tests.gni b/gn/sksl_tests.gni
new file mode 100644
index 0000000..28a653c
--- /dev/null
+++ b/gn/sksl_tests.gni
@@ -0,0 +1,11 @@
+# Copyright 2020 Google LLC
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Things are easiest for everyone if these source paths are absolute.
+_tests = get_path_info("../tests", "abspath")
+
+sksl_fp_tests_sources = [ "$_tests/sksl/fp/GrHelloWorld.fp" ]
+
+sksl_glsl_tests_sources = [ "$_tests/sksl/glsl/HelloWorld.sksl" ]
diff --git a/infra/bots/recipe_modules/build/default.py b/infra/bots/recipe_modules/build/default.py
index 51a64f7..bc31e54 100644
--- a/infra/bots/recipe_modules/build/default.py
+++ b/infra/bots/recipe_modules/build/default.py
@@ -134,6 +134,7 @@
if 'CheckGeneratedFiles' in extra_tokens:
compiler = 'Clang'
args['skia_compile_processors'] = 'true'
+ args['skia_compile_sksl_tests'] = 'true'
args['skia_generate_workarounds'] = 'true'
# ccache + clang-tidy.sh chokes on the argument list.
diff --git a/infra/bots/recipe_modules/build/examples/full.expected/Housekeeper-PerCommit-CheckGeneratedFiles.json b/infra/bots/recipe_modules/build/examples/full.expected/Housekeeper-PerCommit-CheckGeneratedFiles.json
index 8a1520b..60f24b0 100644
--- a/infra/bots/recipe_modules/build/examples/full.expected/Housekeeper-PerCommit-CheckGeneratedFiles.json
+++ b/infra/bots/recipe_modules/build/examples/full.expected/Housekeeper-PerCommit-CheckGeneratedFiles.json
@@ -66,7 +66,7 @@
"[START_DIR]/cache/work/skia/bin/gn",
"gen",
"[START_DIR]/cache/work/skia/out/Housekeeper-PerCommit-CheckGeneratedFiles/Release",
- "--args=cc=\"[START_DIR]/clang_linux/bin/clang\" cc_wrapper=\"[START_DIR]/ccache_linux/bin/ccache\" cxx=\"[START_DIR]/clang_linux/bin/clang++\" extra_cflags=[\"-B[START_DIR]/clang_linux/bin\", \"-DDUMMY_clang_linux_version=42\"] extra_ldflags=[\"-B[START_DIR]/clang_linux/bin\", \"-fuse-ld=lld\", \"-L[START_DIR]/clang_linux/lib\"] is_debug=false skia_compile_processors=true skia_generate_workarounds=true werror=true"
+ "--args=cc=\"[START_DIR]/clang_linux/bin/clang\" cc_wrapper=\"[START_DIR]/ccache_linux/bin/ccache\" cxx=\"[START_DIR]/clang_linux/bin/clang++\" extra_cflags=[\"-B[START_DIR]/clang_linux/bin\", \"-DDUMMY_clang_linux_version=42\"] extra_ldflags=[\"-B[START_DIR]/clang_linux/bin\", \"-fuse-ld=lld\", \"-L[START_DIR]/clang_linux/lib\"] is_debug=false skia_compile_processors=true skia_compile_sksl_tests=true skia_generate_workarounds=true werror=true"
],
"cwd": "[START_DIR]/cache/work/skia",
"env": {
diff --git a/infra/bots/recipes/check_generated_files.expected/Housekeeper-PerCommit-CheckGeneratedFiles.json b/infra/bots/recipes/check_generated_files.expected/Housekeeper-PerCommit-CheckGeneratedFiles.json
index 5b99f28..57dac5a 100644
--- a/infra/bots/recipes/check_generated_files.expected/Housekeeper-PerCommit-CheckGeneratedFiles.json
+++ b/infra/bots/recipes/check_generated_files.expected/Housekeeper-PerCommit-CheckGeneratedFiles.json
@@ -262,7 +262,7 @@
"[START_DIR]/cache/work/skia/bin/gn",
"gen",
"[START_DIR]/build/out/Release",
- "--args=cc=\"[START_DIR]/clang_linux/bin/clang\" cc_wrapper=\"[START_DIR]/ccache_linux/bin/ccache\" cxx=\"[START_DIR]/clang_linux/bin/clang++\" extra_cflags=[\"-B[START_DIR]/clang_linux/bin\", \"-DDUMMY_clang_linux_version=42\"] extra_ldflags=[\"-B[START_DIR]/clang_linux/bin\", \"-fuse-ld=lld\", \"-L[START_DIR]/clang_linux/lib\"] is_debug=false skia_compile_processors=true skia_generate_workarounds=true werror=true"
+ "--args=cc=\"[START_DIR]/clang_linux/bin/clang\" cc_wrapper=\"[START_DIR]/ccache_linux/bin/ccache\" cxx=\"[START_DIR]/clang_linux/bin/clang++\" extra_cflags=[\"-B[START_DIR]/clang_linux/bin\", \"-DDUMMY_clang_linux_version=42\"] extra_ldflags=[\"-B[START_DIR]/clang_linux/bin\", \"-fuse-ld=lld\", \"-L[START_DIR]/clang_linux/lib\"] is_debug=false skia_compile_processors=true skia_compile_sksl_tests=true skia_generate_workarounds=true werror=true"
],
"cwd": "[START_DIR]/cache/work/skia",
"env": {
diff --git a/tests/sksl/fp/GrHelloWorld.fp b/tests/sksl/fp/GrHelloWorld.fp
new file mode 100644
index 0000000..ccf3724
--- /dev/null
+++ b/tests/sksl/fp/GrHelloWorld.fp
@@ -0,0 +1,5 @@
+/* HELLO WORLD */
+
+void main() {
+ sk_OutColor = half4(1);
+}
diff --git a/tests/sksl/fp/golden/GrHelloWorld.cpp b/tests/sksl/fp/golden/GrHelloWorld.cpp
new file mode 100644
index 0000000..da3fab0
--- /dev/null
+++ b/tests/sksl/fp/golden/GrHelloWorld.cpp
@@ -0,0 +1,55 @@
+/* HELLO WORLD */
+
+/**************************************************************************************************
+ *** This file was autogenerated from GrHelloWorld.fp; do not modify.
+ **************************************************************************************************/
+#include "GrHelloWorld.h"
+
+#include "src/core/SkUtils.h"
+#include "src/gpu/GrTexture.h"
+#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
+#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
+#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
+#include "src/sksl/SkSLCPP.h"
+#include "src/sksl/SkSLUtil.h"
+class GrGLSLHelloWorld : public GrGLSLFragmentProcessor {
+public:
+ GrGLSLHelloWorld() {}
+ void emitCode(EmitArgs& args) override {
+ GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+ const GrHelloWorld& _outer = args.fFp.cast<GrHelloWorld>();
+ (void) _outer;
+ fragBuilder->codeAppendf(
+R"SkSL(%s = half4(1.0);
+)SkSL"
+, args.fOutputColor);
+ }
+private:
+ void onSetData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& _proc) override {
+ }
+};
+GrGLSLFragmentProcessor* GrHelloWorld::onCreateGLSLInstance() const {
+ return new GrGLSLHelloWorld();
+}
+void GrHelloWorld::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
+}
+bool GrHelloWorld::onIsEqual(const GrFragmentProcessor& other) const {
+ const GrHelloWorld& that = other.cast<GrHelloWorld>();
+ (void) that;
+ return true;
+}
+bool GrHelloWorld::usesExplicitReturn() const {
+ return false;
+}
+GrHelloWorld::GrHelloWorld(const GrHelloWorld& src)
+: INHERITED(kGrHelloWorld_ClassID, src.optimizationFlags()) {
+ this->cloneAndRegisterAllChildProcessors(src);
+}
+std::unique_ptr<GrFragmentProcessor> GrHelloWorld::clone() const {
+ return std::make_unique<GrHelloWorld>(*this);
+}
+#if GR_TEST_UTILS
+SkString GrHelloWorld::onDumpInfo() const {
+ return SkString();
+}
+#endif
diff --git a/tests/sksl/fp/golden/GrHelloWorld.h b/tests/sksl/fp/golden/GrHelloWorld.h
new file mode 100644
index 0000000..1507038
--- /dev/null
+++ b/tests/sksl/fp/golden/GrHelloWorld.h
@@ -0,0 +1,37 @@
+/* HELLO WORLD */
+
+/**************************************************************************************************
+ *** This file was autogenerated from GrHelloWorld.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrHelloWorld_DEFINED
+#define GrHelloWorld_DEFINED
+
+#include "include/core/SkM44.h"
+#include "include/core/SkTypes.h"
+
+
+#include "src/gpu/GrFragmentProcessor.h"
+
+class GrHelloWorld : public GrFragmentProcessor {
+public:
+ static std::unique_ptr<GrFragmentProcessor> Make() {
+ return std::unique_ptr<GrFragmentProcessor>(new GrHelloWorld());
+ }
+ GrHelloWorld(const GrHelloWorld& src);
+ std::unique_ptr<GrFragmentProcessor> clone() const override;
+ const char* name() const override { return "HelloWorld"; }
+ bool usesExplicitReturn() const override;
+private:
+ GrHelloWorld()
+ : INHERITED(kGrHelloWorld_ClassID, kNone_OptimizationFlags) {
+ }
+ GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+ void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+ bool onIsEqual(const GrFragmentProcessor&) const override;
+#if GR_TEST_UTILS
+ SkString onDumpInfo() const override;
+#endif
+ GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+ using INHERITED = GrFragmentProcessor;
+};
+#endif
diff --git a/tests/sksl/glsl/HelloWorld.sksl b/tests/sksl/glsl/HelloWorld.sksl
new file mode 100644
index 0000000..e74a9d0
--- /dev/null
+++ b/tests/sksl/glsl/HelloWorld.sksl
@@ -0,0 +1 @@
+void main() { sk_FragColor = half4(0.75); }
diff --git a/tests/sksl/glsl/golden/HelloWorld.glsl b/tests/sksl/glsl/golden/HelloWorld.glsl
new file mode 100644
index 0000000..54b3af7
--- /dev/null
+++ b/tests/sksl/glsl/golden/HelloWorld.glsl
@@ -0,0 +1,7 @@
+
+precision mediump float;
+precision mediump sampler2D;
+out mediump vec4 sk_FragColor;
+void main() {
+ sk_FragColor = vec4(0.75);
+}
diff --git a/tools/rewrite_includes.py b/tools/rewrite_includes.py
index 2d9a26c..6ebd460 100755
--- a/tools/rewrite_includes.py
+++ b/tools/rewrite_includes.py
@@ -70,7 +70,9 @@
# Rewrite any #includes relative to Skia's top-level directory.
need_rewriting = []
for file_path in to_rewrite():
- if 'generated' in file_path or 'third_party/skcms' in file_path:
+ if ('/generated/' in file_path or
+ 'tests/sksl/' in file_path or
+ 'third_party/skcms' in file_path):
continue
if (file_path.endswith('.h') or
file_path.endswith('.c') or