Little CMS の fast float プラグイン

# はじめに

lcms2 パッケージとして有名な Little CMS。色空間の CMYK<=>RGB や、RGB 同士(sRGB<=>P3 等)の変換で、よく使われるカラーマネージメントモジュールです。

| 　![lcms_logo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1798/f0821cde-f01d-675d-db6d-6f36ec5b38cd.png)|
|---|
|http://www.littlecms.com/ |

バージョンアップが2017年で止まっていた Little CMS ですが、2020年3月に久しぶりの lcms-2.10 リリースがありました。そのすぐ後に修正版の 2.11 が出ました。

# lcms-2.10 改め 2.11

| |
|---|
|Previouly released as a commercial package, the "fast float" plug-in increases floating point performance significantly. That means, you call a function when initializing your code and you get a throughput gain when doing floating point transforms. The plug-in has also other features like dithered output or fast 8 bit RGB transforms. |

2.10 から商用パッケージである fast float プラグインが内包されました。主に 32bit float 処理が速くなるプラグインで、あと Adobe Photoshop の内部表現で使われる(らしい) 1.15 固定小数点の色深度対応と、一部色空間でのディザ出力、8bit 処理の性能向上を含みます。

Little CMS 本体は MIT ライセンスですが、この fast float プラグインは GPLv3 or お金を払って商用のデュアルライセンスである事に注意して下さい。

なお、2.10 は Windows でのみビルドが出来て、Linux や macOS だとコードを弄らないと動きません。それ以外にも細かい修正や改善があります。実験するのであれば、2.11 以降をお勧めします。

- https://github.com/mm2/Little-CMS/releases/tag/2.11

# fast float プラグイン

## はじめに

付属の testbed を信じるならば、以下の性能改善が期待できます。

- 目玉機能の float(32bit) は Matrix shaper が 90〜265倍の異次元の性能向上
- CMYK (あとごく一部の RGB)変換に使う 8bit CLUT でも 1.2〜2.0 倍
- RGB 同士で使う 8bit Matrix shaper は 2.1~4.5 倍

自分らの使いたいツールの性能改善については、実際に組み込んでみないと分かりませんが、試す価値はありそうです。

## 機能

- RGB,CMYK の 8ビット変換のスループット向上
- Photoshop 内部表現の 1.15 固定小数点フォーマット対応
- 32ビット不動小数点での色変換スループット向上
- Gray,RGB,CMYK の 8-bit ディザ出力。

## ライセンス

GPLv3 を受け入れれば無料で使えます。
sales@littlecms.com を窓口にお金を払えばそれと別の商用ライセンスでも利用できます。

## コンパイルの仕方

ソースコードの Makefile はこの fast float を含みません。本体とライセンスが異なるので、うっかり取り込んで GPL3 対象にならないようにとの配慮だと思われます。ただ、スイッチで有効化みたいな事も出来ないのは、ちょっと残念です。
ちなみに、.so や .dll のような共有オブジェクトをプラグインする機構はありません。

Windows 用には VC2019 のプロジェクトファイルが提供されています。
Linux や Mac でビルトする場合は、自分で C ファイルを取り込んでビルドしろとの事です。

## 使い方

```c:
#include "lcms2_fast_float.h"
```

これでヘッダファイルを取り込んで、以下の一行で有効化出来ます。

```
cmsPlugin(cmsFastFloatExtensions());
```

cmsCreateContext の第一引数に cmsFastFloatExtensions() を渡す事で、プラグインの有効と無効を切り替えられます。

```c:
cmsContext NoPlugin, Plugin;
NoPlugin = cmsCreateContext(NULL, NULL);
Plugin = cmsCreateContext(cmsFastFloatExtensions(), NULL);
```

cmsDoTransform 関数がよく使われると思いますが、これを高速化した cmsDoTransformLineStride 関数がプラグインにより追加されます。条件によって圧倒的な速度が出るので、こちらへの書き換えを検討するのも良いでしょう。

## テストベッド

性能評価用のツールがついています。

| |
|---|
|There is a test bed in the plug-in directory that shows and measures the throughput gain in your target computer.|

早速、試してみましょう。

### Windows で実験

