blob: 9976132087ab4ed0e94552619f545cc8828eb7ba [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/calculations.h"
#include <algorithm>
#include "cobalt/browser/memory_settings/constants.h"
#include "cobalt/math/clamp.h"
#include "cobalt/math/size.h"
namespace cobalt {
namespace browser {
namespace memory_settings {
namespace {
int32_t NextPowerOf2(int32_t num) {
// Return the smallest power of 2 that is greater than or equal to num.
// This flips on all bits <= num, then num+1 will be the next power of 2.
--num;
num |= num >> 1;
num |= num >> 2;
num |= num >> 4;
num |= num >> 8;
num |= num >> 16;
return num + 1;
}
int32_t NearestPowerOf2(int32_t num) {
int32_t nearest = NextPowerOf2(num);
if (static_cast<float>(nearest) / num > 1.5f) {
nearest /= 2;
}
return nearest;
}
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 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) {
DCHECK_NE(amax_, amin_);
}
// 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 *= (bmax_ - bmin_);
value /= (amax_ - amin_);
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
int64_t CalculateImageCacheSize(const math::Size& dimensions) {
const double display_scale = DisplayScaleTo1080p(dimensions);
static const int64_t kReferenceSize1080p = 32 * 1024 * 1024;
double output_bytes = kReferenceSize1080p * display_scale;
return math::Clamp<int64_t>(static_cast<int64_t>(output_bytes),
kMinImageCacheSize, kMaxImageCacheSize);
}
TextureDimensions CalculateSkiaGlyphAtlasTextureSize(
const math::Size& ui_resolution) {
// LinearRemap 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>(kMinSkiaGlyphTextureAtlasWidth, atlas_texture.width()),
std::max<int>(kMinSkiaGlyphTextureAtlasWidth, atlas_texture.height()));
TextureDimensions texture_dimensions(clamped_atlas_texture.width(),
clamped_atlas_texture.height(),
kSkiaGlyphAtlasTextureBytesPerPixel);
return texture_dimensions;
}
int64_t CalculateSoftwareSurfaceCacheSizeInBytes(
const math::Size& ui_resolution) {
// LinearRemap defines a mapping function which will map the number
// of ui_resolution pixels to the number of surface texture cache such:
// 720p (1280x720) => maps to => 4MB &
// 1080p (1920x1080) => maps to => 9MB
LinearRemap remap(1280 * 720, 1920 * 1080, 4 * 1024 * 1024, 9 * 1024 * 1024);
int64_t surface_cache_size_in_bytes =
static_cast<int64_t>(remap.Map(ui_resolution.GetArea()));
return surface_cache_size_in_bytes;
}
int64_t CalculateOffscreenTargetCacheSizeInBytes(
const math::Size& ui_resolution) {
// The offscreen target cache size should be at least half the ui_resolution
// rounded to the nearest power of 2.
int width = NearestPowerOf2(ui_resolution.width());
int height = NearestPowerOf2(ui_resolution.height());
// The surface cache uses RGBA format so requires 4 bytes per pixel.
return (width * height / 2) * 4;
}
int64_t CalculateSkiaCacheSize(const math::Size& ui_resolution) {
// This is normalized return 4MB @ 1080p and scales accordingly.
LinearRemap remap(0, 1920 * 1080, 0, 4 * 1024 * 1024);
int64_t output = static_cast<int64_t>(remap.Map(ui_resolution.GetArea()));
return std::max<int64_t>(output, kMinSkiaCacheSize);
}
int64_t CalculateMiscCobaltGpuSize(const math::Size& ui_resolution) {
// LinearRemap defines a mapping function which will map the number
// of ui_resolution pixels to the misc memory of the GPU. This mapping
// is linear such that:
// 1080p (1920x1080) => maps to => 24MB
LinearRemap remap(0, 1920 * 1080, 0, 24 * 1024 * 1024);
return static_cast<int64_t>(remap.Map(ui_resolution.GetArea()));
}
} // namespace memory_settings
} // namespace browser
} // namespace cobalt