| Index: gpu/tools/compositor_model_bench/compositor_model_bench.cc
|
| diff --git a/gpu/tools/compositor_model_bench/compositor_model_bench.cc b/gpu/tools/compositor_model_bench/compositor_model_bench.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..12942b5323e89607183c51dfbd3a112dae4ae739
|
| --- /dev/null
|
| +++ b/gpu/tools/compositor_model_bench/compositor_model_bench.cc
|
| @@ -0,0 +1,406 @@
|
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +// This tool is used to benchmark the render model used by the compositor
|
| +
|
| +// Most of this file is derived from the source of the tile_render_bench tool,
|
| +// and has been changed to support running a sequence of independent
|
| +// simulations for our different render models and test cases.
|
| +
|
| +#include <stdio.h>
|
| +#include <sys/dir.h>
|
| +#include <sys/file.h>
|
| +#include <sys/stat.h>
|
| +#include <sys/types.h>
|
| +#include <X11/keysym.h>
|
| +#include <X11/Xlib.h>
|
| +#include <X11/Xutil.h>
|
| +
|
| +#include <queue>
|
| +#include <string>
|
| +#include <vector>
|
| +
|
| +#include "base/at_exit.h"
|
| +#include "base/basictypes.h"
|
| +#include "base/command_line.h"
|
| +#include "base/file_path.h"
|
| +#include "base/file_util.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/message_loop.h"
|
| +#include "base/task.h"
|
| +#include "base/time.h"
|
| +
|
| +#include "gpu/tools/compositor_model_bench/render_model_utils.h"
|
| +#include "gpu/tools/compositor_model_bench/render_models.h"
|
| +#include "gpu/tools/compositor_model_bench/render_tree.h"
|
| +
|
| +
|
| +using base::TimeTicks;
|
| +using file_util::CloseFile;
|
| +using file_util::DirectoryExists;
|
| +using file_util::FileEnumerator;
|
| +using file_util::OpenFile;
|
| +using file_util::PathExists;
|
| +using std::queue;
|
| +using std::string;
|
| +
|
| +struct SimulationSpecification {
|
| + string simulation_name;
|
| + FilePath input_path;
|
| + RenderModel model_under_test;
|
| + TimeTicks simulation_start_time;
|
| + int frames_rendered;
|
| +};
|
| +
|
| +// Forward declarations
|
| +class Simulator;
|
| +void _process_events(Simulator* sim);
|
| +void _update_loop(Simulator* sim);
|
| +
|
| +class Simulator {
|
| + public:
|
| + Simulator(int seconds_per_test, const FilePath& output_path)
|
| + : running_(false),
|
| + current_sim_(NULL),
|
| + output_path_(output_path),
|
| + seconds_per_test_(seconds_per_test),
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
|
| + display_(NULL),
|
| + window_(0),
|
| + gl_context_(NULL),
|
| + window_width_(WINDOW_WIDTH),
|
| + window_height_(WINDOW_HEIGHT) {
|
| + }
|
| +
|
| + ~Simulator() {
|
| + // Cleanup GL.
|
| + glXMakeCurrent(display_, 0, NULL);
|
| + glXDestroyContext(display_, gl_context_);
|
| +
|
| + // Destroy window and display.
|
| + XDestroyWindow(display_, window_);
|
| + XCloseDisplay(display_);
|
| + }
|
| +
|
| + void QueueTest(const FilePath& path) {
|
| + SimulationSpecification spec;
|
| +
|
| + // To get a std::string, we'll try to get an ASCII simulation name.
|
| + // If the name of the file wasn't ASCII, this will give an empty simulation
|
| + // name, but that's not really harmful (we'll still warn about it though.)
|
| + spec.simulation_name = path.BaseName().RemoveExtension().MaybeAsASCII();
|
| + if (spec.simulation_name == "") {
|
| + LOG(WARNING) << "Simulation for path " << path.LossyDisplayName() <<
|
| + " will have a blank simulation name, since the file name isn't ASCII";
|
| + }
|
| + spec.input_path = path;
|
| + spec.model_under_test = ForwardRenderModel;
|
| + spec.frames_rendered = 0;
|
| +
|
| + sims_remaining_.push(spec);
|
| +
|
| + // The following lines are commented out pending the addition
|
| + // of the new render model once this version gets fully checked in.
|
| + //
|
| + // spec.model_under_test = KDTreeRenderModel;
|
| + // sims_remaining_.push(spec);
|
| + }
|
| +
|
| + void Run() {
|
| + if (!sims_remaining_.size()) {
|
| + LOG(WARNING) << "No configuration files loaded.";
|
| + return;
|
| + }
|
| +
|
| + base::AtExitManager at_exit;
|
| + MessageLoop loop;
|
| + if (!InitX11() || !InitGLContext()) {
|
| + LOG(FATAL) << "Failed to set up GUI.";
|
| + }
|
| +
|
| + InitBuffers();
|
| +
|
| + LOG(INFO) << "Running " << sims_remaining_.size() << " simulations.";
|
| +
|
| + loop.PostTask(FROM_HERE,
|
| + method_factory_.NewRunnableMethod(&Simulator::ProcessEvents));
|
| + loop.Run();
|
| + }
|
| +
|
| + void ProcessEvents() {
|
| + // Consume all the X events.
|
| + while (XPending(display_)) {
|
| + XEvent e;
|
| + XNextEvent(display_, &e);
|
| + switch (e.type) {
|
| + case Expose:
|
| + UpdateLoop();
|
| + break;
|
| + case ConfigureNotify:
|
| + Resize(e.xconfigure.width, e.xconfigure.height);
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +
|
| + void UpdateLoop() {
|
| + if (UpdateTestStatus())
|
| + UpdateCurrentTest();
|
| + }
|
| +
|
| + private:
|
| + // Initialize X11. Returns true if successful. This method creates the
|
| + // X11 window. Further initialization is done in X11VideoRenderer.
|
| + bool InitX11() {
|
| + display_ = XOpenDisplay(NULL);
|
| + if (!display_) {
|
| + LOG(FATAL) << "Cannot open display";
|
| + return false;
|
| + }
|
| +
|
| + // Get properties of the screen.
|
| + int screen = DefaultScreen(display_);
|
| + int root_window = RootWindow(display_, screen);
|
| +
|
| + // Creates the window.
|
| + window_ = XCreateSimpleWindow(display_,
|
| + root_window,
|
| + 1,
|
| + 1,
|
| + window_width_,
|
| + window_height_,
|
| + 0,
|
| + BlackPixel(display_, screen),
|
| + BlackPixel(display_, screen));
|
| + XStoreName(display_, window_, "Compositor Model Bench");
|
| +
|
| + XSelectInput(display_, window_,
|
| + ExposureMask | KeyPressMask | StructureNotifyMask);
|
| + XMapWindow(display_, window_);
|
| +
|
| + XResizeWindow(display_, window_, WINDOW_WIDTH, WINDOW_HEIGHT);
|
| +
|
| + return true;
|
| + }
|
| +
|
| + // Initialize the OpenGL context.
|
| + bool InitGLContext() {
|
| + if (!InitializeGLBindings(gfx::kGLImplementationDesktopGL)) {
|
| + LOG(FATAL) << "InitializeGLBindings failed";
|
| + return false;
|
| + }
|
| +
|
| + XWindowAttributes attributes;
|
| + XGetWindowAttributes(display_, window_, &attributes);
|
| + XVisualInfo visual_info_template;
|
| + visual_info_template.visualid = XVisualIDFromVisual(attributes.visual);
|
| + int visual_info_count = 0;
|
| + XVisualInfo* visual_info_list = XGetVisualInfo(display_, VisualIDMask,
|
| + &visual_info_template,
|
| + &visual_info_count);
|
| +
|
| + for (int i = 0; i < visual_info_count && !gl_context_; ++i) {
|
| + gl_context_ = glXCreateContext(display_, visual_info_list + i, 0,
|
| + True /* Direct rendering */);
|
| + }
|
| +
|
| + XFree(visual_info_list);
|
| + if (!gl_context_) {
|
| + return false;
|
| + }
|
| +
|
| + if (!glXMakeCurrent(display_, window_, gl_context_)) {
|
| + glXDestroyContext(display_, gl_context_);
|
| + gl_context_ = NULL;
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| + }
|
| +
|
| + bool InitializeNextTest() {
|
| + SimulationSpecification& spec = sims_remaining_.front();
|
| + LOG(INFO) << "Initializing test for " << spec.simulation_name <<
|
| + "(" << ModelToString(spec.model_under_test) << ")";
|
| + const FilePath& path = spec.input_path;
|
| +
|
| + RenderNode* root = NULL;
|
| + if (!(root = BuildRenderTreeFromFile(path))) {
|
| + LOG(ERROR) << "Couldn't parse test configuration file " <<
|
| + path.LossyDisplayName();
|
| + return false;
|
| + }
|
| +
|
| + current_sim_ = ConstructSimulationModel(spec.model_under_test,
|
| + root,
|
| + window_width_,
|
| + window_height_);
|
| + if (!current_sim_)
|
| + return false;
|
| +
|
| + return true;
|
| + }
|
| +
|
| + void CleanupCurrentTest() {
|
| + LOG(INFO) << "Finished test " << sims_remaining_.front().simulation_name;
|
| +
|
| + delete current_sim_;
|
| + current_sim_ = NULL;
|
| + }
|
| +
|
| + void UpdateCurrentTest() {
|
| + ++sims_remaining_.front().frames_rendered;
|
| +
|
| + if (current_sim_)
|
| + current_sim_->Update();
|
| +
|
| + glXSwapBuffers(display_, window_);
|
| +
|
| + XExposeEvent ev = { Expose, 0, 1, display_, window_,
|
| + 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0 };
|
| + XSendEvent(display_,
|
| + window_,
|
| + False,
|
| + ExposureMask,
|
| + reinterpret_cast<XEvent*>(&ev));
|
| +
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE,
|
| + method_factory_.NewRunnableMethod(&Simulator::UpdateLoop));
|
| + }
|
| +
|
| + void DumpOutput() {
|
| + LOG(INFO) << "Successfully ran " << sims_completed_.size() << " tests";
|
| +
|
| + FILE* f = OpenFile(output_path_, "w");
|
| +
|
| + if (!f) {
|
| + LOG(ERROR) << "Failed to open output file " <<
|
| + output_path_.LossyDisplayName();
|
| + exit(-1);
|
| + }
|
| +
|
| + LOG(INFO) << "Writing results to " << output_path_.LossyDisplayName();
|
| +
|
| + fputs("{\n\t\"results\": [\n", f);
|
| +
|
| + while (sims_completed_.size()) {
|
| + SimulationSpecification i = sims_completed_.front();
|
| + fprintf(f,
|
| + "\t\t{\"simulation_name\":\"%s\",\n"
|
| + "\t\t\t\"render_model\":\"%s\",\n"
|
| + "\t\t\t\"frames_drawn\":%d\n"
|
| + "\t\t},\n",
|
| + i.simulation_name.c_str(),
|
| + ModelToString(i.model_under_test),
|
| + i.frames_rendered);
|
| + sims_completed_.pop();
|
| + }
|
| +
|
| + fputs("\t]\n}", f);
|
| + CloseFile(f);
|
| + }
|
| +
|
| + bool UpdateTestStatus() {
|
| + TimeTicks& current_start = sims_remaining_.front().simulation_start_time;
|
| + base::TimeDelta d = TimeTicks::Now() - current_start;
|
| + if (!current_start.is_null() && d.InSeconds() > seconds_per_test_) {
|
| + CleanupCurrentTest();
|
| + sims_completed_.push(sims_remaining_.front());
|
| + sims_remaining_.pop();
|
| + }
|
| +
|
| + if (sims_remaining_.size() &&
|
| + sims_remaining_.front().simulation_start_time.is_null()) {
|
| + while (sims_remaining_.size() && !InitializeNextTest()) {
|
| + sims_remaining_.pop();
|
| + }
|
| + if (sims_remaining_.size()) {
|
| + sims_remaining_.front().simulation_start_time = TimeTicks::Now();
|
| + }
|
| + }
|
| +
|
| + if (!sims_remaining_.size()) {
|
| + DumpOutput();
|
| + MessageLoop::current()->Quit();
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| + }
|
| +
|
| + void Resize(int width, int height) {
|
| + window_width_ = width;
|
| + window_height_ = height;
|
| + if (current_sim_)
|
| + current_sim_->Resize(window_width_, window_height_);
|
| + }
|
| +
|
| + // Simulation task list for this execution
|
| + bool running_;
|
| + RenderModelSimulator* current_sim_;
|
| + queue<SimulationSpecification> sims_remaining_;
|
| + queue<SimulationSpecification> sims_completed_;
|
| + FilePath output_path_;
|
| + // Amount of time to run each simulation
|
| + int seconds_per_test_;
|
| + // GUI data
|
| + ScopedRunnableMethodFactory<Simulator> method_factory_;
|
| + Display* display_;
|
| + Window window_;
|
| + GLXContext gl_context_;
|
| + int window_width_;
|
| + int window_height_;
|
| +};
|
| +
|
| +int main(int argc, char* argv[]) {
|
| + CommandLine::Init(argc, argv);
|
| + const CommandLine* cl = CommandLine::ForCurrentProcess();
|
| +
|
| + if (argc != 3 && argc != 4) {
|
| + LOG(INFO) << "Usage: \n" <<
|
| + cl->GetProgram().BaseName().LossyDisplayName() <<
|
| + "--in=[input path] --out=[output path] (duration=[seconds])\n"
|
| + "The input path specifies either a JSON configuration file or\n"
|
| + "a directory containing only these files\n"
|
| + "(if a directory is specified, simulations will be run for\n"
|
| + "all files in that directory and subdirectories)\n"
|
| + "The optional duration parameter specifies the (integer)\n"
|
| + "number of seconds to be spent on each simulation.\n"
|
| + "Performance measurements for the specified simulation(s) are\n"
|
| + "written to the output path.";
|
| + return -1;
|
| + }
|
| +
|
| + int seconds_per_test = 1;
|
| + if (cl->HasSwitch("duration")) {
|
| + seconds_per_test = atoi(cl->GetSwitchValueASCII("duration").c_str());
|
| + }
|
| +
|
| + Simulator sim(seconds_per_test, cl->GetSwitchValuePath("out"));
|
| + FilePath inPath = cl->GetSwitchValuePath("in");
|
| +
|
| + if (!PathExists(inPath)) {
|
| + LOG(FATAL) << "Path does not exist: " << inPath.LossyDisplayName();
|
| + return -1;
|
| + }
|
| +
|
| + if (DirectoryExists(inPath)) {
|
| + LOG(INFO) << "(input path is a directory)";
|
| + FileEnumerator dirItr(inPath, true, FileEnumerator::FILES);
|
| + for (FilePath f = dirItr.Next(); !f.empty(); f = dirItr.Next()) {
|
| + sim.QueueTest(f);
|
| + }
|
| + } else {
|
| + LOG(INFO) << "(input path is a file)";
|
| + sim.QueueTest(inPath);
|
| + }
|
| +
|
| + sim.Run();
|
| +
|
| + return 0;
|
| +}
|
| +
|
|
|