Visual Studio 2019 で git レポジトリ(https://github.com/mm2/Little-CMS)から引っ張ってきて、メニューからビルドを指定するだけです。
実行ファイルとして Little-CMS\plugins\fast_float\testbed>lcms2_fast_float_plugin_testbed.exe が生成されます。
もし生成されなければ、plugins/fast_float/lcms2_fast_float_plugin_testbed を指定してリビルドすると良いでしょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1798/0d183a50-e12f-2bcf-b159-c16409f7028f.png)

i7-9700K(3.6GHz/8core/8thread/12MB) + 64GBメモリのそこそこ性能の良いマシンで実験しました。
結果を以下に貼りますが、float は凄まじい性能改善が見込まれます。Matrix-Shaper が圧巻です。
あと、8bit も結構速くなります。

```
C:\Users\yoya\source\repos\Little-CMS\plugins\fast_float\testbed>lcms2_fast_float_plugin_testbed.exe
FastFloating point extensions testbed - 1.2
Copyright (c) 1998-2020 Marti Maria Saguer, all rights reserved

Installing error logger ... done.
Installing plug-in ... done.

Checking 15 bit <=> 8 bit macros...ok
Checking accuracy of 15 bits on CLUT...Ok
Checking accuracy of 15 bits on same profile ...Ok
Checking accuracy of 15 bits on Matrix...Ok
All 15 bits tests passed OK

Checking accuracy of 16 bits CLUT...All 16 bits tests passed OK

Checking change format feature...Ok
Crash test...Ok
Crash (II) test...Ok
Checking accuracy on Matrix-shaper...Ok
Checking accuracy of CLUT...Ok
Checking accuracy on same profile ...Ok
All floating point tests passed OK


P E R F O R M A N C E   T E S T S   8 B I T S  (D E F A U L T)
==============================================================

                                  MPixel/sec.   MByte/sec.
8 bits on CLUT profiles       : 13.45        40.34
8 bits on Matrix-Shaper       : 19.21        57.62
8 bits on same MatrixSh       : 22.63        67.89
8 bits on curves              : 20.73        62.18


P E R F O R M A N C E   T E S T S  8 B I T S  (P L U G I N)
===========================================================

                                  MPixel/sec.   MByte/sec.
8 bits on CLUT profiles       : 26.67        80.00        (x 2.0)
8 bits on Matrix-Shaper       : 86.49        259.46       (x 4.5)
8 bits on same MatrixSh       : 285.71       857.14       (x 12.6)
8 bits on curves              : 238.81       716.42       (x 11.5)


P E R F O R M A N C E   T E S T S   1 6  B I T S
================================================

                                  MPixel/sec.   MByte/sec.
16 bits on CLUT profiles         : 14.56        87.35


P E R F O R M A N C E   T E S T S   1 5  B I T S
================================================

                                  MPixel/sec.   MByte/sec.
15 bits on CLUT profiles         : 4.41         26.45
15 bits on Matrix-Shaper profiles: 64.26        385.54
15 bits on same Matrix-Shaper    : 81.22        487.31
15 bits on curves                : 5.86         35.15
15 bits on CMYK CLUT profiles    : 2.03         16.22


P E R F O R M A N C E   T E S T S   F L O A T  (D E F A U L T)
==============================================================

                                  MPixel/sec.   MByte/sec.
Floating point on CLUT profiles  : 0.54         6.43
Floating point on Matrix-Shaper  : 1.07         12.83
Floating point on same MatrixSh  : 1.15         13.83
Floating point on curves         : 1.21         14.52


P E R F O R M A N C E   T E S T S  F L O A T  (P L U G I N)
===========================================================

                                  MPixel/sec.   MByte/sec.
Floating point on CLUT profiles  : 6.41         76.86        (x 11.9)
Floating point on Matrix-Shaper  : 2.68         32.13        (x 2.5)
Floating point on same MatrixSh  : 103.23       1238.71      (x 89.6)
Floating point on curves         : 5.29         63.53        (x 4.4)


C O M P A R A T I V E  converting to 16 bit vs. using float plug-in.
                              values given in MegaPixels per second.
====================================================================
                                  16 bits tmp.  Float plugin
Floating point on CLUT profiles  : 11.75        5.66
Floating point on Matrix-Shaper  : 11.73        2.64
Floating point on same MatrixSh  : 11.83        104.58
Floating point on curves         : 11.71        5.36


C O M P A R A T I V E cmsDoTransform() vs. cmsDoTransformLineStride()
                              values given in MegaPixels per second.
====================================================================
CLUT profiles                 : 11.33        26.02
CLUT 16 bits                  : 9.60         14.52
Matrix-Shaper                 : 15.58        79.60
same MatrixSh                 : 17.56        231.88
curves                        : 16.39        195.12


F L O A T   G R A Y   conversions performance.
====================================================================
Gray conversion using two gray profiles  16.18        MPixels/Sec.
Gray conversion using two devicelinks    16.46        MPixels/Sec.

All tests passed OK

C:\Users\yoya\source\repos\Little-CMS\plugins\fast_float\testbed>
```


