Add option to not generate resources on bind in OpenGL ES

This allowes us to more efficiently manage ids. It is
not OpenGL ES 2.0 compatible though it probably fits most OpenGL ES
programs.

Note that we need to turn this off on Pepper and/or probably
provide a way for Pepper to turn on on. I'm not sure of the
path Pepper takes to setup. Assuming it goes through
GraphicsContext3D then changes to webkit will be needed to
get the flag all the way down through IPC to the GPU process.

TEST=unit tests and ran a few pages in a chrome build
BUG=92260

Review URL: http://codereview.chromium.org/7633060

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@96904 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc
index 36c8d039..b93c034c 100644
--- a/gpu/command_buffer/service/context_group.cc
+++ b/gpu/command_buffer/service/context_group.cc
@@ -16,9 +16,10 @@
 namespace gpu {
 namespace gles2 {
 
-ContextGroup::ContextGroup()
+ContextGroup::ContextGroup(bool bind_generates_resource)
     : initialized_(false),
       have_context_(true),
+      bind_generates_resource_(bind_generates_resource),
       max_vertex_attribs_(0u),
       max_texture_units_(0u),
       max_texture_image_units_(0u),
diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h
index a2e6382..f130dc6f 100644
--- a/gpu/command_buffer/service/context_group.h
+++ b/gpu/command_buffer/service/context_group.h
@@ -36,7 +36,7 @@
  public:
   typedef scoped_refptr<ContextGroup> Ref;
 
-  ContextGroup();
+  explicit ContextGroup(bool bind_generates_resource);
   ~ContextGroup();
 
   // This should only be called by GLES2Decoder.
@@ -48,6 +48,10 @@
     have_context_ = have_context;
   }
 
+  bool bind_generates_resource() {
+    return bind_generates_resource_;
+  }
+
   uint32 max_vertex_attribs() const {
     return max_vertex_attribs_;
   }
@@ -113,6 +117,7 @@
   // Whether or not this context is initialized.
   bool initialized_;
   bool have_context_;
+  bool bind_generates_resource_;
 
   uint32 max_vertex_attribs_;
   uint32 max_texture_units_;
diff --git a/gpu/command_buffer/service/context_group_unittest.cc b/gpu/command_buffer/service/context_group_unittest.cc
index a651854b..c8a78f3 100644
--- a/gpu/command_buffer/service/context_group_unittest.cc
+++ b/gpu/command_buffer/service/context_group_unittest.cc
@@ -36,7 +36,7 @@
   virtual void SetUp() {
     gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
     ::gfx::GLInterface::SetGLInterface(gl_.get());
-    group_ = ContextGroup::Ref(new ContextGroup());
+    group_ = ContextGroup::Ref(new ContextGroup(true));
   }
 
   virtual void TearDown() {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 7a04a7c7..22e01c29 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -2682,6 +2682,12 @@
   if (client_id != 0) {
     info = GetBufferInfo(client_id);
     if (!info) {
+      if (!group_->bind_generates_resource()) {
+        SetGLError(GL_INVALID_VALUE,
+                   "glBindBuffer: id not generated by glGenBuffers");
+        return;
+      }
+
       // It's a new id so make a buffer info for it.
       glGenBuffersARB(1, &service_id);
       CreateBufferInfo(client_id, service_id);
@@ -2761,6 +2767,12 @@
   if (client_id != 0) {
     info = GetFramebufferInfo(client_id);
     if (!info) {
+      if (!group_->bind_generates_resource()) {
+        SetGLError(GL_INVALID_VALUE,
+                   "glBindFramebuffer: id not generated by glGenFramebuffers");
+        return;
+      }
+
       // It's a new id so make a framebuffer info for it.
       glGenFramebuffersEXT(1, &service_id);
       CreateFramebufferInfo(client_id, service_id);
@@ -2800,6 +2812,13 @@
   if (client_id != 0) {
     info = GetRenderbufferInfo(client_id);
     if (!info) {
+      if (!group_->bind_generates_resource()) {
+        SetGLError(
+            GL_INVALID_VALUE,
+            "glBindRenderbuffer: id not generated by glGenRenderbuffers");
+        return;
+      }
+
       // It's a new id so make a renderbuffer info for it.
       glGenRenderbuffersEXT(1, &service_id);
       CreateRenderbufferInfo(client_id, service_id);
@@ -2822,6 +2841,12 @@
   if (client_id != 0) {
     info = GetTextureInfo(client_id);
     if (!info) {
+      if (!group_->bind_generates_resource()) {
+        SetGLError(GL_INVALID_VALUE,
+                   "glBindTexture: id not generated by glGenTextures");
+        return;
+      }
+
       // It's a new id so make a texture info for it.
       glGenTextures(1, &service_id);
       CreateTextureInfo(client_id, service_id);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index d619b120..fa85ea5 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -96,7 +96,8 @@
         false,  // has stencil
         false,  // request alpha
         false,  // request depth
-        false); // request stencil
+        false,  // request stencil
+        true);   // bind generates resource
     SetupDefaultProgram();
   }
 };
@@ -3190,7 +3191,8 @@
       false,   // has stencil
       true,    // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
 
   EXPECT_CALL(*gl_, GetError())
       .WillOnce(Return(GL_NO_ERROR))
@@ -3220,7 +3222,8 @@
       false,   // has stencil
       false,   // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
 
   EXPECT_CALL(*gl_, GetError())
       .WillOnce(Return(GL_NO_ERROR))
@@ -3250,7 +3253,8 @@
       false,   // has stencil
       false,   // request alpha
       true,    // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
 
   EXPECT_CALL(*gl_, GetError())
       .WillOnce(Return(GL_NO_ERROR))
@@ -3280,7 +3284,8 @@
       false,   // has stencil
       false,   // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
 
   EXPECT_CALL(*gl_, GetError())
       .WillOnce(Return(GL_NO_ERROR))
@@ -3310,7 +3315,8 @@
       true,    // has stencil
       false,   // request alpha
       false,   // request depth
-      true);   // request stencil
+      true,    // request stencil
+      true);   // bind generates resource
 
   EXPECT_CALL(*gl_, GetError())
       .WillOnce(Return(GL_NO_ERROR))
@@ -3340,7 +3346,8 @@
       true,    // has stencil
       false,   // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
 
   EXPECT_CALL(*gl_, GetError())
       .WillOnce(Return(GL_NO_ERROR))
@@ -3370,7 +3377,8 @@
       false,   // has stencil
       false,   // request alpha
       true,    // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
 
   Enable cmd;
   cmd.Init(GL_DEPTH_TEST);
@@ -3426,7 +3434,8 @@
       false,   // has stencil
       false,   // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
 
   Enable cmd;
   cmd.Init(GL_DEPTH_TEST);
@@ -3482,7 +3491,8 @@
       true,    // has stencil
       false,   // request alpha
       false,   // request depth
-      true);   // request stencil
+      true,    // request stencil
+      true);   // bind generates resource
 
   Enable cmd;
   cmd.Init(GL_STENCIL_TEST);
@@ -3538,7 +3548,8 @@
       true,    // has stencil
       false,   // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
 
   Enable cmd;
   cmd.Init(GL_STENCIL_TEST);
@@ -3594,7 +3605,8 @@
       true,    // has stencil
       false,   // request alpha
       true,    // request depth
-      true);   // request stencil
+      true,    // request stencil
+      true);   // bind generates resource
 
   EXPECT_CALL(*gl_, GetError())
       .WillOnce(Return(GL_NO_ERROR))
