content/common/gpu/gpu_memory_manager.cc
// The current Manage algorithm simply classifies contexts (clients) into
// "foreground", "background", or "hibernated" categories.
// For each of these three categories, there are predefined memory allocation
// limits and front/backbuffer states.
//
// Users may or may not have a surfaces, and the rules are different for each.
//
// The rules for categorizing contexts with a surface are:
//  1. Foreground: All visible surfaces.
//                 * Must have both front and back buffer.
//
//  2. Background: Non visible surfaces, which have not surpassed the
//                 max_surfaces_with_frontbuffer_soft_limit_ limit.
//                 * Will have only a frontbuffer.
//
//  3. Hibernated: Non visible surfaces, which have surpassed the
//                 max_surfaces_with_frontbuffer_soft_limit_ limit.
//                 * Will not have either buffer.
//
// The considerations for categorizing contexts without a surface are:
//  1. These contexts do not track {visibility,last_used_time}, so cannot
//     sort them directly.
//  2. These contexts may be used by, and thus affect, other contexts, and so
//     cannot be less visible than any affected context.
//  3. Contexts belong to share groups within which resources can be shared.
//
// As such, the rule for categorizing contexts without a surface is:
//  1. Find the most visible context-with-a-surface within each
//     context-without-a-surface's share group, and inherit its visibilty.


Users may or may not have a surfaces, and the rules are different for each.

The rules for categorizing contexts with a surface are:
1. Foreground: All visible surfaces.
Must have both front and back buffer.

2. Background: Non visible surfaces, which have not surpassed the
max_surfaces_with_frontbuffer_soft_limit_ limit.
Will have only a frontbuffer.

3. Hibernated: Non visible surfaces, which have surpassed the
max_surfaces_with_frontbuffer_soft_limit_ limit.
Will not have either buffer.

The considerations for categorizing contexts without a surface are:
1. These contexts do not track {visibility,last_used_time}, so cannot
sort them directly.
2. These contexts may be used by, and thus affect, other contexts, and so
cannot be less visible than any affected context.
3. Contexts belong to share groups within which resources can be shared.

