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 16TextureGenerator::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 27TextureGenerator::~TextureGenerator() { 28 if (tex_ids_.get()) { 29 glDeleteTextures(discovered_ids_.size(), tex_ids_.get()); 30 } 31} 32 33void 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 43void 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 51void TextureGenerator::DiscoverInputIDs(RenderNode* root) { 52 // Pass 1: see which texture ID's have been used. 53 stage_ = DiscoveryStage; 54 root->Accept(this); 55} 56 57void TextureGenerator::GenerateGLTexIDs() { 58 int numTextures = discovered_ids_.size(); 59 tex_ids_.reset(new GLuint[numTextures]); 60 glGenTextures(numTextures, tex_ids_.get()); 61} 62 63void 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 87void 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 93void TextureGenerator::AllocateImageArray() { 94 image_data_.reset(new ImagePtr[discovered_ids_.size()]); 95 images_generated_ = 0; 96} 97 98void 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 108void 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 132void 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