From 186e1ae7ffd48e96e3de93f09381230d3b0911d5 Mon Sep 17 00:00:00 2001
From: "zmo@chromium.org"
 <zmo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Mon, 19 Aug 2013 20:58:26 +0000
Subject: Cache varying variable info in Shader object in command buffer.

Also, check uniform data type and precision match.

BUG=249018
TEST=webgl conformance tests
R=apatrick@chromium.org

Review URL: https://codereview.chromium.org/22330003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@218309 0039d316-1c4b-4281-b951-d872f2087c98
---
 gpu/command_buffer/service/disk_cache_proto.proto  |  2 +
 gpu/command_buffer/service/memory_program_cache.cc | 50 +++++++++--
 gpu/command_buffer/service/memory_program_cache.h  | 12 +++
 .../service/memory_program_cache_unittest.cc       | 44 +++++++---
 gpu/command_buffer/service/mocks.h                 |  1 +
 gpu/command_buffer/service/program_manager.cc      | 54 ++++++++++++
 gpu/command_buffer/service/program_manager.h       |  5 ++
 .../service/program_manager_unittest.cc            | 97 ++++++++++++++++++++--
 gpu/command_buffer/service/shader_manager.cc       |  2 +
 gpu/command_buffer/service/shader_manager.h        | 12 +++
 .../service/shader_manager_unittest.cc             | 18 +++-
 gpu/command_buffer/service/shader_translator.cc    | 29 ++++---
 gpu/command_buffer/service/shader_translator.h     | 11 ++-
 13 files changed, 290 insertions(+), 47 deletions(-)

(limited to 'gpu')

