shithub: libgraphics

Download patch

ref: d8f71404ffd54af08bc84dbb04e60cb07e83a021
parent: 2fd16cbf190d5c37fc627f79bf586f66129fea46
author: rodri <rgl@antares-labs.eu>
date: Fri Sep 20 17:44:07 EDT 2024

implement clipped drawing. take branching out of the upscaler loop.

the rasterizers now produce a bbox of used fragments/pixels that
are unified at the end of every job/frame. we use that when
drawing so only the part that was rasterized gets sent to devdraw.

--- a/camera.c
+++ b/camera.c
@@ -273,6 +273,7 @@
 	free(job->times.Tn);
 	free(job->times.Rn);
 
+	free(job->cliprects);
 	chanfree(job->donec);
 	free(job->camera);
 	free(job);
--- a/fb.c
+++ b/fb.c
@@ -14,7 +14,7 @@
  * see https://www.scale2x.it/algorithm
  */
 static void
-scale2x_filter(ulong *dst, Raster *fb, Point sp)
+scale2x_filter(ulong *dst, Raster *fb, Point sp, ulong)
 {
 	ulong B, D, E, F, H;
 
@@ -34,7 +34,7 @@
 }
 
 static void
-scale3x_filter(ulong *dst, Raster *fb, Point sp)
+scale3x_filter(ulong *dst, Raster *fb, Point sp, ulong)
 {
 	ulong A, B, C, D, E, F, G, H, I;
 
@@ -71,11 +71,17 @@
 }
 
 //static void
-//scale4x_filter(ulong *dst, Framebuf *fb, Point sp)
+//scale4x_filter(ulong *dst, Raster *fb, Point sp, ulong)
 //{
 //
 //}
 
+static void
+ident_filter(ulong *dst, Raster *fb, Point sp, ulong len)
+{
+	memsetl(dst, getpixel(fb, sp), len);
+}
+
 /* convert a float raster to a greyscale color one */
 static void
 rasterconvF2C(Raster *dst, Raster *src)
@@ -168,7 +174,7 @@
 static void
 upscaledraw(Raster *fb, Image *dst, Point off, Point scale, uint filter)
 {
-	void (*filterfn)(ulong*, Raster*, Point);
+	void (*filterfn)(ulong*, Raster*, Point, ulong);
 	Rectangle blkr;
 	Point sp, dp;
 	Image *tmp;
@@ -177,7 +183,7 @@
 	filterfn = nil;
 	blk = emalloc(scale.x*scale.y*4);
 	blkr = Rect(0,0,scale.x,scale.y);
-	tmp = allocimage(display, dst->r, RGBA32, 0, DNofill);
+	tmp = allocimage(display, dst->r, RGBA32, 0, 0);
 	if(tmp == nil)
 		sysfatal("allocimage: %r");
 
@@ -190,14 +196,12 @@
 		if(scale.x == scale.y && scale.y == 3)
 			filterfn = scale3x_filter;
 		break;
+	default: filterfn = ident_filter;
 	}
 
 	for(sp.y = fb->r.min.y, dp.y = dst->r.min.y+off.y; sp.y < fb->r.max.y; sp.y++, dp.y += scale.y)
 	for(sp.x = fb->r.min.x, dp.x = dst->r.min.x+off.x; sp.x < fb->r.max.x; sp.x++, dp.x += scale.x){
-		if(filterfn != nil)
-			filterfn(blk, fb, sp);
-		else
-			memsetl(blk, getpixel(fb, sp), scale.x*scale.y);
+		filterfn(blk, fb, sp, scale.x*scale.y);
 		loadimage(tmp, rectaddpt(blkr, dp), (uchar*)blk, scale.x*scale.y*4);
 	}
 	draw(dst, dst->r, tmp, nil, tmp->r.min);
@@ -244,21 +248,14 @@
 		return;
 	}
 
-	sr = rectaddpt(fb->r, off);
+	/* TODO use the clipr in upscaledraw too */
+	sr = rectaddpt(fb->clipr, off);
 	dr = rectsubpt(dst->r, dst->r.min);
