~eliasnaur/gio-patches

gio: internal/f32color: optimize LinearFromSRGB v1 PROPOSED

~egonelbre: 1
 internal/f32color: optimize LinearFromSRGB

 4 files changed, 109 insertions(+), 3 deletions(-)
#792325 apple.yml success
#792326 freebsd.yml success
#792327 linux.yml success
#792328 openbsd.yml success
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~eliasnaur/gio-patches/patches/33468/mbox | git am -3
Learn more about email & git

[PATCH gio] internal/f32color: optimize LinearFromSRGB Export this patch

From: Egon Elbre <egonelbre@gmail.com>

Previously each call was ~100ns, the new implementation is ~1ns.

Signed-off-by: Egon Elbre <egonelbre@gmail.com>
---
 internal/f32color/f32colorgen/main.go | 59 +++++++++++++++++++++++++++
 internal/f32color/rgba.go             |  8 ++--
 internal/f32color/rgba_test.go        | 20 +++++++++
 internal/f32color/tables.go           | 25 ++++++++++++
 4 files changed, 109 insertions(+), 3 deletions(-)
 create mode 100644 internal/f32color/f32colorgen/main.go
 create mode 100644 internal/f32color/tables.go

diff --git a/internal/f32color/f32colorgen/main.go b/internal/f32color/f32colorgen/main.go
new file mode 100644
index 00000000..3e157250
--- /dev/null
+++ b/internal/f32color/f32colorgen/main.go
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: Unlicense OR MIT

package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/format"
	"math"
	"os"
)

func main() {
	out := flag.String("out", "", "output file")
	flag.Parse()

	var b bytes.Buffer
	printf := func(content string, args ...interface{}) {
		fmt.Fprintf(&b, content, args...)
	}

	printf("// SPDX-License-Identifier: Unlicense OR MIT\n\n")
	printf("// Code generated by f32colorgen. DO NOT EDIT.\n")
	printf("\n")
	printf("package f32color\n\n")

	printf("// table corresponds to sRGBToLinear(float32(index)/0xff)\n")
	printf("var srgb8ToLinear = [...]float32{")
	for b := 0; b <= 0xFF; b++ {
		if b%0x10 == 0 {
			printf("\n\t")
		}
		v := sRGBToLinear(float32(b) / 0xff)
		printf("%#v,", v)
	}
	printf("\n}\n")

	data, err := format.Source(b.Bytes())
	if err != nil {
		fmt.Fprint(os.Stderr, b.String())
		panic(err)
	}

	err = os.WriteFile(*out, data, 0755)
	if err != nil {
		panic(err)
	}
}

// sRGBToLinear transforms color value from sRGB to linear.
func sRGBToLinear(c float32) float32 {
	// Formula from EXT_sRGB.
	if c <= 0.04045 {
		return c / 12.92
	} else {
		return float32(math.Pow(float64((c+0.055)/1.055), 2.4))
	}
}
diff --git a/internal/f32color/rgba.go b/internal/f32color/rgba.go
index c4db58ad..5488a0cc 100644
--- a/internal/f32color/rgba.go
+++ b/internal/f32color/rgba.go
@@ -7,6 +7,8 @@ import (
	"math"
)

//go:generate go run ./f32colorgen -out tables.go

// RGBA is a 32 bit floating point linear premultiplied color space.
type RGBA struct {
	R, G, B, A float32
@@ -53,9 +55,9 @@ func (col RGBA) Opaque() RGBA {
func LinearFromSRGB(col color.NRGBA) RGBA {
	af := float32(col.A) / 0xFF
	return RGBA{
		R: sRGBToLinear(float32(col.R)/0xff) * af,
		G: sRGBToLinear(float32(col.G)/0xff) * af,
		B: sRGBToLinear(float32(col.B)/0xff) * af,
		R: srgb8ToLinear[col.R] * af, // sRGBToLinear(float32(col.R)/0xff) * af,
		G: srgb8ToLinear[col.G] * af, // sRGBToLinear(float32(col.G)/0xff) * af,
		B: srgb8ToLinear[col.B] * af, // sRGBToLinear(float32(col.B)/0xff) * af,
		A: af,
	}
}
diff --git a/internal/f32color/rgba_test.go b/internal/f32color/rgba_test.go
index ea0f8712..eb255d00 100644
--- a/internal/f32color/rgba_test.go
+++ b/internal/f32color/rgba_test.go
@@ -36,3 +36,23 @@ func TestLinearToRGBARoundtrip(t *testing.T) {
		}
	}
}

var sink RGBA

func BenchmarkLinearFromSRGB(b *testing.B) {
	b.Run("opaque", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			sink = LinearFromSRGB(color.NRGBA{R: byte(i), G: byte(i >> 8), B: byte(i >> 16), A: 0xFF})
		}
	})
	b.Run("translucent", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			sink = LinearFromSRGB(color.NRGBA{R: byte(i), G: byte(i >> 8), B: byte(i >> 16), A: 0x50})
		}
	})
	b.Run("transparent", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			sink = LinearFromSRGB(color.NRGBA{R: byte(i), G: byte(i >> 8), B: byte(i >> 16), A: 0x00})
		}
	})
}
diff --git a/internal/f32color/tables.go b/internal/f32color/tables.go
new file mode 100644
index 00000000..b8047862
--- /dev/null
+++ b/internal/f32color/tables.go
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: Unlicense OR MIT

// Code generated by f32colorgen. DO NOT EDIT.

package f32color