@@ -3637,7 +3649,8 @@
       true,    // has stencil
       false,   // request alpha
       true,    // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
 
   EXPECT_CALL(*gl_, GetError())
       .WillOnce(Return(GL_NO_ERROR))
@@ -3680,7 +3693,8 @@
       false,   // has stencil
       false,   // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
   DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
                     kServiceRenderbufferId);
   DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
@@ -3756,7 +3770,8 @@
       false,   // has stencil
       false,   // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
   DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
                     kServiceRenderbufferId);
   DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
@@ -4107,7 +4122,8 @@
       false,   // has stencil
       false,   // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
   DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
                     kServiceRenderbufferId);
   EXPECT_CALL(*gl_, GetError())
@@ -4169,7 +4185,8 @@
       false,   // has stencil
       false,   // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
 
   EXPECT_CALL(*gl_, GetError())
       .WillOnce(Return(GL_NO_ERROR))
@@ -4225,7 +4242,8 @@
       false,   // has stencil
       false,   // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
 
   EXPECT_CALL(*gl_, GetError())
       .WillOnce(Return(GL_NO_ERROR))
@@ -4296,7 +4314,8 @@
       false,   // has stencil
       false,   // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
   EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_EXTERNAL_OES, kNewServiceId));
   EXPECT_CALL(*gl_, GenTextures(1, _))
      .WillOnce(SetArgumentPointee<1>(kNewServiceId));