-	if(rectinrect(sr, dr)){
+	if(rectclip(&sr, dr)){
 		tmp = allocimage(display, sr, RGBA32, 0, DNofill);
 		if(tmp == nil)
 			sysfatal("allocimage: %r");
 
-		loadimage(tmp, sr, (uchar*)r->data, Dx(fb->r)*Dy(r->r)*4);
-		draw(dst, rectaddpt(sr, dst->r.min), tmp, nil, ZP);
-		freeimage(tmp);
-	}else if(rectclip(&sr, dr)){
-		tmp = allocimage(display, sr, RGBA32, 0, DNofill);
-		if(tmp == nil)
-			sysfatal("allocimage: %r");
-
 		dr = sr;
 		dr.max.y = dr.min.y + 1;
 		/* remove offset to get the actual rect within the framebuffer */
@@ -275,7 +272,7 @@
 static void
 upscalememdraw(Raster *fb, Memimage *dst, Point off, Point scale, uint filter)
 {
-	void (*filterfn)(ulong*, Raster*, Point);
+	void (*filterfn)(ulong*, Raster*, Point, ulong);
 	Rectangle blkr;
 	Point sp, dp;
 	Memimage *tmp;
@@ -297,14 +294,12 @@
 		if(scale.x == scale.y && scale.y == 3)
 			filterfn = scale3x_filter;
 		break;
+	default: filterfn = ident_filter;
 	}
 
 	for(sp.y = fb->r.min.y, dp.y = dst->r.min.y+off.y; sp.y < fb->r.max.y; sp.y++, dp.y += scale.y)
 	for(sp.x = fb->r.min.x, dp.x = dst->r.min.x+off.x; sp.x < fb->r.max.x; sp.x++, dp.x += scale.x){
-		if(filterfn != nil)
-			filterfn(blk, fb, sp);
-		else
-			memsetl(blk, getpixel(fb, sp), scale.x*scale.y);
+		filterfn(blk, fb, sp, scale.x*scale.y);
 		loadmemimage(tmp, rectaddpt(blkr, dp), (uchar*)blk, scale.x*scale.y*4);
 	}
 	memimagedraw(dst, dst->r, tmp, tmp->r.min, nil, ZP, S);
--- a/graphics.h
+++ b/graphics.h
@@ -258,6 +258,8 @@
 	Scene *scene;
 	Shadertab *shaders;
 	Channel *donec;
+	Rectangle *cliprects;	/* one per rasterizer */
+	int ncliprects;
 
 	struct {
 		/* renderer, entityproc, tilers, rasterizers */
@@ -302,6 +304,7 @@
 struct Framebuf
 {
 	Rectangle r;
+	Rectangle clipr;
 	Raster *rasters;	/* [0] color, [1] depth, [n] user-defined */
 	Abuf abuf;		/* A-buffer */
 
@@ -432,6 +435,8 @@
 Color samplecubemap(Cubemap*, Point3, Color(*)(Texture*, Point2));
 
 /* util */
+Point minpt(Point, Point);
+Point maxpt(Point, Point);
 Point2 modulapt2(Point2, Point2);
 Point2 minpt2(Point2, Point2);
 Point2 maxpt2(Point2, Point2);
--- a/internal.h
+++ b/internal.h
@@ -36,6 +36,7 @@
 {
 	SUparams *params;
 	Rectangle wr;		/* working rect */
+	Rectangle *clipr;
 	Primitive p;
 };
 
--- a/render.c
+++ b/render.c
@@ -212,6 +212,14 @@
 			pushtoAbuf(params->fb, p, c, z);
 		else
 			pixel(cr, p, c, ropts & ROBlend);
+
+		if(task->clipr->min.x < 0){
+			task->clipr->min = p;
+			task->clipr->max = addpt(p, Pt(1,1));
+		}else{
+			task->clipr->min = minpt(task->clipr->min, p);
+			task->clipr->max = maxpt(task->clipr->max, addpt(p, Pt(1,1)));
+		}
 		delvattrs(fsp.v);
 		break;
 	case PLine:
@@ -270,6 +278,14 @@
 				pushtoAbuf(params->fb, p, c, z);
 			else
 				pixel(cr, p, c, ropts & ROBlend);
+
+			if(task->clipr->min.x < 0){
+				task->clipr->min = p;
+				task->clipr->max = addpt(p, Pt(1,1));
+			}else{
+				task->clipr->min = minpt(task->clipr->min, p);
+				task->clipr->max = maxpt(task->clipr->max, addpt(p, Pt(1,1)));
+			}
 discard:
 			if(steep) SWAP(int, &p.x, &p.y);
 
@@ -316,6 +332,14 @@
 				pushtoAbuf(params->fb, p, c, z);
 			else
 				pixel(cr, p, c, ropts & ROBlend);
+
+			if(task->clipr->min.x < 0){
+				task->clipr->min = p;
+				task->clipr->max = addpt(p, Pt(1,1));
+			}else{
+				task->clipr->min = minpt(task->clipr->min, p);
+				task->clipr->max = maxpt(task->clipr->max, addpt(p, Pt(1,1)));
+			}
 		}
 		delvattrs(fsp.v);
 		break;
@@ -349,8 +373,23 @@
 			if(decref(job) < 1){
 				if(job->camera->rendopts & ROAbuff)
 					squashAbuf(job->fb, job->camera->rendopts & ROBlend);
+
+				/* set the clipr to the union of bboxes from the rasterizers */
+				for(i = 1; i < job->ncliprects; i++){
+					if(job->cliprects[i].min.x < 0)
+						continue;
+					job->cliprects[0].min = job->cliprects[0].min.x < 0?
+						job->cliprects[i].min:
+						minpt(job->cliprects[0].min, job->cliprects[i].min);
+					job->cliprects[0].max = job->cliprects[0].max.x < 0?
+						job->cliprects[i].max:
+						maxpt(job->cliprects[0].max, job->cliprects[i].max);
+				}
+				job->fb->clipr = job->cliprects[0];
+
 				if(job->rctl->doprof)
 					job->times.Rn[rp->id].t1 = nanosec();
+
 				nbsend(job->donec, nil);
 				free(params);
 			}else if(job->rctl->doprof)
@@ -458,6 +497,7 @@
 						*newparams = *params;
 						task = emalloc(sizeof *task);
 						task->params = newparams;
+						task->clipr = &params->job->cliprects[i];
 						task->p = *p;
 						task->p.v[0] = dupvertex(&p->v[0]);
 						sendp(taskchans[i], task);
@@ -501,6 +541,7 @@
 						task = emalloc(sizeof *task);
 						task->params = newparams;
 						task->wr = wr[i];
+						task->clipr = &params->job->cliprects[i];
 						task->p = *p;
 						task->p.v[0] = dupvertex(&p->v[0]);
 						task->p.v[1] = dupvertex(&p->v[1]);
@@ -554,6 +595,7 @@
 							task->params = newparams;
 							task->wr = bbox;
 							rectclip(&task->wr, wr[i]);
+							task->clipr = &params->job->cliprects[i];
 							task->p = *p;
 							task->p.v[0] = dupvertex(&p->v[0]);
 							task->p.v[1] = dupvertex(&p->v[1]);
@@ -635,6 +677,15 @@
 			if(params->job->rctl->doprof)
 				params->job->times.E.t1 = nanosec();
 			continue;
+		}
+
+		if(params->job->cliprects == nil){
+			params->job->cliprects = emalloc(nproc*sizeof(Rectangle));
+			params->job->ncliprects = nproc;
+			for(i = 0; i < nproc; i++){
+				params->job->cliprects[i].min = Pt(-1,-1);
+				params->job->cliprects[i].max = Pt(-1,-1);
+			}
 		}
 
 		eb = params->entity->mdl->prims;
--- a/util.c
+++ b/util.c
@@ -8,6 +8,24 @@
 #include "graphics.h"
 #include "internal.h"
 
+Point
+minpt(Point a, Point b)
+{
+	return (Point){
+		min(a.x, b.x),
+		min(a.y, b.y)
+	};
+}
+
+Point
+maxpt(Point a, Point b)
+{
+	return (Point){
+		max(a.x, b.x),
+		max(a.y, b.y)
+	};
+}
+
 Point2
 modulapt2(Point2 a, Point2 b)
 {