Home | History | Annotate | Download | only in compositor_model_bench
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Whole-tree processing that's likely to be helpful in multiple render models.
      6 
      7 #include "gpu/tools/compositor_model_bench/render_model_utils.h"
      8 
      9 #include <cstdlib>
     10 #include <map>
     11 #include <set>
     12 #include <vector>
     13 
     14 #include "base/logging.h"
     15 
     16 TextureGenerator::TextureGenerator(RenderNode* root)
     17     : stage_(DiscoveryStage),
     18       images_generated_(0) {
     19   DiscoverInputIDs(root);
     20   GenerateGLTexIDs();
     21   AssignIDMapping();
     22   WriteOutNewIDs(root);
     23   AllocateImageArray();
     24   BuildTextureImages(root);
     25 }
     26 
     27 TextureGenerator::~TextureGenerator() {
     28   if (tex_ids_.get()) {
     29     glDeleteTextures(discovered_ids_.size(), tex_ids_.get());
     30   }
     31 }
     32 
     33 void TextureGenerator::BeginVisitRenderNode(RenderNode* node) {
     34   for (size_t n = 0; n < node->num_tiles(); ++n) {
     35     Tile* i = node->tile(n);
     36     HandleTexture(&i->texID,
     37                   node->tile_width(),
     38                   node->tile_height(),
     39                   GL_RGBA);
     40   }
     41 }
     42 
     43 void TextureGenerator::BeginVisitCCNode(CCNode* node) {
     44   for (size_t n = 0; n < node->num_textures(); ++n) {
     45     Texture* i = node->texture(n);
     46     HandleTexture(&i->texID, i->width, i->height, i->format);
     47   }
     48   BeginVisitRenderNode(node);
     49 }
     50 
     51 void TextureGenerator::DiscoverInputIDs(RenderNode* root) {
     52   // Pass 1: see which texture ID's have been used.
     53   stage_ = DiscoveryStage;
     54   root->Accept(this);
     55 }
     56 
     57 void TextureGenerator::GenerateGLTexIDs() {
     58   int numTextures = discovered_ids_.size();
     59   tex_ids_.reset(new GLuint[numTextures]);
     60   glGenTextures(numTextures, tex_ids_.get());
     61 }
     62 
     63 void TextureGenerator::AssignIDMapping() {
     64   // In the original version of this code the assigned ID's were not
     65   // GL tex ID's, but newly generated consecutive ID's that indexed
     66   // into an array of GL tex ID's. There's no need for this and now
     67   // I'm instead generating the GL tex ID's upfront and assigning
     68   // *those* in the remapping -- this more accurately reflects the
     69   // behavior in Chromium, and it also takes out some design
     70   // complexity that came from the extra layer of indirection.
     71   // HOWEVER -- when I was assigning my own ID's before, I did some
     72   // clever tricks to make sure the assignation was idempotent.
     73   // Instead of going to even more clever lengths to preserve that
     74   // property, I now just assume that the visitor will encounter each
     75   // node (and consequently each texture) exactly once during a
     76   // traversal of the tree -- this shouldn't be a hard guarantee
     77   // to make.
     78   int j = 0;
     79   typedef std::set<int>::iterator id_itr;
     80   for (id_itr i = discovered_ids_.begin();
     81        i != discovered_ids_.end();
     82        ++i, ++j) {
     83     remapped_ids_[*i] = tex_ids_[j];
     84   }
     85 }
     86 
     87 void TextureGenerator::WriteOutNewIDs(RenderNode* root) {
     88   // Pass 2: write the new texture ID's back into the texture objects.
     89   stage_ = RemappingStage;
     90   root->Accept(this);
     91 }
     92 
     93 void TextureGenerator::AllocateImageArray() {
     94   image_data_.reset(new ImagePtr[discovered_ids_.size()]);
     95   images_generated_ = 0;
     96 }
     97 
     98 void TextureGenerator::BuildTextureImages(RenderNode* root) {
     99   // Pass 3: use the texture metadata to generate images for the
    100   // textures, and set up the textures for use by OpenGL. This
    101   // doesn't *have* to be a separate pass (it could be rolled
    102   // into pass 2) but I think this is more clear and performance
    103   // shouldn't be bad.
    104   stage_ = ImageGenerationStage;
    105   root->Accept(this);
    106 }
    107 
    108 void TextureGenerator::HandleTexture(int* texID,
    109                                      int width,
    110                                      int height,
    111                                      GLenum format) {
    112   if (*texID == -1)
    113     return;    // -1 means it's not a real texture.
    114   switch (stage_) {
    115     case DiscoveryStage:
    116       discovered_ids_.insert(*texID);
    117       break;
    118     case RemappingStage:
    119       *texID = remapped_ids_[*texID];
    120       break;
    121     case ImageGenerationStage:
    122       // Only handle this one if we haven't already built a
    123       // texture for its ID.
    124       if (ids_for_completed_textures_.count(*texID))
    125         return;
    126       GenerateImageForTexture(*texID, width, height, format);
    127       ids_for_completed_textures_.insert(*texID);
    128       break;
    129   }
    130 }
    131 
    132 void TextureGenerator::GenerateImageForTexture(int texID,
    133                                                int width,
    134                                                int height,
    135                                                GLenum format) {
    136   int bytes_per_pixel = FormatBytesPerPixel(format);
    137   DCHECK_LE(bytes_per_pixel, 4);
    138   int imgID = images_generated_++;
    139   image_data_[imgID].reset(new uint8[width*height*bytes_per_pixel]);
    140   // Pick random colors to use for this texture.
    141   uint8 random_color[4];
    142   for (int c = 0; c < 4; ++c) {
    143     random_color[c] = std::rand() % 255;
    144   }
    145   // Create the image from those colors.
    146   for (int x = 0; x < width; ++x) {
    147     for (int y = 0; y < height; ++y) {
    148       int pix_addr = (y * width + x) * bytes_per_pixel;
    149       for (int c = 0; c < bytes_per_pixel; ++c) {
    150         bool on = ((x/8) + (y/8)) % 2;
    151         uint8 v = on ? random_color[c] : ~random_color[c];
    152         (image_data_[imgID])[pix_addr + c] = v;
    153       }
    154       if (bytes_per_pixel == 4) {    // Randomize alpha.
    155         image_data_[imgID][pix_addr + 3] = std::rand() % 255;
    156       }
    157     }
    158   }
    159   // Set up GL texture.
    160   glBindTexture(GL_TEXTURE_2D, texID);
    161   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    162   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    163   glPixelStorei(GL_PACK_ALIGNMENT, 1);
    164   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    165   glTexImage2D(GL_TEXTURE_2D,
    166                0,
    167                format,
    168                width, height,
    169                0,
    170                format,
    171                GL_UNSIGNED_BYTE,
    172                image_data_[imgID].get());
    173 }
    174 
    175