blob: e0d128d1b1b0b4f3e935a993ea5299b36013105e [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/webcodecs/codec_pressure_gauge.h"
#include "build/build_config.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#if !BUILDFLAG(IS_WIN)
#define USE_SHARED_INSTANCE
#endif
// These numbers were picked as roughly 1/4th of the empirical lower limit at
// which we start getting errors when allocating new codecs. Some platforms have
// a decoder limit and an encoder limit, whereas others have a common shared
// limit. These estimates are conservative, but they take into account the fact
// that the true limits are OS-wide, while these thresholds are per-process. It
// also takes into account that we never actually gate codec creation, and we
// only vary the eagerness with which we will try to reclaim codecs instead.
#if BUILDFLAG(IS_WIN)
constexpr int kDecoderPressureThreshold = 6;
constexpr int kEncoderPressureThreshold = 0;
#elif BUILDFLAG(IS_CHROMEOS)
constexpr int kSharedPressureThreshold = 3;
#elif BUILDFLAG(IS_MAC)
constexpr int kSharedPressureThreshold = 24;
#elif BUILDFLAG(IS_ANDROID)
constexpr int kSharedPressureThreshold = 4;
#else
// By default (e.g. for Linux, Fuschia, Chromecast...), any codec with pressure
// should be reclaimable, regardless of global presure.
constexpr int kSharedPressureThreshold = 0;
#endif
namespace blink {
CodecPressureGauge::CodecPressureGauge(size_t pressure_threshold)
: pressure_threshold_(pressure_threshold) {}
// static
CodecPressureGauge& CodecPressureGauge::GetInstance(
ReclaimableCodec::CodecType type) {
#if defined(USE_SHARED_INSTANCE)
return SharedInstance();
#else
switch (type) {
case ReclaimableCodec::CodecType::kDecoder:
return DecoderInstance();
case ReclaimableCodec::CodecType::kEncoder:
return EncoderInstance();
}
#endif
}
#if defined(USE_SHARED_INSTANCE)
// static
CodecPressureGauge& CodecPressureGauge::SharedInstance() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(CodecPressureGauge, shared_instance,
(kSharedPressureThreshold));
return shared_instance;
}
#else
// static
CodecPressureGauge& CodecPressureGauge::DecoderInstance() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(CodecPressureGauge, decoder_instance,
(kDecoderPressureThreshold));
return decoder_instance;
}
// static
CodecPressureGauge& CodecPressureGauge::EncoderInstance() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(CodecPressureGauge, encoder_instance,
(kEncoderPressureThreshold));
return encoder_instance;
}
#endif
#undef USE_SHARED_INSTANCE
void CodecPressureGauge::Increment() {
base::AutoLock locker(lock_);
DCHECK(pressure_callbacks_.size());
++global_pressure_;
CheckForThresholdChanges_Locked();
}
void CodecPressureGauge::Decrement() {
base::AutoLock locker(lock_);
DCHECK(pressure_callbacks_.size());
DCHECK(global_pressure_);
--global_pressure_;
CheckForThresholdChanges_Locked();
}
std::pair<CodecPressureGauge::PressureCallbackId, bool>
CodecPressureGauge::RegisterPressureCallback(
PressureThresholdChangedCallback pressure_callback) {
base::AutoLock locker(lock_);
PressureCallbackId id = next_pressure_callback_id_++;
auto result = pressure_callbacks_.insert(id, std::move(pressure_callback));
DCHECK(result.is_new_entry);
return std::make_pair(id, global_pressure_exceeded_);
}
void CodecPressureGauge::UnregisterPressureCallback(
PressureCallbackId callback_id,
size_t pressure_released) {
base::AutoLock locker(lock_);
DCHECK(pressure_callbacks_.Contains(callback_id));
pressure_callbacks_.erase(callback_id);
DCHECK_GE(global_pressure_, pressure_released);
global_pressure_ -= pressure_released;
// Make sure we still have callbacks left if we have leftover pressure.
DCHECK(!global_pressure_ || pressure_callbacks_.size());
CheckForThresholdChanges_Locked();
}
void CodecPressureGauge::CheckForThresholdChanges_Locked() {
lock_.AssertAcquired();
bool pressure_exceeded = global_pressure_ > pressure_threshold_;
if (pressure_exceeded == global_pressure_exceeded_)
return;
global_pressure_exceeded_ = pressure_exceeded;
// Notify all callbacks of pressure threshold changes.
// Note: we normally should make a copy of |pressure_callbacks_| and release
// |lock_|, to avoid deadlocking on reentrant calls. However, the only
// callbacks registered are from CodecPressureManagers, which do not
// reentranly call into this class.
for (auto& callback : pressure_callbacks_.Values())
callback.Run(global_pressure_exceeded_);
}
} // namespace blink