text: // Copyright (c) 2014 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include <stdint.h>
  
  #include "gpu/command_buffer/service/gl_utils.h"
  #include "gpu/command_buffer/service/program_manager.h"
  #include "gpu/command_buffer/service/valuebuffer_manager.h"
  
  namespace gpu {
  namespace gles2 {
  
  SubscriptionRefSet::Observer::~Observer() {
  }
  
  SubscriptionRefSet::SubscriptionRefSet() {
  }
  
  SubscriptionRefSet::~SubscriptionRefSet() {
    // Make sure no valuebuffers are still holding references to targets
    DCHECK(reference_set_.empty());
  }
  
  void SubscriptionRefSet::AddSubscription(unsigned int target) {
    RefSet::iterator it = reference_set_.find(target);
    if (it == reference_set_.end()) {
      reference_set_.insert(std::make_pair(target, 1));
      FOR_EACH_OBSERVER(Observer, observers_, OnAddSubscription(target));
    } else {
      ++it->second;
    }
  }
  
  void SubscriptionRefSet::RemoveSubscription(unsigned int target) {
    RefSet::iterator it = reference_set_.find(target);
    DCHECK(it != reference_set_.end());
    if (it->second == 1) {
      reference_set_.erase(it);
      FOR_EACH_OBSERVER(Observer, observers_, OnRemoveSubscription(target));
    } else {
      --it->second;
    }
  }
  
  void SubscriptionRefSet::AddObserver(Observer* observer) {
    observers_.AddObserver(observer);
  }
  
  void SubscriptionRefSet::RemoveObserver(Observer* observer) {
    observers_.RemoveObserver(observer);
  }
  
  Valuebuffer::Valuebuffer(ValuebufferManager* manager, unsigned int client_id)
      : manager_(manager), client_id_(client_id), has_been_bound_(false) {
    manager_->StartTracking(this);
    active_state_map_ = new ValueStateMap();
  }
  
  Valuebuffer::~Valuebuffer() {
    if (manager_) {
      for (SubscriptionSet::const_iterator it = subscriptions_.begin();
          it != subscriptions_.end(); ++it) {
        manager_->NotifyRemoveSubscription(*it);
      }
      manager_->StopTracking(this);
      manager_ = NULL;
    }
  }
  
  void Valuebuffer::AddSubscription(unsigned int subscription) {
    if (subscriptions_.find(subscription) == subscriptions_.end()) {
      subscriptions_.insert(subscription);
      manager_->NotifyAddSubscription(subscription);
    }
  }
  
  void Valuebuffer::RemoveSubscription(unsigned int subscription) {
    SubscriptionSet::iterator it = subscriptions_.find(subscription);
    if (subscriptions_.find(subscription) != subscriptions_.end()) {
      subscriptions_.erase(it);
      manager_->NotifyRemoveSubscription(subscription);
    }
  }
  
  bool Valuebuffer::IsSubscribed(unsigned int subscription) {
    return subscriptions_.find(subscription) != subscriptions_.end();
  }
  
  const ValueState* Valuebuffer::GetState(unsigned int target) const {
    return active_state_map_->GetState(target);
  }
  
  void Valuebuffer::UpdateState(const ValueStateMap* pending_state) {
    DCHECK(pending_state);
    for (SubscriptionSet::const_iterator it = subscriptions_.begin();
         it != subscriptions_.end(); ++it) {
      const ValueState *state = pending_state->GetState(*it);
      if (state != NULL) {
        active_state_map_->UpdateState(*it, *state);
      }
    }
  }
  
  ValuebufferManager::ValuebufferManager(SubscriptionRefSet* ref_set,
                                         ValueStateMap* state_map)
      : valuebuffer_count_(0),
        pending_state_map_(state_map),
        subscription_ref_set_(ref_set) {
  }
  
  ValuebufferManager::~ValuebufferManager() {
    DCHECK(valuebuffer_map_.empty());
    // If this triggers, that means something is keeping a reference to
    // a Valuebuffer belonging to this.
    CHECK_EQ(valuebuffer_count_, 0u);
  }
  
  void ValuebufferManager::Destroy() {
    valuebuffer_map_.clear();
  }
  
  void ValuebufferManager::StartTracking(Valuebuffer* /* valuebuffer */) {
    ++valuebuffer_count_;
  }
  
  void ValuebufferManager::StopTracking(Valuebuffer* /* valuebuffer */) {
    --valuebuffer_count_;
  }
  
  void ValuebufferManager::NotifyAddSubscription(unsigned int target) {
    subscription_ref_set_->AddSubscription(target);
  }
  void ValuebufferManager::NotifyRemoveSubscription(unsigned int target) {
    subscription_ref_set_->RemoveSubscription(target);
  }
  
  void ValuebufferManager::CreateValuebuffer(unsigned int client_id) {
    scoped_refptr<Valuebuffer> valuebuffer(new Valuebuffer(this, client_id));
    std::pair<ValuebufferMap::iterator, bool> result =
        valuebuffer_map_.insert(std::make_pair(client_id, valuebuffer));
    DCHECK(result.second);
  }
  
  Valuebuffer* ValuebufferManager::GetValuebuffer(unsigned int client_id) {
    ValuebufferMap::iterator it = valuebuffer_map_.find(client_id);
    return it != valuebuffer_map_.end() ? it->second.get() : NULL;
  }
  
  void ValuebufferManager::RemoveValuebuffer(unsigned int client_id) {
    ValuebufferMap::iterator it = valuebuffer_map_.find(client_id);
    if (it != valuebuffer_map_.end()) {
      Valuebuffer* valuebuffer = it->second.get();
      valuebuffer->MarkAsDeleted();
      valuebuffer_map_.erase(it);
    }
  }
  
  void ValuebufferManager::UpdateValuebufferState(Valuebuffer* valuebuffer) {
    DCHECK(valuebuffer);
    valuebuffer->UpdateState(pending_state_map_.get());
  }
  
  uint32_t ValuebufferManager::ApiTypeForSubscriptionTarget(unsigned int target) {
    switch (target) {
      case GL_MOUSE_POSITION_CHROMIUM:
        return Program::kUniform2i;
    }
    NOTREACHED() << "Unhandled uniform subscription target " << target;
    return Program::kUniformNone;
  }
  
  }  // namespace gles2
  }  // namespace gpu
  