// table corresponds to sRGBToLinear(float32(index)/0xff)
var srgb8ToLinear = [...]float32{
	0, 0.000303527, 0.000607054, 0.000910581, 0.001214108, 0.001517635, 0.001821162, 0.0021246888, 0.002428216, 0.002731743, 0.00303527, 0.0033465363, 0.0036765079, 0.004024718, 0.004391443, 0.004776954,
	0.005181518, 0.0056053926, 0.006048834, 0.0065120924, 0.0069954116, 0.007499033, 0.008023194, 0.008568126, 0.009134059, 0.00972122, 0.010329825, 0.010960096, 0.011612247, 0.012286489, 0.0129830325, 0.013702083,
	0.014443846, 0.015208517, 0.015996296, 0.016807377, 0.017641956, 0.01850022, 0.019382365, 0.020288566, 0.021219013, 0.022173887, 0.023153368, 0.024157634, 0.025186861, 0.026241226, 0.027320895, 0.028426042,
	0.029556837, 0.030713446, 0.031896036, 0.033104766, 0.03433981, 0.035601318, 0.03688945, 0.03820437, 0.039546244, 0.040915202, 0.042311415, 0.043735035, 0.04518621, 0.04666509, 0.048171826, 0.049706567,
	0.05126947, 0.05286066, 0.05448029, 0.056128502, 0.05780544, 0.059511248, 0.06124608, 0.06301004, 0.06480329, 0.06662596, 0.06847819, 0.07036012, 0.07227187, 0.07421359, 0.0761854, 0.078187436,
	0.080219835, 0.08228272, 0.08437622, 0.08650047, 0.08865561, 0.09084174, 0.09305899, 0.09530749, 0.09758737, 0.09989875, 0.102241755, 0.10461651, 0.10702312, 0.10946173, 0.11193245, 0.11443539,
	0.11697068, 0.11953844, 0.122138806, 0.12477185, 0.12743771, 0.1301365, 0.13286835, 0.13563335, 0.13843164, 0.14126332, 0.14412849, 0.14702728, 0.1499598, 0.15292618, 0.15592648, 0.15896088,
	0.16202942, 0.16513222, 0.16826941, 0.17144111, 0.1746474, 0.17788842, 0.18116425, 0.18447499, 0.18782078, 0.19120169, 0.19461782, 0.19806932, 0.20155625, 0.20507872, 0.20863685, 0.21223074,
	0.21586055, 0.21952623, 0.223228, 0.2269659, 0.23074009, 0.23455067, 0.23839766, 0.24228121, 0.24620141, 0.25015837, 0.25415218, 0.25818294, 0.26225075, 0.2663557, 0.27049786, 0.2746774,
	0.27889434, 0.28314883, 0.2874409, 0.29177073, 0.29613835, 0.30054384, 0.30498737, 0.30946898, 0.31398878, 0.31854683, 0.32314327, 0.32777816, 0.33245158, 0.33716366, 0.34191447, 0.3467041,
	0.35153273, 0.35640025, 0.3613069, 0.36625272, 0.37123778, 0.37626222, 0.3813261, 0.38642955, 0.39157256, 0.39675534, 0.40197787, 0.4072403, 0.4125427, 0.41788515, 0.42326775, 0.42869058,
	0.4341537, 0.43965724, 0.44520128, 0.45078585, 0.4564111, 0.46207705, 0.46778387, 0.47353154, 0.47932023, 0.48515, 0.4910209, 0.49693304, 0.5028866, 0.50888145, 0.5149178, 0.5209957,
	0.5271153, 0.53327656, 0.5394796, 0.5457246, 0.55201155, 0.5583405, 0.56471163, 0.5711249, 0.5775806, 0.58407855, 0.59061897, 0.5972019, 0.6038274, 0.6104957, 0.61720663, 0.6239605,
	0.6307572, 0.63759696, 0.64447975, 0.6514057, 0.6583749, 0.66538733, 0.6724432, 0.67954254, 0.6866855, 0.6938719, 0.7011021, 0.70837593, 0.71569365, 0.7230553, 0.7304609, 0.73791057,
	0.74540436, 0.7529423, 0.76052463, 0.7681513, 0.77582234, 0.7835379, 0.79129803, 0.79910284, 0.80695236, 0.8148467, 0.82278585, 0.83076996, 0.8387991, 0.84687334, 0.8549927, 0.8631573,
	0.8713672, 0.87962234, 0.8879232, 0.89626944, 0.90466136, 0.9130987, 0.92158204, 0.9301109, 0.9386859, 0.9473066, 0.9559735, 0.9646863, 0.9734455, 0.9822506, 0.9911022, 1,
}
-- 
2.34.2
gio/patches: SUCCESS in 22m0s

[internal/f32color: optimize LinearFromSRGB][0] from [~egonelbre][1]

[0]: https://lists.sr.ht/~eliasnaur/gio-patches/patches/33468
[1]: mailto:egonelbre@gmail.com

✓ #792327 SUCCESS gio/patches/linux.yml   https://builds.sr.ht/~eliasnaur/job/792327
✓ #792326 SUCCESS gio/patches/freebsd.yml https://builds.sr.ht/~eliasnaur/job/792326
✓ #792328 SUCCESS gio/patches/openbsd.yml https://builds.sr.ht/~eliasnaur/job/792328
✓ #792325 SUCCESS gio/patches/apple.yml   https://builds.sr.ht/~eliasnaur/job/792325
Thanks, merged.

Elias