blob: 8a8587654afc5ad577986b41d922edafefd659b9 [file] [log] [blame]
/*
* Copyright 2017 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "cobalt/browser/memory_settings/memory_settings.h"
#include <algorithm>
#include "base/compiler_specific.h"
#include "base/logging.h"
namespace cobalt {
namespace browser {
namespace memory_settings {
namespace {
template <typename T>
T ClampValue(const T& input, const T& minimum, const T& maximum) {
return std::max<T>(minimum, std::min<T>(maximum, input));
}
double DisplayScaleTo1080p(const math::Size& dimensions) {
static const double kNumReferencePixels = 1920. * 1080.;
const double num_pixels = static_cast<double>(dimensions.width()) *
static_cast<double>(dimensions.height());
return num_pixels / kNumReferencePixels;
}
// LinearRemap is a type of linear interpolation which maps a value from
// one number line to a corresponding value on another number line.
// Example:
// LinearRemap linear_remap(0, 1, 5, 10);
// EXPECT_EQ(5.0f, linear_remap.Map(0));
// EXPECT_EQ(7.5f, linear_remap.Map(.5));
// EXPECT_EQ(10.f, linear_remap.Map(1));
class LinearRemap {
public:
LinearRemap(double amin, double amax, double bmin, double bmax)
: amin_(amin), amax_(amax), bmin_(bmin), bmax_(bmax) {}
// Maps the value from the number line [amin,amax] to [bmin,bmax]. For
// example:
// Map(amin) -> bmin.
// Map(amax) -> bmax.
// Map((amax+amin)/2) -> (bmax+bmin)/2.
double Map(double value) const {
value -= amin_;
value /= (amax_ - amin_);
value *= (bmax_ - bmin_);
value += bmin_;
return value;
}
private:
const double amin_, amax_, bmin_, bmax_;
};
math::Size ExpandTextureSizeToContain(const int64_t num_pixels) {
// Iterate through to find size to contain number of pixels.
math::Size texture_size(1, 1);
bool toggle = false;
// Expand the texture by powers of two until the specific number of pixels
// is contained.
while (texture_size.GetArea() < num_pixels) {
if (!toggle) {
texture_size.set_width(texture_size.width() * 2);
} else {
texture_size.set_height(texture_size.height() * 2);
}
toggle = !toggle;
}
return texture_size;
}
} // namespace
size_t GetImageCacheSize(const math::Size& dimensions) {
if (COBALT_IMAGE_CACHE_SIZE_IN_BYTES >= 0) {
return COBALT_IMAGE_CACHE_SIZE_IN_BYTES;
}
size_t return_val = CalculateImageCacheSize(dimensions);
return static_cast<int>(return_val);
}
math::Size GetSkiaAtlasTextureSize(const math::Size& ui_resolution,
const base::optional<math::Size> override) {
math::Size texture_size = CalculateSkiaAtlasTextureSize(ui_resolution);
if (override) {
texture_size = override.value();
if (texture_size.width() < memory_settings::kMinSkiaTextureAtlasWidth) {
texture_size.set_width(memory_settings::kMinSkiaTextureAtlasWidth);
LOG(ERROR) << "Width was invalid and was instead set to "
<< memory_settings::kMinSkiaTextureAtlasWidth;
}
if (texture_size.height() < memory_settings::kMinSkiaTextureAtlasHeight) {
texture_size.set_height(memory_settings::kMinSkiaTextureAtlasHeight);
LOG(ERROR) << "Height was invalid and was instead set to "
<< memory_settings::kMinSkiaTextureAtlasHeight;
}
} else {
#if COBALT_SKIA_GLYPH_ATLAS_WIDTH >= 0
// Width was overridden.
texture_size.set_width(COBALT_SKIA_GLYPH_ATLAS_WIDTH);
#endif
#if COBALT_SKIA_GLYPH_ATLAS_HEIGHT >= 0
// Width was overridden.
texture_size.set_height(COBALT_SKIA_GLYPH_ATLAS_HEIGHT);
#endif
}
return texture_size;
}
size_t GetSoftwareSurfaceCacheSizeInBytes(const math::Size& ui_resolution) {
SB_UNREFERENCED_PARAMETER(ui_resolution);
#if COBALT_SOFTWARE_SURFACE_CACHE_SIZE_IN_BYTES >= 0
return COBALT_SOFTWARE_SURFACE_CACHE_SIZE_IN_BYTES;
#endif
return kDefaultSoftwareSurfaceCacheSize;
}
size_t GetSkiaCacheSizeInBytes(const math::Size& ui_resolution) {
SB_UNREFERENCED_PARAMETER(ui_resolution);
#if COBALT_SKIA_CACHE_SIZE_IN_BYTES >= 0
return COBALT_SKIA_CACHE_SIZE_IN_BYTES;
#endif
return kMinSkiaCacheSize;
}
uint32_t GetJsEngineGarbageCollectionThresholdInBytes() {
return COBALT_JS_GARBAGE_COLLECTION_THRESHOLD_IN_BYTES;
}
size_t CalculateImageCacheSize(const math::Size& dimensions) {
const double display_scale = DisplayScaleTo1080p(dimensions);
static const size_t kReferenceSize1080p = 32 * 1024 * 1024;
double output_bytes = kReferenceSize1080p * display_scale;
return ClampValue<size_t>(static_cast<size_t>(output_bytes),
kMinImageCacheSize, kMaxImageCacheSize);
}
math::Size CalculateSkiaAtlasTextureSize(const math::Size& ui_resolution) {
// LinearInterpolate defines a mapping function which will map the number
// of ui_resolution pixels to the number of texture atlas pixels such that:
// 1080p (1920x1080) => maps to => 2048x2048 texture atlas pixels
// 4k (3840x2160) => maps to => 8192x4096 texture atlas pixels
LinearRemap remap(1920 * 1080, 3840 * 2160, 2048 * 2048, 4096 * 8192);
// Apply mapping.
const int num_ui_pixels = ui_resolution.GetArea();
const int64_t num_atlas_pixels =
static_cast<int64_t>(remap.Map(num_ui_pixels));
// Texture atlas sizes are generated in powers of two. This function will
// produce such a texture.
math::Size atlas_texture = ExpandTextureSizeToContain(num_atlas_pixels);
// Clamp the atlas texture to be within a minimum range.
math::Size clamped_atlas_texture(
std::max<int>(kMinSkiaTextureAtlasWidth, atlas_texture.width()),
std::max<int>(kMinSkiaTextureAtlasWidth, atlas_texture.height()));
return clamped_atlas_texture;
}
} // namespace memory_settings
} // namespace browser
} // namespace cobalt