root/gpu/tools/compositor_model_bench/render_tree.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. TextureFormatFromString
  2. TextureFormatName
  3. FormatBytesPerPixel
  4. Accept
  5. Accept
  6. Accept
  7. BeginVisitContentLayerNode
  8. BeginVisitCCNode
  9. EndVisitRenderNode
  10. EndVisitContentLayerNode
  11. EndVisitCCNode
  12. ValueTypeAsString
  13. VerifyDictionaryEntry
  14. VerifyListEntry
  15. InterpretCommonContents
  16. InterpretCCData
  17. InterpretContentLayer
  18. InterpretCanvasLayer
  19. InterpretVideoLayer
  20. InterpretImageLayer
  21. InterpretNode
  22. BuildRenderTreeFromFile

// Copyright (c) 2012 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.

#include "gpu/tools/compositor_model_bench/render_tree.h"

#include <sstream>
#include <vector>

#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"

#include "gpu/tools/compositor_model_bench/shaders.h"

using base::JSONReader;
using base::JSONWriter;
using base::ReadFileToString;
using std::string;
using std::vector;

GLenum TextureFormatFromString(std::string format) {
  if (format == "RGBA")
    return GL_RGBA;
  if (format == "RGB")
    return GL_RGB;
  if (format == "LUMINANCE")
    return GL_LUMINANCE;
  return GL_INVALID_ENUM;
}

const char* TextureFormatName(GLenum format) {
  switch (format) {
    case GL_RGBA:
      return "RGBA";
    case GL_RGB:
      return "RGB";
    case GL_LUMINANCE:
      return "LUMINANCE";
    default:
      return "(unknown format)";
  }
}

int FormatBytesPerPixel(GLenum format) {
  switch (format) {
    case GL_RGBA:
      return 4;
    case GL_RGB:
      return 3;
    case GL_LUMINANCE:
      return 1;
    default:
      return 0;
  }
}

RenderNode::RenderNode() {
}

RenderNode::~RenderNode() {
}

void RenderNode::Accept(RenderNodeVisitor* v) {
  v->BeginVisitRenderNode(this);
  v->EndVisitRenderNode(this);
}

ContentLayerNode::ContentLayerNode() {
}

ContentLayerNode::~ContentLayerNode() {
}

void ContentLayerNode::Accept(RenderNodeVisitor* v) {
  v->BeginVisitContentLayerNode(this);
  typedef vector<RenderNode*>::iterator node_itr;
  for (node_itr i = children_.begin(); i != children_.end(); ++i) {
    (*i)->Accept(v);
  }
  v->EndVisitContentLayerNode(this);
}

CCNode::CCNode() {
}

CCNode::~CCNode() {
}

void CCNode::Accept(RenderNodeVisitor* v) {
  v->BeginVisitCCNode(this);
  v->EndVisitCCNode(this);
}

RenderNodeVisitor::~RenderNodeVisitor() {
}

void RenderNodeVisitor::BeginVisitContentLayerNode(ContentLayerNode* v) {
  this->BeginVisitRenderNode(v);
}

void RenderNodeVisitor::BeginVisitCCNode(CCNode* v) {
  this->BeginVisitRenderNode(v);
}

void RenderNodeVisitor::EndVisitRenderNode(RenderNode* v) {
}

void RenderNodeVisitor::EndVisitContentLayerNode(ContentLayerNode* v) {
  this->EndVisitRenderNode(v);
}

void RenderNodeVisitor::EndVisitCCNode(CCNode* v) {
  this->EndVisitRenderNode(v);
}

RenderNode* InterpretNode(base::DictionaryValue* node);

std::string ValueTypeAsString(base::Value::Type type) {
  switch (type) {
    case base::Value::TYPE_NULL:
      return "NULL";
    case base::Value::TYPE_BOOLEAN:
      return "BOOLEAN";
    case base::Value::TYPE_INTEGER:
      return "INTEGER";
    case base::Value::TYPE_DOUBLE:
      return "DOUBLE";
    case base::Value::TYPE_STRING:
      return "STRING";
    case base::Value::TYPE_BINARY:
      return "BINARY";
    case base::Value::TYPE_DICTIONARY:
      return "DICTIONARY";
    case base::Value::TYPE_LIST:
      return "LIST";
    default:
      return "(UNKNOWN TYPE)";
  }
}

