cache fbo combos

BUG=159991


Review URL: https://chromiumcodereview.appspot.com/11365145

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@166858 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/gpu/command_buffer/service/framebuffer_manager.cc b/gpu/command_buffer/service/framebuffer_manager.cc
index 0dab7458..0d73f96 100644
--- a/gpu/command_buffer/service/framebuffer_manager.cc
+++ b/gpu/command_buffer/service/framebuffer_manager.cc
@@ -4,11 +4,22 @@
 
 #include "gpu/command_buffer/service/framebuffer_manager.h"
 #include "base/logging.h"
+#include "base/stringprintf.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "ui/gl/gl_bindings.h"
 
 namespace gpu {
 namespace gles2 {
 
+FramebufferManager::FramebufferInfo::FramebufferComboCompleteMap*
+    FramebufferManager::FramebufferInfo::framebuffer_combo_complete_map_;
+
+void FramebufferManager::FramebufferInfo::ClearFramebufferCompleteComboMap() {
+  if (framebuffer_combo_complete_map_) {
+    framebuffer_combo_complete_map_->clear();
+  }
+}
+
 class RenderbufferAttachment
     : public FramebufferManager::FramebufferInfo::Attachment {
  public:
@@ -72,6 +83,12 @@
     return renderbuffer_.get();
   }
 
+  virtual void AddToSignature(
+      TextureManager* texture_manager, std::string* signature) const OVERRIDE {
+    DCHECK(signature);
+    renderbuffer_->AddToSignature(signature);
+  }
+
  protected:
   virtual ~RenderbufferAttachment() { }
 
@@ -160,6 +177,12 @@
     return (need & have) != 0;
   }
 
+  virtual void AddToSignature(
+      TextureManager* texture_manager, std::string* signature) const OVERRIDE {
+    DCHECK(signature);
+    texture_manager->AddToSignature(texture_, target_, level_, signature);
+  }
+
  protected:
   virtual ~TextureAttachment() {}
 
@@ -317,6 +340,34 @@
   return GL_FRAMEBUFFER_COMPLETE;
 }
 
