shithub: libgraphics

Download patch

ref: a961748acce8e85042c85fc36e074aaa71cd3b01
parent: c928eb5927903cb3e390aa5ff391ea91113517e1
author: rodri <rgl@antares-labs.eu>
date: Mon Feb 16 12:41:46 EST 2026

premultiply alpha when writing to color rasters

with this we can avoid duplicating the raster on
every framebufctl_(mem)draw() call.

we already apply gamma correction to the colors
before storage, so with this change the rasters
are effectively just Memimages.

--- a/color.c
+++ b/color.c
@@ -10,13 +10,13 @@
 ulong
 col2ul(Color c)
 {
-	uchar cbuf[4];
+	ulong l;
 
-	cbuf[0] = fclamp(c.a, 0, 1)*0xFF;
-	cbuf[1] = fclamp(c.b, 0, 1)*0xFF;
-	cbuf[2] = fclamp(c.g, 0, 1)*0xFF;
-	cbuf[3] = fclamp(c.r, 0, 1)*0xFF;
-	return cbuf[3]<<24 | cbuf[2]<<16 | cbuf[1]<<8 | cbuf[0];
+	l  = (int)(fclamp(c.a, 0, 1)*0xFF);
+	l |= (int)(fclamp(c.b, 0, 1)*0xFF) << 8;
+	l |= (int)(fclamp(c.g, 0, 1)*0xFF) << 16;
+	l |= (int)(fclamp(c.r, 0, 1)*0xFF) << 24;
+	return l;
 }
 
 Color
@@ -126,7 +126,7 @@
  * Equations 5.32 and 5.30 from “Display Encoding”, Real-Time Rendering 4th ed. § 5.6
  */
 //static double
-//_srgb2linear(double c)
+//srgb2linear1(double c)
 //{
 //	if(c > 0.04045)
 //		return pow((c + 0.055)/1.055, 2.4);
@@ -134,7 +134,7 @@
 //}
 //
 //static double
-//_linear2srgb(double c)
+//linear2srgb1(double c)
 //{
 //	if(c > 0.0031308)
 //		return 1.055*pow(c, 1.0/2.4) - 0.055;
@@ -142,7 +142,7 @@
 //}
 
 static double
-_srgb2linear(double c)
+srgb2linear1(double c)
 {
 	c = fclamp(c, 0, 1);
 	return srgb2lineartab[(int)(c*255)]/255.0;
@@ -149,7 +149,7 @@
 }
 
 static double
-_linear2srgb(double c)
+linear2srgb1(double c)
 {
 	c = fclamp(c, 0, 1);
 	return linear2srgbtab[(int)(c*255)]/255.0;
@@ -158,9 +158,9 @@
 Color
 srgb2linear(Color c)
 {
-	c.r = _srgb2linear(c.r);
-	c.g = _srgb2linear(c.g);
-	c.b = _srgb2linear(c.b);
+	c.r = srgb2linear1(c.r);
+	c.g = srgb2linear1(c.g);
+	c.b = srgb2linear1(c.b);
 	return c;
 }
 
@@ -167,9 +167,9 @@
 Color
 linear2srgb(Color c)
 {
-	c.r = _linear2srgb(c.r);
-	c.g = _linear2srgb(c.g);
-	c.b = _linear2srgb(c.b);
+	c.r = linear2srgb1(c.r);
+	c.g = linear2srgb1(c.g);
+	c.b = linear2srgb1(c.b);
 	return c;
 }
 
@@ -181,7 +181,7 @@
  * https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
  */
 static double
-_aces(double value)
+aces1(double value)
 {
 	double a = 2.51;
 	double b = 0.03;
@@ -195,9 +195,9 @@
 Color
 aces(Color c)
 {
-	c.r = _aces(c.r);
-	c.g = _aces(c.g);
-	c.b = _aces(c.b);
+	c.r = aces1(c.r);
+	c.g = aces1(c.g);
+	c.b = aces1(c.b);
 	return c;
 }
 
--- a/fb.c
+++ b/fb.c
@@ -129,23 +129,6 @@
 }
 
 static void
-premulalpha(Raster *r)
-{
-	Color c;
-	ulong *p, len;
-
-	len = Dx(r->r)*Dy(r->r);
-	p = r->data;
-	while(len--){
-		c = ul2col(*p);
-		c.r *= c.a;
-		c.g *= c.a;
-		c.b *= c.a;
-		*p++ = col2ul(c);
-	}
-}
-
-static void
 upscaledraw(Raster *fb, Image *dst, Point off, Point scale, uint filter)
 {
 	void (*filterfn)(ulong*, Raster*, Point, Point, ulong);
@@ -212,14 +195,6 @@
 		r = r2;
 	}
 
-	/* this means the raster is a color one, so duplicate it */
-	if(r2 == nil){
-		r2 = _allocraster(nil, r->r, COLOR32);
-		memmove(r2->data, r->data, Dx(r->r)*Dy(r->r)*4);
-		r = r2;
-	}
-	premulalpha(r);
-
 	if(scale.x > 1 || scale.y > 1){
 		upscaledraw(r, dst, off, scale, ctl->upfilter);
 		qunlock(ctl);
@@ -311,14 +286,6 @@
 		rasterconvF2C(r2, r);
 		r = r2;
 	}
-
-	/* this means the raster is a color one, so duplicate it */
-	if(r2 == nil){
-		r2 = _allocraster(nil, r->r, COLOR32);
-		memmove(r2->data, r->data, Dx(r->r)*Dy(r->r)*4);
-		r = r2;
-	}
-	premulalpha(r);
 
 	if(scale.x > 1 || scale.y > 1){
 		upscalememdraw(r, dst, off, scale, ctl->upfilter);
--- a/render.c
+++ b/render.c
@@ -31,6 +31,23 @@
 	_addvattr(sp->v, id, type, val);
 }
 
+#define mulalpha1(a, v, tmp)	(tmp=(a)*(v)+128, (tmp+(tmp>>8))>>8)
+
+static ulong
+mulalpha(ulong c)
+{
+	ushort r, g, b, a, t;
+
+	a = c     & 0xff;
+	b = c>>8  & 0xff;
+	g = c>>16 & 0xff;
+	r = c>>24 & 0xff;
+	r = mulalpha1(a, r, t);
+	g = mulalpha1(a, g, t);
+	b = mulalpha1(a, b, t);
+	return (r<<24)|(g<<16)|(b<<8)|a;
+}
+
 static void
 sparams_toraster(Shaderparams *sp, char *rname, void *v)
 {
@@ -49,7 +66,7 @@
 
 	switch(r->chan){
 	case COLOR32:
-		c = col2ul(*(Color*)v);
+		c = mulalpha(col2ul(*(Color*)v));
 		_rasterput(r, sp->p, &c);
 		break;
 	case FLOAT32:
@@ -70,7 +87,7 @@
 //		c = subpt3(Vec3(1,1,1), subpt3(dc, c));
 //		c = subpt3(addpt3(dc, c), Vec3(1,1,1));
 	}
-	putpixel(fb, p, col2ul(linear2srgb(c)));
+	putpixel(fb, p, mulalpha(col2ul(linear2srgb(c))));
 }
 
 static int
--