diff --git a/gpu/command_buffer/service/disk_cache_proto.proto b/gpu/command_buffer/service/disk_cache_proto.proto
index c165443..2c504aa 100644
--- a/gpu/command_buffer/service/disk_cache_proto.proto
+++ b/gpu/command_buffer/service/disk_cache_proto.proto
@@ -5,12 +5,14 @@ message ShaderInfoProto {
   optional int32 size = 2;
   optional string name = 3;
   optional string key = 4;
+  optional int32 precision = 5;
 }
 
 message ShaderProto {
   optional bytes sha = 1;
   repeated ShaderInfoProto attribs = 2;
   repeated ShaderInfoProto uniforms = 3;
+  repeated ShaderInfoProto varyings = 4;
 }
 
 message GpuProgramProto {
diff --git a/gpu/command_buffer/service/memory_program_cache.cc b/gpu/command_buffer/service/memory_program_cache.cc
index e09d132..3bff3dc 100644
--- a/gpu/command_buffer/service/memory_program_cache.cc
+++ b/gpu/command_buffer/service/memory_program_cache.cc
@@ -15,6 +15,7 @@
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
 #include "gpu/command_buffer/service/shader_manager.h"
+#include "gpu/command_buffer/service/shader_translator.h"
 #include "ui/gl/gl_bindings.h"
 
 namespace {
@@ -40,31 +41,40 @@ namespace {
 
 enum ShaderMapType {
   ATTRIB_MAP = 0,
-  UNIFORM_MAP
+  UNIFORM_MAP,
+  VARYING_MAP
 };
 
 void StoreShaderInfo(ShaderMapType type, ShaderProto *proto,
                      const ShaderTranslator::VariableMap& map) {
   ShaderTranslator::VariableMap::const_iterator iter;
-  for (iter = map.begin(); iter != map.end(); iter++) {
-    ShaderInfoProto* info;
-    if (type == UNIFORM_MAP) {
-      info = proto->add_uniforms();
-    } else {
-      info = proto->add_attribs();
+  for (iter = map.begin(); iter != map.end(); ++iter) {
+    ShaderInfoProto* info = NULL;
+    switch (type) {
+      case UNIFORM_MAP:
+        info = proto->add_uniforms();
+        break;
+      case ATTRIB_MAP:
+        info = proto->add_attribs();
+        break;
+      case VARYING_MAP:
+        info = proto->add_varyings();
+        break;
+      default: NOTREACHED();
     }
 
     info->set_key(iter->first);
     info->set_type(iter->second.type);
     info->set_size(iter->second.size);
+    info->set_precision(iter->second.precision);
     info->set_name(iter->second.name);
   }
 }
 
 void RetrieveShaderInfo(const ShaderInfoProto& proto,
                         ShaderTranslator::VariableMap* map) {
-  ShaderTranslator::VariableInfo info(proto.type(), proto.size(),
-                                      proto.name());
+  ShaderTranslator::VariableInfo info(
+      proto.type(), proto.size(), proto.precision(), proto.name());
   (*map)[proto.key()] = info;
 }
 
@@ -73,6 +83,7 @@ void FillShaderProto(ShaderProto* proto, const char* sha,
   proto->set_sha(sha, gpu::gles2::ProgramCache::kHashLength);
   StoreShaderInfo(ATTRIB_MAP, proto, shader->attrib_map());
   StoreShaderInfo(UNIFORM_MAP, proto, shader->uniform_map());
+  StoreShaderInfo(VARYING_MAP, proto, shader->varying_map());
 }
 
 void RunShaderCallback(const ShaderCacheCallback& callback,
@@ -147,8 +158,10 @@ ProgramCache::ProgramLoadResult MemoryProgramCache::LoadLinkedProgram(
   }
   shader_a->set_attrib_map(value->attrib_map_0());
   shader_a->set_uniform_map(value->uniform_map_0());
+  shader_a->set_varying_map(value->varying_map_0());
   shader_b->set_attrib_map(value->attrib_map_1());
   shader_b->set_uniform_map(value->uniform_map_1());
+  shader_b->set_varying_map(value->varying_map_1());
 
   if (!shader_callback.is_null() &&
       !CommandLine::ForCurrentProcess()->HasSwitch(
@@ -241,9 +254,11 @@ void MemoryProgramCache::SaveLinkedProgram(
                                    a_sha,
                                    shader_a->attrib_map(),
                                    shader_a->uniform_map(),
+                                   shader_a->varying_map(),
                                    b_sha,
                                    shader_b->attrib_map(),
                                    shader_b->uniform_map(),
+                                   shader_b->varying_map(),
                                    this));
 
   UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb",
@@ -255,6 +270,7 @@ void MemoryProgramCache::LoadProgram(const std::string& program) {
   if (proto->ParseFromString(program)) {
     ShaderTranslator::VariableMap vertex_attribs;
     ShaderTranslator::VariableMap vertex_uniforms;
+    ShaderTranslator::VariableMap vertex_varyings;
 
     for (int i = 0; i < proto->vertex_shader().attribs_size(); i++) {
       RetrieveShaderInfo(proto->vertex_shader().attribs(i), &vertex_attribs);
@@ -264,8 +280,13 @@ void MemoryProgramCache::LoadProgram(const std::string& program) {
       RetrieveShaderInfo(proto->vertex_shader().uniforms(i), &vertex_uniforms);
     }
 
+    for (int i = 0; i < proto->vertex_shader().varyings_size(); i++) {
+      RetrieveShaderInfo(proto->vertex_shader().varyings(i), &vertex_varyings);
+    }
+
     ShaderTranslator::VariableMap fragment_attribs;
     ShaderTranslator::VariableMap fragment_uniforms;
+    ShaderTranslator::VariableMap fragment_varyings;
 
     for (int i = 0; i < proto->fragment_shader().attribs_size(); i++) {
       RetrieveShaderInfo(proto->fragment_shader().attribs(i),
@@ -277,6 +298,11 @@ void MemoryProgramCache::LoadProgram(const std::string& program) {
                          &fragment_uniforms);
     }
 
+    for (int i = 0; i < proto->fragment_shader().varyings_size(); i++) {
+      RetrieveShaderInfo(proto->fragment_shader().varyings(i),
+                         &fragment_varyings);
+    }
+
     scoped_ptr<char[]> binary(new char[proto->program().length()]);
     memcpy(binary.get(), proto->program().c_str(), proto->program().length());
 
@@ -288,9 +314,11 @@ void MemoryProgramCache::LoadProgram(const std::string& program) {
                                      proto->vertex_shader().sha().c_str(),
                                      vertex_attribs,
                                      vertex_uniforms,
+                                     vertex_varyings,
                                      proto->fragment_shader().sha().c_str(),
                                      fragment_attribs,
                                      fragment_uniforms,
+                                     fragment_varyings,
                                      this));
 
     UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb",
@@ -308,9 +336,11 @@ MemoryProgramCache::ProgramCacheValue::ProgramCacheValue(
     const char* shader_0_hash,
     const ShaderTranslator::VariableMap& attrib_map_0,
     const ShaderTranslator::VariableMap& uniform_map_0,
+    const ShaderTranslator::VariableMap& varying_map_0,
     const char* shader_1_hash,
     const ShaderTranslator::VariableMap& attrib_map_1,
     const ShaderTranslator::VariableMap& uniform_map_1,
+    const ShaderTranslator::VariableMap& varying_map_1,
     MemoryProgramCache* program_cache)
     : length_(length),
       format_(format),
@@ -319,9 +349,11 @@ MemoryProgramCache::ProgramCacheValue::ProgramCacheValue(
       shader_0_hash_(shader_0_hash, kHashLength),
       attrib_map_0_(attrib_map_0),
       uniform_map_0_(uniform_map_0),
+      varying_map_0_(varying_map_0),
       shader_1_hash_(shader_1_hash, kHashLength),
       attrib_map_1_(attrib_map_1),
       uniform_map_1_(uniform_map_1),
+      varying_map_1_(varying_map_1),
       program_cache_(program_cache) {
   program_cache_->curr_size_bytes_ += length_;
   program_cache_->LinkedProgramCacheSuccess(program_hash);
diff --git a/gpu/command_buffer/service/memory_program_cache.h b/gpu/command_buffer/service/memory_program_cache.h
index b2f23e6..e72f9f5 100644
--- a/gpu/command_buffer/service/memory_program_cache.h
+++ b/gpu/command_buffer/service/memory_program_cache.h
@@ -57,9 +57,11 @@ class GPU_EXPORT MemoryProgramCache : public ProgramCache {
                       const char* shader_0_hash,
                       const ShaderTranslator::VariableMap& attrib_map_0,
                       const ShaderTranslator::VariableMap& uniform_map_0,
+                      const ShaderTranslator::VariableMap& varying_map_0,
                       const char* shader_1_hash,
                       const ShaderTranslator::VariableMap& attrib_map_1,
                       const ShaderTranslator::VariableMap& uniform_map_1,
+                      const ShaderTranslator::VariableMap& varying_map_1,
                       MemoryProgramCache* program_cache);
 
     GLsizei length() const {
@@ -86,6 +88,10 @@ class GPU_EXPORT MemoryProgramCache : public ProgramCache {
       return uniform_map_0_;
     }
 
+    const ShaderTranslator::VariableMap& varying_map_0() const {
+      return varying_map_0_;
+    }
+
     const std::string& shader_1_hash() const {
       return shader_1_hash_;
     }
@@ -98,6 +104,10 @@ class GPU_EXPORT MemoryProgramCache : public ProgramCache {
       return uniform_map_1_;
     }
 
+    const ShaderTranslator::VariableMap& varying_map_1() const {
+      return varying_map_1_;
+    }
+
    private:
     friend class base::RefCounted<ProgramCacheValue>;
 
@@ -110,9 +120,11 @@ class GPU_EXPORT MemoryProgramCache : public ProgramCache {
     const std::string shader_0_hash_;
     const ShaderTranslator::VariableMap attrib_map_0_;
     const ShaderTranslator::VariableMap uniform_map_0_;
+    const ShaderTranslator::VariableMap varying_map_0_;
     const std::string shader_1_hash_;
     const ShaderTranslator::VariableMap attrib_map_1_;
     const ShaderTranslator::VariableMap uniform_map_1_;
+    const ShaderTranslator::VariableMap varying_map_1_;
     MemoryProgramCache* const program_cache_;
 
     DISALLOW_COPY_AND_ASSIGN(ProgramCacheValue);
diff --git a/gpu/command_buffer/service/memory_program_cache_unittest.cc b/gpu/command_buffer/service/memory_program_cache_unittest.cc
index 83fc12a..36291c4 100644
--- a/gpu/command_buffer/service/memory_program_cache_unittest.cc
+++ b/gpu/command_buffer/service/memory_program_cache_unittest.cc
@@ -108,19 +108,27 @@ class MemoryProgramCacheTest : public testing::Test {
     typedef ShaderTranslator::VariableMap VariableMap;
     VariableMap vertex_attrib_map;
     VariableMap vertex_uniform_map;
+    VariableMap vertex_varying_map;
     VariableMap fragment_attrib_map;
     VariableMap fragment_uniform_map;
-
-    vertex_attrib_map["a"] = VariableInfo(1, 34, "a");
-    vertex_uniform_map["a"] = VariableInfo(0, 10, "a");
-    vertex_uniform_map["b"] = VariableInfo(2, 3114, "b");
-    fragment_attrib_map["jjjbb"] = VariableInfo(463, 1114, "jjjbb");
-    fragment_uniform_map["k"] = VariableInfo(10, 34413, "k");
+    VariableMap fragment_varying_map;
+
+    vertex_attrib_map["a"] = VariableInfo(1, 34, SH_PRECISION_LOWP, "a");
+    vertex_uniform_map["a"] = VariableInfo(0, 10, SH_PRECISION_MEDIUMP,  "a");
+    vertex_uniform_map["b"] = VariableInfo(2, 3114, SH_PRECISION_HIGHP, "b");
+    vertex_varying_map["c"] = VariableInfo(3, 2, SH_PRECISION_HIGHP, "c");
+    fragment_attrib_map["jjjbb"] =
+        VariableInfo(463, 1114, SH_PRECISION_MEDIUMP, "jjjbb");
+    fragment_uniform_map["k"] =
+        VariableInfo(10, 34413, SH_PRECISION_MEDIUMP, "k");
+    fragment_varying_map["c"] = VariableInfo(3, 2, SH_PRECISION_HIGHP, "c");
 
     vertex_shader_->set_attrib_map(vertex_attrib_map);
     vertex_shader_->set_uniform_map(vertex_uniform_map);
+    vertex_shader_->set_varying_map(vertex_varying_map);
     fragment_shader_->set_attrib_map(vertex_attrib_map);
     fragment_shader_->set_uniform_map(vertex_uniform_map);
+    fragment_shader_->set_varying_map(vertex_varying_map);
 
     vertex_shader_->UpdateSource("bbbalsldkdkdkd");
     fragment_shader_->UpdateSource("bbbal   sldkdkdkas 134 ad");
@@ -262,13 +270,17 @@ TEST_F(MemoryProgramCacheTest, CacheLoadMatchesSave) {
 
   VariableMap vertex_attrib_map = vertex_shader_->attrib_map();
   VariableMap vertex_uniform_map = vertex_shader_->uniform_map();
+  VariableMap vertex_varying_map = vertex_shader_->varying_map();
   VariableMap fragment_attrib_map = fragment_shader_->attrib_map();
   VariableMap fragment_uniform_map = fragment_shader_->uniform_map();
+  VariableMap fragment_varying_map = fragment_shader_->varying_map();
 
   vertex_shader_->set_attrib_map(VariableMap());
   vertex_shader_->set_uniform_map(VariableMap());
+  vertex_shader_->set_varying_map(VariableMap());
   fragment_shader_->set_attrib_map(VariableMap());
   fragment_shader_->set_uniform_map(VariableMap());
+  fragment_shader_->set_varying_map(VariableMap());
 
   SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
 
@@ -286,9 +298,11 @@ TEST_F(MemoryProgramCacheTest, CacheLoadMatchesSave) {
   // equality operator
 #if !defined(OS_ANDROID)
   EXPECT_EQ(vertex_attrib_map, vertex_shader_->attrib_map());
-  EXPECT_EQ(vertex_attrib_map, vertex_shader_->uniform_map());
-  EXPECT_EQ(vertex_attrib_map, fragment_shader_->attrib_map());
-  EXPECT_EQ(vertex_attrib_map, fragment_shader_->uniform_map());
+  EXPECT_EQ(vertex_uniform_map, vertex_shader_->uniform_map());
+  EXPECT_EQ(vertex_varying_map, vertex_shader_->varying_map());
+  EXPECT_EQ(fragment_attrib_map, fragment_shader_->attrib_map());
+  EXPECT_EQ(fragment_uniform_map, fragment_shader_->uniform_map());
+  EXPECT_EQ(fragment_varying_map, fragment_shader_->varying_map());
 #endif
 }
 
@@ -311,13 +325,17 @@ TEST_F(MemoryProgramCacheTest, LoadProgramMatchesSave) {
 
   VariableMap vertex_attrib_map = vertex_shader_->attrib_map();
   VariableMap vertex_uniform_map = vertex_shader_->uniform_map();
+  VariableMap vertex_varying_map = vertex_shader_->varying_map();
   VariableMap fragment_attrib_map = fragment_shader_->attrib_map();
   VariableMap fragment_uniform_map = fragment_shader_->uniform_map();
+  VariableMap fragment_varying_map = fragment_shader_->varying_map();
 
   vertex_shader_->set_attrib_map(VariableMap());
   vertex_shader_->set_uniform_map(VariableMap());
+  vertex_shader_->set_varying_map(VariableMap());
   fragment_shader_->set_attrib_map(VariableMap());
   fragment_shader_->set_uniform_map(VariableMap());
+  fragment_shader_->set_varying_map(VariableMap());
 
   SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
 
@@ -338,9 +356,11 @@ TEST_F(MemoryProgramCacheTest, LoadProgramMatchesSave) {
   // equality operator
 #if !defined(OS_ANDROID)
   EXPECT_EQ(vertex_attrib_map, vertex_shader_->attrib_map());
-  EXPECT_EQ(vertex_attrib_map, vertex_shader_->uniform_map());
-  EXPECT_EQ(vertex_attrib_map, fragment_shader_->attrib_map());
-  EXPECT_EQ(vertex_attrib_map, fragment_shader_->uniform_map());
+  EXPECT_EQ(vertex_uniform_map, vertex_shader_->uniform_map());
+  EXPECT_EQ(vertex_varying_map, vertex_shader_->varying_map());
+  EXPECT_EQ(fragment_attrib_map, fragment_shader_->attrib_map());
+  EXPECT_EQ(fragment_uniform_map, fragment_shader_->uniform_map());
+  EXPECT_EQ(fragment_varying_map, fragment_shader_->varying_map());
 #endif
 }
 
diff --git a/gpu/command_buffer/service/mocks.h b/gpu/command_buffer/service/mocks.h
index fda8722..d05ba39 100644
--- a/gpu/command_buffer/service/mocks.h
+++ b/gpu/command_buffer/service/mocks.h
@@ -90,6 +90,7 @@ class MockShaderTranslator : public ShaderTranslatorInterface {
   MOCK_CONST_METHOD0(info_log, const char*());
   MOCK_CONST_METHOD0(attrib_map, const VariableMap&());
   MOCK_CONST_METHOD0(uniform_map, const VariableMap&());
+  MOCK_CONST_METHOD0(varying_map, const VariableMap&());
   MOCK_CONST_METHOD0(name_map, const NameMap&());
   MOCK_CONST_METHOD0(
       GetStringForOptionsThatWouldEffectCompilation, std::string());
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index 8b1eede..c6d15e5 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -34,6 +34,28 @@ namespace gles2 {
 
 namespace {
 
+struct UniformType {
+  explicit UniformType(const ShaderTranslator::VariableInfo uniform)
+      : type(uniform.type),
+        size(uniform.size),
+        precision(uniform.precision) { }
+
+  UniformType()
+      : type(0),
+        size(0),
+        precision(SH_PRECISION_MEDIUMP) { }
+
+  bool operator==(const UniformType& other) const {
+    return type == other.type &&
+        size == other.size &&
+        precision == other.precision;
+  }
+
+  int type;
+  int size;
+  int precision;
+};
+
 int ShaderTypeToIndex(GLenum shader_type) {
   switch (shader_type) {
     case GL_VERTEX_SHADER:
@@ -512,6 +534,10 @@ bool Program::Link(ShaderManager* manager,
     set_log_info("glBindAttribLocation() conflicts");
     return false;
   }
+  if (DetectUniformsMismatch()) {
+    set_log_info("Uniforms with the same name but different type/precision");
+    return false;
+  }
 
   TimeTicks before_time = TimeTicks::HighResNow();
   bool link = true;
@@ -963,6 +989,34 @@ bool Program::DetectAttribLocationBindingConflicts() const {
   return false;
 }
 
+bool Program::DetectUniformsMismatch() const {
+  typedef std::map<std::string, UniformType> UniformMap;
+  UniformMap uniform_map;
+  for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
+    const ShaderTranslator::VariableMap& shader_uniforms =
+        attached_shaders_[ii]->uniform_map();
+    for (ShaderTranslator::VariableMap::const_iterator iter =
+             shader_uniforms.begin();
+         iter != shader_uniforms.end(); ++iter) {
+      const std::string& name = iter->first;
+      UniformType type(iter->second);
+      UniformMap::iterator map_entry = uniform_map.find(name);
+      if (map_entry == uniform_map.end()) {
+        uniform_map[name] = type;
+      } else {
+        // If a uniform is already in the map, i.e., it has already been
+        // declared by other shader, then the type and precision must match.
+        if (map_entry->second == type)
+          continue;
+        // TODO(zmo): uncomment the next line once we fix the incorrect
+        // shaders for Aura.
+        // return true;
+      }
+    }
+  }
+  return false;
+}
+
 static uint32 ComputeOffset(const void* start, const void* position) {
   return static_cast<const uint8*>(position) -
          static_cast<const uint8*>(start);
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index dca232b..05014ba 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -186,6 +186,11 @@ class GPU_EXPORT Program : public base::RefCounted<Program> {
   // We only consider the declared attributes in the program.
   bool DetectAttribLocationBindingConflicts() const;
 
+  // Detects if there are uniforms of the same name but different type
+  // or precision in vertex/fragment shaders.
+  // Return true if such cases are detected.
+  bool DetectUniformsMismatch() const;
+
   // Visible for testing
   const LocationMap& bind_attrib_location_map() const {
     return bind_attrib_location_map_;
diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc
index 90ce0af..ac4caac 100644
--- a/gpu/command_buffer/service/program_manager_unittest.cc
+++ b/gpu/command_buffer/service/program_manager_unittest.cc
@@ -162,6 +162,9 @@ class ProgramManagerWithShaderTest : public testing::Test {
   static const GLint kAttrib1Size = 1;
   static const GLint kAttrib2Size = 1;
   static const GLint kAttrib3Size = 1;
+  static const int kAttrib1Precision = SH_PRECISION_MEDIUMP;
+  static const int kAttrib2Precision = SH_PRECISION_HIGHP;
+  static const int kAttrib3Precision = SH_PRECISION_LOWP;
   static const GLint kAttrib1Location = 0;
   static const GLint kAttrib2Location = 1;
   static const GLint kAttrib3Location = 2;
@@ -178,6 +181,9 @@ class ProgramManagerWithShaderTest : public testing::Test {
   static const GLint kUniform1Size = 1;
   static const GLint kUniform2Size = 3;
   static const GLint kUniform3Size = 2;
+  static const int kUniform1Precision = SH_PRECISION_LOWP;
+  static const int kUniform2Precision = SH_PRECISION_MEDIUMP;
+  static const int kUniform3Precision = SH_PRECISION_HIGHP;
   static const GLint kUniform1FakeLocation = 0;  // These are hard coded
   static const GLint kUniform2FakeLocation = 1;  // to match
   static const GLint kUniform3FakeLocation = 2;  // ProgramManager.
@@ -670,22 +676,25 @@ TEST_F(ProgramManagerWithShaderTest, GLDriverReturnsWrongTypeInfo) {
   MockShaderTranslator shader_translator;
   ShaderTranslator::VariableMap attrib_map;
   ShaderTranslator::VariableMap uniform_map;
+  ShaderTranslator::VariableMap varying_map;
   attrib_map[kAttrib1Name] = ShaderTranslatorInterface::VariableInfo(
-      kAttrib1Type, kAttrib1Size, kAttrib1Name);
+      kAttrib1Type, kAttrib1Size, kAttrib1Precision, kAttrib1Name);
   attrib_map[kAttrib2Name] = ShaderTranslatorInterface::VariableInfo(
-      kAttrib2GoodType, kAttrib2Size, kAttrib2Name);
+      kAttrib2GoodType, kAttrib2Size, kAttrib2Precision, kAttrib2Name);
   attrib_map[kAttrib3Name] = ShaderTranslatorInterface::VariableInfo(
-      kAttrib3Type, kAttrib3Size, kAttrib3Name);
+      kAttrib3Type, kAttrib3Size, kAttrib3Precision, kAttrib3Name);
   uniform_map[kUniform1Name] = ShaderTranslatorInterface::VariableInfo(
-      kUniform1Type, kUniform1Size, kUniform1Name);
+      kUniform1Type, kUniform1Size, kUniform1Precision, kUniform1Name);
   uniform_map[kUniform2Name] = ShaderTranslatorInterface::VariableInfo(
-      kUniform2GoodType, kUniform2Size, kUniform2Name);
+      kUniform2GoodType, kUniform2Size, kUniform2Precision, kUniform2Name);
   uniform_map[kUniform3GoodName] = ShaderTranslatorInterface::VariableInfo(
-      kUniform3Type, kUniform3Size, kUniform3GoodName);
+      kUniform3Type, kUniform3Size, kUniform3Precision, kUniform3GoodName);
   EXPECT_CALL(shader_translator, attrib_map())
       .WillRepeatedly(ReturnRef(attrib_map));
   EXPECT_CALL(shader_translator, uniform_map())
       .WillRepeatedly(ReturnRef(uniform_map));
+  EXPECT_CALL(shader_translator, varying_map())
+      .WillRepeatedly(ReturnRef(varying_map));
   ShaderTranslator::NameMap name_map;
   EXPECT_CALL(shader_translator, name_map())
       .WillRepeatedly(ReturnRef(name_map));
@@ -937,13 +946,19 @@ TEST_F(ProgramManagerWithShaderTest, BindAttribLocationConflicts) {
   ShaderTranslator::VariableMap attrib_map;
   for (uint32 ii = 0; ii < kNumAttribs; ++ii) {
     attrib_map[kAttribs[ii].name] = ShaderTranslatorInterface::VariableInfo(
-        kAttribs[ii].type, kAttribs[ii].size, kAttribs[ii].name);
+        kAttribs[ii].type,
+        kAttribs[ii].size,
+        SH_PRECISION_MEDIUMP,
+        kAttribs[ii].name);
   }
   ShaderTranslator::VariableMap uniform_map;
+  ShaderTranslator::VariableMap varying_map;
   EXPECT_CALL(shader_translator, attrib_map())
       .WillRepeatedly(ReturnRef(attrib_map));
   EXPECT_CALL(shader_translator, uniform_map())
       .WillRepeatedly(ReturnRef(uniform_map));
+  EXPECT_CALL(shader_translator, varying_map())
+      .WillRepeatedly(ReturnRef(varying_map));
   ShaderTranslator::NameMap name_map;
   EXPECT_CALL(shader_translator, name_map())
       .WillRepeatedly(ReturnRef(name_map));
@@ -964,6 +979,7 @@ TEST_F(ProgramManagerWithShaderTest, BindAttribLocationConflicts) {
     ASSERT_TRUE(variable_info != NULL);
     EXPECT_EQ(it->second.type, variable_info->type);
     EXPECT_EQ(it->second.size, variable_info->size);
+    EXPECT_EQ(it->second.precision, variable_info->precision);
     EXPECT_EQ(it->second.name, variable_info->name);
   }
   fshader->SetStatus(true, "", NULL);
@@ -997,6 +1013,73 @@ TEST_F(ProgramManagerWithShaderTest, BindAttribLocationConflicts) {
   EXPECT_TRUE(LinkAsExpected(program, false));
 }
 
+TEST_F(ProgramManagerWithShaderTest, UniformsPrecisionMismatch) {
+  // Set up shader
+  const GLuint kVShaderClientId = 1;
+  const GLuint kVShaderServiceId = 11;
+  const GLuint kFShaderClientId = 2;
+  const GLuint kFShaderServiceId = 12;
+
+  MockShaderTranslator vertex_shader_translator;
+  ShaderTranslator::VariableMap vertex_attrib_map;
+  ShaderTranslator::VariableMap vertex_uniform_map;
+  vertex_uniform_map["a"] = ShaderTranslator::VariableInfo(
+      1, 3, SH_PRECISION_MEDIUMP, "a");
+  ShaderTranslator::VariableMap vertex_varying_map;
+  ShaderTranslator::NameMap vertex_name_map;
+  EXPECT_CALL(vertex_shader_translator, attrib_map())
+      .WillRepeatedly(ReturnRef(vertex_attrib_map));
+  EXPECT_CALL(vertex_shader_translator, uniform_map())
+      .WillRepeatedly(ReturnRef(vertex_uniform_map));
+  EXPECT_CALL(vertex_shader_translator, varying_map())
+      .WillRepeatedly(ReturnRef(vertex_varying_map));
+  EXPECT_CALL(vertex_shader_translator, name_map())
+    .WillRepeatedly(ReturnRef(vertex_name_map));
+
+  MockShaderTranslator frag_shader_translator;
+  ShaderTranslator::VariableMap frag_attrib_map;
+  ShaderTranslator::VariableMap frag_uniform_map;
+  frag_uniform_map["a"] = ShaderTranslator::VariableInfo(
+      1, 3, SH_PRECISION_LOWP, "a");
+  ShaderTranslator::VariableMap frag_varying_map;
+  ShaderTranslator::NameMap frag_name_map;
+  EXPECT_CALL(frag_shader_translator, attrib_map())
+      .WillRepeatedly(ReturnRef(frag_attrib_map));
+  EXPECT_CALL(frag_shader_translator, uniform_map())
+      .WillRepeatedly(ReturnRef(frag_uniform_map));
+  EXPECT_CALL(frag_shader_translator, varying_map())
+      .WillRepeatedly(ReturnRef(frag_varying_map));
+  EXPECT_CALL(frag_shader_translator, name_map())
+    .WillRepeatedly(ReturnRef(frag_name_map));
+
+  // Check we can create shader.
+  Shader* vshader = shader_manager_.CreateShader(
+      kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER);
+  Shader* fshader = shader_manager_.CreateShader(
+      kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER);
+  // Check shader got created.
+  ASSERT_TRUE(vshader != NULL && fshader != NULL);
+  // Set Status
+  vshader->SetStatus(true, "", &vertex_shader_translator);
+  fshader->SetStatus(true, "", &frag_shader_translator);
+
+  // Set up program
+  const GLuint kClientProgramId = 6666;
+  const GLuint kServiceProgramId = 8888;
+  Program* program =
+      manager_.CreateProgram(kClientProgramId, kServiceProgramId);
+  ASSERT_TRUE(program != NULL);
+  EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
+  EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
+
+  // TODO(zmo): change the expectation from FALSE to TRUE once we turn
+  // on DetectUniformsMismatch().
+  EXPECT_FALSE(program->DetectUniformsMismatch());
+  // TODO(zmo): change the link expectation from true to false once we
+  // turn on DetectUniformsMismatch().
+  EXPECT_TRUE(LinkAsExpected(program, true));
+}
+
 TEST_F(ProgramManagerWithShaderTest, ClearWithSamplerTypes) {
   const GLuint kVShaderClientId = 2001;
   const GLuint kFShaderClientId = 2002;
diff --git a/gpu/command_buffer/service/shader_manager.cc b/gpu/command_buffer/service/shader_manager.cc
index a95b04c..89f21f9 100644
--- a/gpu/command_buffer/service/shader_manager.cc
+++ b/gpu/command_buffer/service/shader_manager.cc
@@ -43,10 +43,12 @@ void Shader::SetStatus(
   if (translator && valid) {
     attrib_map_ = translator->attrib_map();
     uniform_map_ = translator->uniform_map();
+    varying_map_ = translator->varying_map();
     name_map_ = translator->name_map();
   } else {
     attrib_map_.clear();
     uniform_map_.clear();
+    varying_map_.clear();
     name_map_.clear();
   }
   if (valid && source_.get()) {
diff --git a/gpu/command_buffer/service/shader_manager.h b/gpu/command_buffer/service/shader_manager.h
index bc68868..1324238 100644
--- a/gpu/command_buffer/service/shader_manager.h
+++ b/gpu/command_buffer/service/shader_manager.h
@@ -98,6 +98,11 @@ class GPU_EXPORT Shader : public base::RefCounted<Shader> {
   }
 
   // Used by program cache.
+  const ShaderTranslator::VariableMap& varying_map() const {
+    return varying_map_;
+  }
+
+  // Used by program cache.
   void set_attrib_map(const ShaderTranslator::VariableMap& attrib_map) {
     // copied because cache might be cleared
     attrib_map_ = ShaderTranslator::VariableMap(attrib_map);
@@ -109,6 +114,12 @@ class GPU_EXPORT Shader : public base::RefCounted<Shader> {
     uniform_map_ = ShaderTranslator::VariableMap(uniform_map);
   }
 
+  // Used by program cache.
+  void set_varying_map(const ShaderTranslator::VariableMap& varying_map) {
+    // copied because cache might be cleared
+    varying_map_ = ShaderTranslator::VariableMap(varying_map);
+  }
+
  private:
   typedef ShaderTranslator::VariableMap VariableMap;
   typedef ShaderTranslator::NameMap NameMap;
@@ -148,6 +159,7 @@ class GPU_EXPORT Shader : public base::RefCounted<Shader> {
   // The type info when the shader was last compiled.
   VariableMap attrib_map_;
   VariableMap uniform_map_;
+  VariableMap varying_map_;
 
   // The name hashing info when the shader was last compiled.
   NameMap name_map_;
diff --git a/gpu/command_buffer/service/shader_manager_unittest.cc b/gpu/command_buffer/service/shader_manager_unittest.cc
index a225a3c..642b121 100644
--- a/gpu/command_buffer/service/shader_manager_unittest.cc
+++ b/gpu/command_buffer/service/shader_manager_unittest.cc
@@ -134,31 +134,39 @@ TEST_F(ShaderManagerTest, GetInfo) {
   const GLenum kShader1Type = GL_VERTEX_SHADER;
   const GLenum kAttrib1Type = GL_FLOAT_VEC2;
   const GLsizei kAttrib1Size = 2;
+  const int kAttrib1Precision = SH_PRECISION_MEDIUMP;
   const char* kAttrib1Name = "attr1";
   const GLenum kAttrib2Type = GL_FLOAT_VEC3;
   const GLsizei kAttrib2Size = 4;
+  const int kAttrib2Precision = SH_PRECISION_HIGHP;
   const char* kAttrib2Name = "attr2";
   const GLenum kUniform1Type = GL_FLOAT_MAT2;
   const GLsizei kUniform1Size = 3;
+  const int kUniform1Precision = SH_PRECISION_LOWP;
   const char* kUniform1Name = "uni1";
   const GLenum kUniform2Type = GL_FLOAT_MAT3;
   const GLsizei kUniform2Size = 5;
+  const int kUniform2Precision = SH_PRECISION_MEDIUMP;
   const char* kUniform2Name = "uni2";
+
   MockShaderTranslator shader_translator;
   ShaderTranslator::VariableMap attrib_map;
   attrib_map[kAttrib1Name] = ShaderTranslatorInterface::VariableInfo(
-      kAttrib1Type, kAttrib1Size, kAttrib1Name);
+      kAttrib1Type, kAttrib1Size, kAttrib1Precision, kAttrib1Name);
   attrib_map[kAttrib2Name] = ShaderTranslatorInterface::VariableInfo(
-      kAttrib2Type, kAttrib2Size, kAttrib2Name);
+      kAttrib2Type, kAttrib2Size, kAttrib2Precision, kAttrib2Name);
   ShaderTranslator::VariableMap uniform_map;
   uniform_map[kUniform1Name] = ShaderTranslatorInterface::VariableInfo(
-      kUniform1Type, kUniform1Size, kUniform1Name);
+      kUniform1Type, kUniform1Size, kUniform1Precision, kUniform1Name);
   uniform_map[kUniform2Name] = ShaderTranslatorInterface::VariableInfo(
-      kUniform2Type, kUniform2Size, kUniform2Name);
+      kUniform2Type, kUniform2Size, kUniform2Precision, kUniform2Name);
   EXPECT_CALL(shader_translator, attrib_map())
       .WillRepeatedly(ReturnRef(attrib_map));
   EXPECT_CALL(shader_translator, uniform_map())
       .WillRepeatedly(ReturnRef(uniform_map));
+  ShaderTranslator::VariableMap varying_map;
+  EXPECT_CALL(shader_translator, varying_map())
+      .WillRepeatedly(ReturnRef(varying_map));
   ShaderTranslator::NameMap name_map;
   EXPECT_CALL(shader_translator, name_map())
       .WillRepeatedly(ReturnRef(name_map));
@@ -177,6 +185,7 @@ TEST_F(ShaderManagerTest, GetInfo) {
     ASSERT_TRUE(variable_info != NULL);
     EXPECT_EQ(it->second.type, variable_info->type);
     EXPECT_EQ(it->second.size, variable_info->size);
+    EXPECT_EQ(it->second.precision, variable_info->precision);
     EXPECT_EQ(it->second.name, variable_info->name);
   }
   for (ShaderTranslator::VariableMap::const_iterator it = uniform_map.begin();
@@ -186,6 +195,7 @@ TEST_F(ShaderManagerTest, GetInfo) {
     ASSERT_TRUE(variable_info != NULL);
     EXPECT_EQ(it->second.type, variable_info->type);
     EXPECT_EQ(it->second.size, variable_info->size);
+    EXPECT_EQ(it->second.precision, variable_info->precision);
     EXPECT_EQ(it->second.name, variable_info->name);
   }
   // Check attrib and uniform get cleared.
diff --git a/gpu/command_buffer/service/shader_translator.cc b/gpu/command_buffer/service/shader_translator.cc
index 5129bfc..f05c450 100644
--- a/gpu/command_buffer/service/shader_translator.cc
+++ b/gpu/command_buffer/service/shader_translator.cc
@@ -48,6 +48,9 @@ void GetVariableInfo(ShHandle compiler, ShShaderInfo var_type,
     case SH_ACTIVE_UNIFORMS:
       ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &name_len);
       break;
+    case SH_VARYINGS:
+      ShGetInfo(compiler, SH_VARYING_MAX_LENGTH, &name_len);
+      break;
     default: NOTREACHED();
   }
   ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_name_len);
@@ -61,18 +64,11 @@ void GetVariableInfo(ShHandle compiler, ShShaderInfo var_type,
     ANGLEGetInfoType len = 0;
     int size = 0;
     ShDataType type = SH_NONE;
+    ShPrecisionType precision = SH_PRECISION_MEDIUMP;
 
-    switch (var_type) {
-      case SH_ACTIVE_ATTRIBUTES:
-        ShGetActiveAttrib(
-            compiler, i, &len, &size, &type, name.get(), mapped_name.get());
-        break;
-      case SH_ACTIVE_UNIFORMS:
-        ShGetActiveUniform(
-            compiler, i, &len, &size, &type, name.get(), mapped_name.get());
-        break;
-      default: NOTREACHED();
-    }
+    ShGetVariableInfo(compiler, var_type, i,
+                      &len, &size, &type, &precision,
+                      name.get(), mapped_name.get());
 
     // In theory we should CHECK(len <= name_len - 1) here, but ANGLE needs
     // to handle long struct field name mapping before we can do this.
@@ -81,7 +77,7 @@ void GetVariableInfo(ShHandle compiler, ShShaderInfo var_type,
     std::string name_string(name.get(), std::min(len, name_len - 1));
     mapped_name.get()[mapped_name_len - 1] = '\0';
 
-    ShaderTranslator::VariableInfo info(type, size, name_string);
+    ShaderTranslator::VariableInfo info(type, size, precision, name_string);
     (*var_map)[mapped_name.get()] = info;
   }
 }
@@ -156,7 +152,7 @@ bool ShaderTranslator::Init(
 
 int ShaderTranslator::GetCompileOptions() const {
   int compile_options =
-      SH_OBJECT_CODE | SH_ATTRIBUTES_UNIFORMS |
+      SH_OBJECT_CODE | SH_VARIABLES |
       SH_MAP_LONG_VARIABLE_NAMES | SH_ENFORCE_PACKING_RESTRICTIONS |
       SH_LIMIT_EXPRESSION_COMPLEXITY | SH_LIMIT_CALL_STACK_DEPTH;
 
@@ -190,6 +186,7 @@ bool ShaderTranslator::Translate(const char* shader) {
     // Get info for attribs and uniforms.
     GetVariableInfo(compiler_, SH_ACTIVE_ATTRIBUTES, &attrib_map_);
     GetVariableInfo(compiler_, SH_ACTIVE_UNIFORMS, &uniform_map_);
+    GetVariableInfo(compiler_, SH_VARYINGS, &varying_map_);
     // Get info for name hashing.
     GetNameHashingInfo(compiler_, &name_map_);
   }
@@ -281,6 +278,11 @@ ShaderTranslator::uniform_map() const {
   return uniform_map_;
 }
 
+const ShaderTranslatorInterface::VariableMap&
+ShaderTranslator::varying_map() const {
+  return varying_map_;
+}
+
 const ShaderTranslatorInterface::NameMap&
 ShaderTranslator::name_map() const {
   return name_map_;
@@ -310,6 +312,7 @@ void ShaderTranslator::ClearResults() {
   info_log_.reset();
   attrib_map_.clear();
   uniform_map_.clear();
+  varying_map_.clear();
   name_map_.clear();
 }
 
diff --git a/gpu/command_buffer/service/shader_translator.h b/gpu/command_buffer/service/shader_translator.h
index 957f721..d4524d0 100644
--- a/gpu/command_buffer/service/shader_translator.h
+++ b/gpu/command_buffer/service/shader_translator.h
@@ -35,23 +35,27 @@ class ShaderTranslatorInterface {
   struct VariableInfo {
     VariableInfo()
         : type(0),
-          size(0) {
+          size(0),
+          precision(SH_PRECISION_MEDIUMP) {
     }
 
-    VariableInfo(int _type, int _size, std::string _name)
+    VariableInfo(int _type, int _size, int _precision, std::string _name)
         : type(_type),
           size(_size),
+          precision(_precision),
           name(_name) {
     }
     bool operator==(
         const ShaderTranslatorInterface::VariableInfo& other) const {
       return type == other.type &&
           size == other.size &&
+          precision == other.precision &&
           strcmp(name.c_str(), other.name.c_str()) == 0;
     }
 
     int type;
     int size;
+    int precision;
     std::string name;  // name in the original shader source.
   };
 
@@ -82,6 +86,7 @@ class ShaderTranslatorInterface {
 
   virtual const VariableMap& attrib_map() const = 0;
   virtual const VariableMap& uniform_map() const = 0;
+  virtual const VariableMap& varying_map() const = 0;
   virtual const NameMap& name_map() const = 0;
 
   // Return a string that is unique for a specfic set of options that would
@@ -128,6 +133,7 @@ class GPU_EXPORT ShaderTranslator
   // Overridden from ShaderTranslatorInterface.
   virtual const VariableMap& attrib_map() const OVERRIDE;
   virtual const VariableMap& uniform_map() const OVERRIDE;
+  virtual const VariableMap& varying_map() const OVERRIDE;
   virtual const NameMap& name_map() const OVERRIDE;
 
   virtual std::string GetStringForOptionsThatWouldEffectCompilation() const
@@ -149,6 +155,7 @@ class GPU_EXPORT ShaderTranslator
   scoped_ptr<char[]> info_log_;
   VariableMap attrib_map_;
   VariableMap uniform_map_;
+  VariableMap varying_map_;
   NameMap name_map_;
   bool implementation_is_glsl_es_;
   bool needs_built_in_function_emulation_;
-- 
cgit v1.1