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 = ¶ms->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 = ¶ms->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 = ¶ms->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)
{