=== modified file 'src/log.cpp'
--- src/log.cpp	2011-06-08 11:24:18 +0000
+++ src/log.cpp	2011-06-15 11:33:20 +0000
@@ -56,3 +56,9 @@
     va_end(ap);
 }
 
+void
+Log::flush()
+{
+    fflush(stdout);
+    fflush(stderr);
+}

=== modified file 'src/log.h'
--- src/log.h	2011-06-08 11:24:18 +0000
+++ src/log.h	2011-06-15 11:33:20 +0000
@@ -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'
--- src/main.cpp	2011-06-10 11:27:56 +0000
+++ src/main.cpp	2011-06-15 11:36:32 +0000
@@ -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'
--- src/options.cpp	2011-06-09 14:54:24 +0000
+++ src/options.cpp	2011-06-15 11:25:14 +0000
@@ -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'
--- src/options.h	2011-06-09 14:24:50 +0000
+++ src/options.h	2011-06-15 11:25:14 +0000
@@ -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'
--- src/scene.cpp	2011-06-07 21:06:38 +0000
+++ src/scene.cpp	2011-06-15 11:20:45 +0000
@@ -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'
--- src/scene.h	2011-06-09 13:07:57 +0000
+++ src/scene.h	2011-06-16 07:43:05 +0000
@@ -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'
--- src/scenebuild.cpp	2011-06-07 14:36:16 +0000
+++ src/scenebuild.cpp	2011-06-15 11:44:36 +0000
@@ -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'
--- src/sceneshading.cpp	2011-06-07 21:06:38 +0000
+++ src/sceneshading.cpp	2011-06-16 07:43:05 +0000
@@ -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'
--- src/scenetexture.cpp	2011-06-07 21:06:38 +0000
+++ src/scenetexture.cpp	2011-06-16 07:39:55 +0000
@@ -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'
--- src/screen-sdl-gl.cpp	2011-06-09 10:13:18 +0000
+++ src/screen-sdl-gl.cpp	2011-06-15 10:11:13 +0000
@@ -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'
--- src/screen-sdl-gl.h	2011-01-25 15:06:04 +0000
+++ src/screen-sdl-gl.h	2011-06-15 10:11:13 +0000
@@ -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'
--- src/screen-sdl-glesv2.cpp	2011-06-09 10:13:18 +0000
+++ src/screen-sdl-glesv2.cpp	2011-06-15 10:11:13 +0000
@@ -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'
--- src/screen-sdl-glesv2.h	2011-01-25 15:06:04 +0000
+++ src/screen-sdl-glesv2.h	2011-06-15 10:11:13 +0000
@@ -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'
--- src/screen.h	2011-06-09 13:07:57 +0000
+++ src/screen.h	2011-06-15 10:11:13 +0000
@@ -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()
     {

