From 2d2173dc4ed8233292608312d4ef7d46b123795e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 15 Feb 2004 03:46:55 +0000 Subject: [PATCH] make R_RecursiveWorldNode non-recursive (needs a new name, now :). 0.4% speedup in null-renderer gl: unknown for sw and sw32 (could be slightly slower, left recursive version in but #if 0ed out jic) --- libs/video/renderer/gl/gl_rsurf.c | 122 +++++++++++++------- libs/video/renderer/sw/sw_rbsp.c | 163 ++++++++++++++++++++++++++- libs/video/renderer/sw32/sw32_rbsp.c | 163 ++++++++++++++++++++++++++- 3 files changed, 407 insertions(+), 41 deletions(-) diff --git a/libs/video/renderer/gl/gl_rsurf.c b/libs/video/renderer/gl/gl_rsurf.c index 8d9a8e4a0..3bb1eec49 100644 --- a/libs/video/renderer/gl/gl_rsurf.c +++ b/libs/video/renderer/gl/gl_rsurf.c @@ -543,47 +543,33 @@ R_DrawBrushModel (entity_t *e) // WORLD MODEL ================================================================ -static void -R_RecursiveWorldNode (mnode_t *node) +static inline void +visit_leaf (mleaf_t *leaf) { - double dot; - int c, side; - mleaf_t *pleaf; - mplane_t *plane; + // deal with model fragments in this leaf + if (leaf->efrags) + R_StoreEfrags (&leaf->efrags); +} + +static inline int +get_side (mnode_t *node) +{ + // find which side of the node we are on + mplane_t *plane = node->plane; + + if (plane->type < 3) + return (modelorg[plane->type] - plane->dist) < 0; + return (DotProduct (modelorg, plane->normal) - plane->dist) < 0; +} + +static void +visit_node (mnode_t *node, int side) +{ + int c; msurface_t *surf; - if (node->contents == CONTENTS_SOLID) - return; - if (node->visframe != r_visframecount) - return; - - if (R_CullBox (node->minmaxs, node->minmaxs + 3)) - return; - - // if a leaf node, draw stuff - if (node->contents < 0) { - pleaf = (mleaf_t *) node; - // deal with model fragments in this leaf - if (pleaf->efrags) - R_StoreEfrags (&pleaf->efrags); - - return; - } - // node is just a decision point, so go down the appropriate sides - - // find which side of the node we are on - plane = node->plane; - if (plane->type < 3) - dot = modelorg[plane->type] - plane->dist; - else - dot = DotProduct (modelorg, plane->normal) - plane->dist; - side = dot < 0; - - // recurse down the children, front side first - R_RecursiveWorldNode (node->children[side]); - // sneaky hack for side = side ? SURF_PLANEBACK : 0; - side = (~side + 1) & SURF_PLANEBACK; + side = (~side + 1) & SURF_PLANEBACK; // draw stuff if ((c = node->numsurfaces)) { surf = r_worldentity.model->surfaces + node->firstsurface; @@ -616,8 +602,66 @@ R_RecursiveWorldNode (mnode_t *node) } } } - // recurse down the back side - R_RecursiveWorldNode (node->children[!side]); +} + +static inline int +test_node (mnode_t *node) +{ + if (node->contents < 0) + return 0; + if (node->visframe != r_visframecount) + return 0; + if (R_CullBox (node->minmaxs, node->minmaxs + 3)) + return 0; + return 1; +} + +//FIXME no longer recursive: need a new name +static void +R_RecursiveWorldNode (mnode_t *node) +{ + struct { + mnode_t *node; + int side; + } *node_ptr, node_stack[256]; + mnode_t *front; + int side; + + node_ptr = node_stack; + + while (1) { + while (test_node (node)) { + side = get_side (node); + front = node->children[side]; + if (test_node (front)) { + if (node_ptr - node_stack + == sizeof (node_stack) / sizeof (node_stack[0])) + Sys_Error ("node_stack overflow"); + node_ptr->node = node; + node_ptr->side = side; + node_ptr++; + node = front; + continue; + } + if (front->contents < 0 && front->contents != CONTENTS_SOLID) + visit_leaf ((mleaf_t *) front); + visit_node (node, side); + node = node->children[!side]; + } + if (node->contents < 0 && node->contents != CONTENTS_SOLID) + visit_leaf ((mleaf_t *) node); + if (node_ptr != node_stack) { + node_ptr--; + node = node_ptr->node; + side = node_ptr->side; + visit_node (node, side); + node = node->children[!side]; + continue; + } + break; + } + if (node->contents < 0 && node->contents != CONTENTS_SOLID) + visit_leaf ((mleaf_t *) node); } void diff --git a/libs/video/renderer/sw/sw_rbsp.c b/libs/video/renderer/sw/sw_rbsp.c index 37c029cae..64478a2da 100644 --- a/libs/video/renderer/sw/sw_rbsp.c +++ b/libs/video/renderer/sw/sw_rbsp.c @@ -395,7 +395,168 @@ R_DrawSubmodelPolygons (model_t *pmodel, int clipflags) } } +#if 1 +static inline void +visit_leaf (mleaf_t *leaf) +{ + // deal with model fragments in this leaf + if (leaf->efrags) + R_StoreEfrags (&leaf->efrags); + leaf->key = r_currentkey; + r_currentkey++; // all bmodels in a leaf share the same key +} +static inline int +get_side (mnode_t *node) +{ + // find which side of the node we are on + mplane_t *plane = node->plane; + + if (plane->type < 3) + return (modelorg[plane->type] - plane->dist) < 0; + return (DotProduct (modelorg, plane->normal) - plane->dist) < 0; +} + +static void +visit_node (mnode_t *node, int side, int clipflags) +{ + int c; + msurface_t *surf; + + // sneaky hack for side = side ? SURF_PLANEBACK : 0; + side = (~side + 1) & SURF_PLANEBACK; + // draw stuff + if ((c = node->numsurfaces)) { + surf = r_worldentity.model->surfaces + node->firstsurface; + for (; c; c--, surf++) { + if (surf->visframe != r_visframecount) + continue; + + // side is either 0 or SURF_PLANEBACK + if (side ^ (surf->flags & SURF_PLANEBACK)) + continue; // wrong side + + if (r_drawpolys) { + if (r_worldpolysbacktofront) { + if (numbtofpolys < MAX_BTOFPOLYS) { + pbtofpolys[numbtofpolys].clipflags = clipflags; + pbtofpolys[numbtofpolys].psurf = surf; + numbtofpolys++; + } + } else { + R_RenderPoly (surf, clipflags); + } + } else { + R_RenderFace (surf, clipflags); + } + } + // all surfaces on the same node share the same sequence number + r_currentkey++; + } +} + +static inline int +test_node (mnode_t *node, int *_clipflags) +{ + int clipflags = *_clipflags; + int i, *pindex; + vec3_t acceptpt, rejectpt; + double d; + + if (node->contents < 0) + return 0; + if (node->visframe != r_visframecount) + return 0; + // cull the clipping planes if not trivial accept + // FIXME: the compiler is doing a lousy job of optimizing here; it could be + // twice as fast in ASM + if (clipflags) { + for (i = 0; i < 4; i++) { + if (!(clipflags & (1 << i))) + continue; // don't need to clip against it + + // generate accept and reject points + // FIXME: do with fast look-ups or integer tests based on the + // sign bit of the floating point values + + pindex = pfrustum_indexes[i]; + + rejectpt[0] = (float) node->minmaxs[pindex[0]]; + rejectpt[1] = (float) node->minmaxs[pindex[1]]; + rejectpt[2] = (float) node->minmaxs[pindex[2]]; + + d = DotProduct (rejectpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d <= 0) { + *_clipflags = clipflags; + return 0; + } + + acceptpt[0] = (float) node->minmaxs[pindex[3 + 0]]; + acceptpt[1] = (float) node->minmaxs[pindex[3 + 1]]; + acceptpt[2] = (float) node->minmaxs[pindex[3 + 2]]; + + d = DotProduct (acceptpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + if (d >= 0) + clipflags &= ~(1 << i); // node is entirely on screen + } + } + *_clipflags = clipflags; + return 1; +} + +//FIXME no longer recursive: need a new name +static void +R_RecursiveWorldNode (mnode_t *node, int clipflags) +{ + struct { + mnode_t *node; + int side, clipflags; + } *node_ptr, node_stack[256]; + mnode_t *front; + int side; + + node_ptr = node_stack; + + while (1) { + while (test_node (node, &clipflags)) { + side = get_side (node); + front = node->children[side]; + if (test_node (front, &clipflags)) { + if (node_ptr - node_stack + == sizeof (node_stack) / sizeof (node_stack[0])) + Sys_Error ("node_stack overflow"); + node_ptr->node = node; + node_ptr->side = side; + node_ptr->clipflags = clipflags; + node_ptr++; + node = front; + continue; + } + if (front->contents < 0 && front->contents != CONTENTS_SOLID) + visit_leaf ((mleaf_t *) front); + visit_node (node, side, clipflags); + node = node->children[!side]; + } + if (node->contents < 0 && node->contents != CONTENTS_SOLID) + visit_leaf ((mleaf_t *) node); + if (node_ptr != node_stack) { + node_ptr--; + node = node_ptr->node; + side = node_ptr->side; + clipflags = node_ptr->clipflags; + visit_node (node, side, clipflags); + node = node->children[!side]; + continue; + } + break; + } + if (node->contents < 0 && node->contents != CONTENTS_SOLID) + visit_leaf ((mleaf_t *) node); +} +#else static void R_RecursiveWorldNode (mnode_t *node, int clipflags) { @@ -544,7 +705,7 @@ R_RecursiveWorldNode (mnode_t *node, int clipflags) R_RecursiveWorldNode (node->children[!side], clipflags); } } - +#endif void R_RenderWorld (void) diff --git a/libs/video/renderer/sw32/sw32_rbsp.c b/libs/video/renderer/sw32/sw32_rbsp.c index 355154fe6..ada6c20de 100644 --- a/libs/video/renderer/sw32/sw32_rbsp.c +++ b/libs/video/renderer/sw32/sw32_rbsp.c @@ -395,7 +395,168 @@ R_DrawSubmodelPolygons (model_t *pmodel, int clipflags) } } +#if 1 +static inline void +visit_leaf (mleaf_t *leaf) +{ + // deal with model fragments in this leaf + if (leaf->efrags) + R_StoreEfrags (&leaf->efrags); + leaf->key = r_currentkey; + r_currentkey++; // all bmodels in a leaf share the same key +} +static inline int +get_side (mnode_t *node) +{ + // find which side of the node we are on + mplane_t *plane = node->plane; + + if (plane->type < 3) + return (modelorg[plane->type] - plane->dist) < 0; + return (DotProduct (modelorg, plane->normal) - plane->dist) < 0; +} + +static void +visit_node (mnode_t *node, int side, int clipflags) +{ + int c; + msurface_t *surf; + + // sneaky hack for side = side ? SURF_PLANEBACK : 0; + side = (~side + 1) & SURF_PLANEBACK; + // draw stuff + if ((c = node->numsurfaces)) { + surf = r_worldentity.model->surfaces + node->firstsurface; + for (; c; c--, surf++) { + if (surf->visframe != r_visframecount) + continue; + + // side is either 0 or SURF_PLANEBACK + if (side ^ (surf->flags & SURF_PLANEBACK)) + continue; // wrong side + + if (r_drawpolys) { + if (r_worldpolysbacktofront) { + if (numbtofpolys < MAX_BTOFPOLYS) { + pbtofpolys[numbtofpolys].clipflags = clipflags; + pbtofpolys[numbtofpolys].psurf = surf; + numbtofpolys++; + } + } else { + R_RenderPoly (surf, clipflags); + } + } else { + R_RenderFace (surf, clipflags); + } + } + // all surfaces on the same node share the same sequence number + r_currentkey++; + } +} + +static inline int +test_node (mnode_t *node, int *_clipflags) +{ + int clipflags = *_clipflags; + int i, *pindex; + vec3_t acceptpt, rejectpt; + double d; + + if (node->contents < 0) + return 0; + if (node->visframe != r_visframecount) + return 0; + // cull the clipping planes if not trivial accept + // FIXME: the compiler is doing a lousy job of optimizing here; it could be + // twice as fast in ASM + if (clipflags) { + for (i = 0; i < 4; i++) { + if (!(clipflags & (1 << i))) + continue; // don't need to clip against it + + // generate accept and reject points + // FIXME: do with fast look-ups or integer tests based on the + // sign bit of the floating point values + + pindex = pfrustum_indexes[i]; + + rejectpt[0] = (float) node->minmaxs[pindex[0]]; + rejectpt[1] = (float) node->minmaxs[pindex[1]]; + rejectpt[2] = (float) node->minmaxs[pindex[2]]; + + d = DotProduct (rejectpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d <= 0) { + *_clipflags = clipflags; + return 0; + } + + acceptpt[0] = (float) node->minmaxs[pindex[3 + 0]]; + acceptpt[1] = (float) node->minmaxs[pindex[3 + 1]]; + acceptpt[2] = (float) node->minmaxs[pindex[3 + 2]]; + + d = DotProduct (acceptpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + if (d >= 0) + clipflags &= ~(1 << i); // node is entirely on screen + } + } + *_clipflags = clipflags; + return 1; +} + +//FIXME no longer recursive: need a new name +static void +R_RecursiveWorldNode (mnode_t *node, int clipflags) +{ + struct { + mnode_t *node; + int side, clipflags; + } *node_ptr, node_stack[256]; + mnode_t *front; + int side; + + node_ptr = node_stack; + + while (1) { + while (test_node (node, &clipflags)) { + side = get_side (node); + front = node->children[side]; + if (test_node (front, &clipflags)) { + if (node_ptr - node_stack + == sizeof (node_stack) / sizeof (node_stack[0])) + Sys_Error ("node_stack overflow"); + node_ptr->node = node; + node_ptr->side = side; + node_ptr->clipflags = clipflags; + node_ptr++; + node = front; + continue; + } + if (front->contents < 0 && front->contents != CONTENTS_SOLID) + visit_leaf ((mleaf_t *) front); + visit_node (node, side, clipflags); + node = node->children[!side]; + } + if (node->contents < 0 && node->contents != CONTENTS_SOLID) + visit_leaf ((mleaf_t *) node); + if (node_ptr != node_stack) { + node_ptr--; + node = node_ptr->node; + side = node_ptr->side; + clipflags = node_ptr->clipflags; + visit_node (node, side, clipflags); + node = node->children[!side]; + continue; + } + break; + } + if (node->contents < 0 && node->contents != CONTENTS_SOLID) + visit_leaf ((mleaf_t *) node); +} +#else static void R_RecursiveWorldNode (mnode_t *node, int clipflags) { @@ -544,7 +705,7 @@ R_RecursiveWorldNode (mnode_t *node, int clipflags) R_RecursiveWorldNode (node->children[!side], clipflags); } } - +#endif void R_RenderWorld (void)