# HG changeset patch
# User John Tsiombikas <nuclear@member.fsf.org>
# Date 1284170421 -3600
# Node ID df239a52a091013dbe73992467bcf8243690002b
# Parent  6a30f27fa1e6a7425d5d4a25730f2883fce2a8bc
extensive render stats for the CPU raytracer

diff -r 6a30f27fa1e6 -r df239a52a091 src/clray.cc
--- a/src/clray.cc	Fri Sep 10 16:47:00 2010 +0100
+++ b/src/clray.cc	Sat Sep 11 03:00:21 2010 +0100
@@ -198,6 +198,7 @@
 		if(!dbg_glrender) {
 			if(dbg_nocl) {
 				dbg_render(mat.m, inv_trans.m);
+				print_render_stats();
 			} else {
 				if(!render()) {
 					exit(1);
diff -r 6a30f27fa1e6 -r df239a52a091 src/dbgray.cc
--- a/src/dbgray.cc	Fri Sep 10 16:47:00 2010 +0100
+++ b/src/dbgray.cc	Sat Sep 11 03:00:21 2010 +0100
@@ -1,5 +1,6 @@
 #include <string.h>
 #include <assert.h>
+#include <limits.h>
 #include "rt.h"
 #include "ogl.h"
 #include "vector.h"
@@ -25,7 +26,10 @@
 static unsigned int tex;
 static Scene *scn;
 static const Ray *prim_rays;
+static int max_iter;
 
+static RenderStats *rstat;
+static int cur_ray_aabb_tests, cur_ray_triangle_tests;
 
 bool init_dbg_renderer(int width, int height, Scene *scene, unsigned int texid)
 {
@@ -40,6 +44,9 @@
 	ysz = height;
 	tex = texid;
 	scn = scene;
+
+	rstat = (RenderStats*)get_render_stats();
+
 	return true;
 }
 
@@ -58,7 +65,12 @@
 {
 	unsigned long t0 = get_msec();
 
-	int iter = get_render_option_int(ROPT_ITER);
+	max_iter = get_render_option_int(ROPT_ITER);
+
+	// initialize render-stats
+	memset(rstat, 0, sizeof *rstat);
+	rstat->min_aabb_tests = rstat->min_triangle_tests = INT_MAX;
+	rstat->max_aabb_tests = rstat->max_triangle_tests = 0;
 
 	int offs = 0;
 	for(int i=0; i<ysz; i++) {
@@ -66,17 +78,45 @@
 			Ray ray = prim_rays[offs];
 			transform_ray(&ray, xform, invtrans_xform);
 
-			trace_ray(fb + offs * 3, ray, iter, 1.0);
+			cur_ray_aabb_tests = cur_ray_triangle_tests = 0;
+
+			trace_ray(fb + offs * 3, ray, max_iter, 1.0);
 			offs++;
+
+			// update stats as needed
+			if(cur_ray_aabb_tests < rstat->min_aabb_tests) {
+				rstat->min_aabb_tests = cur_ray_aabb_tests;
+			}
+			if(cur_ray_aabb_tests > rstat->max_aabb_tests) {
+				rstat->max_aabb_tests = cur_ray_aabb_tests;
+			}
+			if(cur_ray_triangle_tests < rstat->min_triangle_tests) {
+				rstat->min_triangle_tests = cur_ray_triangle_tests;
+			}
+			if(cur_ray_triangle_tests > rstat->max_triangle_tests) {
+				rstat->max_triangle_tests = cur_ray_triangle_tests;
+			}
+			rstat->prim_rays++;
+			rstat->aabb_tests += cur_ray_aabb_tests;
+			rstat->triangle_tests += cur_ray_triangle_tests;
 		}
 	}
 
+	unsigned long t1 = get_msec();
+
 	glPushAttrib(GL_TEXTURE_BIT);
 	glBindTexture(GL_TEXTURE_2D, tex);
 	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, xsz, ysz, GL_RGB, GL_FLOAT, fb);
 	glPopAttrib();
+	glFinish();
 
-	printf("rendered in %lu msec\n", get_msec() - t0);
+	rstat->render_time = t1 - t0;
+	rstat->tex_update_time = get_msec() - t1;
+
+	rstat->rays_cast = rstat->prim_rays + rstat->refl_rays + rstat->shadow_rays;
+	rstat->rays_per_sec = 1000 * rstat->rays_cast / rstat->render_time;
+	rstat->avg_aabb_tests = (float)rstat->aabb_tests / (float)rstat->rays_cast;
+	rstat->avg_triangle_tests = (float)rstat->triangle_tests / (float)rstat->rays_cast;
 }
 
 static void trace_ray(float *pixel, const Ray &ray, int iter, float energy)
@@ -120,6 +160,7 @@
 		shadowray.dir[2] = ldir.z;
 
 		if(!cast_shadows || !find_intersection(shadowray, scn, scn->kdtree, 0)) {
+			rstat->brdf_evals++;
 
 			ldir.normalize();
 
@@ -140,6 +181,10 @@
 			scol[1] += mat->ks[1] * spec;
 			scol[2] += mat->ks[2] * spec;
 		}
+
+		if(cast_shadows) {
+			rstat->shadow_rays++;
+		}
 	}
 
 	float refl_color[3];