As such, the rule for categorizing contexts without a surface is:
1.
Users may or may not have a surfaces and the rules are different for each . The rules for categorizing contexts with a surface are : 1 . Foreground : All visible surfaces . Must have both front and back buffer . 2 . Background : Non visible surfaces which have not surpassed the max_surfaces_with_frontbuffer_soft_limit_ limit . Will have only a frontbuffer . 3 . Hibernated : Non visible surfaces which have surpassed the max_surfaces_with_frontbuffer_soft_limit_ limit . Will not have either buffer . The considerations for categorizing contexts without a surface are : 1 . These contexts do not track { visibility last_used_time } so cannot sort them directly . 2 . These contexts may be used by and thus affect other contexts and so cannot be less visible than any affected context . 3 . Contexts belong to share groups within which resources can be shared . As such the rule for categorizing contexts without a surface is : 1 .
void GpuMemoryManager::Manage() {
  manage_immediate_scheduled_ = false;
  delayed_manage_callback_.Cancel();
  ClientStateVector clients;
  for (ClientMap::iterator it = clients_.begin(); it != clients_.end(); ++it) {
    clients.push_back(it->second);
  }
  std::sort(clients.begin(), clients.end(), ClientsComparator());
  DCHECK(std::unique(clients.begin(), clients.end()) == clients.end());
  UpdateAvailableGpuMemory(clients);
  SetClientsHibernatedState(clients);
  size_t bytes_limit_when_visible = GetVisibleClientAllocation(clients);
  size_t bytes_allocated_backgrounded = 0;
  for (ClientStateVector::iterator it = clients.begin();
       it != clients.end();
       ++it) {
    ClientState* client_state = *it;
    GpuMemoryAllocation allocation;
    if (client_state->has_surface) {
      allocation.browser_allocation.suggest_have_frontbuffer =
          !client_state->hibernated;
      allocation.renderer_allocation.bytes_limit_when_visible =
          bytes_limit_when_visible;
#if defined(OS_MACOSX)
      allocation.renderer_allocation.priority_cutoff_when_visible =
          GpuMemoryAllocationForRenderer::kPriorityCutoffAllowNiceToHave;
#else
      allocation.renderer_allocation.priority_cutoff_when_visible =
          GpuMemoryAllocationForRenderer::kPriorityCutoffAllowEverything;
#endif
      bool allow_allocation_when_backgrounded = false;
      if (client_state->visible) {
        allow_allocation_when_backgrounded =
            client_state->managed_memory_stats.bytes_required <
            bytes_backgrounded_available_gpu_memory_;
      } else {
        allow_allocation_when_backgrounded =
            client_state->managed_memory_stats.bytes_required +
            bytes_allocated_backgrounded <
            GetCurrentBackgroundedAvailableGpuMemory();
        if (allow_allocation_when_backgrounded) {
          bytes_allocated_backgrounded +=
              client_state->managed_memory_stats.bytes_allocated;
        }
      }
      if (allow_allocation_when_backgrounded) {
        allocation.renderer_allocation.bytes_limit_when_not_visible =
            GetCurrentBackgroundedAvailableGpuMemory();
        allocation.renderer_allocation.priority_cutoff_when_not_visible =
            GpuMemoryAllocationForRenderer::kPriorityCutoffAllowOnlyRequired;
      } else {
        allocation.renderer_allocation.bytes_limit_when_not_visible = 0;
        allocation.renderer_allocation.priority_cutoff_when_not_visible =
            GpuMemoryAllocationForRenderer::kPriorityCutoffAllowNothing;
      }
    } else {
      if (!client_state->hibernated) {
        allocation.renderer_allocation.bytes_limit_when_visible =
            GetMinimumTabAllocation();
        allocation.renderer_allocation.priority_cutoff_when_visible =
            GpuMemoryAllocationForRenderer::kPriorityCutoffAllowEverything;
      }
    }
    client_state->client->SetMemoryAllocation(allocation);
  }
  SendUmaStatsToBrowser();
}
void GpuMemoryManager :: Manage ( ) { manage_immediate_scheduled_ = false ; delayed_manage_callback_ . Cancel ( ) ; ClientStateVector clients ; for ( ClientMap :: iterator it = clients_ . begin ( ) ; it != clients_ . end ( ) ; ++ it ) { clients . push_back ( it -> second ) ; } std :: sort ( clients . begin ( ) , clients . end ( ) , ClientsComparator ( ) ) ; DCHECK ( std :: unique ( clients . begin ( ) , clients . end ( ) ) == clients . end ( ) ) ; UpdateAvailableGpuMemory ( clients ) ; SetClientsHibernatedState ( clients ) ; size_t bytes_limit_when_visible = GetVisibleClientAllocation ( clients ) ; size_t bytes_allocated_backgrounded = 0 ; for ( ClientStateVector :: iterator it = clients . begin ( ) ; it != clients . end ( ) ; ++ it ) { ClientState * client_state = * it ; GpuMemoryAllocation allocation ; if ( client_state -> has_surface ) { allocation . browser_allocation . suggest_have_frontbuffer = ! client_state -> hibernated ; allocation . renderer_allocation . bytes_limit_when_visible = bytes_limit_when_visible ; #if defined ( OS_MACOSX ) allocation . renderer_allocation . priority_cutoff_when_visible = GpuMemoryAllocationForRenderer :: kPriorityCutoffAllowNiceToHave ; #else allocation . renderer_allocation . priority_cutoff_when_visible = GpuMemoryAllocationForRenderer :: kPriorityCutoffAllowEverything ; #endif bool allow_allocation_when_backgrounded = false ; if ( client_state -> visible ) { allow_allocation_when_backgrounded = client_state -> managed_memory_stats . bytes_required < bytes_backgrounded_available_gpu_memory_ ; } else { allow_allocation_when_backgrounded = client_state -> managed_memory_stats . bytes_required + bytes_allocated_backgrounded < GetCurrentBackgroundedAvailableGpuMemory ( ) ; if ( allow_allocation_when_backgrounded ) { bytes_allocated_backgrounded += client_state -> managed_memory_stats . bytes_allocated ; } } if ( allow_allocation_when_backgrounded ) { allocation . renderer_allocation . bytes_limit_when_not_visible = GetCurrentBackgroundedAvailableGpuMemory ( ) ; allocation . renderer_allocation . priority_cutoff_when_not_visible = GpuMemoryAllocationForRenderer :: kPriorityCutoffAllowOnlyRequired ; } else { allocation . renderer_allocation . bytes_limit_when_not_visible = 0 ; allocation . renderer_allocation . priority_cutoff_when_not_visible = GpuMemoryAllocationForRenderer :: kPriorityCutoffAllowNothing ; } } else { if ( ! client_state -> hibernated ) { allocation . renderer_allocation . bytes_limit_when_visible = GetMinimumTabAllocation ( ) ; allocation . renderer_allocation . priority_cutoff_when_visible = GpuMemoryAllocationForRenderer :: kPriorityCutoffAllowEverything ; } } client_state -> client -> SetMemoryAllocation ( allocation ) ; } SendUmaStatsToBrowser ( ) ; }
The current Manage algorithm simply classifies contexts (clients) into
"foreground", "background", or "hibernated" categories.
The current Manage algorithm simply classifies contexts ( clients ) into " foreground " " background " or " hibernated " categories .
// Create a vector of clients, sorted by // - visible clients with surfaces, sorted in MRU order // - backgrounded clients with surfaces, sorted in MRU order // - clients without surfaces // Update the amount of GPU memory available on the system. // Determine which clients are "hibernated" (which determines the // distribution of frontbuffers and memory among clients that don't have // surfaces). // Determine how much memory to assign to give to visible and backgrounded // clients. // Now give out allocations to everyone. // Set the state when visible. // Experiment to determine if aggressively discarding tiles on OS X // results in greater stability. // Set the state when backgrounded. // If the client is visible, then allow it to keep its textures, should // it be backgrounded, but only if all textures required to draw will // fit in total backgrounded memory limit. // If the client is backgrounded, then allow it to keep its textures // if everything required to draw fits in-budget.