diff options
author | Allen Akin <akin@users.sourceforge.net> | 2000-02-02 00:53:46 +0000 |
---|---|---|
committer | Allen Akin <akin@users.sourceforge.net> | 2000-02-02 00:53:46 +0000 |
commit | 1698c783977f304ac585080df12f780640915421 (patch) | |
tree | 49234d161aab945758a650479ad8dbcc68ab67c0 /src | |
parent | b02d1363932393d40686722000b833b8f45c20e6 (diff) |
Tests for measuring performance of various ways to specify vertex data.
This is still work-in-progress, but it seems like a good time for a
checkpoint.
Diffstat (limited to 'src')
-rw-r--r-- | src/glean/tvtxperf.cpp | 421 | ||||
-rw-r--r-- | src/glean/tvtxperf.h | 96 |
2 files changed, 517 insertions, 0 deletions
diff --git a/src/glean/tvtxperf.cpp b/src/glean/tvtxperf.cpp new file mode 100644 index 0000000..8971375 --- /dev/null +++ b/src/glean/tvtxperf.cpp @@ -0,0 +1,421 @@ +// BEGIN_COPYRIGHT +// +// Copyright (C) 2000 Allen Akin All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the +// Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// END_COPYRIGHT + + + + +// tvtxperf.cpp: Test performance of various ways to specify vertex data + +#ifdef __UNIX__ +#include <unistd.h> +#endif + +#include <iostream> +#include <fstream> +#include <algorithm> +#include "codedid.h" +#include "dsconfig.h" +#include "dsfilt.h" +#include "dsurf.h" +#include "winsys.h" +#include "environ.h" +#include "rc.h" +#include "glutils.h" +#include "geomutil.h" +#include "timer.h" +#include "rand.h" +#include "image.h" +#include "tvtxperf.h" +#include "misc.h" + + +namespace { + +const int drawingSize = 256; + +// The current Timer code requires that any parameters to the function +// being timed must be passed through global variables. This probably +// should be changed, but in the meantime, here are the types and globals +// used to pass geometry to the various benchmark functions. + +struct C4UB_N3F_V3F { + GLubyte c[4]; + GLfloat n[3]; + GLfloat v[3]; +}; + +int nVertices; +C4UB_N3F_V3F* c4ub_n3f_v3f; + + +void +coloredLit_imIndTri() { + const C4UB_N3F_V3F* p = c4ub_n3f_v3f; + glBegin(GL_TRIANGLES); + // Assume that the data is complete, thus allowing us + // to unroll 3X and do one tri per iteration rather than + // one vertex. + for (int i = nVertices / 3; i; --i) { + glColor4ubv(p[0].c); + glNormal3fv(p[0].n); + glVertex3fv(p[0].v); + glColor4ubv(p[1].c); + glNormal3fv(p[1].n); + glVertex3fv(p[1].v); + glColor4ubv(p[2].c); + glNormal3fv(p[2].n); + glVertex3fv(p[2].v); + p += 3; + } + glEnd(); +} // coloredLit_imIndTri + +void +logStats(GLEAN::ColoredLitPerf::Result& r, GLEAN::Environment* env) { + env->log << "\tImmediate-mode independent triangle rate = " + << r.imTriTps << " tri/sec.\n" + << "\t\tRange of valid measurements = [" + << r.imTriTpsLow << ", " << r.imTriTpsHigh << "]\n"; +} // logStats + +typedef void (*TIME_FUNC) (); + +} // anonymous namespace + +namespace GLEAN { + +/////////////////////////////////////////////////////////////////////////////// +// Constructor/Destructor: +/////////////////////////////////////////////////////////////////////////////// +ColoredLitPerf::ColoredLitPerf(const char* aName, const char* aFilter, + const char* aDescription): + Test(aName), filter(aFilter), description(aDescription) { +} // ColoredLitPerf::ColoredLitPerf() + +ColoredLitPerf::~ColoredLitPerf() { +} // ColoredLitPerf::~ColoredLitPerf + +/////////////////////////////////////////////////////////////////////////////// +// run: run tests, save results in a vector and in the results file +/////////////////////////////////////////////////////////////////////////////// +void +ColoredLitPerf::run(Environment& environment) { + // Guard against multiple invocations: + if (hasRun) + return; + + // Set up environment for use by other functions: + env = &environment; + + // Document the test in the log, if requested: + logDescription(); + + // Compute results and make them available to subsequent tests: + WindowSystem& ws = env->winSys; + try { + // Open the results file: + OutputStream os(*this); + + // Select the drawing configurations for testing: + DrawingSurfaceFilter f(filter); + vector<DrawingSurfaceConfig*> configs(f.filter(ws.surfConfigs)); + + // Test only one config, otherwise this would take forever. + if (configs.size()) { + vector<DrawingSurfaceConfig*>::const_iterator + p = configs.begin(); + Window w(ws, **p, drawingSize, drawingSize); + RenderingContext rc(ws, **p); + if (!ws.makeCurrent(rc, w)) + ; // XXX need to throw exception here + + // Create a result object and run the test: + Result* r = new Result(); + r->config = *p; + runOne(*r, w); + + // Save the result locally and in the results file: + results.push_back(r); + r->put(os); + } + } + catch (DrawingSurfaceFilter::Syntax e) { + env->log << "Syntax error in test's drawing-surface selection" + "criteria:\n'" << filter << "'\n"; + for (int i = 0; i < e.position; ++i) + env->log << ' '; + env->log << "^ " << e.err << '\n'; + } + catch (RenderingContext::Error) { + env->log << "Could not create a rendering context\n"; + } + + env->log << '\n'; + + // Note that we've completed the run: + hasRun = true; +} + +void +ColoredLitPerf::compare(Environment& environment) { + // Save the environment for use by other member functions: + env = &environment; + + // Display the description if needed: + logDescription(); + + // Read results from previous runs: + Input1Stream is1(*this); + vector<Result*> oldR(getResults(is1)); + Input2Stream is2(*this); + vector<Result*> newR(getResults(is2)); + + // Construct a vector of surface configurations from the old run. + // (Later we'll find the best match in this vector for each config + // in the new run.) + vector<DrawingSurfaceConfig*> oldConfigs; + for (vector<Result*>::const_iterator p = oldR.begin(); p < oldR.end(); + ++p) + oldConfigs.push_back((*p)->config); + + // Compare results: + for (vector<Result*>::const_iterator newP = newR.begin(); + newP < newR.end(); ++newP) { + + // Find the drawing surface config that most closely matches + // the config for this result: + int c = (*newP)->config->match(oldConfigs); + + // If there was a match, compare the results: + if (c < 0) + env->log << name << ": NOTE no matching config for " << + (*newP)->config->conciseDescription() << '\n'; + else + compareOne(*(oldR[c]), **newP); + } + + // Get rid of the results; we don't need them for future comparisons. + for (vector<Result*>::iterator np = newR.begin(); np < newR.end(); ++np) + delete *np; + for (vector<Result*>::iterator op = oldR.begin(); op < oldR.end(); ++op) + delete *op; +} + +/////////////////////////////////////////////////////////////////////////////// +// runOne: Run a single test case +/////////////////////////////////////////////////////////////////////////////// + +void +ColoredLitPerf::runOne(Result& r, Window& w) { + // Make colors deterministic, so we can check them easily if we + // choose: + RGBCodedID colorGen(r.config->r, r.config->g, r.config->b); + int IDModulus = colorGen.maxID() + 1; + + // We need to minimize the number of pixels per triangle, so that + // we're measuring vertex-processing rate rather than fill rate. + // However, we'd also like to guarantee that every triangle covers + // at least one pixel, so that we can confirm drawing actually took + // place. As a compromise, we'll choose a number of triangles that + // yields approximately 5 pixels per triangle. + // We're drawing a filled spiral that approximates a circle, so + // pi * (drawingSize/2)**2 / nTris = 5 implies... + const int nTris = static_cast<int> + (((3.14159 / 4.0) * drawingSize * drawingSize) / 5.0 + 0.5); + nVertices = nTris * 3; + + c4ub_n3f_v3f = new C4UB_N3F_V3F[nVertices]; + SpiralTri2D it(nTris, 0, drawingSize, 0, drawingSize); + int k = 0; + for (int j = 0; j < nTris; ++j) { + float* t = it(j); + GLubyte r, g, b; + colorGen.toRGB(j % IDModulus, r, g, b); + + c4ub_n3f_v3f[k+0].c[0] = r; + c4ub_n3f_v3f[k+0].c[1] = g; + c4ub_n3f_v3f[k+0].c[2] = b; + c4ub_n3f_v3f[k+0].c[3] = 0xFF; + c4ub_n3f_v3f[k+0].n[0] = 0.0; + c4ub_n3f_v3f[k+0].n[1] = 0.0; + c4ub_n3f_v3f[k+0].n[2] = 1.0; + c4ub_n3f_v3f[k+0].v[0] = t[0]; + c4ub_n3f_v3f[k+0].v[1] = t[1]; + c4ub_n3f_v3f[k+0].v[2] = 0.0; + + c4ub_n3f_v3f[k+1].c[0] = r; + c4ub_n3f_v3f[k+1].c[1] = g; + c4ub_n3f_v3f[k+1].c[2] = b; + c4ub_n3f_v3f[k+1].c[3] = 0xFF; + c4ub_n3f_v3f[k+1].n[0] = 0.0; + c4ub_n3f_v3f[k+1].n[1] = 0.0; + c4ub_n3f_v3f[k+1].n[2] = 1.0; + c4ub_n3f_v3f[k+1].v[0] = t[2]; + c4ub_n3f_v3f[k+1].v[1] = t[3]; + c4ub_n3f_v3f[k+1].v[2] = 0.0; + + c4ub_n3f_v3f[k+2].c[0] = r; + c4ub_n3f_v3f[k+2].c[1] = g; + c4ub_n3f_v3f[k+2].c[2] = b; + c4ub_n3f_v3f[k+2].c[3] = 0xFF; + c4ub_n3f_v3f[k+2].n[0] = 0.0; + c4ub_n3f_v3f[k+2].n[1] = 0.0; + c4ub_n3f_v3f[k+2].n[2] = 1.0; + c4ub_n3f_v3f[k+2].v[0] = t[4]; + c4ub_n3f_v3f[k+2].v[1] = t[5]; + c4ub_n3f_v3f[k+2].v[2] = 0.0; + + k += 3; + } + + glDisable(GL_DITHER); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + GLUtils::useScreenCoords(drawingSize, drawingSize); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + + Timer time; + time.calibrate(static_cast<TIME_FUNC>(glFinish), + static_cast<TIME_FUNC>(glFinish)); + + vector<float> measurements; + for (int i = 0; i < 5; ++i) { + env->quiesce(); + double t = time.time(static_cast<TIME_FUNC>(glFinish), + static_cast<TIME_FUNC>(coloredLit_imIndTri), + static_cast<TIME_FUNC>(glFinish)); + w.swap(); // So the user can see something happening. + measurements.push_back(nTris / t); + } + + delete[] c4ub_n3f_v3f; + + sort(measurements.begin(), measurements.end()); + r.imTriTps = measurements[2]; + r.imTriTpsLow = measurements[1]; + r.imTriTpsHigh = measurements[3]; + + env->log << name << ": PASS " + << r.config->conciseDescription() << '\n'; + logStats(r, env); +} // ColoredLitPerf::runOne + +/////////////////////////////////////////////////////////////////////////////// +// compareOne: Compare results for a single test case +/////////////////////////////////////////////////////////////////////////////// +void +ColoredLitPerf::compareOne(Result& oldR, Result& newR) { + if (oldR.imTriTpsLow < newR.imTriTps && newR.imTriTps < oldR.imTriTpsHigh + && newR.imTriTpsLow < oldR.imTriTps && oldR.imTriTps < newR.imTriTpsHigh){ + if (env->options.verbosity) + env->log << name << ": SAME " + << newR.config->conciseDescription() + << "\n\tEach test time falls within the " + "valid measurement range of the\n" + "\tother test time.\n"; + } else { + env->log << name << ": DIFF " + << newR.config->conciseDescription() << '\n'; + env->log << '\t' + << ((oldR.imTriTps < newR.imTriTps)? + env->options.db1Name: env->options.db2Name) + << " appears to have higher performance.\n"; + } + if (env->options.verbosity) { + env->log << env->options.db1Name << ':'; + logStats(oldR, env); + env->log << env->options.db2Name << ':'; + logStats(newR, env); + } +} // ColoredLitPerf::compareOne + +/////////////////////////////////////////////////////////////////////////////// +// logDescription: Print description on the log file, according to the +// current verbosity level. +/////////////////////////////////////////////////////////////////////////////// +void +ColoredLitPerf::logDescription() { + if (env->options.verbosity) + env->log << +"----------------------------------------------------------------------\n" + << description << '\n'; +} // ColoredLitPerf::logDescription + +/////////////////////////////////////////////////////////////////////////////// +// Result I/O functions: +/////////////////////////////////////////////////////////////////////////////// +void +ColoredLitPerf::Result::put(ostream& s) const { + s << config->canonicalDescription() << '\n'; + + s << imTriTps << ' ' << imTriTpsLow << ' ' << imTriTpsHigh << '\n'; +} // ColoredLitPerf::Result::put + +bool +ColoredLitPerf::Result::get(istream& s) { + SkipWhitespace(s); + string configDesc; + if (!getline(s, configDesc)) + return false; + config = new DrawingSurfaceConfig(configDesc); + + s >> imTriTps >> imTriTpsLow >> imTriTpsHigh; + return s.good(); +} // ColoredLitPerf::Result::get + +vector<ColoredLitPerf::Result*> +ColoredLitPerf::getResults(istream& s) { + vector<Result*> v; + while (s.good()) { + Result* r = new Result(); + if (r->get(s)) + v.push_back(r); + else { + delete r; + break; + } + } + + return v; +} // ColoredLitPerf::getResults + +/////////////////////////////////////////////////////////////////////////////// +// The test object itself: +/////////////////////////////////////////////////////////////////////////////// +ColoredLitPerf coloredLitPerfTest("coloredLitPerf", "window, rgb, z, fast", + + "This test examines rendering performance for colored, lit\n" + "triangles. It checks several different ways to specify the\n" + "vertex data in order to determine which is fastest. The test\n" + "result is performance measured in triangles per second for\n" + "each of the various vertex specification methods.\n" + + ); + + +} // namespace GLEAN diff --git a/src/glean/tvtxperf.h b/src/glean/tvtxperf.h new file mode 100644 index 0000000..3cff07d --- /dev/null +++ b/src/glean/tvtxperf.h @@ -0,0 +1,96 @@ +// BEGIN_COPYRIGHT +// +// Copyright (C) 2000 Allen Akin All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the +// Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// END_COPYRIGHT + + + + +// tvtxperf.h: Test performance of various ways to specify vertex data + +#ifndef __tvtxperf_h__ +#define __tvtxperf_h__ + +#include "test.h" + +class DrawingSurfaceConfig; // Forward reference. +class GLEAN::Window; + +namespace GLEAN { + +class ColoredLitPerf: public Test { + public: + ColoredLitPerf(const char* testName, const char* filter, + const char* description); + virtual ~ColoredLitPerf(); + + const char* filter; // Drawing surface configuration filter. + const char* description; // Verbose description of test. + + virtual void run(Environment& env); // Run test, save results. + + virtual void compare(Environment& env); + // Compare two previous runs. + + // Class for a single test result. All basic tests have a + // drawing surface configuration, plus other information + // that's specific to the test. + class Result: public Test::Result { + public: + DrawingSurfaceConfig* config; + + float imTriTps; // immediate-mode independent triangles + float imTriTpsLow; + float imTriTpsHigh; + + float dlTriTps; // display-listed independent triangles + float dlTriTpsLow; + float dlTriTpsHigh; + + float imStripTps; // immediate-mode triangle strip + float imStripTpsLow; + float imStripTpsHigh; + + virtual void put(ostream& s) const; + virtual bool get(istream& s); + + Result() { } + virtual ~Result() { } + }; + + vector<Result*> results; + + virtual void runOne(Result& r, GLEAN::Window& w); + virtual void compareOne(Result& oldR, Result& newR); + virtual vector<Result*> getResults(istream& s); + + void logDescription(); + +}; // class ColoredLitPerf + +} // namespace GLEAN + +#endif // __tvtxperf_h__ |