@@ -4317,7 +4336,8 @@
       false,   // has stencil
       false,   // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
   DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId);
 
   EXPECT_CALL(*gl_, GetError())
@@ -4349,7 +4369,8 @@
       false,   // has stencil
       false,   // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
   DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId);
 
   TextureManager::TextureInfo* info = GetTextureInfo(client_texture_id_);
@@ -4368,7 +4389,8 @@
       false,   // has stencil
       false,   // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
 
   DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId);
 
@@ -4425,7 +4447,8 @@
       false,   // has stencil
       false,   // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
 
   DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId);
 
@@ -4464,7 +4487,8 @@
       false,   // has stencil
       false,   // request alpha
       false,   // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
 
   GLenum target = GL_TEXTURE_EXTERNAL_OES;
   GLint level = 0;
@@ -4485,6 +4509,38 @@
   EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
 }
 
+TEST_F(GLES2DecoderManualInitTest, BindGeneratesResourceFalse) {
+  InitDecoder(
+      "",      // extensions
+      false,   // has alpha
+      false,   // has depth
+      false,   // has stencil
+      false,   // request alpha
+      false,   // request depth
+      false,   // request stencil
+      false);  // bind generates resource
+
+  BindTexture cmd1;
+  cmd1.Init(GL_TEXTURE_2D, kInvalidClientId);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+
+  BindBuffer cmd2;
+  cmd2.Init(GL_ARRAY_BUFFER, kInvalidClientId);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+
+  BindFramebuffer cmd3;
+  cmd3.Init(GL_FRAMEBUFFER, kInvalidClientId);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd3));
+  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+
+  BindRenderbuffer cmd4;
+  cmd4.Init(GL_RENDERBUFFER, kInvalidClientId);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd4));
+  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
 // TODO(gman): Complete this test.
 // TEST_F(GLES2DecoderTest, CompressedTexImage2DGLError) {
 // }
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 d80576d..41e42ad0 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -55,7 +55,8 @@
       false,   // has stencil
       true,    // request alpha
       true,    // request depth
-      false);  // request stencil
+      false,   // request stencil
+      true);   // bind generates resource
 }
 
 void GLES2DecoderTestBase::InitDecoder(
@@ -65,11 +66,12 @@
     bool has_stencil,
     bool request_alpha,
     bool request_depth,
-    bool request_stencil) {
+    bool request_stencil,
+    bool bind_generates_resource) {
   gl_.reset(new StrictMock<MockGLInterface>());
   ::gfx::GLInterface::SetGLInterface(gl_.get());
   surface_manager_.reset(new StrictMock<MockSurfaceManager>);
-  group_ = ContextGroup::Ref(new ContextGroup());
+  group_ = ContextGroup::Ref(new ContextGroup(bind_generates_resource));
 
   InSequence sequence;
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
index 22d341a..be2ba020 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -168,7 +168,8 @@
       bool has_stencil,
       bool request_alpha,
       bool request_depth,
-      bool request_stencil);
+      bool request_stencil,
+      bool bind_generates_resource);
 
   const ContextGroup& group() const {
     return *group_.get();