shithub: libgraphics

Download patch

ref: 9caf2a01d069fde4648d3f247c9db40275b70b3f
parent: 39681ad94171c38431a2f2c525f8dd3931aa57f0
author: rodri <rgl@antares-labs.eu>
date: Sun Feb 22 06:16:53 EST 2026

preallocate drawing artefacts in the Viewport

keep an Image the size of the framebuffer to use for draw()
and upscaled lines that depend on the viewport scaling
for upscale(mem)?draw().

--- a/fb.c
+++ b/fb.c
@@ -129,7 +129,7 @@
 }
 
 static void
-upscaledraw(Raster *fb, Image *dst, Point off, Point scale, uint filter)
+upscaledraw(Raster *fb, Image *dst, Point off, Point scale, uint filter, Viewdrawctx *ctx)
 {
 	void (*filterfn)(ulong*, Raster*, Point, Point, ulong);
 	Rectangle blkr, dr;
@@ -139,9 +139,9 @@
 	int dx, nl;
 
 	filterfn = nil;
-	dx = Dx(fb->r);
-	blk = _emalloc(scale.x*dx*scale.y*4);
-	blkr = Rect(0,0,scale.x*dx,scale.y);
+	blk = ctx->blk;
+	blkr = ctx->blkr;
+	dx = Dx(blkr);
 	tmp = allocimage(display, dst->r, RGBA32, 0, 0);
 	if(tmp == nil)
 		sysfatal("allocimage: %r");
@@ -170,7 +170,7 @@
 	blkr = rectaddpt(blkr, addpt(dst->r.min, off));
 	for(sp.y = fb->r.min.y; sp.y < fb->r.max.y; sp.y++){
 	for(sp.x = fb->r.min.x, blkp = blk; sp.x < fb->r.max.x; sp.x++, blkp += scale.x){
-		filterfn(blkp, fb, sp, scale, scale.x*dx);
+		filterfn(blkp, fb, sp, scale, dx);
 	}
 		dr = blkr;
 		if(rectclip(&dr, dst->r)){
@@ -180,7 +180,7 @@
 			nl = Dy(dr);
 			dr.max.y = dr.min.y+1;
 			for(; nl-- > 0; dp.y++, dr.min.y++, dr.max.y++)
-				loadimage(tmp, dr, (uchar*)(blk + dp.y*scale.x*dx + dp.x), Dx(dr)*4);
+				loadimage(tmp, dr, (uchar*)(blk + dp.y*dx + dp.x), Dx(dr)*4);
 		}
 		blkr.min.y += scale.y;
 		blkr.max.y += scale.y;
@@ -187,16 +187,15 @@
 	}
 	draw(dst, dst->r, tmp, nil, tmp->r.min);
 	freeimage(tmp);
-	free(blk);
 }
 
 static void
-framebufctl_draw(Framebufctl *ctl, Image *dst, char *name, Point off, Point scale)
+framebufctl_draw(Framebufctl *ctl, Image *dst, char *name, Point off, Point scale, Viewdrawctx *ctx)
 {
 	Framebuf *fb;
 	Raster *r, *r2;
-	Rectangle sr, dr;
 	Image *tmp;
+	Rectangle sr, dr, lr;
 
 	qlock(ctl);
 	fb = ctl->getfb(ctl);
@@ -215,7 +214,7 @@
 	}
 
 	if(scale.x > 1 || scale.y > 1){
-		upscaledraw(r, dst, off, scale, ctl->upfilter);
+		upscaledraw(r, dst, off, scale, ctl->upfilter, ctx);
 		qunlock(ctl);
 		_freeraster(r2);
 		return;
@@ -222,21 +221,19 @@
 	}
 
 	/* TODO use the clipr in upscaledraw too */