### Linux(Ubuntu)で実験


fast_float plugin の macOS や Linux 用 Makefile はありません。ましてや testbed のもありません。
Makefuke を自分で作るか、以下のように手動でビルド出来ます。なお、testbed の幾つかのテストはパスしません。


```
ubuntu18.04:~/src/Little-CMS-2.11/plugins/fast_float/testbed$ gcc -g -O2 -fvisibility=hidden -pthread  \
     -I ../src/  -I ../include  -I ../../../include/  \
     ./fast_float_testbed.c  ../src/*.c  ../../../src/*.c  -lm
```

実験機は Windows と同じです。(ちなみに dual boot で切り替えてます)
実行結果を以下に貼りますが、凄まじい性能改善が見込まれます。
こちらも float の Matrix-Shaper が圧巻です。

```
ubuntu18.04:~/src/Little-CMS-2.11/plugins/fast_float/testbed$ ./a.out
FastFloating point extensions testbed - 1.2
Copyright (c) 1998-2020 Marti Maria Saguer, all rights reserved

Installing error logger ... done.
Installing plug-in ... done.

Checking 15 bit <=> 8 bit macros...ok
Checking accuracy of 15 bits on CLUT...Ok
Checking accuracy of 15 bits on same profile ...Ok
Checking accuracy of 15 bits on Matrix...Ok
All 15 bits tests passed OK

Checking accuracy of 16 bits CLUT...All 16 bits tests passed OK

Checking change format feature...Ok
Crash test...Ok
Crash (II) test...Ok
Checking accuracy on Matrix-shaper...Ok
Checking accuracy of CLUT...Ok
Checking accuracy on same profile ...Ok
All floating point tests passed OK


P E R F O R M A N C E   T E S T S   8 B I T S  (D E F A U L T)
==============================================================

                                  MPixel/sec.   MByte/sec.
8 bits on CLUT profiles       : 49.99        149.97
8 bits on Matrix-Shaper       : 125.85       377.55
8 bits on same MatrixSh       : 182.78       548.35
8 bits on curves              : 180.60       541.80


P E R F O R M A N C E   T E S T S  8 B I T S  (P L U G I N)
===========================================================

                                  MPixel/sec.   MByte/sec.
8 bits on CLUT profiles       : 59.70        179.10       (x 1.2)
8 bits on Matrix-Shaper       : 283.92       851.77       (x 2.3)
8 bits on same MatrixSh       : 970.34       2911.03      (x 5.3)
8 bits on curves              : 833.94       2501.82      (x 4.6)


P E R F O R M A N C E   T E S T S   1 6  B I T S
================================================

                                  MPixel/sec.   MByte/sec.
16 bits on CLUT profiles         : 80.83        484.99


P E R F O R M A N C E   T E S T S   1 5  B I T S
================================================

                                  MPixel/sec.   MByte/sec.
15 bits on CLUT profiles         : 63.49        380.92
15 bits on Matrix-Shaper profiles: 180.27       1081.59
15 bits on same Matrix-Shaper    : 366.81       2200.88
15 bits on curves                : 157.00       941.99
15 bits on CMYK CLUT profiles    : 21.43        171.44


P E R F O R M A N C E   T E S T S   F L O A T  (D E F A U L T)
==============================================================

                                  MPixel/sec.   MByte/sec.
Floating point on CLUT profiles  : 3.46         41.52
Floating point on Matrix-Shaper  : 4.73         56.72
Floating point on same MatrixSh  : 3.12         37.43
Floating point on curves         : 3.16         37.96


P E R F O R M A N C E   T E S T S  F L O A T  (P L U G I N)
===========================================================

                                  MPixel/sec.   MByte/sec.
Floating point on CLUT profiles  : 58.94        707.24       (x 17.0)
Floating point on Matrix-Shaper  : 34.88        418.56       (x 7.4)
Floating point on same MatrixSh  : 827.90       9934.80      (x 265.4)
Floating point on curves         : 89.98        1079.81      (x 28.4)


C O M P A R A T I V E  converting to 16 bit vs. using float plug-in.
                              values given in MegaPixels per second.
====================================================================
                                  16 bits tmp.  Float plugin
Floating point on CLUT profiles  : 53.32        58.92
Floating point on Matrix-Shaper  : 53.60        34.94
Floating point on same MatrixSh  : 53.87        820.89
Floating point on curves         : 53.78        89.93


C O M P A R A T I V E cmsDoTransform() vs. cmsDoTransformLineStride()
                              values given in MegaPixels per second.
====================================================================
CLUT profiles                 : 39.05        54.06
CLUT 16 bits                  : 72.40        80.85
Matrix-Shaper                 : 71.06        225.59
same MatrixSh                 : 101.23       469.72
curves                        : 95.38        456.41


F L O A T   G R A Y   conversions performance.
====================================================================
Gray conversion using two gray profiles	 265.44       MPixels/Sec.
Gray conversion using two devicelinks	 271.30       MPixels/Sec.

All tests passed OK
ubuntu18.04:~/src/Little-CMS-2.11/plugins/fast_float/testbed$ 
```

