Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / gpu / command_buffer / service / context_state.cc
index e8912cf..a44d65c 100644 (file)
@@ -18,7 +18,7 @@ namespace gles2 {
 
 namespace {
 
-void EnableDisable(GLenum pname, bool enable) {
+static void EnableDisable(GLenum pname, bool enable) {
   if (enable) {
     glEnable(pname);
   } else {
@@ -26,6 +26,58 @@ void EnableDisable(GLenum pname, bool enable) {
   }
 }
 
+GLuint Get2dServiceId(const TextureUnit& unit) {
+  return unit.bound_texture_2d.get()
+      ? unit.bound_texture_2d->service_id() : 0;
+}
+
+GLuint GetCubeServiceId(const TextureUnit& unit) {
+  return unit.bound_texture_cube_map.get()
+      ? unit.bound_texture_cube_map->service_id() : 0;
+}
+
+GLuint GetOesServiceId(const TextureUnit& unit) {
+  return unit.bound_texture_external_oes.get()
+      ? unit.bound_texture_external_oes->service_id() : 0;
+}
+
+GLuint GetArbServiceId(const TextureUnit& unit) {
+  return unit.bound_texture_rectangle_arb.get()
+      ? unit.bound_texture_rectangle_arb->service_id() : 0;
+}
+
+GLuint GetServiceId(const TextureUnit& unit, GLuint target) {
+  switch (target) {
+    case GL_TEXTURE_2D:
+      return Get2dServiceId(unit);
+    case GL_TEXTURE_CUBE_MAP:
+      return GetCubeServiceId(unit);
+    case GL_TEXTURE_RECTANGLE_ARB:
+      return GetArbServiceId(unit);
+    case GL_TEXTURE_EXTERNAL_OES:
+      return GetOesServiceId(unit);
+    default:
+      NOTREACHED();
+      return 0;
+  }
+}
+
+bool TargetIsSupported(const FeatureInfo* feature_info, GLuint target) {
+  switch (target) {
+    case GL_TEXTURE_2D:
+      return true;
+    case GL_TEXTURE_CUBE_MAP:
+      return true;
+    case GL_TEXTURE_RECTANGLE_ARB:
+      return feature_info->feature_flags().arb_texture_rectangle;
+    case GL_TEXTURE_EXTERNAL_OES:
+      return feature_info->feature_flags().oes_egl_image_external;
+    default:
+      NOTREACHED();
+      return false;
+  }
+}
+
 }  // anonymous namespace.
 
 TextureUnit::TextureUnit()
@@ -35,43 +87,64 @@ TextureUnit::TextureUnit()
 TextureUnit::~TextureUnit() {
 }
 
-ContextState::ContextState(FeatureInfo* feature_info, Logger* logger)
+ContextState::ContextState(FeatureInfo* feature_info,
+                           ErrorStateClient* error_state_client,
+                           Logger* logger)
     : active_texture_unit(0),
+      bound_renderbuffer_valid(false),
       pack_reverse_row_order(false),
+      ignore_cached_state(false),
       fbo_binding_for_scissor_workaround_dirty_(false),
       feature_info_(feature_info),
-      error_state_(ErrorState::Create(logger)) {
+      error_state_(ErrorState::Create(error_state_client, logger)) {
   Initialize();
 }
 
 ContextState::~ContextState() {
 }
 
-void ContextState::RestoreTextureUnitBindings(GLuint unit) const {
+void ContextState::RestoreTextureUnitBindings(
+    GLuint unit, const ContextState* prev_state) const {
   DCHECK_LT(unit, texture_units.size());
   const TextureUnit& texture_unit = texture_units[unit];
-  glActiveTexture(GL_TEXTURE0 + unit);
-  GLuint service_id = texture_unit.bound_texture_2d.get()
-                          ? texture_unit.bound_texture_2d->service_id()
-                          : 0;
-  glBindTexture(GL_TEXTURE_2D, service_id);
-  service_id = texture_unit.bound_texture_cube_map.get()
-                   ? texture_unit.bound_texture_cube_map->service_id()
-                   : 0;
-  glBindTexture(GL_TEXTURE_CUBE_MAP, service_id);
-
-  if (feature_info_->feature_flags().oes_egl_image_external) {
-    service_id = texture_unit.bound_texture_external_oes.get()
-                     ? texture_unit.bound_texture_external_oes->service_id()
-                     : 0;
-    glBindTexture(GL_TEXTURE_EXTERNAL_OES, service_id);
+  GLuint service_id_2d = Get2dServiceId(texture_unit);
+  GLuint service_id_cube = GetCubeServiceId(texture_unit);
+  GLuint service_id_oes = GetOesServiceId(texture_unit);
+  GLuint service_id_arb = GetArbServiceId(texture_unit);
+
+  bool bind_texture_2d = true;
+  bool bind_texture_cube = true;
+  bool bind_texture_oes = feature_info_->feature_flags().oes_egl_image_external;
+  bool bind_texture_arb = feature_info_->feature_flags().arb_texture_rectangle;
+
+  if (prev_state) {
+    const TextureUnit& prev_unit = prev_state->texture_units[unit];
+    bind_texture_2d = service_id_2d != Get2dServiceId(prev_unit);
+    bind_texture_cube = service_id_cube != GetCubeServiceId(prev_unit);
+    bind_texture_oes =
+        bind_texture_oes && service_id_oes != GetOesServiceId(prev_unit);
+    bind_texture_arb =
+        bind_texture_arb && service_id_arb != GetArbServiceId(prev_unit);
+  }
+
+  // Early-out if nothing has changed from the previous state.
+  if (!bind_texture_2d && !bind_texture_cube
+      && !bind_texture_oes && !bind_texture_arb) {
+    return;
   }
 
-  if (feature_info_->feature_flags().arb_texture_rectangle) {
-    service_id = texture_unit.bound_texture_rectangle_arb.get()
-                     ? texture_unit.bound_texture_rectangle_arb->service_id()
-                     : 0;
-    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, service_id);
+  glActiveTexture(GL_TEXTURE0 + unit);
+  if (bind_texture_2d) {
+    glBindTexture(GL_TEXTURE_2D, service_id_2d);
+  }
+  if (bind_texture_cube) {
+    glBindTexture(GL_TEXTURE_CUBE_MAP, service_id_cube);
+  }
+  if (bind_texture_oes) {
+    glBindTexture(GL_TEXTURE_EXTERNAL_OES, service_id_oes);
+  }
+  if (bind_texture_arb) {
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, service_id_arb);
   }
 }
 
@@ -86,11 +159,9 @@ void ContextState::RestoreBufferBindings() const {
                bound_array_buffer.get() ? bound_array_buffer->service_id() : 0);
 }
 
-void ContextState::RestoreRenderbufferBindings() const {
-  // Restore Bindings
-  glBindRenderbufferEXT(
-      GL_RENDERBUFFER,
-      bound_renderbuffer.get() ? bound_renderbuffer->service_id() : 0);
+void ContextState::RestoreRenderbufferBindings() {
+  // Require Renderbuffer rebind.
+  bound_renderbuffer_valid = false;
 }
 
 void ContextState::RestoreProgramBindings() const {
@@ -101,62 +172,117 @@ void ContextState::RestoreActiveTexture() const {
   glActiveTexture(GL_TEXTURE0 + active_texture_unit);
 }
 
-void ContextState::RestoreAllTextureUnitBindings() const {
+void ContextState::RestoreAllTextureUnitBindings(
+    const ContextState* prev_state) const {
   // Restore Texture state.
   for (size_t ii = 0; ii < texture_units.size(); ++ii) {
-    RestoreTextureUnitBindings(ii);
+    RestoreTextureUnitBindings(ii, prev_state);
   }
   RestoreActiveTexture();
 }
 
-void ContextState::RestoreAttribute(GLuint attrib_index) const {
-  const VertexAttrib* attrib =
-      vertex_attrib_manager->GetVertexAttrib(attrib_index);
-  const void* ptr = reinterpret_cast<const void*>(attrib->offset());
-  Buffer* buffer = attrib->buffer();
-  glBindBuffer(GL_ARRAY_BUFFER, buffer ? buffer->service_id() : 0);
-  glVertexAttribPointer(
-      attrib_index, attrib->size(), attrib->type(), attrib->normalized(),
-      attrib->gl_stride(), ptr);
-  if (attrib->divisor())
-    glVertexAttribDivisorANGLE(attrib_index, attrib->divisor());
-  // Never touch vertex attribute 0's state (in particular, never
-  // disable it) when running on desktop GL because it will never be
-  // re-enabled.
-  if (attrib_index != 0 ||
-      gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
-    if (attrib->enabled()) {
-      glEnableVertexAttribArray(attrib_index);
-    } else {
-      glDisableVertexAttribArray(attrib_index);
-    }
-  }
-  glVertexAttrib4fv(attrib_index, attrib_values[attrib_index].v);
+void ContextState::RestoreActiveTextureUnitBinding(unsigned int target) const {
+  DCHECK_LT(active_texture_unit, texture_units.size());
+  const TextureUnit& texture_unit = texture_units[active_texture_unit];
+  if (TargetIsSupported(feature_info_, target))
+    glBindTexture(target, GetServiceId(texture_unit, target));
 }
 
-void ContextState::RestoreGlobalState() const {
-  InitCapabilities();
-  InitState();
+void ContextState::RestoreVertexAttribValues() const {
+  for (size_t attrib = 0; attrib < vertex_attrib_manager->num_attribs();
+       ++attrib) {
+    glVertexAttrib4fv(attrib, attrib_values[attrib].v);
+  }
 }
 
-void ContextState::RestoreState() const {
-  RestoreAllTextureUnitBindings();
+void ContextState::RestoreVertexAttribArrays(
+    const scoped_refptr<VertexAttribManager> attrib_manager) const {
+  // This is expected to be called only for VAO with service_id 0,
+  // either to restore the default VAO or a virtual VAO with service_id 0.
+  GLuint vao_service_id = attrib_manager->service_id();
+  DCHECK(vao_service_id == 0);
+
+  // Bind VAO if supported.
+  if (feature_info_->feature_flags().native_vertex_array_object)
+    glBindVertexArrayOES(vao_service_id);
+
+  // Restore vertex attrib arrays.
+  for (size_t attrib_index = 0; attrib_index < attrib_manager->num_attribs();
+       ++attrib_index) {
+    const VertexAttrib* attrib = attrib_manager->GetVertexAttrib(attrib_index);
+
+    // Restore vertex array.
+    Buffer* buffer = attrib->buffer();
+    GLuint buffer_service_id = buffer ? buffer->service_id() : 0;
+    glBindBuffer(GL_ARRAY_BUFFER, buffer_service_id);
+    const void* ptr = reinterpret_cast<const void*>(attrib->offset());
+    glVertexAttribPointer(attrib_index,
+                          attrib->size(),
+                          attrib->type(),
+                          attrib->normalized(),
+                          attrib->gl_stride(),
+                          ptr);
+
+    // Restore attrib divisor if supported.
+    if (feature_info_->feature_flags().angle_instanced_arrays)
+      glVertexAttribDivisorANGLE(attrib_index, attrib->divisor());
 
-  // Restore Attrib State
+    // Never touch vertex attribute 0's state (in particular, never
+    // disable it) when running on desktop GL because it will never be
+    // re-enabled.
+    if (attrib_index != 0 ||
+        gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
+      if (attrib->enabled()) {
+        glEnableVertexAttribArray(attrib_index);
+      } else {
+        glDisableVertexAttribArray(attrib_index);
+      }
+    }
+  }
+}
+
+void ContextState::RestoreVertexAttribs() const {
+  // Restore Vertex Attrib Arrays
   // TODO: This if should not be needed. RestoreState is getting called
   // before GLES2Decoder::Initialize which is a bug.
   if (vertex_attrib_manager.get()) {
-    // TODO(gman): Move this restoration to VertexAttribManager.
-    for (size_t attrib = 0; attrib < vertex_attrib_manager->num_attribs();
-         ++attrib) {
-      RestoreAttribute(attrib);
+    // Restore VAOs.
+    if (feature_info_->feature_flags().native_vertex_array_object) {
+      // If default VAO is still using shared id 0 instead of unique ids
+      // per-context, default VAO state must be restored.
+      GLuint default_vao_service_id =
+          default_vertex_attrib_manager->service_id();
+      if (default_vao_service_id == 0)
+        RestoreVertexAttribArrays(default_vertex_attrib_manager);
+
+      // Restore the current VAO binding, unless it's the same as the
+      // default above.
+      GLuint curr_vao_service_id = vertex_attrib_manager->service_id();
+      if (curr_vao_service_id != 0)
+        glBindVertexArrayOES(curr_vao_service_id);
+    } else {
+      // If native VAO isn't supported, emulated VAOs are used.
+      // Restore to the currently bound VAO.
+      RestoreVertexAttribArrays(vertex_attrib_manager);
     }
   }
 
+  // glVertexAttrib4fv aren't part of VAO state and must be restored.
+  RestoreVertexAttribValues();
+}
+
+void ContextState::RestoreGlobalState(const ContextState* prev_state) const {
+  InitCapabilities(prev_state);
+  InitState(prev_state);
+}
+
+void ContextState::RestoreState(const ContextState* prev_state) {
+  RestoreAllTextureUnitBindings(prev_state);
+  RestoreVertexAttribs();
   RestoreBufferBindings();
   RestoreRenderbufferBindings();
   RestoreProgramBindings();
-  RestoreGlobalState();
+  RestoreGlobalState(prev_state);
 }
 
 ErrorState* ContextState::GetErrorState() {