+GLenum FramebufferManager::FramebufferInfo::GetStatus(
+    TextureManager* texture_manager, GLenum target) const {
+  // Check if we have this combo already.
+  std::string signature(base::StringPrintf("|FBO|target=%04x", target));
+  for (AttachmentMap::const_iterator it = attachments_.begin();
+       it != attachments_.end(); ++it) {
+    Attachment* attachment = it->second;
+    signature += base::StringPrintf(
+        "|Attachment|attachmentpoint=%04x", it->first);
+    attachment->AddToSignature(texture_manager, &signature);
+  }
+
+  if (!framebuffer_combo_complete_map_) {
+    framebuffer_combo_complete_map_ = new FramebufferComboCompleteMap();
+  }
+
+  FramebufferComboCompleteMap::const_iterator it =
+      framebuffer_combo_complete_map_->find(signature);
+  if (it != framebuffer_combo_complete_map_->end()) {
+    return GL_FRAMEBUFFER_COMPLETE;
+  }
+  GLenum result = glCheckFramebufferStatusEXT(target);
+  if (result == GL_FRAMEBUFFER_COMPLETE) {
+    framebuffer_combo_complete_map_->insert(std::make_pair(signature, true));
+  }
+  return result;
+}
+
 bool FramebufferManager::FramebufferInfo::IsCleared() const {
   // are all the attachments cleaared?
   for (AttachmentMap::const_iterator it = attachments_.begin();
diff --git a/gpu/command_buffer/service/framebuffer_manager.h b/gpu/command_buffer/service/framebuffer_manager.h
index cc2cefb..80cf428 100644
--- a/gpu/command_buffer/service/framebuffer_manager.h
+++ b/gpu/command_buffer/service/framebuffer_manager.h
@@ -44,6 +44,8 @@
       virtual bool CanRenderTo() const = 0;
       virtual void DetachFromFramebuffer() = 0;
       virtual bool ValidForAttachmentType(GLenum attachment_type) = 0;
+      virtual void AddToSignature(
+          TextureManager* texture_manager, std::string* signature) const = 0;
 
      protected:
       friend class base::RefCounted<Attachment>;
@@ -103,9 +105,14 @@
     // means it passed our tests.
     GLenum IsPossiblyComplete() const;
 
+    // Implements optimized glGetFramebufferStatus.
+    GLenum GetStatus(TextureManager* texture_manager, GLenum target) const;
+
     // Check all attachments are cleared
     bool IsCleared() const;
 
+    static void ClearFramebufferCompleteComboMap();
+
    private:
     friend class FramebufferManager;
     friend class base::RefCounted<FramebufferInfo>;
@@ -144,6 +151,11 @@
     typedef base::hash_map<GLenum, Attachment::Ref> AttachmentMap;
     AttachmentMap attachments_;
 
+    // A map of successful frame buffer combos. If it's in the map
+    // it should be FRAMEBUFFER_COMPLETE.
+    typedef base::hash_map<std::string, bool> FramebufferComboCompleteMap;
+    static FramebufferComboCompleteMap* framebuffer_combo_complete_map_;
+
     DISALLOW_COPY_AND_ASSIGN(FramebufferInfo);
   };
 
diff --git a/gpu/command_buffer/service/framebuffer_manager_unittest.cc b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
index 7727ebe..31261ea 100644
--- a/gpu/command_buffer/service/framebuffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
@@ -8,6 +8,8 @@
 #include "gpu/command_buffer/common/gl_mock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using ::testing::Return;
+
 namespace gpu {
 namespace gles2 {
 
@@ -630,6 +632,84 @@
   EXPECT_FALSE(manager_.IsComplete(info_));
 }
 
+TEST_F(FramebufferInfoTest, Gettatus) {
+  const GLuint kRenderbufferClient1Id = 33;
+  const GLuint kRenderbufferService1Id = 333;
+  const GLuint kTextureClient2Id = 34;
+  const GLuint kTextureService2Id = 334;
+  const GLenum kTarget1 = GL_TEXTURE_2D;
+  const GLint kLevel1 = 0;
+
+  renderbuffer_manager_.CreateRenderbufferInfo(
+      kRenderbufferClient1Id, kRenderbufferService1Id);
+  RenderbufferManager::RenderbufferInfo* rb_info1 =
+      renderbuffer_manager_.GetRenderbufferInfo(kRenderbufferClient1Id);
+  ASSERT_TRUE(rb_info1 != NULL);
+  texture_manager_.CreateTextureInfo(kTextureClient2Id, kTextureService2Id);
+  TextureManager::TextureInfo::Ref tex_info2 =
+      texture_manager_.GetTextureInfo(kTextureClient2Id);
+  ASSERT_TRUE(tex_info2 != NULL);
+  texture_manager_.SetInfoTarget(tex_info2, GL_TEXTURE_2D);
+
+  EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+      .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+      .RetiresOnSaturation();
+  info_->GetStatus(&texture_manager_, GL_FRAMEBUFFER);
+
+  // Check a second call for the same type does not call anything
+  info_->GetStatus(&texture_manager_, GL_FRAMEBUFFER);
+
+  // Check changing the attachments calls CheckFramebufferStatus.
+  info_->AttachTexture(GL_COLOR_ATTACHMENT0, tex_info2, kTarget1, kLevel1);
+  EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+      .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+      .RetiresOnSaturation();
+  info_->GetStatus(&texture_manager_, GL_FRAMEBUFFER);
+
+  // Check a second call for the same type does not call anything.
+  info_->GetStatus(&texture_manager_, GL_FRAMEBUFFER);
+
+  // Check a second call with a different target calls CheckFramebufferStatus.
+  EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER))
+      .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+      .RetiresOnSaturation();
+  info_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER);
+
+  // Check a second call for the same type does not call anything.
+  info_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER);
+
+  // Check adding another attachment calls CheckFramebufferStatus.
+  info_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, rb_info1);
+  EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER))
+      .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+      .RetiresOnSaturation();
+  info_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER);
+
+  // Check a second call for the same type does not call anything.
+  info_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER);
+
+  // Check changing the format calls CheckFramebuffferStatus.
+  texture_manager_.SetParameter(tex_info2, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+
+  EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER))
+      .WillOnce(Return(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT))
+      .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+      .RetiresOnSaturation();
+  info_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER);
+
+  // Check since it did not return FRAMEBUFFER_COMPLETE that it calls
+  // CheckFramebufferStatus
+  info_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER);
+
+  // Check putting it back does not call CheckFramebufferStatus.
+  texture_manager_.SetParameter(tex_info2, GL_TEXTURE_WRAP_S, GL_REPEAT);
+  info_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER);
+
+  // Check Unbinding does not call CheckFramebufferStatus
+  info_->UnbindRenderbuffer(GL_RENDERBUFFER, rb_info1);
+  info_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER);
+}
+
 }  // namespace gles2
 }  // namespace gpu
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 6b2194f..075bb6b 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -2615,7 +2615,8 @@
       texture_manager()->HaveUnclearedMips()) {
     if (!framebuffer->IsCleared()) {
       // Can we clear them?
-      if (glCheckFramebufferStatusEXT(target) != GL_FRAMEBUFFER_COMPLETE) {
+      if (framebuffer->GetStatus(texture_manager(), target) !=
+          GL_FRAMEBUFFER_COMPLETE) {
         SetGLError(
             GL_INVALID_FRAMEBUFFER_OPERATION, func_name,
             "framebuffer incomplete (clear)");
@@ -2626,7 +2627,8 @@
   }
 
   if (!framebuffer_manager()->IsComplete(framebuffer)) {
-    if (glCheckFramebufferStatusEXT(target) != GL_FRAMEBUFFER_COMPLETE) {
+    if (framebuffer->GetStatus(texture_manager(), target) !=
+        GL_FRAMEBUFFER_COMPLETE) {
       SetGLError(
           GL_INVALID_FRAMEBUFFER_OPERATION, func_name,
           "framebuffer incomplete (check)");
@@ -4371,7 +4373,7 @@
   if (completeness != GL_FRAMEBUFFER_COMPLETE) {
     return completeness;
   }
-  return glCheckFramebufferStatusEXT(target);
+  return framebuffer->GetStatus(texture_manager(), target);
 }
 
 void GLES2DecoderImpl::DoFramebufferTexture2D(
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index 83c7e44..1b0697a6 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -84,6 +84,7 @@
     bool request_depth,
     bool request_stencil,
     bool bind_generates_resource) {
+  FramebufferManager::FramebufferInfo::ClearFramebufferCompleteComboMap();
   gl_.reset(new StrictMock<MockGLInterface>());
   ::gfx::GLInterface::SetGLInterface(gl_.get());
   group_ = ContextGroup::Ref(new ContextGroup(NULL,
diff --git a/gpu/command_buffer/service/renderbuffer_manager.cc b/gpu/command_buffer/service/renderbuffer_manager.cc
index 7169027..496b746 100644
--- a/gpu/command_buffer/service/renderbuffer_manager.cc
+++ b/gpu/command_buffer/service/renderbuffer_manager.cc
@@ -5,6 +5,7 @@
 #include "gpu/command_buffer/service/renderbuffer_manager.h"
 #include "base/logging.h"
 #include "base/debug/trace_event.h"
+#include "base/stringprintf.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
@@ -40,6 +41,14 @@
          GLES2Util::RenderbufferBytesPerPixel(internal_format_);
 }
 
+void RenderbufferManager::RenderbufferInfo::AddToSignature(
+    std::string* signature) const {
+  DCHECK(signature);
+  *signature += base::StringPrintf(
+      "|Renderbuffer|internal_format=%04x|samples=%d|width=%d|height=%d",
+      internal_format_, samples_, width_, height_);
+}
+
 RenderbufferManager::RenderbufferInfo::~RenderbufferInfo() {
   if (manager_) {
     if (manager_->have_context_) {
@@ -51,6 +60,7 @@
   }
 }
 
+
 void RenderbufferManager::UpdateMemRepresented() {
   renderbuffer_memory_tracker_->UpdateMemRepresented(mem_represented_);
 }
diff --git a/gpu/command_buffer/service/renderbuffer_manager.h b/gpu/command_buffer/service/renderbuffer_manager.h
index c562185..2edfc34a 100644
--- a/gpu/command_buffer/service/renderbuffer_manager.h
+++ b/gpu/command_buffer/service/renderbuffer_manager.h
@@ -5,6 +5,7 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_RENDERBUFFER_MANAGER_H_
 #define GPU_COMMAND_BUFFER_SERVICE_RENDERBUFFER_MANAGER_H_
 
+#include <string>
 #include "base/basictypes.h"
 #include "base/hash_tables.h"
 #include "base/memory/ref_counted.h"
@@ -79,6 +80,8 @@
 
     size_t EstimatedSize();
 
+    void AddToSignature(std::string* signature) const;
+
    private:
     friend class RenderbufferManager;
     friend class base::RefCounted<RenderbufferInfo>;
diff --git a/gpu/command_buffer/service/renderbuffer_manager_unittest.cc b/gpu/command_buffer/service/renderbuffer_manager_unittest.cc
index 8e13ac9c..1ac8bcb 100644
--- a/gpu/command_buffer/service/renderbuffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/renderbuffer_manager_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "gpu/command_buffer/service/renderbuffer_manager.h"
 
+#include <set>
 #include "gpu/command_buffer/common/gl_mock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -165,6 +166,65 @@
   info1 = NULL;
 }
 
+namespace {
+
+bool InSet(std::set<std::string>* string_set, const std::string& str) {
+  std::pair<std::set<std::string>::iterator, bool> result =
+      string_set->insert(str);
+  return !result.second;
+}
+
+}  // anonymous namespace
+
+TEST_F(RenderbufferManagerTest, AddToSignature) {
+  const GLuint kClient1Id = 1;
+  const GLuint kService1Id = 11;
+  manager_.CreateRenderbufferInfo(kClient1Id, kService1Id);
+  RenderbufferManager::RenderbufferInfo::Ref info1(
+      manager_.GetRenderbufferInfo(kClient1Id));
+  ASSERT_TRUE(info1 != NULL);
+  const GLsizei kSamples = 4;
+  const GLenum kFormat = GL_RGBA4;
+  const GLsizei kWidth = 128;
+  const GLsizei kHeight = 64;
+  manager_.SetInfo(info1, kSamples, kFormat, kWidth, kHeight);
+  std::string signature1;
+  std::string signature2;
+  info1->AddToSignature(&signature1);
+
+  std::set<std::string> string_set;
+  EXPECT_FALSE(InSet(&string_set, signature1));
+
+  // change things and see that the signatures change.
+  manager_.SetInfo(info1, kSamples +  1, kFormat, kWidth, kHeight);
+  info1->AddToSignature(&signature2);
+  EXPECT_FALSE(InSet(&string_set, signature2));
+
+  manager_.SetInfo(info1, kSamples, kFormat + 1, kWidth, kHeight);
+  signature2.clear();
+  info1->AddToSignature(&signature2);
+  EXPECT_FALSE(InSet(&string_set, signature2));
+
+  manager_.SetInfo(info1, kSamples, kFormat, kWidth + 1, kHeight);
+  signature2.clear();
+  info1->AddToSignature(&signature2);
+  EXPECT_FALSE(InSet(&string_set, signature2));
+
+  manager_.SetInfo(info1, kSamples, kFormat, kWidth, kHeight + 1);
+  signature2.clear();
+  info1->AddToSignature(&signature2);
+  EXPECT_FALSE(InSet(&string_set, signature2));
+
+  // put it back to the same and it should be the same.
+  manager_.SetInfo(info1, kSamples, kFormat, kWidth, kHeight);
+  signature2.clear();
+  info1->AddToSignature(&signature2);
+  EXPECT_EQ(signature1, signature2);
+
+  // Check the set was acutally getting different signatures.
+  EXPECT_EQ(5u, string_set.size());
+}
+
 }  // namespace gles2
 }  // namespace gpu
 
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index 32062817..8573f33 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -4,6 +4,7 @@
 
 #include "gpu/command_buffer/service/texture_manager.h"
 #include "base/bits.h"
+#include "base/stringprintf.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
@@ -180,6 +181,34 @@
   }
 }
 
+void TextureManager::TextureInfo::AddToSignature(
+    const FeatureInfo* feature_info,
+    GLenum target,
+    GLint level,
+    std::string* signature) const {
+  DCHECK(feature_info);
+  DCHECK(signature);
+  DCHECK_GE(level, 0);
+  DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
+            level_infos_.size());
+  DCHECK_LT(static_cast<size_t>(level),
+            level_infos_[GLTargetToFaceIndex(target)].size());
+  const TextureInfo::LevelInfo& info =
+      level_infos_[GLTargetToFaceIndex(target)][level];
+  *signature += base::StringPrintf(
+      "|Texture|target=%04x|level=%d|internal_format=%04x"
+      "|width=%d|height=%d|depth=%d|border=%d|format=%04x|type=%04x"
+      "|image=%d|canrender=%d|canrenderto=%d|npot_=%d"
+      "|min_filter=%04x|mag_filter=%04x|wrap_s=%04x|wrap_t=%04x"
+      "|usage=%04x",
+      target, level, info.internal_format,
+      info.width, info.height, info.depth, info.border,
+      info.format, info.type, info.image.get() != NULL,
+      CanRender(feature_info), CanRenderTo(), npot_,
+      min_filter_, mag_filter_, wrap_s_, wrap_t_,
+      usage_);
+}
+
 bool TextureManager::TextureInfo::MarkMipmapsGenerated(
     const FeatureInfo* feature_info) {
   if (!CanGenerateMipmaps(feature_info)) {
@@ -1129,5 +1158,13 @@
   }
 }
 
+void TextureManager::AddToSignature(
+    TextureInfo* info,
+    GLenum target,
+    GLint level,
+    std::string* signature) const {
+  info->AddToSignature(feature_info_.get(), target, level, signature);
+}
+
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h
index ef9e020a..ed4c8c9e 100644
--- a/gpu/command_buffer/service/texture_manager.h
+++ b/gpu/command_buffer/service/texture_manager.h
@@ -5,6 +5,7 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_TEXTURE_MANAGER_H_
 #define GPU_COMMAND_BUFFER_SERVICE_TEXTURE_MANAGER_H_
 
+#include <string>
 #include <vector>
 #include "base/basictypes.h"
 #include "base/hash_tables.h"
@@ -279,6 +280,11 @@
         GLint level,
         gfx::GLImage* image);
 
+    // Appends a signature for the given level.
+    void AddToSignature(
+        const FeatureInfo* feature_info,
+        GLenum target, GLint level, std::string* signature) const;
+
     // Info about each face and level of texture.
     std::vector<std::vector<LevelInfo> > level_infos_;
 
@@ -510,6 +516,12 @@
       GLint level,
       gfx::GLImage* image);
 