### MacOS で実験

Linux と同じで Makefile を自分で作るか、以下のように手動でビルド出来ます。

```
MBP:~/src/Little-CMS-2.11/plugins/fast_float/testbed$ gcc -g -O2 -fvisibility=hidden -pthread  \
     -I ../src/  -I ../include  -I ../../../include/  \
     ./fast_float_testbed.c  ../src/*.c  ../../../src/*.c  -lm
```

MacBookPro 2018 の中でも安い方のモデルで実験しました。ちなみに i7 6core 2.2GHz + メモリ32GB 2400MHz DDR4 。

```
MBP:~/src/Little-CMS-2.11/plugins/fast_float/testbed$ ./a.out
FastFloating point extensions testbed - 1.2
Copyright (c) 1998-2020 Marti Maria Saguer, all rights reserved

Installing error logger ... done.
Installing plug-in ... done.

Checking 15 bit <=> 8 bit macros...ok
Checking accuracy of 15 bits on CLUT...Ok
Checking accuracy of 15 bits on same profile ...Ok
Checking accuracy of 15 bits on Matrix...Ok
All 15 bits tests passed OK

Checking accuracy of 16 bits CLUT...All 16 bits tests passed OK

Checking change format feature...Ok
Crash test...Ok
Crash (II) test...** Fatal error: Conversion failed at (0.000000 0.000000 0.000000 0.000000) != (0.000000 0.000000 0.000000 1.000000)
MBP:~/src/Little-CMS-2.11/plugins/fast_float/testbed$
```

そのままだと fast_float_testbed.c がろくに動きません。

エラーになる箇所を抜いたコードを作成しました。具体的には TryAllValuesFloatAlpha が駄目でした。

- https://gist.github.com/yoya/564a34e9f317ec85c9f94470b867c187

```
909,911c909,910
<        // TryAllValuesFloatAlpha(cmsOpenProfileFromFile("test0.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL);
<        // printf("Ok\n");
<        printf("Skip\n");
---
>        TryAllValuesFloatAlpha(cmsOpenProfileFromFile("test0.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL);
>        printf("Ok\n");
```

さて、改めて性能テスト @ macOS