// Makes sure that the key exists and has the type we expect.
bool VerifyDictionaryEntry(base::DictionaryValue* node,
                           const std::string& key,
                           base::Value::Type type) {
  if (!node->HasKey(key)) {
    LOG(ERROR) << "Missing value for key: " << key;
    return false;
  }

  base::Value* child;
  node->Get(key, &child);
  if (!child->IsType(type)) {
    LOG(ERROR) << key << " did not have the expected type "
      "(expected " << ValueTypeAsString(type) << ")";
    return false;
  }

  return true;
}

// Makes sure that the list entry has the type we expect.
bool VerifyListEntry(base::ListValue* l,
                     int idx,
                     base::Value::Type type,
                     const char* listName = 0) {
  // Assume the idx is valid (since we'll be able to generate a better
  // error message for this elsewhere.)
  base::Value* el;
  l->Get(idx, &el);
  if (!el->IsType(type)) {
    LOG(ERROR) << (listName ? listName : "List") << "element " << idx <<
      " did not have the expected type (expected " <<
      ValueTypeAsString(type) << ")\n";
    return false;
  }

  return true;
}

bool InterpretCommonContents(base::DictionaryValue* node, RenderNode* c) {
  if (!VerifyDictionaryEntry(node, "layerID", base::Value::TYPE_INTEGER) ||
      !VerifyDictionaryEntry(node, "width", base::Value::TYPE_INTEGER) ||
      !VerifyDictionaryEntry(node, "height", base::Value::TYPE_INTEGER) ||
      !VerifyDictionaryEntry(node, "drawsContent", base::Value::TYPE_BOOLEAN) ||
      !VerifyDictionaryEntry(node, "targetSurfaceID",
                             base::Value::TYPE_INTEGER) ||
      !VerifyDictionaryEntry(node, "transform", base::Value::TYPE_LIST)
    ) {
    return false;
  }

  int layerID;
  node->GetInteger("layerID", &layerID);
  c->set_layerID(layerID);
  int width;
  node->GetInteger("width", &width);
  c->set_width(width);
  int height;
  node->GetInteger("height", &height);
  c->set_height(height);
  bool drawsContent;
  node->GetBoolean("drawsContent", &drawsContent);
  c->set_drawsContent(drawsContent);
  int targetSurface;
  node->GetInteger("targetSurfaceID", &targetSurface);
  c->set_targetSurface(targetSurface);

  base::ListValue* transform;
  node->GetList("transform", &transform);
  if (transform->GetSize() != 16) {
    LOG(ERROR) << "4x4 transform matrix did not have 16 elements";
    return false;
  }
  float transform_mat[16];
  for (int i = 0; i < 16; ++i) {
    if (!VerifyListEntry(transform, i, base::Value::TYPE_DOUBLE, "Transform"))
      return false;
    double el;
    transform->GetDouble(i, &el);
    transform_mat[i] = el;
  }
  c->set_transform(transform_mat);

  if (node->HasKey("tiles")) {
    if (!VerifyDictionaryEntry(node, "tiles", base::Value::TYPE_DICTIONARY))
      return false;
    base::DictionaryValue* tiles_dict;
    node->GetDictionary("tiles", &tiles_dict);
    if (!VerifyDictionaryEntry(tiles_dict, "dim", base::Value::TYPE_LIST))
      return false;
    base::ListValue* dim;
    tiles_dict->GetList("dim", &dim);
    if (!VerifyListEntry(dim, 0, base::Value::TYPE_INTEGER, "Tile dimension") ||
        !VerifyListEntry(dim, 1, base::Value::TYPE_INTEGER, "Tile dimension")) {
      return false;
    }
    int tile_width;
    dim->GetInteger(0, &tile_width);
    c->set_tile_width(tile_width);
    int tile_height;
    dim->GetInteger(1, &tile_height);
    c->set_tile_height(tile_height);

    if (!VerifyDictionaryEntry(tiles_dict, "info", base::Value::TYPE_LIST))
      return false;
    base::ListValue* tiles;
    tiles_dict->GetList("info", &tiles);
    for (unsigned int i = 0; i < tiles->GetSize(); ++i) {
      if (!VerifyListEntry(tiles, i, base::Value::TYPE_DICTIONARY, "Tile info"))
        return false;
      base::DictionaryValue* tdict;
      tiles->GetDictionary(i, &tdict);

      if (!VerifyDictionaryEntry(tdict, "x", base::Value::TYPE_INTEGER) ||
          !VerifyDictionaryEntry(tdict, "y", base::Value::TYPE_INTEGER)) {
        return false;
      }
      Tile t;
      tdict->GetInteger("x", &t.x);
      tdict->GetInteger("y", &t.y);
      if (tdict->HasKey("texID")) {
        if (!VerifyDictionaryEntry(tdict, "texID", base::Value::TYPE_INTEGER))
          return false;
        tdict->GetInteger("texID", &t.texID);
      } else {
        t.texID = -1;
      }
      c->add_tile(t);
    }
  }
  return true;
}