@@ -164,6 +209,8 @@
 		scol[0] += rcol[0] * mat->ks[0] * mat->kr;
 		scol[1] += rcol[1] * mat->ks[1] * mat->kr;
 		scol[2] += rcol[2] * mat->ks[2] * mat->kr;
+
+		rstat->refl_rays++;
 	}
 
 	pixel[0] = dcol[0] + scol[0];
@@ -210,6 +257,8 @@
 
 static bool ray_aabb_test(const Ray &ray, const AABBox &aabb)
 {
+	cur_ray_aabb_tests++;
+
 	if(ray.origin[0] >= aabb.min[0] && ray.origin[1] >= aabb.min[1] && ray.origin[2] >= aabb.min[2] &&
 			ray.origin[0] < aabb.max[0] && ray.origin[1] < aabb.max[1] && ray.origin[2] < aabb.max[2]) {
 		return true;
@@ -252,6 +301,8 @@
 
 static bool ray_triangle_test(const Ray &ray, const Face *face, SurfPoint *sp)
 {
+	cur_ray_triangle_tests++;
+
 	Vector3 origin = ray.origin;
 	Vector3 dir = ray.dir;
 	Vector3 norm = face->normal;
diff -r 6a30f27fa1e6 -r df239a52a091 src/rt.cc
--- a/src/rt.cc	Fri Sep 10 16:47:00 2010 +0100
+++ b/src/rt.cc	Sat Sep 11 03:00:21 2010 +0100
@@ -35,6 +35,7 @@
 
 
 static RendInfo rinf;
+static RenderStats rstat;
 static int saved_iter_val;
 
 static long timing_sample_sum;
@@ -211,6 +212,31 @@
 	return &rinf;
 }
 
+const RenderStats *get_render_stats()
+{
+	return &rstat;
+}
+
+void print_render_stats(FILE *fp)
+{
+	fprintf(fp, "-- render stats --\n");
+	fprintf(fp, "> timing\n");
+	fprintf(fp, "   render time (msec): %lu\n", rstat.render_time);
+	fprintf(fp, "   tex update time (msec): %lu\n", rstat.tex_update_time);
+	fprintf(fp, "> counters\n");
+	fprintf(fp, "   AABB tests: %d\n", rstat.aabb_tests);
+	fprintf(fp, "   AABB tests per ray (min/max/avg): %d/%d/%f\n",
+			rstat.min_aabb_tests, rstat.max_aabb_tests, rstat.avg_aabb_tests);
+	fprintf(fp, "   triangle tests: %d\n", rstat.triangle_tests);
+	fprintf(fp, "   triangle tests per ray (min/max/avg): %d/%d/%f\n",
+			rstat.min_triangle_tests, rstat.max_triangle_tests, rstat.avg_triangle_tests);
+	fprintf(fp, "   rays cast: %dp %dr %ds (sum: %d)\n", rstat.prim_rays,
+			rstat.refl_rays, rstat.shadow_rays, rstat.rays_cast);
+	fprintf(fp, "   rays per second: %d\n", rstat.rays_per_sec);
+	fprintf(fp, "   BRDF evaluations: %d\n", rstat.brdf_evals);
+	fputc('\n', fp);
+}
+
 void set_render_option(int opt, bool val)
 {
 	switch(opt) {
diff -r 6a30f27fa1e6 -r df239a52a091 src/rt.h
--- a/src/rt.h	Fri Sep 10 16:47:00 2010 +0100
+++ b/src/rt.h	Sat Sep 11 03:00:21 2010 +0100
@@ -1,6 +1,7 @@
 #ifndef RT_H_
 #define RT_H_
 
+#include <stdio.h>
 #include "scene.h"
 
 enum {
@@ -23,6 +24,20 @@
 	float origin[4], dir[4];
 };
 
+struct RenderStats {
+	unsigned long render_time, tex_update_time;
+
+	int aabb_tests, triangle_tests;
+	int min_aabb_tests, max_aabb_tests;
+	float avg_aabb_tests;
+	int min_triangle_tests, max_triangle_tests;
+	float avg_triangle_tests;
+
+	int rays_cast, rays_per_sec;
+	int prim_rays, refl_rays, shadow_rays;
+	int brdf_evals;
+};
+
 
 bool init_renderer(int xsz, int ysz, Scene *scn, unsigned int tex);
 void destroy_renderer();
@@ -30,6 +45,8 @@
 void set_xform(float *matrix, float *invtrans);
 
 const RendInfo *get_render_info();
+const RenderStats *get_render_stats();
+void print_render_stats(FILE *out = stdout);
 
 void set_render_option(int opt, bool val);
 void set_render_option(int opt, int val);
@@ -39,12 +56,13 @@
 int get_render_option_int(int opt);
 float get_render_option_float(int opt);
 
-// raytrace in the CPU
+// regular C++ raytracing using the KD-tree (single-threaded, keeps extensive debug stats)
 bool init_dbg_renderer(int xsz, int ysz, Scene *scn, unsigned int texid);
 void destroy_dbg_renderer();
 void dbg_set_primary_rays(const Ray *rays);
 void dbg_render(const float *xform, const float *invtrans_xform, int num_threads = -1);
 
+
 // visualize the scene using OpenGL
 void dbg_render_gl(Scene *scn, bool show_tree = false, bool show_obj = true);