=== modified file 'src/log.cpp'
@@ -56,3 +56,9 @@
va_end(ap);
}
+void
+Log::flush()
+{
+ fflush(stdout);
+ fflush(stderr);
+}
=== modified file 'src/log.h'
@@ -30,6 +30,7 @@
static void info(const char *fmt, ...);
static void debug(const char *fmt, ...);
static void error(const char *fmt, ...);
+ static void flush();
};
#endif /* LOG_H_ */
=== modified file 'src/main.cpp'
@@ -119,9 +119,86 @@
}
}
+void
+do_benchmark(Screen &screen, vector<Benchmark *> &benchmarks)
+{
+ unsigned score = 0;
+
+ for (vector<Benchmark *>::iterator bench_iter = benchmarks.begin();
+ bench_iter != benchmarks.end();
+ bench_iter++)
+ {
+ bool keep_running = true;
+ Benchmark *bench = *bench_iter;
+ Scene &scene = bench->setup_scene();
+ Log::info("%s", scene.info_string().c_str());
+ Log::flush();
+
+ while (scene.is_running() &&
+ (keep_running = should_keep_running()))
+ {
+ screen.clear();
+
+ scene.draw();
+ scene.update();
+
+ screen.update();
+ }
+
+ Log::info(" FPS: %u\n", scene.average_fps());
+ score += scene.average_fps();
+
+ bench->teardown_scene();
+
+ if (!keep_running)
+ break;
+ }
+
+ Log::info("=======================================================\n");
+ Log::info(" glmark2 Score: %u \n", score);
+ Log::info("=======================================================\n");
+
+}
+
+void
+do_validation(Screen &screen, vector<Benchmark *> &benchmarks)
+{
+ for (vector<Benchmark *>::iterator bench_iter = benchmarks.begin();
+ bench_iter != benchmarks.end();
+ bench_iter++)
+ {
+ Benchmark *bench = *bench_iter;
+ Scene &scene = bench->setup_scene();
+ Log::info("%s", scene.info_string().c_str());
+ Log::flush();
+
+ screen.clear();
+ scene.draw();
+ screen.update();
+
+ string result;
+ switch(scene.validate()) {
+ case Scene::ValidationSuccess:
+ result = "Success";
+ break;
+ case Scene::ValidationFailure:
+ result = "Failure";
+ break;
+ case Scene::ValidationUnknown:
+ result = "Unknown";
+ break;
+ default:
+ break;
+ }
+
+ Log::info(" Validation: %s\n", result.c_str());
+
+ bench->teardown_scene();
+ }
+}
+
int main(int argc, char *argv[])
{
- unsigned score = 0;
if (!Options::parse_args(argc, argv))
return 1;
@@ -139,7 +216,7 @@
#endif
if (!screen.mInitSuccess) {
- printf("Error: %s: Could not initialize screen\n", __FUNCTION__);
+ Log::error("Error: %s: Could not initialize screen\n", __FUNCTION__);
return 1;
}
@@ -161,45 +238,16 @@
else
add_custom_benchmarks(benchmarks);
- printf("=======================================================\n");
- printf(" glmark2 %s\n", GLMARK_VERSION);
- printf("=======================================================\n");
+ Log::info("=======================================================\n");
+ Log::info(" glmark2 %s\n", GLMARK_VERSION);
+ Log::info("=======================================================\n");
screen.print_info();
- printf("=======================================================\n");
-
- // Run the benchmarks
- for (vector<Benchmark *>::iterator bench_iter = benchmarks.begin();
- bench_iter != benchmarks.end();
- bench_iter++)
- {
- bool keep_running = true;
- Benchmark *bench = *bench_iter;
- Scene &scene = bench->setup_scene();
- std::cout << scene.info_string() << std::flush;
-
- while (scene.is_running() &&
- (keep_running = should_keep_running()))
- {
- screen.clear();
-
- scene.draw();
- scene.update();
-
- screen.update();
- }
-
- std::cout << " FPS: " << scene.average_fps() << std::endl;
- score += scene.average_fps();
-
- bench->teardown_scene();
-
- if (!keep_running)
- break;
- }
-
- printf("=======================================================\n");
- printf(" glmark2 Score: %u \n", score);
- printf("=======================================================\n");
+ Log::info("=======================================================\n");
+
+ if (Options::validate)
+ do_validation(screen, benchmarks);
+ else
+ do_benchmark(screen, benchmarks);
return 0;
}
=== modified file 'src/options.cpp'
@@ -29,6 +29,7 @@
#include "options.h"
std::vector<std::string> Options::benchmarks;
+bool Options::validate = false;
bool Options::swap_buffers = true;
bool Options::list_scenes = false;
bool Options::show_debug = false;
@@ -36,6 +37,7 @@
static struct option long_options[] = {
{"benchmark", 1, 0, 0},
+ {"validate", 0, 0, 0},
{"no-swap-buffers", 0, 0, 0},
{"list-scenes", 0, 0, 0},
{"debug", 0, 0, 0},
@@ -51,6 +53,8 @@
"Options:\n"
" -b, --benchmark BENCH A benchmark to run: 'scene(:opt1=val1)*'\n"
" (the option can be used multiple times)\n"
+ " --validate Run a quick output validation test instead of \n"
+ " running the benchmarks\n"
" --no-swap-buffers Don't update the screen by swapping the front and\n"
" back buffer, use glFinish() instead\n"
" -l, --list-scenes Display information about the available scenes\n"
@@ -79,6 +83,8 @@
if (c == 'b' || !strcmp(optname, "benchmark"))
Options::benchmarks.push_back(optarg);
+ else if (!strcmp(optname, "validate"))
+ Options::validate = true;
else if (!strcmp(optname, "no-swap-buffers"))
Options::swap_buffers = false;
else if (c == 'l' || !strcmp(optname, "list-scenes"))
=== modified file 'src/options.h'
@@ -32,6 +32,7 @@
static void print_help();
static std::vector<std::string> benchmarks;
+ static bool validate;
static bool swap_buffers;
static bool list_scenes;
static bool show_debug;
=== modified file 'src/scene.cpp'
@@ -23,6 +23,7 @@
*/
#include "scene.h"
#include <sstream>
+#include <cmath>
using std::stringstream;
using std::string;
@@ -133,4 +134,23 @@
ss << title;
return ss.str();
+
+}
+
+double
+Scene::pixel_value_distance(Screen::Pixel p1, Screen::Pixel p2,
+ bool use_alpha)
+{
+ double s(0.0);
+
+ // These work without casts because of integer promotion rules
+ // (the Uint8s are promoted to ints)
+ s += (p1.r - p2.r) * (p1.r - p2.r);
+ s += (p1.g - p2.g) * (p1.g - p2.g);
+ s += (p1.b - p2.b) * (p1.b - p2.b);
+
+ if (use_alpha)
+ s += (p1.a - p2.a) * (p1.a - p2.a);
+
+ return std::sqrt(s);
}
=== modified file 'src/scene.h'
@@ -51,6 +51,12 @@
std::string description;
};
+ enum ValidationResult {
+ ValidationFailure,
+ ValidationSuccess,
+ ValidationUnknown
+ };
+
// load() and unload() handle option-independent configuration.
// It should be safe to call these only once per program execution,
// although you may choose to do so more times to better manage
@@ -82,9 +88,13 @@
return dummy_scene;
}
+ virtual ValidationResult validate() { return ValidationUnknown; }
+
protected:
Scene(Screen &pScreen, const std::string &name);
std::string construct_title(const std::string &title);
+ double pixel_value_distance(Screen::Pixel p1, Screen::Pixel p2,
+ bool use_alpha=false);
Screen &mScreen;
std::string mName;
@@ -109,6 +119,7 @@
void teardown();
void update();
void draw();
+ ValidationResult validate();
~SceneBuild();
@@ -131,6 +142,7 @@
void teardown();
void update();
void draw();
+ ValidationResult validate();
~SceneTexture();
@@ -153,6 +165,7 @@
void teardown();
void update();
void draw();
+ ValidationResult validate();
~SceneShading();
=== modified file 'src/scenebuild.cpp'
@@ -22,6 +22,8 @@
* Alexandros Frantzis (glmark2)
*/
#include "scene.h"
+#include "log.h"
+#include <cmath>
SceneBuild::SceneBuild(Screen &pScreen) :
Scene(pScreen, "build")
@@ -146,3 +148,26 @@
else
mMesh.render_array();
}
+
+Scene::ValidationResult
+SceneBuild::validate()
+{
+ static const double radius_3d(std::sqrt(3.0));
+
+ if (mRotation != 0)
+ return Scene::ValidationUnknown;
+
+ Screen::Pixel ref(0xa7, 0xa7, 0xa7, 0xff);
+ Screen::Pixel pixel = mScreen.read_pixel(mScreen.mWidth / 2,
+ mScreen.mHeight / 2);
+
+ double dist = pixel_value_distance(pixel, ref);
+ if (dist < radius_3d + 0.01) {
+ return Scene::ValidationSuccess;
+ }
+ else {
+ Log::debug("Validation failed! Expected: 0x%x Actual: 0x%x Distance: %f\n",
+ ref.to_le32(), pixel.to_le32(), dist);
+ return Scene::ValidationFailure;
+ }
+}
=== modified file 'src/sceneshading.cpp'
@@ -23,6 +23,9 @@
*/
#include "scene.h"
#include "matrix.h"
+#include "log.h"
+
+#include <cmath>
SceneShading::SceneShading(Screen &pScreen) :
Scene(pScreen, "shading")
@@ -160,3 +163,37 @@
mMesh.render_vbo();
}
+
+Scene::ValidationResult
+SceneShading::validate()
+{
+ static const double radius_3d(std::sqrt(3.0));
+
+ if (mRotation != 0)
+ return Scene::ValidationUnknown;
+
+ Screen::Pixel ref;
+
+ Screen::Pixel pixel = mScreen.read_pixel(mScreen.mWidth / 2,
+ mScreen.mHeight / 2);
+
+ const std::string &filter = mOptions["shading"].value;
+
+ if (filter == "gouraud")
+ ref = Screen::Pixel(0x00, 0x00, 0xca, 0xff);
+ else if (filter == "phong")
+ ref = Screen::Pixel(0x1a, 0x1a, 0xbb, 0xff);
+ else
+ return Scene::ValidationUnknown;
+
+ double dist = pixel_value_distance(pixel, ref);
+
+ if (dist < radius_3d + 0.01) {
+ return Scene::ValidationSuccess;
+ }
+ else {
+ Log::debug("Validation failed! Expected: 0x%x Actual: 0x%x Distance: %f\n",
+ ref.to_le32(), pixel.to_le32(), dist);
+ return Scene::ValidationFailure;
+ }
+}
=== modified file 'src/scenetexture.cpp'
@@ -23,6 +23,9 @@
*/
#include "scene.h"
#include "matrix.h"
+#include "log.h"
+
+#include <cmath>
SceneTexture::SceneTexture(Screen &pScreen) :
Scene(pScreen, "texture")
@@ -161,3 +164,39 @@
mCubeMesh.render_vbo();
}
+
+Scene::ValidationResult
+SceneTexture::validate()
+{
+ static const double radius_3d(std::sqrt(3.0));
+
+ if (mRotation.x != 0 || mRotation.y != 0 || mRotation.z != 0)
+ return Scene::ValidationUnknown;
+
+ Screen::Pixel ref;
+
+ Screen::Pixel pixel = mScreen.read_pixel(mScreen.mWidth / 2,
+ mScreen.mHeight / 2);
+
+ const std::string &filter = mOptions["texture-filter"].value;
+
+ if (filter == "nearest")
+ ref = Screen::Pixel(0x3a, 0x3a, 0x3b, 0xff);
+ else if (filter == "linear")
+ ref = Screen::Pixel(0x34, 0x34, 0x35, 0xff);
+ else if (filter == "mipmap")
+ ref = Screen::Pixel(0x33, 0x33, 0x35, 0xff);
+ else
+ return Scene::ValidationUnknown;
+
+ double dist = pixel_value_distance(pixel, ref);
+
+ if (dist < radius_3d + 0.01) {
+ return Scene::ValidationSuccess;
+ }
+ else {
+ Log::debug("Validation failed! Expected: 0x%x Actual: 0x%x Distance: %f\n",
+ ref.to_le32(), pixel.to_le32(), dist);
+ return Scene::ValidationFailure;
+ }
+}
=== modified file 'src/screen-sdl-gl.cpp'
@@ -23,6 +23,7 @@
*/
#include "screen-sdl-gl.h"
#include "options.h"
+#include <fstream>
ScreenSDLGL::ScreenSDLGL(int pWidth, int pHeight, int pBpp, int pFullScreen, int pFlags)
: ScreenSDL(pWidth, pHeight, pBpp, pFullScreen, pFlags | SDL_OPENGL)
@@ -64,3 +65,29 @@
printf(" GL_RENDERER: %s\n", glGetString(GL_RENDERER));
printf(" GL_VERSION: %s\n", glGetString(GL_VERSION));
}
+
+Screen::Pixel
+ScreenSDLGL::read_pixel(int x, int y)
+{
+ Uint8 pixel[4];
+
+ glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
+
+ return Screen::Pixel(pixel[0], pixel[1], pixel[2], pixel[3]);
+}
+
+void
+ScreenSDLGL::write_to_file(std::string &filename)
+{
+ char *pixels = new char[mWidth * mHeight * 4];
+
+ for (int i = 0; i < mHeight; i++) {
+ glReadPixels(0, i, mWidth, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ &pixels[(mHeight - i - 1) * mWidth * 4]);
+ }
+
+ std::ofstream output(filename.c_str(), std::ios::out | std::ios::binary);
+ output.write(pixels, 4 * mWidth * mHeight);
+
+ delete [] pixels;
+}
=== modified file 'src/screen-sdl-gl.h'
@@ -35,6 +35,8 @@
virtual void clear();
virtual void update();
virtual void print_info();
+ virtual Pixel read_pixel(int x, int y);
+ virtual void write_to_file(std::string &filename);
};
#endif
=== modified file 'src/screen-sdl-glesv2.cpp'
@@ -24,6 +24,7 @@
#include "screen-sdl-glesv2.h"
#include "sdlgles/SDL_gles.h"
#include "options.h"
+#include <fstream>
ScreenSDLGLESv2::ScreenSDLGLESv2(int pWidth, int pHeight, int pBpp, int pFullScreen, int pFlags)
: ScreenSDL(pWidth, pHeight, pBpp, pFullScreen, pFlags)
@@ -111,3 +112,28 @@
printf(" GL_VERSION: %s\n", glGetString(GL_VERSION));
}
+Screen::Pixel
+ScreenSDLGLESv2::read_pixel(int x, int y)
+{
+ Uint8 pixel[4];
+
+ glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
+
+ return Screen::Pixel(pixel[0], pixel[1], pixel[2], pixel[3]);
+}
+
+void
+ScreenSDLGLESv2::write_to_file(std::string &filename)
+{
+ char *pixels = new char[mWidth * mHeight * 4];
+
+ for (int i = 0; i < mHeight; i++) {
+ glReadPixels(0, i, mWidth, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ &pixels[(mHeight - i - 1) * mWidth * 4]);
+ }
+
+ std::ofstream output (filename.c_str(), std::ios::out | std::ios::binary);
+ output.write(pixels, 4 * mWidth * mHeight);
+
+ delete [] pixels;
+}
=== modified file 'src/screen-sdl-glesv2.h'
@@ -35,6 +35,8 @@
virtual void clear();
virtual void update();
virtual void print_info();
+ virtual Pixel read_pixel(int x, int y);
+ virtual void write_to_file(std::string &filename);
};
#endif
=== modified file 'src/screen.h'
@@ -27,6 +27,7 @@
#include "oglsdl.h"
#include "matrix.h"
+#include <string>
#include <stdio.h>
class Screen
@@ -34,6 +35,25 @@
public:
~Screen() {}
+ struct Pixel {
+ Pixel():
+ r(0), g(0), b(0), a(0) {}
+ Pixel(Uint8 r, Uint8 g, Uint8 b, Uint8 a):
+ r(r), g(g), b(b), a(a) {}
+ Uint32 to_le32()
+ {
+ return static_cast<Uint32>(r) +
+ (static_cast<Uint32>(g) << 8) +
+ (static_cast<Uint32>(b) << 16) +
+ (static_cast<Uint32>(a) << 24);
+
+ }
+ Uint8 r;
+ Uint8 g;
+ Uint8 b;
+ Uint8 a;
+ };
+
int mWidth;
int mHeight;
int mBpp;
@@ -44,6 +64,13 @@
virtual void clear() {}
virtual void update() {}
virtual void print_info() {}
+ virtual Pixel read_pixel(int x, int y)
+ {
+ (void)x;
+ (void)y;
+ return Pixel();
+ }
+ virtual void write_to_file(std::string &filename) { (void)filename; }
static Screen &dummy()
{