bool InterpretCCData(base::DictionaryValue* node, CCNode* c) {
  if (!VerifyDictionaryEntry(node, "vertex_shader", base::Value::TYPE_STRING) ||
      !VerifyDictionaryEntry(node, "fragment_shader",
                             base::Value::TYPE_STRING) ||
      !VerifyDictionaryEntry(node, "textures", base::Value::TYPE_LIST)) {
    return false;
  }
  string vertex_shader_name, fragment_shader_name;
  node->GetString("vertex_shader", &vertex_shader_name);
  node->GetString("fragment_shader", &fragment_shader_name);

  c->set_vertex_shader(ShaderIDFromString(vertex_shader_name));
  c->set_fragment_shader(ShaderIDFromString(fragment_shader_name));
  base::ListValue* textures;
  node->GetList("textures", &textures);
  for (unsigned int i = 0; i < textures->GetSize(); ++i) {
    if (!VerifyListEntry(textures, i, base::Value::TYPE_DICTIONARY, "Tex list"))
      return false;
    base::DictionaryValue* tex;
    textures->GetDictionary(i, &tex);

    if (!VerifyDictionaryEntry(tex, "texID", base::Value::TYPE_INTEGER) ||
        !VerifyDictionaryEntry(tex, "height", base::Value::TYPE_INTEGER) ||
        !VerifyDictionaryEntry(tex, "width", base::Value::TYPE_INTEGER) ||
        !VerifyDictionaryEntry(tex, "format", base::Value::TYPE_STRING)) {
      return false;
    }
    Texture t;
    tex->GetInteger("texID", &t.texID);
    tex->GetInteger("height", &t.height);
    tex->GetInteger("width", &t.width);

    string formatName;
    tex->GetString("format", &formatName);
    t.format = TextureFormatFromString(formatName);
    if (t.format == GL_INVALID_ENUM) {
      LOG(ERROR) << "Unrecognized texture format in layer " << c->layerID() <<
        " (format: " << formatName << ")\n"
        "The layer had " << textures->GetSize() << " children.";
      return false;
    }

    c->add_texture(t);
  }

  if (c->vertex_shader() == SHADER_UNRECOGNIZED) {
    LOG(ERROR) << "Unrecognized vertex shader name, layer " << c->layerID() <<
      " (shader: " << vertex_shader_name << ")";
    return false;
  }

  if (c->fragment_shader() == SHADER_UNRECOGNIZED) {
    LOG(ERROR) << "Unrecognized fragment shader name, layer " << c->layerID() <<
      " (shader: " << fragment_shader_name << ")";
    return false;
  }

  return true;
}

