<commit_before>// Copyright 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 "cc/resources/texture_uploader.h"

#include <algorithm>
#include <vector>

#include "base/debug/trace_event.h"
#include "base/metrics/histogram.h"
#include "cc/base/util.h"
#include "cc/resources/prioritized_resource.h"
#include "cc/resources/resource.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/vector2d.h"

using gpu::gles2::GLES2Interface;

namespace {

// How many previous uploads to use when predicting future throughput.
static const size_t kUploadHistorySizeMax = 1000;
static const size_t kUploadHistorySizeInitial = 100;

// Global estimated number of textures per second to maintain estimates across
// subsequent instances of TextureUploader.
// More than one thread will not access this variable, so we do not need to
// synchronize access.
static const double kDefaultEstimatedTexturesPerSecond = 48.0 * 60.0;

// Flush interval when performing texture uploads.
static const size_t kTextureUploadFlushPeriod = 4;

}  // anonymous namespace

namespace cc {

TextureUploader::Query::Query(GLES2Interface* gl)
    : gl_(gl),
      query_id_(0),
      value_(0),
      has_value_(false),
      is_non_blocking_(false) {
  gl_->GenQueriesEXT(1, &query_id_);
}

TextureUploader::Query::~Query() { gl_->DeleteQueriesEXT(1, &query_id_); }

void TextureUploader::Query::Begin() {
  has_value_ = false;
  is_non_blocking_ = false;
  gl_->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, query_id_);
}

void TextureUploader::Query::End() {
  gl_->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
}

bool TextureUploader::Query::IsPending() {
  unsigned available = 1;
  gl_->GetQueryObjectuivEXT(
      query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
  return !available;
}

unsigned TextureUploader::Query::Value() {
  if (!has_value_) {
    gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &value_);
    has_value_ = true;
  }
  return value_;
}

TextureUploader::TextureUploader(GLES2Interface* gl)
    : gl_(gl),
      num_blocking_texture_uploads_(0),
      sub_image_size_(0),
      num_texture_uploads_since_last_flush_(0) {
  for (size_t i = kUploadHistorySizeInitial; i > 0; i--)
    textures_per_second_history_.insert(kDefaultEstimatedTexturesPerSecond);
}

TextureUploader::~TextureUploader() {}

size_t TextureUploader::NumBlockingUploads() {
  ProcessQueries();
  return num_blocking_texture_uploads_;
}

void TextureUploader::MarkPendingUploadsAsNonBlocking() {
  for (ScopedPtrDeque<Query>::iterator it = pending_queries_.begin();
       it != pending_queries_.end();
       ++it) {
    if ((*it)->is_non_blocking())
      continue;

    num_blocking_texture_uploads_--;
    (*it)->mark_as_non_blocking();
  }

  DCHECK(!num_blocking_texture_uploads_);
}

double TextureUploader::EstimatedTexturesPerSecond() {
  ProcessQueries();

  // Use the median as our estimate.
  std::multiset<double>::iterator median = textures_per_second_history_.begin();
  std::advance(median, textures_per_second_history_.size() / 2);
  return *median;
}

void TextureUploader::BeginQuery() {
  if (available_queries_.empty())
    available_queries_.push_back(Query::Create(gl_));

  available_queries_.front()->Begin();
}

void TextureUploader::EndQuery() {
  available_queries_.front()->End();
  pending_queries_.push_back(available_queries_.take_front());
  num_blocking_texture_uploads_++;
}

