static void RE_rayobject_blibvh_add(RayObject *o, RayObject *ob) { BVHObject *obj = (BVHObject*)o; float min_max[6]; INIT_MINMAX(min_max, min_max+3); RE_rayobject_merge_bb(ob, min_max, min_max+3); DO_MIN(min_max, obj->bb[0]); DO_MAX(min_max + 3, obj->bb[1]); BLI_bvhtree_insert(obj->bvh, obj->next_leaf - obj->leafs, min_max, 2); *(obj->next_leaf++) = ob; }
/* ==================== CL_FinishTimeDemo ==================== */ static void CL_FinishTimeDemo (void) { int frames; int i; double time, totalfpsavg; double fpsmin, fpsavg, fpsmax; // report min/avg/max fps static int benchmark_runs = 0; char vabuf[1024]; cls.timedemo = false; frames = cls.td_frames; time = realtime - cls.td_starttime; totalfpsavg = time > 0 ? frames / time : 0; fpsmin = cls.td_onesecondminfps; fpsavg = cls.td_onesecondavgcount ? cls.td_onesecondavgfps / cls.td_onesecondavgcount : 0; fpsmax = cls.td_onesecondmaxfps; // LordHavoc: timedemo now prints out 7 digits of fraction, and min/avg/max Con_Printf("%i frames %5.7f seconds %5.7f fps, one-second fps min/avg/max: %.0f %.0f %.0f (%i seconds)\n", frames, time, totalfpsavg, fpsmin, fpsavg, fpsmax, cls.td_onesecondavgcount); Log_Printf("benchmark.log", "date %s | enginedate %s | demo %s | commandline %s | run %d | result %i frames %5.7f seconds %5.7f fps, one-second fps min/avg/max: %.0f %.0f %.0f (%i seconds)\n", Sys_TimeString("%Y-%m-%d %H:%M:%S"), buildstring, cls.demoname, cmdline.string, benchmark_runs + 1, frames, time, totalfpsavg, fpsmin, fpsavg, fpsmax, cls.td_onesecondavgcount); if (COM_CheckParm("-benchmark")) { ++benchmark_runs; i = COM_CheckParm("-benchmarkruns"); if(i && i + 1 < com_argc) { static benchmarkhistory_t *history = NULL; if(!history) history = (benchmarkhistory_t *)Z_Malloc(sizeof(*history) * atoi(com_argv[i + 1])); history[benchmark_runs - 1].frames = frames; history[benchmark_runs - 1].time = time; history[benchmark_runs - 1].totalfpsavg = totalfpsavg; history[benchmark_runs - 1].fpsmin = fpsmin; history[benchmark_runs - 1].fpsavg = fpsavg; history[benchmark_runs - 1].fpsmax = fpsmax; if(atoi(com_argv[i + 1]) > benchmark_runs) { // restart the benchmark Cbuf_AddText(va(vabuf, sizeof(vabuf), "timedemo %s\n", cls.demoname)); // cannot execute here } else { // print statistics int first = COM_CheckParm("-benchmarkruns_skipfirst") ? 1 : 0; if(benchmark_runs > first) { #define DO_MIN(f) \ for(i = first; i < benchmark_runs; ++i) if((i == first) || (history[i].f < f)) f = history[i].f #define DO_MAX(f) \ for(i = first; i < benchmark_runs; ++i) if((i == first) || (history[i].f > f)) f = history[i].f #define DO_MED(f) \ doublecmp_offset = (char *)&history->f - (char *)history; \ qsort(history + first, benchmark_runs - first, sizeof(*history), doublecmp_withoffset); \ if((first + benchmark_runs) & 1) \ f = history[(first + benchmark_runs - 1) / 2].f; \ else \ f = (history[(first + benchmark_runs - 2) / 2].f + history[(first + benchmark_runs) / 2].f) / 2 DO_MIN(frames); DO_MAX(time); DO_MIN(totalfpsavg); DO_MIN(fpsmin); DO_MIN(fpsavg); DO_MIN(fpsmax); Con_Printf("MIN: %i frames %5.7f seconds %5.7f fps, one-second fps min/avg/max: %.0f %.0f %.0f (%i seconds)\n", frames, time, totalfpsavg, fpsmin, fpsavg, fpsmax, cls.td_onesecondavgcount); DO_MED(frames); DO_MED(time); DO_MED(totalfpsavg); DO_MED(fpsmin); DO_MED(fpsavg); DO_MED(fpsmax); Con_Printf("MED: %i frames %5.7f seconds %5.7f fps, one-second fps min/avg/max: %.0f %.0f %.0f (%i seconds)\n", frames, time, totalfpsavg, fpsmin, fpsavg, fpsmax, cls.td_onesecondavgcount); DO_MAX(frames); DO_MIN(time); DO_MAX(totalfpsavg); DO_MAX(fpsmin); DO_MAX(fpsavg); DO_MAX(fpsmax); Con_Printf("MAX: %i frames %5.7f seconds %5.7f fps, one-second fps min/avg/max: %.0f %.0f %.0f (%i seconds)\n", frames, time, totalfpsavg, fpsmin, fpsavg, fpsmax, cls.td_onesecondavgcount); } Z_Free(history); history = NULL; Host_Quit_f(); } } else Host_Quit_f(); } }
static void RE_rayobject_blibvh_bb(RayObject *o, float *min, float *max) { BVHObject *obj = (BVHObject*)o; DO_MIN(obj->bb[0], min); DO_MAX(obj->bb[1], max); }
/* Object Surface Area Heuristic splitter */ int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds) { int size = rtbuild_size(b); assert(nchilds == 2); assert(size > 1); int baxis = -1, boffset = 0; if (size > nchilds) { float bcost = FLT_MAX; baxis = -1, boffset = size / 2; SweepCost *sweep = (SweepCost *)MEM_mallocN(sizeof(SweepCost) * size, "RTBuilder.HeuristicSweep"); for (int axis = 0; axis < 3; axis++) { SweepCost sweep_left; RTBuilder::Object **obj = b->sorted_begin[axis]; // float right_cost = 0; for (int i = size - 1; i >= 0; i--) { if (i == size - 1) { copy_v3_v3(sweep[i].bb, obj[i]->bb); copy_v3_v3(sweep[i].bb + 3, obj[i]->bb + 3); sweep[i].cost = obj[i]->cost; } else { sweep[i].bb[0] = min_ff(obj[i]->bb[0], sweep[i + 1].bb[0]); sweep[i].bb[1] = min_ff(obj[i]->bb[1], sweep[i + 1].bb[1]); sweep[i].bb[2] = min_ff(obj[i]->bb[2], sweep[i + 1].bb[2]); sweep[i].bb[3] = max_ff(obj[i]->bb[3], sweep[i + 1].bb[3]); sweep[i].bb[4] = max_ff(obj[i]->bb[4], sweep[i + 1].bb[4]); sweep[i].bb[5] = max_ff(obj[i]->bb[5], sweep[i + 1].bb[5]); sweep[i].cost = obj[i]->cost + sweep[i + 1].cost; } // right_cost += obj[i]->cost; } sweep_left.bb[0] = obj[0]->bb[0]; sweep_left.bb[1] = obj[0]->bb[1]; sweep_left.bb[2] = obj[0]->bb[2]; sweep_left.bb[3] = obj[0]->bb[3]; sweep_left.bb[4] = obj[0]->bb[4]; sweep_left.bb[5] = obj[0]->bb[5]; sweep_left.cost = obj[0]->cost; // right_cost -= obj[0]->cost; if (right_cost < 0) right_cost = 0; for (int i = 1; i < size; i++) { //Worst case heuristic (cost of each child is linear) float hcost, left_side, right_side; // not using log seems to have no impact on raytracing perf, but // makes tree construction quicker, left out for now to test (brecht) // left_side = bb_area(sweep_left.bb, sweep_left.bb + 3) * (sweep_left.cost + logf((float)i)); // right_side = bb_area(sweep[i].bb, sweep[i].bb + 3) * (sweep[i].cost + logf((float)size - i)); left_side = bb_area(sweep_left.bb, sweep_left.bb + 3) * (sweep_left.cost); right_side = bb_area(sweep[i].bb, sweep[i].bb + 3) * (sweep[i].cost); hcost = left_side + right_side; assert(left_side >= 0); assert(right_side >= 0); if (left_side > bcost) break; //No way we can find a better heuristic in this axis assert(hcost >= 0); // this makes sure the tree built is the same whatever is the order of the sorting axis if (hcost < bcost || (hcost == bcost && axis < baxis)) { bcost = hcost; baxis = axis; boffset = i; } DO_MIN(obj[i]->bb, sweep_left.bb); DO_MAX(obj[i]->bb + 3, sweep_left.bb + 3); sweep_left.cost += obj[i]->cost; // right_cost -= obj[i]->cost; if (right_cost < 0) right_cost = 0; } //assert(baxis >= 0 && baxis < 3); if (!(baxis >= 0 && baxis < 3)) baxis = 0; } MEM_freeN(sweep); } else if (size == 2) { baxis = 0; boffset = 1; } else if (size == 1) { b->child_offset[0] = 0; b->child_offset[1] = 1; return 1; } b->child_offset[0] = 0; b->child_offset[1] = boffset; b->child_offset[2] = size; /* Adjust sorted arrays for childs */ for (int i = 0; i < boffset; i++) b->sorted_begin[baxis][i]->selected = true; for (int i = boffset; i < size; i++) b->sorted_begin[baxis][i]->selected = false; for (int i = 0; i < 3; i++) std::stable_partition(b->sorted_begin[i], b->sorted_end[i], selected_node); return nchilds; }
void rtbuild_merge_bb(RTBuilder *b, float min[3], float max[3]) { rtbuild_calc_bb(b); DO_MIN(b->bb, min); DO_MAX(b->bb + 3, max); }