```
MBP:~/src/Little-CMS-2.11/plugins/fast_float/testbed$  ./a.out
FastFloating point extensions testbed - 1.2
Copyright (c) 1998-2020 Marti Maria Saguer, all rights reserved

Installing error logger ... done.
Installing plug-in ... done.

Checking 15 bit <=> 8 bit macros...ok
Checking accuracy of 15 bits on CLUT...Ok
Checking accuracy of 15 bits on same profile ...Ok
Checking accuracy of 15 bits on Matrix...Ok
All 15 bits tests passed OK

Checking accuracy of 16 bits CLUT...All 16 bits tests passed OK

Checking change format feature...Ok
Crash test...Ok
Crash (II) test...Skip
Checking accuracy on Matrix-shaper...Ok
Checking accuracy of CLUT...Ok
Checking accuracy on same profile ...Ok
All floating point tests passed OK


P E R F O R M A N C E   T E S T S   8 B I T S  (D E F A U L T)
==============================================================

                                  MPixel/sec.   MByte/sec.
8 bits on CLUT profiles       : 39.60        118.80
8 bits on Matrix-Shaper       : 103.49       310.48
8 bits on same MatrixSh       : 152.19       456.57
8 bits on curves              : 136.73       410.20


P E R F O R M A N C E   T E S T S  8 B I T S  (P L U G I N)
===========================================================

                                  MPixel/sec.   MByte/sec.
8 bits on CLUT profiles       : 49.23        147.69       (x 1.2)
8 bits on Matrix-Shaper       : 217.68       653.05       (x 2.1)
8 bits on same MatrixSh       : 501.22       1503.67      (x 3.3)
8 bits on curves              : 316.58       949.74       (x 2.3)


P E R F O R M A N C E   T E S T S   1 6  B I T S
================================================

                                  MPixel/sec.   MByte/sec.
16 bits on CLUT profiles         : 58.50        351.01


P E R F O R M A N C E   T E S T S   1 5  B I T S
================================================

                                  MPixel/sec.   MByte/sec.
15 bits on CLUT profiles         : 49.98        299.90
15 bits on Matrix-Shaper profiles: 144.64       867.87
15 bits on same Matrix-Shaper    : 234.11       1404.68
15 bits on curves                : 123.52       741.11
15 bits on CMYK CLUT profiles    : 18.15        145.21


P E R F O R M A N C E   T E S T S   F L O A T  (D E F A U L T)
==============================================================

                                  MPixel/sec.   MByte/sec.
Floating point on CLUT profiles  : 3.57         42.87
Floating point on Matrix-Shaper  : 5.76         69.07
Floating point on same MatrixSh  : 4.65         55.76
Floating point on curves         : 4.68         56.14


P E R F O R M A N C E   T E S T S  F L O A T  (P L U G I N)
===========================================================

                                  MPixel/sec.   MByte/sec.
Floating point on CLUT profiles  : 47.96        575.58       (x 13.4)
Floating point on Matrix-Shaper  : 37.13        445.62       (x 6.5)
Floating point on same MatrixSh  : 544.74       6536.84      (x 117.2)
Floating point on curves         : 111.86       1342.38      (x 23.9)


C O M P A R A T I V E  converting to 16 bit vs. using float plug-in.
                              values given in MegaPixels per second.
====================================================================
                                  16 bits tmp.  Float plugin
Floating point on CLUT profiles  : 49.68        48.11
Floating point on Matrix-Shaper  : 49.99        37.57
Floating point on same MatrixSh  : 50.26        554.42
Floating point on curves         : 49.84        113.55


C O M P A R A T I V E cmsDoTransform() vs. cmsDoTransformLineStride()
                              values given in MegaPixels per second.
====================================================================
CLUT profiles                 : 29.60        43.36
CLUT 16 bits                  : 56.10        63.69
Matrix-Shaper                 : 48.31        202.04
same MatrixSh                 : 77.25        414.63
curves                        : 74.30        301.93


F L O A T   G R A Y   conversions performance.
====================================================================
Gray conversion using two gray profiles	 295.86       MPixels/Sec.
Gray conversion using two devicelinks	 317.33       MPixels/Sec.

All tests passed OK
MBP:~/src/Little-CMS-2.11/plugins/fast_float/testbed$
```