+	tmp = ctx->img;
 	sr = rectaddpt(fb->clipr, off);
 	dr = rectsubpt(dst->r, dst->r.min);
 	if(rectclip(&sr, dr)){
-		tmp = allocimage(display, sr, RGBA32, 0, 0);
-		if(tmp == nil)
-			sysfatal("allocimage: %r");
-
 		dr = rectaddpt(sr, dst->r.min);
-		dr.max.y = dr.min.y + 1;
 		/* remove offset to get the actual rect within the framebuffer */
-		sr = rectsubpt(sr, off);
-		for(; sr.min.y < sr.max.y; sr.min.y++, dr.min.y++, dr.max.y++)
-			loadimage(tmp, dr, _rasterbyteaddr(r, sr.min), Dx(dr)*4);
-		draw(dst, rectaddpt(tmp->r, dst->r.min), tmp, nil, tmp->r.min);
-		freeimage(tmp);
+		lr = sr = rectsubpt(sr, off);
+		lr.max.y = lr.min.y + 1;
+		for(; lr.min.y < sr.max.y; lr.min.y++, lr.max.y++)
+			loadimage(tmp, lr, _rasterbyteaddr(r, lr.min), Dx(sr)*4);
+		draw(dst, dr, tmp, nil, sr.min);
+//		border(dst, dr, 1, display->black, ZP);
+//		border(dst, rectaddpt(sr, dst->r.min), 1, display->white, ZP);
 	}
 	qunlock(ctl);
 	_freeraster(r2);
@@ -243,7 +240,7 @@
 }
 
 static void
