diff options
Diffstat (limited to 'render.c')
-rw-r--r-- | render.c | 789 |
1 files changed, 455 insertions, 334 deletions
@@ -42,143 +42,16 @@ isvisible(Point3 p) } static int -isfacingback(Triangle t) +isfacingback(Primitive p) { double sa; /* signed area */ - sa = t[0].p.x * t[1].p.y - t[0].p.y * t[1].p.x + - t[1].p.x * t[2].p.y - t[1].p.y * t[2].p.x + - t[2].p.x * t[0].p.y - t[2].p.y * t[0].p.x; + sa = p.v[0].p.x * p.v[1].p.y - p.v[0].p.y * p.v[1].p.x + + p.v[1].p.x * p.v[2].p.y - p.v[1].p.y * p.v[2].p.x + + p.v[2].p.x * p.v[0].p.y - p.v[2].p.y * p.v[0].p.x; return sa <= 0; } -static void -mulsdm(double r[6], double m[6][4], Point3 p) -{ - int i; - - for(i = 0; i < 6; i++) - r[i] = m[i][0]*p.x + m[i][1]*p.y + m[i][2]*p.z + m[i][3]*p.w; -} - -typedef struct -{ - Vertex *v; - ulong n; - ulong cap; -} Polygon; - -static int -addvert(Polygon *p, Vertex v) -{ - if(++p->n > p->cap) - p->v = erealloc(p->v, (p->cap = p->n)*sizeof(*p->v)); - p->v[p->n-1] = v; - return p->n; -} - -static void -swappoly(Polygon *a, Polygon *b) -{ - Polygon tmp; - - tmp = *a; - *a = *b; - *b = tmp; -} - -static void -cleanpoly(Polygon *p) -{ - int i; - - for(i = 0; i < p->n; i++) - delvattrs(&p->v[i]); - p->n = 0; -} - -/* - * references: - * - James F. Blinn, Martin E. Newell, “Clipping Using Homogeneous Coordinates”, - * SIGGRAPH '78, pp. 245-251 - * - https://cs418.cs.illinois.edu/website/text/clipping.html - * - https://github.com/aap/librw/blob/14dab85dcae6f3762fb2b1eda4d58d8e67541330/tools/playground/tl_tests.cpp#L522 - */ -static int -cliptriangle(Triangle *t) -{ - /* signed distance from each clipping plane */ - static double sdm[6][4] = { - 1, 0, 0, 1, /* l */ - -1, 0, 0, 1, /* r */ - 0, 1, 0, 1, /* b */ - 0, -1, 0, 1, /* t */ - 0, 0, 1, 1, /* f */ - 0, 0, -1, 1, /* n */ - }; - double sd0[6], sd1[6]; - double d0, d1, perc; - Polygon Vin, Vout; - Vertex *v0, *v1, v; /* edge verts and new vertex (line-plane intersection) */ - int i, j, nt; - - nt = 0; - memset(&Vin, 0, sizeof Vin); - memset(&Vout, 0, sizeof Vout); - for(i = 0; i < 3; i++) - addvert(&Vin, t[0][i]); - - for(j = 0; j < 6 && Vin.n > 0; j++){ - for(i = 0; i < Vin.n; i++){ - v0 = &Vin.v[i]; - v1 = &Vin.v[(i+1) % Vin.n]; - - mulsdm(sd0, sdm, v0->p); - mulsdm(sd1, sdm, v1->p); - - if(sd0[j] < 0 && sd1[j] < 0) - continue; - - if(sd0[j] >= 0 && sd1[j] >= 0) - goto allin; - - d0 = (j&1) == 0? sd0[j]: -sd0[j]; - d1 = (j&1) == 0? sd1[j]: -sd1[j]; - perc = d0/(d0 - d1); - - lerpvertex(&v, v0, v1, perc); - addvert(&Vout, v); - - if(sd1[j] >= 0){ -allin: - addvert(&Vout, dupvertex(v1)); - } - } - cleanpoly(&Vin); - if(j < 6-1) - swappoly(&Vin, &Vout); - } - - /* triangulate */ - if(Vout.n < 3) - cleanpoly(&Vout); - else - for(i = 0; i < Vout.n-2; i++, nt++){ - /* - * when performing fan triangulation, indices 0 and 2 - * are referenced on every triangle, so duplicate them - * to avoid complications during rasterization. - */ - t[nt][0] = i < Vout.n-2-1? dupvertex(&Vout.v[0]): Vout.v[0]; - t[nt][1] = Vout.v[i+1]; - t[nt][2] = i < Vout.n-2-1? dupvertex(&Vout.v[i+2]): Vout.v[i+2]; - } - free(Vout.v); - free(Vin.v); - - return nt; -} - /* * transforms p from e's reference frame into * the world. @@ -292,57 +165,89 @@ orthographic(Matrix3 m, double l, double r, double b, double t, double n, double } static void -rasterize(SUparams *params, Triangle t) +rasterize(Rastertask *task) { + SUparams *params; + Primitive prim; FSparams fsp; - Triangle2 t₂; + Triangle2 t; Rectangle bbox; - Point p; + Point p, dp, Δp, p0, p1; Point3 bc; Color c; - double z, depth; - - t₂.p0 = Pt2(t[0].p.x, t[0].p.y, 1); - t₂.p1 = Pt2(t[1].p.x, t[1].p.y, 1); - t₂.p2 = Pt2(t[2].p.x, t[2].p.y, 1); - /* find the triangle's bbox and clip it against the fb */ - bbox = Rect( - min(min(t₂.p0.x, t₂.p1.x), t₂.p2.x), min(min(t₂.p0.y, t₂.p1.y), t₂.p2.y), - max(max(t₂.p0.x, t₂.p1.x), t₂.p2.x)+1, max(max(t₂.p0.y, t₂.p1.y), t₂.p2.y)+1 - ); - bbox.min.x = max(bbox.min.x, params->fb->r.min.x); - bbox.min.y = max(bbox.min.y, params->fb->r.min.y); - bbox.max.x = min(bbox.max.x, params->fb->r.max.x); - bbox.max.y = min(bbox.max.y, params->fb->r.max.y); + double z, depth, dplen, perc; + int steep = 0, Δe, e, Δy; + + params = task->params; + prim = task->p; + memmove(prim.v, task->p.v, sizeof prim.v); fsp.su = params; memset(&fsp.v, 0, sizeof fsp.v); - for(p.y = bbox.min.y; p.y < bbox.max.y; p.y++) - for(p.x = bbox.min.x; p.x < bbox.max.x; p.x++){ - bc = barycoords(t₂, Pt2(p.x,p.y,1)); - if(bc.x < 0 || bc.y < 0 || bc.z < 0) - continue; + switch(prim.type){ + case PPoint: + p = Pt(prim.v[0].p.x, prim.v[0].p.y); + + depth = fclamp(prim.v[0].p.z, 0, 1); + if(depth <= params->fb->zb[p.x + p.y*Dx(params->fb->r)]) + break; + params->fb->zb[p.x + p.y*Dx(params->fb->r)] = depth; + + fsp.v = dupvertex(&prim.v[0]); + fsp.p = p; + c = params->fshader(&fsp); + memfillcolor(params->frag, col2ul(c)); + + pixel(params->fb->cb, p, params->frag); + delvattrs(&fsp.v); + break; + case PLine: + p0 = Pt(prim.v[0].p.x, prim.v[0].p.y); + p1 = Pt(prim.v[1].p.x, prim.v[1].p.y); + /* clip it against our wr */ + if(rectclipline(task->wr, &p0, &p1) < 0) + break; + + /* transpose the points */ + if(abs(p0.x-p1.x) < abs(p0.y-p1.y)){ + steep = 1; + swapi(&p0.x, &p0.y); + swapi(&p1.x, &p1.y); + } + + /* make them left-to-right */ + if(p0.x > p1.x){ + swapi(&p0.x, &p1.x); + swapi(&p0.y, &p1.y); + } + + dp = subpt(p1, p0); + Δe = 2*abs(dp.y); + e = 0; + Δy = p1.y > p0.y? 1: -1; + + /* TODO find out why sometimes lines go invisible depending on their location */ + + for(p = p0; p.x <= p1.x; p.x++){ + Δp = subpt(p, p0); + dplen = hypot(dp.x, dp.y); + perc = dplen == 0? 0: hypot(Δp.x, Δp.y)/dplen; - z = fberp(t[0].p.z, t[1].p.z, t[2].p.z, bc); + if(steep) swapi(&p.x, &p.y); + + z = flerp(prim.v[0].p.z, prim.v[1].p.z, perc); depth = fclamp(z, 0, 1); - lock(¶ms->fb->zbuflk); - if(depth <= params->fb->zbuf[p.x + p.y*Dx(params->fb->r)]){ - unlock(¶ms->fb->zbuflk); - continue; - } - params->fb->zbuf[p.x + p.y*Dx(params->fb->r)] = depth; - unlock(¶ms->fb->zbuflk); + if(depth <= params->fb->zb[p.x + p.y*Dx(params->fb->r)]) + break; + params->fb->zb[p.x + p.y*Dx(params->fb->r)] = depth; /* interpolate z⁻¹ and get actual z */ - z = fberp(t[0].p.w, t[1].p.w, t[2].p.w, bc); + z = flerp(prim.v[0].p.w, prim.v[1].p.w, perc); z = 1.0/(z < 1e-5? 1e-5: z); /* perspective-correct attribute interpolation */ - bc.x *= t[0].p.w; - bc.y *= t[1].p.w; - bc.z *= t[2].p.w; - bc = mulpt3(bc, z); - berpvertex(&fsp.v, &t[0], &t[1], &t[2], bc); + perc *= prim.v[0].p.w * z; + lerpvertex(&fsp.v, &prim.v[0], &prim.v[1], perc); fsp.p = p; c = params->fshader(&fsp); @@ -350,127 +255,378 @@ rasterize(SUparams *params, Triangle t) pixel(params->fb->cb, p, params->frag); delvattrs(&fsp.v); + + if(steep) swapi(&p.x, &p.y); + + e += Δe; + if(e > dp.x){ + p.y += Δy; + e -= 2*dp.x; + } } + break; + case PTriangle: + t.p0 = Pt2(prim.v[0].p.x, prim.v[0].p.y, 1); + t.p1 = Pt2(prim.v[1].p.x, prim.v[1].p.y, 1); + t.p2 = Pt2(prim.v[2].p.x, prim.v[2].p.y, 1); + /* find the triangle's bbox and clip it against our wr */ + bbox.min.x = min(min(t.p0.x, t.p1.x), t.p2.x); + bbox.min.y = min(min(t.p0.y, t.p1.y), t.p2.y); + bbox.max.x = max(max(t.p0.x, t.p1.x), t.p2.x)+1; + bbox.max.y = max(max(t.p0.y, t.p1.y), t.p2.y)+1; + bbox.min.x = max(bbox.min.x, task->wr.min.x); + bbox.min.y = max(bbox.min.y, task->wr.min.y); + bbox.max.x = min(bbox.max.x, task->wr.max.x); + bbox.max.y = min(bbox.max.y, task->wr.max.y); + + for(p.y = bbox.min.y; p.y < bbox.max.y; p.y++) + for(p.x = bbox.min.x; p.x < bbox.max.x; p.x++){ + bc = barycoords(t, Pt2(p.x,p.y,1)); + if(bc.x < 0 || bc.y < 0 || bc.z < 0) + continue; + + z = fberp(prim.v[0].p.z, prim.v[1].p.z, prim.v[2].p.z, bc); + depth = fclamp(z, 0, 1); + if(depth <= params->fb->zb[p.x + p.y*Dx(params->fb->r)]) + continue; + params->fb->zb[p.x + p.y*Dx(params->fb->r)] = depth; + + /* interpolate z⁻¹ and get actual z */ + z = fberp(prim.v[0].p.w, prim.v[1].p.w, prim.v[2].p.w, bc); + z = 1.0/(z < 1e-5? 1e-5: z); + + /* perspective-correct attribute interpolation */ + bc.x *= prim.v[0].p.w; + bc.y *= prim.v[1].p.w; + bc.z *= prim.v[2].p.w; + bc = mulpt3(bc, z); + berpvertex(&fsp.v, &prim.v[0], &prim.v[1], &prim.v[2], bc); + + fsp.p = p; + c = params->fshader(&fsp); + memfillcolor(params->frag, col2ul(c)); + + pixel(params->fb->cb, p, params->frag); + delvattrs(&fsp.v); + } + break; + } } static void -entityproc(void *arg) +rasterizer(void *arg) { - Channel *paramsc; + Rasterparam *rp; + Rastertask *task; SUparams *params; - VSparams vsp; - OBJVertex *verts, *tverts, *nverts; /* geometric, texture and normals vertices */ - OBJIndexArray *idxtab; - OBJElem **ep, **eb, **ee; - Point3 n; /* surface normal */ - Triangle *t; /* triangles to raster */ - int i, nt; + Memimage *frag; + uvlong t0; + int i; - threadsetname("entityproc"); + rp = arg; + frag = rgb(DBlack); - paramsc = arg; - t = emalloc(sizeof(*t)*16); + threadsetname("rasterizer %d", rp->id); - while((params = recvp(paramsc)) != nil){ - vsp.su = params; + while((task = recvp(rp->taskc)) != nil){ + t0 = nanosec(); - verts = params->entity->mdl->obj->vertdata[OBJVGeometric].verts; - tverts = params->entity->mdl->obj->vertdata[OBJVTexture].verts; - nverts = params->entity->mdl->obj->vertdata[OBJVNormal].verts; - - eb = params->entity->mdl->elems; - ee = eb + params->entity->mdl->nelems; - - for(ep = eb; ep != ee; ep++){ - nt = 1; /* start with one. after clipping it might change */ - - idxtab = &(*ep)->indextab[OBJVGeometric]; - t[0][0].p = Pt3(verts[idxtab->indices[0]].x, - verts[idxtab->indices[0]].y, - verts[idxtab->indices[0]].z, - verts[idxtab->indices[0]].w); - t[0][1].p = Pt3(verts[idxtab->indices[1]].x, - verts[idxtab->indices[1]].y, - verts[idxtab->indices[1]].z, - verts[idxtab->indices[1]].w); - t[0][2].p = Pt3(verts[idxtab->indices[2]].x, - verts[idxtab->indices[2]].y, - verts[idxtab->indices[2]].z, - verts[idxtab->indices[2]].w); - - idxtab = &(*ep)->indextab[OBJVNormal]; - if(idxtab->nindex == 3){ - t[0][0].n = Vec3(nverts[idxtab->indices[0]].i, - nverts[idxtab->indices[0]].j, - nverts[idxtab->indices[0]].k); - t[0][0].n = normvec3(t[0][0].n); - t[0][1].n = Vec3(nverts[idxtab->indices[1]].i, - nverts[idxtab->indices[1]].j, - nverts[idxtab->indices[1]].k); - t[0][1].n = normvec3(t[0][1].n); - t[0][2].n = Vec3(nverts[idxtab->indices[2]].i, - nverts[idxtab->indices[2]].j, - nverts[idxtab->indices[2]].k); - t[0][2].n = normvec3(t[0][2].n); - }else{ - /* TODO build a list of per-vertex normals earlier */ - n = normvec3(crossvec3(subpt3(t[0][1].p, t[0][0].p), subpt3(t[0][2].p, t[0][0].p))); - t[0][0].n = t[0][1].n = t[0][2].n = n; + params = task->params; + /* end of job */ + if(params->entity == nil){ + if(decref(params->job) < 1){ + nbsend(params->job->donec, nil); + free(params); } + free(task); + continue; + } - idxtab = &(*ep)->indextab[OBJVTexture]; - if(idxtab->nindex == 3){ - t[0][0].uv = Pt2(tverts[idxtab->indices[0]].u, - tverts[idxtab->indices[0]].v, 1); - t[0][1].uv = Pt2(tverts[idxtab->indices[1]].u, - tverts[idxtab->indices[1]].v, 1); - t[0][2].uv = Pt2(tverts[idxtab->indices[2]].u, - tverts[idxtab->indices[2]].v, 1); - }else{ - t[0][0].uv = t[0][1].uv = t[0][2].uv = Vec2(0,0); - } + if(params->job->times.Rn.t0 == 0) + params->job->times.Rn.t0 = t0; + + params->frag = frag; + rasterize(task); - for(i = 0; i < 3; i++){ - t[0][i].c = Pt3(1,1,1,1); - t[0][i].mtl = (*ep)->mtl; - t[0][i].attrs = nil; - t[0][i].nattrs = 0; + for(i = 0; i < task->p.type+1; i++) + delvattrs(&task->p.v[i]); + params->job->times.Rn.t1 = nanosec(); + free(params); + free(task); + } +} + +static void +tilerdurden(void *arg) +{ + Tilerparam *tp; + SUparams *params, *newparams; + Rastertask *task; + VSparams vsp; + Primitive *ep, *p; /* primitives to raster */ + Rectangle *wr, bbox; + Channel **taskchans; + ulong Δy, nproc; + int i, np; + uvlong t0; + + tp = arg; + p = emalloc(sizeof(*p)*16); + taskchans = tp->taskchans; + nproc = tp->nproc; + wr = emalloc(nproc*sizeof(Rectangle)); + + threadsetname("tilerdurden %d", tp->id); + + while((params = recvp(tp->paramsc)) != nil){ + t0 = nanosec(); + if(params->job->times.Tn.t0 == 0) + params->job->times.Tn.t0 = t0; + + /* end of job */ + if(params->entity == nil){ + if(decref(params->job) < 1){ + params->job->ref = nproc; + for(i = 0; i < nproc; i++){ + task = emalloc(sizeof *task); + memset(task, 0, sizeof *task); + task->params = params; + sendp(taskchans[i], task); + } } + continue; + } + vsp.su = params; + + wr[0] = params->fb->r; + Δy = Dy(wr[0])/nproc; + wr[0].max.y = wr[0].min.y + Δy; + for(i = 1; i < nproc; i++) + wr[i] = rectaddpt(wr[i-1], Pt(0,Δy)); + if(wr[nproc-1].max.y < params->fb->r.max.y) + wr[nproc-1].max.y = params->fb->r.max.y; + + for(ep = params->eb; ep != params->ee; ep++){ + np = 1; /* start with one. after clipping it might change */ + + memmove(p, ep, sizeof *p); + switch(ep->type){ + case PPoint: + p[0].v[0].c = Pt3(1,1,1,1); + p[0].v[0].mtl = ep->mtl; + p[0].v[0].attrs = nil; + p[0].v[0].nattrs = 0; + + vsp.v = &p[0].v[0]; + vsp.idx = 0; + p[0].v[0].p = params->vshader(&vsp); + + if(!isvisible(p[0].v[0].p)) + break; + + p[0].v[0].p = clip2ndc(p[0].v[0].p); + p[0].v[0].p = ndc2viewport(params->fb, p[0].v[0].p); + + bbox.min.x = p[0].v[0].p.x; + bbox.min.y = p[0].v[0].p.y; + bbox.max.x = p[0].v[0].p.x+1; + bbox.max.y = p[0].v[0].p.y+1; + + for(i = 0; i < nproc; i++) + if(rectXrect(bbox,wr[i])){ + newparams = emalloc(sizeof *newparams); + *newparams = *params; + task = emalloc(sizeof *task); + task->params = newparams; + task->wr = wr[i]; + memmove(&task->p, &p[0], sizeof task->p); + task->p.v[0] = dupvertex(&p[0].v[0]); + sendp(taskchans[i], task); + } + delvattrs(&p[0].v[0]); + break; + case PLine: + for(i = 0; i < 2; i++){ + p[0].v[i].c = Pt3(1,1,1,1); + p[0].v[i].mtl = ep->mtl; + p[0].v[i].attrs = nil; + p[0].v[i].nattrs = 0; + + vsp.v = &p[0].v[i]; + vsp.idx = i; + p[0].v[i].p = params->vshader(&vsp); + } + + if(!isvisible(p[0].v[0].p) || !isvisible(p[0].v[1].p)) + np = clipprimitive(p); + + while(np--){ + p[np].v[0].p = clip2ndc(p[np].v[0].p); + p[np].v[1].p = clip2ndc(p[np].v[1].p); + + /* culling */ +// if(isfacingback(p[np])) +// goto skiptri2; + + p[np].v[0].p = ndc2viewport(params->fb, p[np].v[0].p); + p[np].v[1].p = ndc2viewport(params->fb, p[np].v[1].p); + + bbox.min.x = min(p[np].v[0].p.x, p[np].v[1].p.x); + bbox.min.y = min(p[np].v[0].p.y, p[np].v[1].p.y); + bbox.max.x = max(p[np].v[0].p.x, p[np].v[1].p.x)+1; + bbox.max.y = max(p[np].v[0].p.y, p[np].v[1].p.y)+1; + + for(i = 0; i < nproc; i++) + if(rectXrect(bbox,wr[i])){ + newparams = emalloc(sizeof *newparams); + *newparams = *params; + task = emalloc(sizeof *task); + task->params = newparams; + task->wr = wr[i]; + memmove(&task->p, &p[np], sizeof task->p); + task->p.v[0] = dupvertex(&p[np].v[0]); + task->p.v[1] = dupvertex(&p[np].v[1]); + sendp(taskchans[i], task); + } +//skiptri2: + delvattrs(&p[np].v[0]); + delvattrs(&p[np].v[1]); + } + break; + case PTriangle: + for(i = 0; i < 3; i++){ + p[0].v[i].c = Pt3(1,1,1,1); + p[0].v[i].mtl = p->mtl; + p[0].v[i].attrs = nil; + p[0].v[i].nattrs = 0; + + vsp.v = &p[0].v[i]; + vsp.idx = i; + p[0].v[i].p = params->vshader(&vsp); + } - vsp.v = &t[0][0]; - vsp.idx = 0; - t[0][0].p = params->vshader(&vsp); - vsp.v = &t[0][1]; - vsp.idx = 1; - t[0][1].p = params->vshader(&vsp); - vsp.v = &t[0][2]; - vsp.idx = 2; - t[0][2].p = params->vshader(&vsp); - - if(!isvisible(t[0][0].p) || !isvisible(t[0][1].p) || !isvisible(t[0][2].p)) - nt = cliptriangle(t); - - while(nt--){ - t[nt][0].p = clip2ndc(t[nt][0].p); - t[nt][1].p = clip2ndc(t[nt][1].p); - t[nt][2].p = clip2ndc(t[nt][2].p); - - /* culling */ -// if(isfacingback(t[nt])) -// goto skiptri; - - t[nt][0].p = ndc2viewport(params->fb, t[nt][0].p); - t[nt][1].p = ndc2viewport(params->fb, t[nt][1].p); - t[nt][2].p = ndc2viewport(params->fb, t[nt][2].p); - - rasterize(params, t[nt]); + if(!isvisible(p[0].v[0].p) || !isvisible(p[0].v[1].p) || !isvisible(p[0].v[2].p)) + np = clipprimitive(p); + + while(np--){ + p[np].v[0].p = clip2ndc(p[np].v[0].p); + p[np].v[1].p = clip2ndc(p[np].v[1].p); + p[np].v[2].p = clip2ndc(p[np].v[2].p); + + /* culling */ +// if(isfacingback(p[np])) +// goto skiptri; + + p[np].v[0].p = ndc2viewport(params->fb, p[np].v[0].p); + p[np].v[1].p = ndc2viewport(params->fb, p[np].v[1].p); + p[np].v[2].p = ndc2viewport(params->fb, p[np].v[2].p); + + bbox.min.x = min(min(p[np].v[0].p.x, p[np].v[1].p.x), p[np].v[2].p.x); + bbox.min.y = min(min(p[np].v[0].p.y, p[np].v[1].p.y), p[np].v[2].p.y); + bbox.max.x = max(max(p[np].v[0].p.x, p[np].v[1].p.x), p[np].v[2].p.x)+1; + bbox.max.y = max(max(p[np].v[0].p.y, p[np].v[1].p.y), p[np].v[2].p.y)+1; + + for(i = 0; i < nproc; i++) + if(rectXrect(bbox,wr[i])){ + newparams = emalloc(sizeof *newparams); + *newparams = *params; + task = emalloc(sizeof *task); + task->params = newparams; + task->wr = wr[i]; + memmove(&task->p, &p[np], sizeof task->p); + task->p.v[0] = dupvertex(&p[np].v[0]); + task->p.v[1] = dupvertex(&p[np].v[1]); + task->p.v[2] = dupvertex(&p[np].v[2]); + sendp(taskchans[i], task); + } //skiptri: - delvattrs(&t[nt][0]); - delvattrs(&t[nt][1]); - delvattrs(&t[nt][2]); + delvattrs(&p[np].v[0]); + delvattrs(&p[np].v[1]); + delvattrs(&p[np].v[2]); + } + break; } } - sendp(params->donec, params); + params->job->times.Tn.t1 = nanosec(); + free(params); + } +} + +static void +entityproc(void *arg) +{ + Channel *paramsin, **paramsout, **taskchans; + Tilerparam *tp; + Rasterparam *rp; + SUparams *params, *newparams; + Primitive *eb, *ee; + char *nprocs; + ulong stride, nprims, nproc, nworkers; + int i; + uvlong t0; + + threadsetname("entityproc"); + + paramsin = arg; + nprocs = getenv("NPROC"); + if(nprocs == nil || (nproc = strtoul(nprocs, nil, 10)) < 2) + nproc = 1; + else + nproc /= 2; + free(nprocs); + + paramsout = emalloc(nproc*sizeof(*paramsout)); + taskchans = emalloc(nproc*sizeof(*taskchans)); + for(i = 0; i < nproc; i++){ + paramsout[i] = chancreate(sizeof(SUparams*), 8); + tp = emalloc(sizeof *tp); + tp->id = i; + tp->paramsc = paramsout[i]; + tp->taskchans = taskchans; + tp->nproc = nproc; + proccreate(tilerdurden, tp, mainstacksize); + } + for(i = 0; i < nproc; i++){ + rp = emalloc(sizeof *rp); + rp->id = i; + rp->taskc = taskchans[i] = chancreate(sizeof(Rastertask*), 32); + proccreate(rasterizer, rp, mainstacksize); + } + + while((params = recvp(paramsin)) != nil){ + t0 = nanosec(); + if(params->job->times.E.t0 == 0) + params->job->times.E.t0 = t0; + + /* end of job */ + if(params->entity == nil){ + params->job->ref = nproc; + for(i = 0; i < nproc; i++) + sendp(paramsout[i], params); + continue; + } + + eb = params->entity->mdl->prims; + nprims = params->entity->mdl->nprims; + ee = eb + nprims; + + if(nprims <= nproc){ + nworkers = nprims; + stride = 1; + }else{ + nworkers = nproc; + stride = nprims/nproc; + } + + for(i = 0; i < nworkers; i++){ + newparams = emalloc(sizeof *newparams); + *newparams = *params; + newparams->eb = eb + i*stride; + newparams->ee = i == nworkers-1? ee: newparams->eb + stride; + sendp(paramsout[i], newparams); + } + params->job->times.E.t1 = nanosec(); + free(params); } } @@ -478,83 +634,48 @@ static void renderer(void *arg) { Channel *jobc; - Jobqueue jobq; Renderjob *job; Scene *sc; Entity *ent; - SUparams *params, *params2; - Channel *paramsc, *donec; + SUparams *params; + Channel *paramsc; + uvlong time; threadsetname("renderer"); jobc = arg; - jobq.tl = jobq.hd = nil; - ent = nil; paramsc = chancreate(sizeof(SUparams*), 8); - donec = chancreate(sizeof(SUparams*), 0); proccreate(entityproc, paramsc, mainstacksize); - enum { JOB, PARM, DONE }; - Alt a[] = { - [JOB] {jobc, &job, CHANRCV}, - [PARM] {paramsc, ¶ms, CHANNOP}, - [DONE] {donec, ¶ms2, CHANRCV}, - {nil, nil, CHANEND} - }; - for(;;) - switch(alt(a)){ - case JOB: - sc = job->scene; - job->nrem = sc->nents; - job->lastid = 0; - job->time0 = nanosec(); - - if(jobq.tl == nil){ - jobq.tl = jobq.hd = job; - ent = sc->ents.next; - a[PARM].op = CHANSND; - goto sendparams; - }else - jobq.tl = jobq.tl->next = job; - break; - case PARM: -sendparams: - job = jobq.hd; - sc = job->scene; - - if(ent != nil && ent != &sc->ents){ - params = emalloc(sizeof *params); - memset(params, 0, sizeof *params); - params->fb = job->fb; - params->id = job->lastid++; - params->frag = rgb(DBlack); - params->donec = donec; - params->job = job; - params->entity = ent; - params->uni_time = job->time0; - params->vshader = job->shaders->vshader; - params->fshader = job->shaders->fshader; - ent = ent->next; - }else{ - jobq.hd = job->next; - if((job = jobq.hd) != nil){ - ent = job->scene->ents.next; - goto sendparams; - } - - jobq.tl = jobq.hd; - a[PARM].op = CHANNOP; - } - break; - case DONE: - if(--params2->job->nrem < 1) - send(params2->job->donec, nil); + while((job = recvp(jobc)) != nil){ + time = nanosec(); + job->times.R.t0 = time; + sc = job->scene; + if(sc->nents < 1){ + nbsend(job->donec, nil); + continue; + } - freememimage(params2->frag); - free(params2); - break; + for(ent = sc->ents.next; ent != &sc->ents; ent = ent->next){ + params = emalloc(sizeof *params); + memset(params, 0, sizeof *params); + params->fb = job->fb; + params->job = job; + params->entity = ent; + params->uni_time = time; + params->vshader = job->shaders->vshader; + params->fshader = job->shaders->fshader; + sendp(paramsc, params); } + /* mark end of job */ + params = emalloc(sizeof *params); + memset(params, 0, sizeof *params); + params->job = job; + sendp(paramsc, params); + + job->times.R.t1 = nanosec(); + } } Renderer * |