build regenerating SkJumper stages into GN
I _think_ this makes it so changes to _stages.cpp or _lowp.cpp get
noticed, regenerated, and baked into Skia all in the same Ninja
invocation.
Now you just need to set up the tools we use in GN:
skia_jumper_clang = ...
skia_jumper_objdump = ...
skia_jumper_ccache = ...
Change-Id: I09fb54d965644ff6e5825056fb0be2c7cab2ea92
Reviewed-on: https://skia-review.googlesource.com/21140
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Mike Klein <mtklein@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index 9ba71b2..0401d08 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -41,6 +41,10 @@
skia_enable_tools = is_skia_dev_build
skia_enable_vulkan_debug_layers = is_skia_dev_build && is_debug
skia_vulkan_sdk = getenv("VULKAN_SDK")
+
+ skia_jumper_clang = ""
+ skia_jumper_objdump = ""
+ skia_jumper_ccache = ""
}
declare_args() {
skia_use_dng_sdk = !is_fuchsia && skia_use_libjpeg_turbo && skia_use_zlib
@@ -1542,3 +1546,28 @@
}
}
}
+
+if (skia_jumper_clang != "") {
+ action("regen_jumper") {
+ script = "src/jumper/build_stages.py"
+
+ inputs = [
+ "src/jumper/SkJumper_stages.cpp",
+ "src/jumper/SkJumper_stages_lowp.cpp",
+ ]
+
+ # GN insists its outputs should go somewhere underneath target_out_dir, so we trick it.
+ outputs = [
+ "$target_out_dir/" +
+ rebase_path("src/jumper/SkJumper_generated.S", target_out_dir),
+ "$target_out_dir/" +
+ rebase_path("src/jumper/SkJumper_generated_win.S", target_out_dir),
+ ]
+
+ args = [
+ skia_jumper_clang,
+ skia_jumper_objdump,
+ skia_jumper_ccache,
+ ] + rebase_path(inputs) + rebase_path(outputs)
+ }
+}
diff --git a/site/dev/contrib/jumper.md b/site/dev/contrib/jumper.md
index 520876c..757697f 100644
--- a/site/dev/contrib/jumper.md
+++ b/site/dev/contrib/jumper.md
@@ -8,19 +8,16 @@
(This is where I'd put my link to design document if I had one...)
SkJumper is more annoying to contribute to than most Skia code because of its
-offline compilation step. `src/jumper/build_stages.py` compiles
-`src/jumper/SkJumper_stages.cpp` several different ways and parses the object
-files it generates into `src/jumper/SkJumper_generated.S` and
-`src/jumper/SkJumper_generated_win.S`. This document is designed to guide you
+offline compilation step. You'll need particular tools installed on your
+machine and to tell GN about them. This document is designed to guide you
through this process and ease some of that annoyance.
One-time Setup
--------------
-To run `build_stages.py` you need Clang 4.0 and objdump, and probably want
-ccache. It's best that Clang is exactly the same version we typically use (as
-of writing 4.0.0) and you'll need objdump to be compiled with support for
-x86-64, ARMv7, and ARMv8.
+To generate stage code you need Clang 4.0, objdump, and ccache. It's best that
+Clang is exactly the same version we typically use (as of writing 4.0.0) and
+you'll need objdump to be compiled with support for x86-64, ARMv7, and ARMv8.
The easiest way to satisfy these contraints is to get your hands on a Mac and
install [Homebrew](https://brew.sh). Once you have `brew` installed, run this
@@ -30,28 +27,22 @@
brew install llvm binutils ccache
-Running `build_stages.py`
+Setting up GN
-------------------------
-With your tools installed, try a no-op run of `build_stages.py`:
+With your tools installed, tell GN about them
-<!--?prettify lang=sh?-->
+ skia_jumper_clang = path/to/clang-4.0
+ skia_jumper_objdump = path/to/gobjdump
+ skia_jumper_ccache = path/to/ccache
- python src/jumper/build_stages.py path/to/clang-4.0 path/to/gobjdump path/to/ccache
- git status
+then regenerate and build as normal.
-When you run `git status` you should see a bunch of untracked `.o` files
-sitting in skia/, and no changes to `src/jumper/SkJumper_generated*.S`.
+If you look in your GN out directory, you should now see a bunch of `.o` files,
+and `git status` should show no changes to `src/jumper/SkJumper_generated*.S`.
That's good. Those object files are the intermediates we parse to produce
the assembly files. We just leave them around in case you want to look at
-them yourself. If you don't like them, it's safe to just
-
-<!--?prettify lang=sh?-->
-
- rm *.o
-
-If `clang-4.0`, `gobjdump`, and `ccache` are on your path, `build_stages.py`
-should find them without you needing to pass them on the command line.
+them yourself.
Make A Change
-------------
@@ -65,7 +56,9 @@
<!--?prettify lang=cc?-->
STAGE(from_srgb) {
- ...
+ r = from_srgb(r);
+ g = from_srgb(g);
+ b = from_srgb(b);
}
Let's replace whatever's there with our fast approximation:
@@ -78,7 +71,7 @@
b *= b;
}
-When you save and re-run `build_stages.py`, you should now see changes to
+When you save and re-Ninja, you should now see changes to
`src/jumper/SkJumper_generated.S` and `src/jumper/SkJumper_generated_win.S`.
If you can't read assembly, no big deal. If you can, run `git diff`. You
should see the various `sk_from_srgb_*` functions get dramatically simpler,
@@ -94,17 +87,14 @@
any of this worries you, please do go running to someone who knows more for
help, but odds are everything is fine.
-At this point you can re-build Skia, run DM, compare images, etc. as normal.
-Any time you change `SkJumper_stages.cpp`, you need to re-run `build_stages.py`
-for those changes to take effect. Believe me, I'd bake this into our GN build
-if I could figure out a way.
+At this point things should just be business as usual. Any time you change
+`SkJumper_stages.cpp`, Ninja ought to notice and regenerate the assembly files.
Adding a new Stage
------------------
Adding a new stage is a lot like changing an existing stage. Edit
-`SkJumper_stages.cpp`, run `build_stages.py`, build Skia, test, repeat until
-correct.
+`SkJumper_stages.cpp`, build Skia, test, repeat until correct.
You'll just need to also edit `SkRasterPipeline.h` to add your new stage to the
macro listing all the stages. The stage name is the handle normal Skia code
diff --git a/src/jumper/build_stages.py b/src/jumper/build_stages.py
index 6678020..c1a22b0 100755
--- a/src/jumper/build_stages.py
+++ b/src/jumper/build_stages.py
@@ -9,9 +9,21 @@
import subprocess
import sys
-clang = sys.argv[1] if len(sys.argv) > 1 else 'clang-4.0'
-objdump = sys.argv[2] if len(sys.argv) > 2 else 'gobjdump'
-ccache = sys.argv[3] if len(sys.argv) > 3 else 'ccache'
+clang = 'clang-4.0'
+objdump = 'gobjdump'
+ccache = 'ccache'
+stages = 'src/jumper/SkJumper_stages.cpp'
+stages_lowp = 'src/jumper/SkJumper_stages_lowp.cpp'
+generated = 'src/jumper/SkJumper_generated.S'
+generated_win = 'src/jumper/SkJumper_generated_win.S'
+
+clang = sys.argv[1] if len(sys.argv) > 1 else clang
+objdump = sys.argv[2] if len(sys.argv) > 2 else objdump
+ccache = sys.argv[3] if len(sys.argv) > 3 else ccache
+stages = sys.argv[4] if len(sys.argv) > 4 else stages
+stages_lowp = sys.argv[5] if len(sys.argv) > 5 else stages_lowp
+generated = sys.argv[6] if len(sys.argv) > 6 else generated
+generated_win = sys.argv[7] if len(sys.argv) > 7 else generated_win
clang = [ccache, clang, '-x', 'c++']
@@ -24,56 +36,56 @@
win = ['-DWIN', '-mno-red-zone']
sse2 = ['-msse2', '-mno-sse3', '-mno-ssse3', '-mno-sse4.1']
subprocess.check_call(clang + cflags + sse2 +
- ['-c', 'src/jumper/SkJumper_stages.cpp'] +
+ ['-c', stages] +
['-o', 'sse2.o'])
subprocess.check_call(clang + cflags + sse2 + win +
- ['-c', 'src/jumper/SkJumper_stages.cpp'] +
+ ['-c', stages] +
['-o', 'win_sse2.o'])
subprocess.check_call(clang + cflags + sse2 + x86 +
- ['-c', 'src/jumper/SkJumper_stages.cpp'] +
+ ['-c', stages] +
['-o', 'x86_sse2.o'])
ssse3 = ['-mssse3', '-mno-sse4.1']
subprocess.check_call(clang + cflags + ssse3 +
- ['-c', 'src/jumper/SkJumper_stages_lowp.cpp'] +
+ ['-c', stages_lowp] +
['-o', 'lowp_ssse3.o'])
subprocess.check_call(clang + cflags + ssse3 + win +
- ['-c', 'src/jumper/SkJumper_stages_lowp.cpp'] +
+ ['-c', stages_lowp] +
['-o', 'win_lowp_ssse3.o'])
sse41 = ['-msse4.1']
subprocess.check_call(clang + cflags + sse41 +
- ['-c', 'src/jumper/SkJumper_stages.cpp'] +
+ ['-c', stages] +
['-o', 'sse41.o'])
subprocess.check_call(clang + cflags + sse41 + win +
- ['-c', 'src/jumper/SkJumper_stages.cpp'] +
+ ['-c', stages] +
['-o', 'win_sse41.o'])
avx = ['-mavx']
subprocess.check_call(clang + cflags + avx +
- ['-c', 'src/jumper/SkJumper_stages.cpp'] +
+ ['-c', stages] +
['-o', 'avx.o'])
subprocess.check_call(clang + cflags + avx + win +
- ['-c', 'src/jumper/SkJumper_stages.cpp'] +
+ ['-c', stages] +
['-o', 'win_avx.o'])
hsw = ['-mavx2', '-mfma', '-mf16c']
subprocess.check_call(clang + cflags + hsw +
- ['-c', 'src/jumper/SkJumper_stages.cpp'] +
+ ['-c', stages] +
['-o', 'hsw.o'])
subprocess.check_call(clang + cflags + hsw + win +
- ['-c', 'src/jumper/SkJumper_stages.cpp'] +
+ ['-c', stages] +
['-o', 'win_hsw.o'])
subprocess.check_call(clang + cflags + hsw +
- ['-c', 'src/jumper/SkJumper_stages_lowp.cpp'] +
+ ['-c', stages_lowp] +
['-o', 'lowp_hsw.o'])
subprocess.check_call(clang + cflags + hsw + win +
- ['-c', 'src/jumper/SkJumper_stages_lowp.cpp'] +
+ ['-c', stages_lowp] +
['-o', 'win_lowp_hsw.o'])
aarch64 = [ '--target=aarch64' ]
subprocess.check_call(clang + cflags + aarch64 +
- ['-c', 'src/jumper/SkJumper_stages.cpp'] +
+ ['-c', stages] +
['-o', 'aarch64.o'])
vfp4 = [
@@ -81,7 +93,7 @@
'-mfpu=neon-vfpv4',
]
subprocess.check_call(clang + cflags + vfp4 +
- ['-c', 'src/jumper/SkJumper_stages.cpp'] +
+ ['-c', stages] +
['-o', 'vfp4.o'])
def parse_object_file(dot_o, directive, target=None):
@@ -162,7 +174,7 @@
print ' ' + directive + ' ' + hexed + ' '*(36-len(hexed)) + \
comment + inst + (' '*(14-len(inst)) + args if args else '')
-sys.stdout = open('src/jumper/SkJumper_generated.S', 'w')
+sys.stdout = open(generated, 'w')
print '''# Copyright 2017 Google Inc.
#
@@ -216,7 +228,7 @@
print '#endif'
-sys.stdout = open('src/jumper/SkJumper_generated_win.S', 'w')
+sys.stdout = open(generated_win, 'w')
print '''; Copyright 2017 Google Inc.
;
; Use of this source code is governed by a BSD-style license that can be