RenderNode* InterpretContentLayer(base::DictionaryValue* node) {
  ContentLayerNode* n = new ContentLayerNode;
  if (!InterpretCommonContents(node, n))
    return NULL;

  if (!VerifyDictionaryEntry(node, "type", base::Value::TYPE_STRING) ||
      !VerifyDictionaryEntry(node, "skipsDraw", base::Value::TYPE_BOOLEAN) ||
      !VerifyDictionaryEntry(node, "children", base::Value::TYPE_LIST)) {
    return NULL;
  }

  string type;
  node->GetString("type", &type);
  DCHECK_EQ(type, "ContentLayer");
  bool skipsDraw;
  node->GetBoolean("skipsDraw", &skipsDraw);
  n->set_skipsDraw(skipsDraw);

  base::ListValue* children;
  node->GetList("children", &children);
  for (unsigned int i = 0; i < children->GetSize(); ++i) {
    base::DictionaryValue* childNode;
    children->GetDictionary(i, &childNode);
    RenderNode* child = InterpretNode(childNode);
    if (child)
      n->add_child(child);
  }

  return n;
}

RenderNode* InterpretCanvasLayer(base::DictionaryValue* node) {
  CCNode* n = new CCNode;
  if (!InterpretCommonContents(node, n))
    return NULL;

  if (!VerifyDictionaryEntry(node, "type", base::Value::TYPE_STRING)) {
    return NULL;
  }

  string type;
  node->GetString("type", &type);
  assert(type == "CanvasLayer");

  if (!InterpretCCData(node, n))
    return NULL;

  return n;
}

RenderNode* InterpretVideoLayer(base::DictionaryValue* node) {
  CCNode* n = new CCNode;
  if (!InterpretCommonContents(node, n))
    return NULL;

  if (!VerifyDictionaryEntry(node, "type", base::Value::TYPE_STRING)) {
    return NULL;
  }

  string type;
  node->GetString("type", &type);
  assert(type == "VideoLayer");

  if (!InterpretCCData(node, n))
    return NULL;

  return n;
}

RenderNode* InterpretImageLayer(base::DictionaryValue* node) {
  CCNode* n = new CCNode;
  if (!InterpretCommonContents(node, n))
    return NULL;

  if (!VerifyDictionaryEntry(node, "type", base::Value::TYPE_STRING)) {
    return NULL;
  }

  string type;
  node->GetString("type", &type);
  assert(type == "ImageLayer");

  if (!InterpretCCData(node, n))
    return NULL;

  return n;
}

RenderNode* InterpretNode(base::DictionaryValue* node) {
  if (!VerifyDictionaryEntry(node, "type", base::Value::TYPE_STRING)) {
    return NULL;
  }

  string type;
  node->GetString("type", &type);
  if (type == "ContentLayer")
    return InterpretContentLayer(node);
  if (type == "CanvasLayer")
    return InterpretCanvasLayer(node);
  if (type == "VideoLayer")
    return InterpretVideoLayer(node);
  if (type == "ImageLayer")
    return InterpretImageLayer(node);


  string outjson;
  JSONWriter::WriteWithOptions(node, base::JSONWriter::OPTIONS_PRETTY_PRINT,
                               &outjson);
  LOG(ERROR) << "Unrecognized node type! JSON:\n\n"
      "-----------------------\n" <<
      outjson <<
      "-----------------------";

  return NULL;
}

RenderNode* BuildRenderTreeFromFile(const base::FilePath& path) {
  LOG(INFO) << "Reading " << path.LossyDisplayName();
  string contents;
  if (!ReadFileToString(path, &contents))
    return NULL;

  scoped_ptr<base::Value> root;
  int error_code = 0;
  string error_message;
  root.reset(JSONReader::ReadAndReturnError(contents,
            base::JSON_ALLOW_TRAILING_COMMAS,
            &error_code,
            &error_message));
  if (!root.get()) {
    LOG(ERROR) << "Failed to parse JSON file " << path.LossyDisplayName() <<
        "\n(" << error_message << ")";
    return NULL;
  }

  if (root->IsType(base::Value::TYPE_DICTIONARY)) {
    base::DictionaryValue* v = static_cast<base::DictionaryValue*>(root.get());
    RenderNode* tree = InterpretContentLayer(v);
    return tree;
  } else {
    LOG(ERROR) << path.LossyDisplayName() <<
        " doesn not encode a JSON dictionary.";
    return NULL;
  }
}


/* [<][>][^][v][top][bottom][index][help] */