-upscalememdraw(Raster *fb, Memimage *dst, Point off, Point scale, uint filter)
+upscalememdraw(Raster *fb, Memimage *dst, Point off, Point scale, uint filter, Viewdrawctx *ctx)
 {
 	void (*filterfn)(ulong*, Raster*, Point, Point, ulong);
 	Rectangle blkr, dr;
@@ -253,9 +250,9 @@
 	int dx, nl;
 
 	filterfn = nil;
-	dx = Dx(fb->r);
-	blk = _emalloc(scale.x*dx*scale.y*4);
-	blkr = Rect(0,0,scale.x*dx,scale.y);
+	blk = ctx->blk;
+	blkr = ctx->blkr;
+	dx = Dx(blkr);
 	tmp = _eallocmemimage(dst->r, RGBA32);
 
 	switch(filter){
@@ -282,7 +279,7 @@
 	blkr = rectaddpt(blkr, addpt(dst->r.min, off));
 	for(sp.y = fb->r.min.y; sp.y < fb->r.max.y; sp.y++){
 	for(sp.x = fb->r.min.x, blkp = blk; sp.x < fb->r.max.x; sp.x++, blkp += scale.x){
-		filterfn(blkp, fb, sp, scale, scale.x*dx);
+		filterfn(blkp, fb, sp, scale, dx);
 	}
 		dr = blkr;
 		if(rectclip(&dr, dst->r)){
@@ -292,7 +289,7 @@
 			nl = Dy(dr);
 			dr.max.y = dr.min.y+1;
 			for(; nl-- > 0; dp.y++, dr.min.y++, dr.max.y++)
-				loadmemimage(tmp, dr, (uchar*)(blk + dp.y*scale.x*dx + dp.x), Dx(dr)*4);
+				loadmemimage(tmp, dr, (uchar*)(blk + dp.y*dx + dp.x), Dx(dr)*4);
 		}
 		blkr.min.y += scale.y;
 		blkr.max.y += scale.y;
@@ -299,11 +296,10 @@
 	}
 	memimagedraw(dst, dst->r, tmp, tmp->r.min, nil, ZP, SoverD);
 	freememimage(tmp);
-	free(blk);
 }
 
 static void
-framebufctl_memdraw(Framebufctl *ctl, Memimage *dst, char *name, Point off, Point scale)
+framebufctl_memdraw(Framebufctl *ctl, Memimage *dst, char *name, Point off, Point scale, Viewdrawctx *ctx)
 {
 	Framebuf *fb;
 	Raster *r, *r2;
@@ -328,7 +324,7 @@
 	}
 
 	if(scale.x > 1 || scale.y > 1){
-		upscalememdraw(r, dst, off, scale, ctl->upfilter);
+		upscalememdraw(r, dst, off, scale, ctl->upfilter, ctx);
 		qunlock(ctl);
 		_freeraster(r2);
 		return;
--- a/graphics.h
+++ b/graphics.h
@@ -82,6 +82,7 @@
 typedef struct Raster Raster;
 typedef struct Framebuf Framebuf;
 typedef struct Framebufctl Framebufctl;
+typedef struct Viewdrawctx Viewdrawctx;
 typedef struct Viewport Viewport;
 typedef struct Camera Camera;
 
@@ -359,8 +360,8 @@
 	uint idx;		/* front buffer index */
 	uint upfilter;		/* upscaling filter */
 
-	void (*draw)(Framebufctl*, Image*, char*, Point, Point);
-	void (*memdraw)(Framebufctl*, Memimage*, char*, Point, Point);
+	void (*draw)(Framebufctl*, Image*, char*, Point, Point, Viewdrawctx*);
+	void (*memdraw)(Framebufctl*, Memimage*, char*, Point, Point, Viewdrawctx*);
 	void (*swap)(Framebufctl*);
 	void (*reset)(Framebufctl*);
 	void (*createraster)(Framebufctl*, char*, ulong);
@@ -369,11 +370,21 @@
 	Framebuf *(*getbb)(Framebufctl*);
 };
 
+struct Viewdrawctx
+{
+	/* draw */
+	Image *img;
+	/* upscaled (mem)?draw */
+	ulong *blk;	/* upscaled scanline */
+	Rectangle blkr;
+};
+
 struct Viewport
 {
 	RFrame;
 	Framebufctl *fbctl;
 	Rectangle r;
+	Viewdrawctx dctx;
 
 	struct {
 		uvlong min, avg, max, acc, n, v;
--- a/render.c
+++ b/render.c
@@ -843,7 +843,7 @@
 	proccreate(entityproc, ep, PROCSTKSZ);
 
 	while((job = recvp(rctl->jobq)) != nil){
-		if(job->rctl->doprof)
+		if(rctl->doprof)
 			job->times.R.t0 = nanosec();
 
 		job->id = lastid++;
@@ -867,7 +867,7 @@
 		task.islast = 1;
 		send(ep->taskc, &task);
 
-		if(job->rctl->doprof)
+		if(rctl->doprof)
 			job->times.R.t1 = nanosec();
 	}
 }
--- a/viewport.c
+++ b/viewport.c
@@ -22,16 +22,24 @@
 static void
 viewport_draw(Viewport *v, Image *dst, char *rname)
 {
+	Viewdrawctx *ctx;
 	Point off, scale;
 	uvlong t0, t1;
 
+	ctx = &v->dctx;
+	if(ctx->img == nil){
+		ctx->img = allocimage(display, v->r, RGBA32, 0, 0);
+		if(ctx->img == nil)
+			sysfatal("allocimage: %r");
+	}
+
 	off = Pt(v->p.x, v->p.y);
 	/* no downsampling support yet */
-	scale.x = max(v->bx.x, 1);
-	scale.y = max(v->by.y, 1);
+	scale.x = v->bx.x;
+	scale.y = v->by.y;
 
 	t0 = nanosec();
-	v->fbctl->draw(v->fbctl, dst, rname, off, scale);
+	v->fbctl->draw(v->fbctl, dst, rname, off, scale, ctx);
 	t1 = nanosec();
 	updatestats(v, t1-t0);
 }
@@ -43,19 +51,32 @@
 
 	off = Pt(v->p.x, v->p.y);
 	/* no downsampling support yet */
-	scale.x = max(v->bx.x, 1);
-	scale.y = max(v->by.y, 1);
+	scale.x = v->bx.x;
+	scale.y = v->by.y;
 
-	v->fbctl->memdraw(v->fbctl, dst, rname, off, scale);
+	v->fbctl->memdraw(v->fbctl, dst, rname, off, scale, &v->dctx);
 }
 
 static void
 viewport_setscale(Viewport *v, double sx, double sy)
 {
+	Viewdrawctx *ctx;
+
 	assert(sx > 0 && sy > 0);
 
 	v->bx.x = sx;
 	v->by.y = sy;
+
+	ctx = &v->dctx;
+	if(sx > 1 || sy > 1){
+		if(ctx->blk != nil)
+			free(ctx->blk);
+		ctx->blk = _emalloc(sx*Dx(v->r)*sy*4);
+		ctx->blkr = Rect(0, 0, sx*Dx(v->r), sy);
+	}else if(ctx->blk != nil){
+		free(ctx->blk);
+		ctx->blk = nil;
+	}
 }
 
 static void
@@ -105,7 +126,7 @@
 	}
 
 	v = _emalloc(sizeof *v);
-	memset(&v->stats, 0, sizeof v->stats);
+	memset(v, 0, sizeof *v);
 	v->p = Pt2(0,0,1);
 	v->bx = Vec2(1,0);
 	v->by = Vec2(0,1);
@@ -128,6 +149,8 @@
 {
 	if(v == nil)
 		return;
+	free(v->dctx.blk);
+	freeimage(v->dctx.img);
 	_rmfbctl(v->fbctl);
 	free(v);
 }
--