void TextureUploader::Upload(const uint8* image,
                             const gfx::Rect& image_rect,
                             const gfx::Rect& source_rect,
                             gfx::Vector2d dest_offset,
                             ResourceFormat format,
                             const gfx::Size& size) {
  CHECK(image_rect.Contains(source_rect));

  bool is_full_upload = dest_offset.IsZero() && source_rect.size() == size;

  if (is_full_upload)
    BeginQuery();

  if (format == ETC1) {
    // ETC1 does not support subimage uploads.
    DCHECK(is_full_upload);<commit_msg>Fix unbounded allocation of GL queries<commit_after>// Copyright 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 "cc/resources/texture_uploader.h"

#include <algorithm>
#include <vector>

#include "base/debug/trace_event.h"
#include "base/metrics/histogram.h"
#include "cc/base/util.h"
#include "cc/resources/prioritized_resource.h"
#include "cc/resources/resource.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/vector2d.h"

using gpu::gles2::GLES2Interface;

namespace {

// How many previous uploads to use when predicting future throughput.
static const size_t kUploadHistorySizeMax = 1000;
static const size_t kUploadHistorySizeInitial = 100;

// Global estimated number of textures per second to maintain estimates across
// subsequent instances of TextureUploader.
// More than one thread will not access this variable, so we do not need to
// synchronize access.
static const double kDefaultEstimatedTexturesPerSecond = 48.0 * 60.0;

// Flush interval when performing texture uploads.
static const size_t kTextureUploadFlushPeriod = 4;

}  // anonymous namespace

namespace cc {

TextureUploader::Query::Query(GLES2Interface* gl)
    : gl_(gl),
      query_id_(0),
      value_(0),
      has_value_(false),
      is_non_blocking_(false) {
  gl_->GenQueriesEXT(1, &query_id_);
}

TextureUploader::Query::~Query() { gl_->DeleteQueriesEXT(1, &query_id_); }

void TextureUploader::Query::Begin() {
  has_value_ = false;
  is_non_blocking_ = false;
  gl_->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, query_id_);
}

void TextureUploader::Query::End() {
  gl_->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
}

bool TextureUploader::Query::IsPending() {
  unsigned available = 1;
  gl_->GetQueryObjectuivEXT(
      query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
  return !available;
}

unsigned TextureUploader::Query::Value() {
  if (!has_value_) {
    gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &value_);
    has_value_ = true;
  }
  return value_;
}

TextureUploader::TextureUploader(GLES2Interface* gl)
    : gl_(gl),
      num_blocking_texture_uploads_(0),
      sub_image_size_(0),
      num_texture_uploads_since_last_flush_(0) {
  for (size_t i = kUploadHistorySizeInitial; i > 0; i--)
    textures_per_second_history_.insert(kDefaultEstimatedTexturesPerSecond);
}

TextureUploader::~TextureUploader() {}

size_t TextureUploader::NumBlockingUploads() {
  ProcessQueries();
  return num_blocking_texture_uploads_;
}

void TextureUploader::MarkPendingUploadsAsNonBlocking() {
  for (ScopedPtrDeque<Query>::iterator it = pending_queries_.begin();
       it != pending_queries_.end();
       ++it) {
    if ((*it)->is_non_blocking())
      continue;

    num_blocking_texture_uploads_--;
    (*it)->mark_as_non_blocking();
  }

  DCHECK(!num_blocking_texture_uploads_);
}

double TextureUploader::EstimatedTexturesPerSecond() {
  ProcessQueries();

  // Use the median as our estimate.
  std::multiset<double>::iterator median = textures_per_second_history_.begin();
  std::advance(median, textures_per_second_history_.size() / 2);
  return *median;
}

void TextureUploader::BeginQuery() {
  // Check to see if any of the pending queries are free before allocating a
  // new one. If this is not done, queries may be allocated without bound.
  // http://crbug.com/398072
  if (available_queries_.empty())
    ProcessQueries();

  if (available_queries_.empty())
    available_queries_.push_back(Query::Create(gl_));

  available_queries_.front()->Begin();
}

void TextureUploader::EndQuery() {
  available_queries_.front()->End();
  pending_queries_.push_back(available_queries_.take_front());
  num_blocking_texture_uploads_++;
}

void TextureUploader::Upload(const uint8* image,
                             const gfx::Rect& image_rect,
                             const gfx::Rect& source_rect,
                             gfx::Vector2d dest_offset,
                             ResourceFormat format,
                             const gfx::Size& size) {
  CHECK(image_rect.Contains(source_rect));

  bool is_full_upload = dest_offset.IsZero() && source_rect.size() == size;

  if (is_full_upload)
    BeginQuery();

  if (format == ETC1) {
    // ETC1 does not support subimage uploads.
    DCHECK(is_full_upload);
{'fraction_non_alphanumeric': 0.11513568752128989, 'fraction_numerical': 0.010673328034517997, 'mean_word_length': 4.286914765906363, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5194271', 'n_tokens_mistral': 2939, 'n_tokens_neox': 2848, 'n_words': 587}