+  void AddToSignature(
+      TextureInfo* info,
+      GLenum target,
+      GLint level,
+      std::string* signature) const;
+
  private:
   // Helper for Initialize().
   TextureInfo::Ref CreateDefaultAndBlackTextures(
diff --git a/gpu/command_buffer/service/texture_manager_unittest.cc b/gpu/command_buffer/service/texture_manager_unittest.cc
index 487bde7..da56669 100644
--- a/gpu/command_buffer/service/texture_manager_unittest.cc
+++ b/gpu/command_buffer/service/texture_manager_unittest.cc
@@ -1019,6 +1019,121 @@
   EXPECT_TRUE(info_->GetLevelImage(GL_TEXTURE_2D, 1) == NULL);
 }
 
+namespace {
+
+bool InSet(std::set<std::string>* string_set, const std::string& str) {
+  std::pair<std::set<std::string>::iterator, bool> result =
+      string_set->insert(str);
+  return !result.second;
+}
+
+}  // anonymous namespace
+
+TEST_F(TextureInfoTest, AddToSignature) {
+  manager_.SetInfoTarget(info_, GL_TEXTURE_2D);
+  manager_.SetLevelInfo(info_,
+      GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
+  std::string signature1;
+  std::string signature2;
+  manager_.AddToSignature(info_, GL_TEXTURE_2D, 1, &signature1);
+
+  std::set<std::string> string_set;
+  EXPECT_FALSE(InSet(&string_set, signature1));
+
+  // check changing 1 thing makes a different signature.
+  manager_.SetLevelInfo(info_,
+      GL_TEXTURE_2D, 1, GL_RGBA, 4, 2, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
+  manager_.AddToSignature(info_, GL_TEXTURE_2D, 1, &signature2);
+  EXPECT_FALSE(InSet(&string_set, signature2));
+
+  // check putting it back makes the same signature.
+  manager_.SetLevelInfo(info_,
+      GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
+  signature2.clear();
+  manager_.AddToSignature(info_, GL_TEXTURE_2D, 1, &signature2);
+  EXPECT_EQ(signature1, signature2);
+
+  // Check setting cleared status does not change signature.
+  manager_.SetLevelInfo(info_,
+      GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+  signature2.clear();
+  manager_.AddToSignature(info_, GL_TEXTURE_2D, 1, &signature2);
+  EXPECT_EQ(signature1, signature2);
+
+  // Check changing other settings changes signature.
+  manager_.SetLevelInfo(info_,
+      GL_TEXTURE_2D, 1, GL_RGBA, 2, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+  signature2.clear();
+  manager_.AddToSignature(info_, GL_TEXTURE_2D, 1, &signature2);
+  EXPECT_FALSE(InSet(&string_set, signature2));
+
+  manager_.SetLevelInfo(info_,
+      GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+  signature2.clear();
+  manager_.AddToSignature(info_, GL_TEXTURE_2D, 1, &signature2);
+  EXPECT_FALSE(InSet(&string_set, signature2));
+
+  manager_.SetLevelInfo(info_,
+      GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, false);
+  signature2.clear();
+  manager_.AddToSignature(info_, GL_TEXTURE_2D, 1, &signature2);
+  EXPECT_FALSE(InSet(&string_set, signature2));
+
+  manager_.SetLevelInfo(info_,
+      GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, false);
+  signature2.clear();
+  manager_.AddToSignature(info_, GL_TEXTURE_2D, 1, &signature2);
+  EXPECT_FALSE(InSet(&string_set, signature2));
+
+  manager_.SetLevelInfo(info_,
+      GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1, 0, GL_RGBA, GL_FLOAT,
+      false);
+  signature2.clear();
+  manager_.AddToSignature(info_, GL_TEXTURE_2D, 1, &signature2);
+  EXPECT_FALSE(InSet(&string_set, signature2));
+
+  // put it back
+  manager_.SetLevelInfo(info_,
+      GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+      false);
+  signature2.clear();
+  manager_.AddToSignature(info_, GL_TEXTURE_2D, 1, &signature2);
+  EXPECT_EQ(signature1, signature2);
+
+  // check changing parameters changes signature.
+  manager_.SetParameter(info_, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+  signature2.clear();
+  manager_.AddToSignature(info_, GL_TEXTURE_2D, 1, &signature2);
+  EXPECT_FALSE(InSet(&string_set, signature2));
+
+  manager_.SetParameter(info_, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
+  manager_.SetParameter(info_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  signature2.clear();
+  manager_.AddToSignature(info_, GL_TEXTURE_2D, 1, &signature2);
+  EXPECT_FALSE(InSet(&string_set, signature2));
+
+  manager_.SetParameter(info_, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  manager_.SetParameter(info_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  signature2.clear();
+  manager_.AddToSignature(info_, GL_TEXTURE_2D, 1, &signature2);
+  EXPECT_FALSE(InSet(&string_set, signature2));
+
+  manager_.SetParameter(info_, GL_TEXTURE_WRAP_S, GL_REPEAT);
+  manager_.SetParameter(info_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  signature2.clear();
+  manager_.AddToSignature(info_, GL_TEXTURE_2D, 1, &signature2);
+  EXPECT_FALSE(InSet(&string_set, signature2));
+
+  // Check putting it back genenerates the same signature
+  manager_.SetParameter(info_, GL_TEXTURE_WRAP_T, GL_REPEAT);
+  signature2.clear();
+  manager_.AddToSignature(info_, GL_TEXTURE_2D, 1, &signature2);
+  EXPECT_EQ(signature1, signature2);
+
+  // Check the set was acutally getting different signatures.
+  EXPECT_EQ(11u, string_set.size());
+}
+
 }  // namespace gles2
 }  // namespace gpu