aboutsummaryrefslogtreecommitdiffhomepage
path: root/site/dev/contrib/jumper.md
blob: 520876cd19cbf5e897b347fe581b9bd504a87415 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
Contributing to SkJumper
========================

SkJumper is the execution engine of SkRasterPipeline, a system we've been using
to accelerate CPU-bound work inside Skia, most notably color-space conversions
and color-correct drawing.

(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
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.

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
to get the tools you need:

<!--?prettify lang=sh?-->

    brew install llvm binutils ccache

Running `build_stages.py`
-------------------------

With your tools installed, try a no-op run of `build_stages.py`:

<!--?prettify lang=sh?-->

    python src/jumper/build_stages.py path/to/clang-4.0 path/to/gobjdump path/to/ccache
    git status

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`.
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.

Make A Change
-------------

Let's use the `from_srgb` stage as a little playground to make a real change.
Linearizing sRGB encoded bytes is slow, so let's pretend we've decided to trade
quality for speed, approximating the existing implementation with a simple square.

Open up `SkJumper_stages.cpp` and find the `from_srgb` stage.  It'll look like

<!--?prettify lang=cc?-->

    STAGE(from_srgb) {
        ...
    }

Let's replace whatever's there with our fast approximation:

<!--?prettify lang=cc?-->

    STAGE(from_srgb) {
        r *= r;
        g *= g;
        b *= b;
    }

When you save and re-run `build_stages.py`, 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,
something like three multiplies and a couple other bookkeeping instructions.

It's not unusual for isolated changes in one stage to cause seemingly unrelated
changes in another.  When adding or removing any code you'll usually see all
the comments in branch instructions change a little bit, but the actual
instruction on the left won't change.  When adding or removing uses of
constants, you'll often see both the comment and instruction on the left change
for other loads of constants from memory, especially on x86-64.  You'll also
see some code that looks like garbage change; those are the constants.  If
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.

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.

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
uses to refer to the stage abstractly, and the wiring between
`SkRasterPipeline::foo` and `STAGE(foo) { ... }` should work automatically.