diff options
Diffstat (limited to 'libs')
50 files changed, 429 insertions, 389 deletions
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 5667f9283241..ab7e14de48fb 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -533,8 +533,8 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { // Create the max possible entries we can make. Once we construct the bag, // we will realloc to fit to size. const size_t max_count = parent_bag->entry_count + dtohl(map->count); - ResolvedBag* new_bag = reinterpret_cast<ResolvedBag*>( - malloc(sizeof(ResolvedBag) + (max_count * sizeof(ResolvedBag::Entry)))); + util::unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>( + malloc(sizeof(ResolvedBag) + (max_count * sizeof(ResolvedBag::Entry))))}; ResolvedBag::Entry* new_entry = new_bag->entries; const ResolvedBag::Entry* parent_entry = parent_bag->entries; @@ -601,15 +601,14 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { // Resize the resulting array to fit. const size_t actual_count = new_entry - new_bag->entries; if (actual_count != max_count) { - new_bag = reinterpret_cast<ResolvedBag*>( - realloc(new_bag, sizeof(ResolvedBag) + (actual_count * sizeof(ResolvedBag::Entry)))); + new_bag.reset(reinterpret_cast<ResolvedBag*>(realloc( + new_bag.release(), sizeof(ResolvedBag) + (actual_count * sizeof(ResolvedBag::Entry))))); } - util::unique_cptr<ResolvedBag> final_bag{new_bag}; - final_bag->type_spec_flags = flags; - final_bag->entry_count = static_cast<uint32_t>(actual_count); - ResolvedBag* result = final_bag.get(); - cached_bags_[resid] = std::move(final_bag); + new_bag->type_spec_flags = flags; + new_bag->entry_count = static_cast<uint32_t>(actual_count); + ResolvedBag* result = new_bag.get(); + cached_bags_[resid] = std::move(new_bag); return result; } diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 2fdfcd42a1e1..0700d1fb9f70 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -50,9 +50,9 @@ Caches* Caches::sInstance = nullptr; /////////////////////////////////////////////////////////////////////////////// Caches::Caches(RenderState& renderState) - : gradientCache(mExtensions) + : gradientCache(extensions()) , patchCache(renderState) - , programCache(mExtensions) + , programCache(extensions()) , mRenderState(&renderState) , mInitialized(false) { INIT_LOGD("Creating OpenGL renderer caches"); @@ -80,7 +80,7 @@ bool Caches::init() { } void Caches::initExtensions() { - if (mExtensions.hasDebugMarker()) { + if (extensions().hasDebugMarker()) { eventMark = glInsertEventMarkerEXT; startMark = glPushGroupMarkerEXT; @@ -93,12 +93,12 @@ void Caches::initExtensions() { } void Caches::initConstraints() { - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); + maxTextureSize = DeviceInfo::get()->maxTextureSize(); } void Caches::initStaticProperties() { // OpenGL ES 3.0+ specific features - gpuPixelBuffersEnabled = mExtensions.hasPixelBufferObjects() + gpuPixelBuffersEnabled = extensions().hasPixelBufferObjects() && property_get_bool(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, true); } diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index 19063e3768cd..29eddde1e42b 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -16,6 +16,7 @@ #pragma once +#include "DeviceInfo.h" #include "Extensions.h" #include "FboCache.h" #include "GammaFontRenderer.h" @@ -145,10 +146,6 @@ public: // Misc GLint maxTextureSize; -private: - // Declared before gradientCache and programCache which need this to initialize. - // TODO: cleanup / move elsewhere - Extensions mExtensions; public: TextureCache textureCache; RenderBufferCache renderBufferCache; @@ -174,7 +171,7 @@ public: void setProgram(const ProgramDescription& description); void setProgram(Program* program); - const Extensions& extensions() const { return mExtensions; } + const Extensions& extensions() const { return DeviceInfo::get()->extensions(); } Program& program() { return *mProgram; } PixelBufferState& pixelBufferState() { return *mPixelBufferState; } TextureState& textureState() { return *mTextureState; } diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp index d180ba51b304..37965daf9a8d 100644 --- a/libs/hwui/DeviceInfo.cpp +++ b/libs/hwui/DeviceInfo.cpp @@ -16,7 +16,8 @@ #include <DeviceInfo.h> -#include "Extensions.h" +#include <gui/ISurfaceComposer.h> +#include <gui/SurfaceComposerClient.h> #include <thread> #include <mutex> @@ -46,13 +47,22 @@ void DeviceInfo::initialize() { void DeviceInfo::initialize(int maxTextureSize) { std::call_once(sInitializedFlag, [maxTextureSize]() { sDeviceInfo = new DeviceInfo(); + sDeviceInfo->loadDisplayInfo(); sDeviceInfo->mMaxTextureSize = maxTextureSize; }); } void DeviceInfo::load() { + loadDisplayInfo(); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); } +void DeviceInfo::loadDisplayInfo() { + sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay( + ISurfaceComposer::eDisplayIdMain)); + status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo); + LOG_ALWAYS_FATAL_IF(status, "Failed to get display info, error %d", status); +} + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h index aff84b02d85a..5bd7b14b156d 100644 --- a/libs/hwui/DeviceInfo.h +++ b/libs/hwui/DeviceInfo.h @@ -16,7 +16,10 @@ #ifndef DEVICEINFO_H #define DEVICEINFO_H +#include <ui/DisplayInfo.h> + #include "utils/Macros.h" +#include "Extensions.h" namespace android { namespace uirenderer { @@ -35,14 +38,24 @@ public: static void initialize(int maxTextureSize); int maxTextureSize() const { return mMaxTextureSize; } + const DisplayInfo& displayInfo() const { return mDisplayInfo; } + const Extensions& extensions() const { return mExtensions; } + + static uint32_t multiplyByResolution(uint32_t in) { + auto di = DeviceInfo::get()->displayInfo(); + return di.w * di.h * in; + } private: DeviceInfo() {} ~DeviceInfo() {} void load(); + void loadDisplayInfo(); int mMaxTextureSize; + DisplayInfo mDisplayInfo; + Extensions mExtensions; }; } /* namespace uirenderer */ diff --git a/libs/hwui/FboCache.cpp b/libs/hwui/FboCache.cpp index b2181b60054f..a39e49f82eb0 100644 --- a/libs/hwui/FboCache.cpp +++ b/libs/hwui/FboCache.cpp @@ -28,7 +28,7 @@ namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// FboCache::FboCache() - : mMaxSize(Properties::fboCacheSize) {} + : mMaxSize(0) {} FboCache::~FboCache() { clear(); diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index ee99018fb652..bc4181075319 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -32,7 +32,6 @@ #include "utils/Timing.h" #include <algorithm> -#include <cutils/properties.h> #include <RenderScript.h> #include <SkGlyph.h> #include <SkUtils.h> @@ -99,22 +98,14 @@ FontRenderer::FontRenderer(const uint8_t* gammaTable) INIT_LOGD("Creating FontRenderer"); } - mSmallCacheWidth = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_WIDTH, - DEFAULT_TEXT_SMALL_CACHE_WIDTH); - mSmallCacheHeight = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, - DEFAULT_TEXT_SMALL_CACHE_HEIGHT); + auto deviceInfo = DeviceInfo::get(); + int maxTextureSize = deviceInfo->maxTextureSize(); - mLargeCacheWidth = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_WIDTH, - DEFAULT_TEXT_LARGE_CACHE_WIDTH); - mLargeCacheHeight = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, - DEFAULT_TEXT_LARGE_CACHE_HEIGHT); - - uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize; - - mSmallCacheWidth = std::min(mSmallCacheWidth, maxTextureSize); - mSmallCacheHeight = std::min(mSmallCacheHeight, maxTextureSize); - mLargeCacheWidth = std::min(mLargeCacheWidth, maxTextureSize); - mLargeCacheHeight = std::min(mLargeCacheHeight, maxTextureSize); + // TODO: Most devices are hardcoded with this configuration, does it need to be dynamic? + mSmallCacheWidth = std::min(1024, maxTextureSize); + mSmallCacheHeight = std::min(1024, maxTextureSize); + mLargeCacheWidth = std::min(2048, maxTextureSize); + mLargeCacheHeight = std::min(1024, maxTextureSize); if (sLogFontRendererCreate) { INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i", diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp index c19c1a11e3e2..8727a1d20dfd 100644 --- a/libs/hwui/GlopBuilder.cpp +++ b/libs/hwui/GlopBuilder.cpp @@ -296,6 +296,7 @@ void GlopBuilder::setFill(int color, float alphaScale, colorVector[2] = EOCF(srcColorMatrix[14] / 255.0f); colorVector[3] = srcColorMatrix[19] / 255.0f; // alpha is linear } else { + ALOGE("unsupported ColorFilter type: %s", colorFilter->getTypeName()); LOG_ALWAYS_FATAL("unsupported ColorFilter"); } } else { diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index d4d0c997be11..20262349dda4 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -20,6 +20,7 @@ #include "Debug.h" #include "GradientCache.h" #include "Properties.h" +#include "DeviceInfo.h" #include <cutils/properties.h> @@ -62,14 +63,14 @@ int GradientCacheEntry::compare(const GradientCacheEntry& lhs, const GradientCac // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// -GradientCache::GradientCache(Extensions& extensions) +GradientCache::GradientCache(const Extensions& extensions) : mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity) , mSize(0) - , mMaxSize(Properties::gradientCacheSize) + , mMaxSize(MB(1)) , mUseFloatTexture(extensions.hasFloatTextures()) , mHasNpot(extensions.hasNPot()) , mHasLinearBlending(extensions.hasLinearBlending()) { - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); + mMaxTextureSize = DeviceInfo::get()->maxTextureSize(); mCache.setOnEntryRemovedListener(this); } diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h index f299a40e994f..d95589c514eb 100644 --- a/libs/hwui/GradientCache.h +++ b/libs/hwui/GradientCache.h @@ -105,7 +105,7 @@ inline hash_t hash_type(const GradientCacheEntry& entry) { */ class GradientCache: public OnEntryRemoved<GradientCacheEntry, Texture*> { public: - explicit GradientCache(Extensions& extensions); + explicit GradientCache(const Extensions& extensions); ~GradientCache(); /** diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp index 983c17e92266..78c7eb9ad809 100644 --- a/libs/hwui/PatchCache.cpp +++ b/libs/hwui/PatchCache.cpp @@ -32,7 +32,7 @@ namespace uirenderer { PatchCache::PatchCache(RenderState& renderState) : mRenderState(renderState) - , mMaxSize(Properties::patchCacheSize) + , mMaxSize(KB(128)) , mSize(0) , mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity) , mMeshBuffer(0) diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index cc96de71df82..8d4ae1b6622a 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -38,6 +38,8 @@ namespace android { namespace uirenderer { +static constexpr size_t PATH_CACHE_COUNT_LIMIT = 256; + template <class T> static bool compareWidthHeight(const T& lhs, const T& rhs) { return (lhs.mWidth == rhs.mWidth) && (lhs.mHeight == rhs.mHeight); @@ -179,13 +181,9 @@ static sk_sp<Bitmap> drawPath(const SkPath* path, const SkPaint* paint, PathText PathCache::PathCache() : mCache(LruCache<PathDescription, PathTexture*>::kUnlimitedCapacity) , mSize(0) - , mMaxSize(Properties::pathCacheSize) { + , mMaxSize(DeviceInfo::multiplyByResolution(4)) { mCache.setOnEntryRemovedListener(this); - - GLint maxTextureSize; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); - mMaxTextureSize = maxTextureSize; - + mMaxTextureSize = DeviceInfo::get()->maxTextureSize(); mDebugEnabled = Properties::debugLevel & kDebugCaches; } @@ -259,12 +257,7 @@ void PathCache::purgeCache(uint32_t width, uint32_t height) { } void PathCache::trim() { - // 25 is just an arbitrary lower bound to ensure we aren't in weird edge cases - // of things like a cap of 0 or 1 as that's going to break things. - // It does not represent a reasonable minimum value - static_assert(DEFAULT_PATH_TEXTURE_CAP > 25, "Path cache texture cap is too small"); - - while (mSize > mMaxSize || mCache.size() > DEFAULT_PATH_TEXTURE_CAP) { + while (mSize > mMaxSize || mCache.size() > PATH_CACHE_COUNT_LIMIT) { LOG_ALWAYS_FATAL_IF(!mCache.size(), "Inconsistent mSize! Ran out of items to remove!" " mSize = %u, mMaxSize = %u", mSize, mMaxSize); mCache.removeOldest(); diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 8cc0aa7b414c..b767046f1a4f 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -505,7 +505,7 @@ const char* gBlendOps[18] = { // Constructors/destructors /////////////////////////////////////////////////////////////////////////////// -ProgramCache::ProgramCache(Extensions& extensions) +ProgramCache::ProgramCache(const Extensions& extensions) : mHasES3(extensions.getMajorGlVersion() >= 3) , mHasLinearBlending(extensions.hasLinearBlending()) { } diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h index cedd854bb48b..ee76f22f35d4 100644 --- a/libs/hwui/ProgramCache.h +++ b/libs/hwui/ProgramCache.h @@ -40,7 +40,7 @@ namespace uirenderer { */ class ProgramCache { public: - explicit ProgramCache(Extensions& extensions); + explicit ProgramCache(const Extensions& extensions); ~ProgramCache(); Program* get(const ProgramDescription& description); diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index b5872485b136..acc75393ebcf 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -16,6 +16,7 @@ #include "Properties.h" #include "Debug.h" +#include "DeviceInfo.h" #include <algorithm> #include <cstdlib> @@ -36,20 +37,6 @@ bool Properties::skipEmptyFrames = true; bool Properties::useBufferAge = true; bool Properties::enablePartialUpdates = true; -float Properties::textGamma = DEFAULT_TEXT_GAMMA; - -int Properties::fboCacheSize = DEFAULT_FBO_CACHE_SIZE; -int Properties::gradientCacheSize = MB(DEFAULT_GRADIENT_CACHE_SIZE); -int Properties::layerPoolSize = MB(DEFAULT_LAYER_CACHE_SIZE); -int Properties::patchCacheSize = KB(DEFAULT_PATCH_CACHE_SIZE); -int Properties::pathCacheSize = MB(DEFAULT_PATH_CACHE_SIZE); -int Properties::renderBufferCacheSize = MB(DEFAULT_RENDER_BUFFER_CACHE_SIZE); -int Properties::tessellationCacheSize = MB(DEFAULT_VERTEX_CACHE_SIZE); -int Properties::textDropShadowCacheSize = MB(DEFAULT_DROP_SHADOW_CACHE_SIZE); -int Properties::textureCacheSize = MB(DEFAULT_TEXTURE_CACHE_SIZE); - -float Properties::textureCacheFlushRate = DEFAULT_TEXTURE_CACHE_FLUSH_RATE; - DebugLevel Properties::debugLevel = kDebugDisabled; OverdrawColorSet Properties::overdrawColorSet = OverdrawColorSet::Default; StencilClipDebug Properties::debugStencilClip = StencilClipDebug::Hide; @@ -80,15 +67,6 @@ static int property_get_int(const char* key, int defaultValue) { return defaultValue; } -static float property_get_float(const char* key, float defaultValue) { - char buf[PROPERTY_VALUE_MAX] = {'\0',}; - - if (property_get(key, buf, "") > 0) { - return atof(buf); - } - return defaultValue; -} - bool Properties::load() { char property[PROPERTY_VALUE_MAX]; bool prevDebugLayersUpdates = debugLayersUpdates; @@ -147,20 +125,6 @@ bool Properties::load() { useBufferAge = property_get_bool(PROPERTY_USE_BUFFER_AGE, true); enablePartialUpdates = property_get_bool(PROPERTY_ENABLE_PARTIAL_UPDATES, true); - textGamma = property_get_float(PROPERTY_TEXT_GAMMA, DEFAULT_TEXT_GAMMA); - - fboCacheSize = property_get_int(PROPERTY_FBO_CACHE_SIZE, DEFAULT_FBO_CACHE_SIZE); - gradientCacheSize = MB(property_get_float(PROPERTY_GRADIENT_CACHE_SIZE, DEFAULT_GRADIENT_CACHE_SIZE)); - layerPoolSize = MB(property_get_float(PROPERTY_LAYER_CACHE_SIZE, DEFAULT_LAYER_CACHE_SIZE)); - patchCacheSize = KB(property_get_float(PROPERTY_PATCH_CACHE_SIZE, DEFAULT_PATCH_CACHE_SIZE)); - pathCacheSize = MB(property_get_float(PROPERTY_PATH_CACHE_SIZE, DEFAULT_PATH_CACHE_SIZE)); - renderBufferCacheSize = MB(property_get_float(PROPERTY_RENDER_BUFFER_CACHE_SIZE, DEFAULT_RENDER_BUFFER_CACHE_SIZE)); - tessellationCacheSize = MB(property_get_float(PROPERTY_VERTEX_CACHE_SIZE, DEFAULT_VERTEX_CACHE_SIZE)); - textDropShadowCacheSize = MB(property_get_float(PROPERTY_DROP_SHADOW_CACHE_SIZE, DEFAULT_DROP_SHADOW_CACHE_SIZE)); - textureCacheSize = MB(property_get_float(PROPERTY_TEXTURE_CACHE_SIZE, DEFAULT_TEXTURE_CACHE_SIZE)); - textureCacheFlushRate = std::max(0.0f, std::min(1.0f, - property_get_float(PROPERTY_TEXTURE_CACHE_FLUSH_RATE, DEFAULT_TEXTURE_CACHE_FLUSH_RATE))); - filterOutTestOverhead = property_get_bool(PROPERTY_FILTER_TEST_OVERHEAD, false); return (prevDebugLayersUpdates != debugLayersUpdates) diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 91b4a2d440e2..47ae9e912127 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -153,79 +153,16 @@ enum DebugLevel { #define PROPERTY_FILTER_TEST_OVERHEAD "debug.hwui.filter_test_overhead" /** - * Allows to set rendering pipeline mode to OpenGL (default), Skia OpenGL - * or Vulkan. - */ -#define PROPERTY_RENDERER "debug.hwui.renderer" - -/////////////////////////////////////////////////////////////////////////////// -// Runtime configuration properties -/////////////////////////////////////////////////////////////////////////////// - -/** - * Used to enable/disable scissor optimization. The accepted values are - * "true" and "false". The default value is "false". - * - * When scissor optimization is enabled, libhwui will attempt to - * minimize the use of scissor by selectively enabling and disabling the - * GL scissor test. - * When the optimization is disabled, OpenGLRenderer will keep the GL - * scissor test enabled and change the scissor rect as needed. - * Some GPUs (for instance the SGX 540) perform better when changing - * the scissor rect often than when enabling/disabling the scissor test - * often. - */ -#define PROPERTY_DISABLE_SCISSOR_OPTIMIZATION "ro.hwui.disable_scissor_opt" - -/** * Indicates whether PBOs can be used to back pixel buffers. * Accepted values are "true" and "false". Default is true. */ -#define PROPERTY_ENABLE_GPU_PIXEL_BUFFERS "ro.hwui.use_gpu_pixel_buffers" - -// These properties are defined in mega-bytes -#define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size" -#define PROPERTY_LAYER_CACHE_SIZE "ro.hwui.layer_cache_size" -#define PROPERTY_RENDER_BUFFER_CACHE_SIZE "ro.hwui.r_buffer_cache_size" -#define PROPERTY_GRADIENT_CACHE_SIZE "ro.hwui.gradient_cache_size" -#define PROPERTY_PATH_CACHE_SIZE "ro.hwui.path_cache_size" -#define PROPERTY_VERTEX_CACHE_SIZE "ro.hwui.vertex_cache_size" -#define PROPERTY_PATCH_CACHE_SIZE "ro.hwui.patch_cache_size" -#define PROPERTY_DROP_SHADOW_CACHE_SIZE "ro.hwui.drop_shadow_cache_size" -#define PROPERTY_FBO_CACHE_SIZE "ro.hwui.fbo_cache_size" - -// These properties are defined in percentage (range 0..1) -#define PROPERTY_TEXTURE_CACHE_FLUSH_RATE "ro.hwui.texture_cache_flushrate" - -// These properties are defined in pixels -#define PROPERTY_TEXT_SMALL_CACHE_WIDTH "ro.hwui.text_small_cache_width" -#define PROPERTY_TEXT_SMALL_CACHE_HEIGHT "ro.hwui.text_small_cache_height" -#define PROPERTY_TEXT_LARGE_CACHE_WIDTH "ro.hwui.text_large_cache_width" -#define PROPERTY_TEXT_LARGE_CACHE_HEIGHT "ro.hwui.text_large_cache_height" - -// Gamma (>= 1.0, <= 3.0) -#define PROPERTY_TEXT_GAMMA "hwui.text_gamma" - -/////////////////////////////////////////////////////////////////////////////// -// Default property values -/////////////////////////////////////////////////////////////////////////////// - -#define DEFAULT_TEXTURE_CACHE_SIZE 24.0f -#define DEFAULT_LAYER_CACHE_SIZE 16.0f -#define DEFAULT_RENDER_BUFFER_CACHE_SIZE 2.0f -#define DEFAULT_PATH_CACHE_SIZE 4.0f -#define DEFAULT_VERTEX_CACHE_SIZE 1.0f -#define DEFAULT_PATCH_CACHE_SIZE 128.0f // in kB -#define DEFAULT_GRADIENT_CACHE_SIZE 0.5f -#define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f -#define DEFAULT_FBO_CACHE_SIZE 0 - -#define DEFAULT_TEXTURE_CACHE_FLUSH_RATE 0.6f +#define PROPERTY_ENABLE_GPU_PIXEL_BUFFERS "debug.hwui.use_gpu_pixel_buffers" -#define DEFAULT_TEXT_GAMMA 1.45f // Match design tools - -// cap to 256 to limite paths in the path cache -#define DEFAULT_PATH_TEXTURE_CAP 256 +/** + * Allows to set rendering pipeline mode to OpenGL (default), Skia OpenGL + * or Vulkan. + */ +#define PROPERTY_RENDERER "debug.hwui.renderer" /////////////////////////////////////////////////////////////////////////////// // Misc @@ -279,18 +216,8 @@ public: static bool useBufferAge; static bool enablePartialUpdates; - static float textGamma; - - static int fboCacheSize; - static int gradientCacheSize; - static int layerPoolSize; - static int patchCacheSize; - static int pathCacheSize; - static int renderBufferCacheSize; - static int tessellationCacheSize; - static int textDropShadowCacheSize; - static int textureCacheSize; - static float textureCacheFlushRate; + // TODO: Move somewhere else? + static constexpr float textGamma = 1.45f; static DebugLevel debugLevel; static OverdrawColorSet overdrawColorSet; diff --git a/libs/hwui/RenderBufferCache.cpp b/libs/hwui/RenderBufferCache.cpp index 1ac57cdbac0c..2f8ddfe6d660 100644 --- a/libs/hwui/RenderBufferCache.cpp +++ b/libs/hwui/RenderBufferCache.cpp @@ -17,6 +17,7 @@ #include "Debug.h" #include "Properties.h" #include "RenderBufferCache.h" +#include "DeviceInfo.h" #include <utils/Log.h> @@ -36,13 +37,20 @@ namespace uirenderer { #define RENDER_BUFFER_LOGD(...) #endif +static uint32_t calculateRboCacheSize() { + // TODO: Do we need to use extensions().has4BitStencil() here? + // The tuning guide recommends it, but all real devices are configured + // with a larger cache than necessary by 4x, so keep the 2x for now regardless + return DeviceInfo::multiplyByResolution(2); +} + /////////////////////////////////////////////////////////////////////////////// // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// RenderBufferCache::RenderBufferCache() : mSize(0) - , mMaxSize(Properties::renderBufferCacheSize) {} + , mMaxSize(calculateRboCacheSize()) {} RenderBufferCache::~RenderBufferCache() { clear(); diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 0a642b60d4c7..d191b56768e8 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -24,6 +24,7 @@ #include "pipeline/skia/AnimatedDrawables.h" #include <SkCanvasStateUtils.h> +#include <SkColorFilter.h> #include <SkColorSpaceXformCanvas.h> #include <SkDrawable.h> #include <SkDeque.h> @@ -46,25 +47,33 @@ Canvas* Canvas::create_canvas(const SkBitmap& bitmap) { return new SkiaCanvas(bitmap); } -Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas, XformToSRGB xformToSRGB) { - return new SkiaCanvas(skiaCanvas, xformToSRGB); +Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas) { + return new SkiaCanvas(skiaCanvas); } SkiaCanvas::SkiaCanvas() {} -SkiaCanvas::SkiaCanvas(SkCanvas* canvas, XformToSRGB xformToSRGB) - : mCanvas(canvas) -{ - LOG_ALWAYS_FATAL_IF(XformToSRGB::kImmediate == xformToSRGB); -} +SkiaCanvas::SkiaCanvas(SkCanvas* canvas) : mCanvas(canvas) {} SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) { sk_sp<SkColorSpace> cs = bitmap.refColorSpace(); mCanvasOwned = std::unique_ptr<SkCanvas>(new SkCanvas(bitmap, SkCanvas::ColorBehavior::kLegacy)); - mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), - cs == nullptr ? SkColorSpace::MakeSRGB() : std::move(cs)); - mCanvas = mCanvasWrapper.get(); + if (cs.get() == nullptr || cs->isSRGB()) { + if(!uirenderer::Properties::isSkiaEnabled()) { + mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), SkColorSpace::MakeSRGB()); + mCanvas = mCanvasWrapper.get(); + } else { + mCanvas = mCanvasOwned.get(); + } + } else { + /** The wrapper is needed if we are drawing into a non-sRGB destination, since + * we need to transform all colors (not just bitmaps via filters) into the + * destination's colorspace. + */ + mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), std::move(cs)); + mCanvas = mCanvasWrapper.get(); + } } SkiaCanvas::~SkiaCanvas() {} @@ -73,6 +82,7 @@ void SkiaCanvas::reset(SkCanvas* skiaCanvas) { if (mCanvas != skiaCanvas) { mCanvas = skiaCanvas; mCanvasOwned.reset(); + mCanvasWrapper.reset(); } mSaveStack.reset(nullptr); mHighContrastText = false; @@ -86,13 +96,18 @@ void SkiaCanvas::setBitmap(const SkBitmap& bitmap) { sk_sp<SkColorSpace> cs = bitmap.refColorSpace(); std::unique_ptr<SkCanvas> newCanvas = std::unique_ptr<SkCanvas>(new SkCanvas(bitmap, SkCanvas::ColorBehavior::kLegacy)); - std::unique_ptr<SkCanvas> newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), - cs == nullptr ? SkColorSpace::MakeSRGB() : std::move(cs)); + std::unique_ptr<SkCanvas> newCanvasWrapper; + if (cs.get() != nullptr && !cs->isSRGB()) { + newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), std::move(cs)); + } + else if(!uirenderer::Properties::isSkiaEnabled()) { + newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), SkColorSpace::MakeSRGB()); + } // deletes the previously owned canvas (if any) mCanvasOwned = std::move(newCanvas); mCanvasWrapper = std::move(newCanvasWrapper); - mCanvas = mCanvasWrapper.get(); + mCanvas = mCanvasWrapper ? mCanvasWrapper.get() : mCanvasOwned.get(); // clean up the old save stack mSaveStack.reset(nullptr); @@ -529,25 +544,63 @@ void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, cons // Canvas draw operations: Bitmaps // ---------------------------------------------------------------------------- +const SkPaint* SkiaCanvas::addFilter(const SkPaint* origPaint, SkPaint* tmpPaint, + sk_sp<SkColorFilter> colorSpaceFilter) { + /* We don't apply the colorSpace filter if this canvas is already wrapped with + * a SkColorSpaceXformCanvas since it already takes care of converting the + * contents of the bitmap into the appropriate colorspace. The mCanvasWrapper + * should only be used if this canvas is backed by a surface/bitmap that is known + * to have a non-sRGB colorspace. + */ + if (!mCanvasWrapper && colorSpaceFilter) { + if (origPaint) { + *tmpPaint = *origPaint; + } + + if (tmpPaint->getColorFilter()) { + tmpPaint->setColorFilter(SkColorFilter::MakeComposeFilter( + tmpPaint->refColorFilter(), colorSpaceFilter)); + LOG_ALWAYS_FATAL_IF(!tmpPaint->getColorFilter()); + } else { + tmpPaint->setColorFilter(colorSpaceFilter); + } + + return tmpPaint; + } else { + return origPaint; + } +} + void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { - mCanvas->drawImage(bitmap.makeImage(), left, top, paint); + SkPaint tmpPaint; + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mCanvas->drawImage(image, left, top, addFilter(paint, &tmpPaint, colorFilter)); } -void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix, const SkPaint* paint) { +void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { SkAutoCanvasRestore acr(mCanvas, true); mCanvas->concat(matrix); - mCanvas->drawImage(hwuiBitmap.makeImage(), 0, 0, paint); + + SkPaint tmpPaint; + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mCanvas->drawImage(image, 0, 0, addFilter(paint, &tmpPaint, colorFilter)); } -void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop, +void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) { SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - mCanvas->drawImageRect(hwuiBitmap.makeImage(), srcRect, dstRect, paint); + + SkPaint tmpPaint; + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mCanvas->drawImageRect(image, srcRect, dstRect, addFilter(paint, &tmpPaint, colorFilter)); } -void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeight, +void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight, const float* vertices, const int* colors, const SkPaint* paint) { const int ptCount = (meshWidth + 1) * (meshHeight + 1); const int indexCount = meshWidth * meshHeight * 6; @@ -565,8 +618,8 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeigh // cons up texture coordinates and indices { - const SkScalar w = SkIntToScalar(hwuiBitmap.width()); - const SkScalar h = SkIntToScalar(hwuiBitmap.height()); + const SkScalar w = SkIntToScalar(bitmap.width()); + const SkScalar h = SkIntToScalar(bitmap.height()); const SkScalar dx = w / meshWidth; const SkScalar dy = h / meshHeight; @@ -627,17 +680,22 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeigh tmpPaint = *paint; } - sk_sp<SkImage> image = hwuiBitmap.makeImage(); - tmpPaint.setShader(image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)); + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + sk_sp<SkShader> shader = image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); + if(colorFilter) { + shader = shader->makeWithColorFilter(colorFilter); + } + tmpPaint.setShader(shader); mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate, tmpPaint); } -void SkiaCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk, +void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) { SkCanvas::Lattice lattice; - NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height()); + NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height()); lattice.fFlags = nullptr; int numFlags = 0; @@ -654,7 +712,11 @@ void SkiaCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk, lattice.fBounds = nullptr; SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - mCanvas->drawImageLattice(hwuiBitmap.makeImage().get(), lattice, dst, paint); + + SkPaint tmpPaint; + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mCanvas->drawImageLattice(image.get(), lattice, dst, addFilter(paint, &tmpPaint, colorFilter)); } void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) { diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h index af2c23e4a2b7..6a01f964873b 100644 --- a/libs/hwui/SkiaCanvas.h +++ b/libs/hwui/SkiaCanvas.h @@ -37,12 +37,8 @@ public: * @param canvas SkCanvas to handle calls made to this SkiaCanvas. Must * not be NULL. This constructor does not take ownership, so the caller * must guarantee that it remains valid while the SkiaCanvas is valid. - * @param xformToSRGB Indicates if bitmaps should be xformed to the sRGB - * color space before drawing. This makes sense for software rendering. - * For the picture case, it may make more sense to leave bitmaps as is, - * and handle the xform when replaying the picture. */ - explicit SkiaCanvas(SkCanvas* canvas, XformToSRGB xformToSRGB); + explicit SkiaCanvas(SkCanvas* canvas); virtual ~SkiaCanvas(); @@ -182,6 +178,9 @@ private: void drawPoints(const float* points, int count, const SkPaint& paint, SkCanvas::PointMode mode); + const SkPaint* addFilter(const SkPaint* origPaint, SkPaint* tmpPaint, + sk_sp<SkColorFilter> colorSpaceFilter); + class Clip; std::unique_ptr<SkCanvas> mCanvasWrapper; // might own a wrapper on the canvas diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp index 9adf0538203e..63bf7bc443e0 100644 --- a/libs/hwui/TessellationCache.cpp +++ b/libs/hwui/TessellationCache.cpp @@ -290,7 +290,7 @@ public: /////////////////////////////////////////////////////////////////////////////// TessellationCache::TessellationCache() - : mMaxSize(Properties::tessellationCacheSize) + : mMaxSize(MB(1)) , mCache(LruCache<Description, Buffer*>::kUnlimitedCapacity) , mShadowCache(LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) { mCache.setOnEntryRemovedListener(&mBufferRemovedListener); diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp index e1f0b2a20172..c521892c69df 100644 --- a/libs/hwui/TextDropShadowCache.cpp +++ b/libs/hwui/TextDropShadowCache.cpp @@ -94,7 +94,7 @@ int ShadowText::compare(const ShadowText& lhs, const ShadowText& rhs) { /////////////////////////////////////////////////////////////////////////////// TextDropShadowCache::TextDropShadowCache() - : TextDropShadowCache(Properties::textDropShadowCacheSize) {} + : TextDropShadowCache(DeviceInfo::multiplyByResolution(2)) {} TextDropShadowCache::TextDropShadowCache(uint32_t maxByteSize) : mCache(LruCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity) diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index 710cdd9286e8..6fe3606a7576 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -24,6 +24,7 @@ #include "Properties.h" #include "utils/TraceUtils.h" #include "hwui/Bitmap.h" +#include "DeviceInfo.h" namespace android { namespace uirenderer { @@ -35,13 +36,10 @@ namespace uirenderer { TextureCache::TextureCache() : mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity) , mSize(0) - , mMaxSize(Properties::textureCacheSize) - , mFlushRate(Properties::textureCacheFlushRate) { + , mMaxSize(DeviceInfo::multiplyByResolution(4 * 6)) // 6 screen-sized RGBA_8888 bitmaps + , mFlushRate(.4f) { mCache.setOnEntryRemovedListener(this); - - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); - INIT_LOGD(" Maximum texture dimension is %d pixels", mMaxTextureSize); - + mMaxTextureSize = DeviceInfo::get()->maxTextureSize(); mDebugEnabled = Properties::debugLevel & kDebugCaches; } diff --git a/libs/hwui/font/FontUtil.h b/libs/hwui/font/FontUtil.h index 07e8b34ac66f..d4b4ff949f5a 100644 --- a/libs/hwui/font/FontUtil.h +++ b/libs/hwui/font/FontUtil.h @@ -25,11 +25,6 @@ // Defines /////////////////////////////////////////////////////////////////////////////// -#define DEFAULT_TEXT_SMALL_CACHE_WIDTH 1024 -#define DEFAULT_TEXT_SMALL_CACHE_HEIGHT 512 -#define DEFAULT_TEXT_LARGE_CACHE_WIDTH 2048 -#define DEFAULT_TEXT_LARGE_CACHE_HEIGHT 512 - #ifdef TEXTURE_BORDER_SIZE #if TEXTURE_BORDER_SIZE != 1 #error TEXTURE_BORDER_SIZE other than 1 is not currently supported diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 75b6d233643d..0aeb7627233a 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -31,6 +31,7 @@ #include <ui/PixelFormat.h> #include <SkCanvas.h> +#include <SkToSRGBColorFilter.h> #include <SkImagePriv.h> namespace android { @@ -208,11 +209,8 @@ Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info) buffer->incStrong(buffer); setImmutable(); // HW bitmaps are always immutable if (uirenderer::Properties::isSkiaEnabled()) { - // GraphicBuffer should be in the display color space (Bitmap::createFrom is always - // passing SRGB). The code that uploads into a GraphicBuffer should do color conversion if - // needed. mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast<AHardwareBuffer*>(buffer), - mInfo.alphaType(), nullptr); + mInfo.alphaType(), mInfo.refColorSpace()); } } @@ -319,7 +317,7 @@ GraphicBuffer* Bitmap::graphicBuffer() { return nullptr; } -sk_sp<SkImage> Bitmap::makeImage() { +sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) { sk_sp<SkImage> image = mImage; if (!image) { SkASSERT(!(isHardware() && uirenderer::Properties::isSkiaEnabled())); @@ -330,12 +328,11 @@ sk_sp<SkImage> Bitmap::makeImage() { // Note we don't cache in this case, because the raster image holds a pointer to this Bitmap // internally and ~Bitmap won't be invoked. // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here. - if (uirenderer::Properties::isSkiaEnabled()) { - image = SkMakeImageInColorSpace(skiaBitmap, SkColorSpace::MakeSRGB(), - skiaBitmap.getGenerationID(), kNever_SkCopyPixelsMode); - } else { - image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode); - } + image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode); + } + if(uirenderer::Properties::isSkiaEnabled() && image->colorSpace() != nullptr + && !image->colorSpace()->isSRGB()) { + *outputColorFilter = SkToSRGBColorFilter::Make(image->refColorSpace()); } return image; } diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h index 634e76450c38..fc27af9fb4e7 100644 --- a/libs/hwui/hwui/Bitmap.h +++ b/libs/hwui/hwui/Bitmap.h @@ -16,6 +16,7 @@ #pragma once #include <SkBitmap.h> +#include <SkColorFilter.h> #include <SkColorSpace.h> #include <SkImage.h> #include <SkImageInfo.h> @@ -96,9 +97,18 @@ public: GraphicBuffer* graphicBuffer(); - // makeImage creates or returns a cached SkImage. Can be invoked from UI or render thread. - // Caching is supported only for HW Bitmaps with skia pipeline. - sk_sp<SkImage> makeImage(); + /** + * Creates or returns a cached SkImage and is safe to be invoked from either + * the UI or RenderThread. + * + * @param outputColorFilter is a required param that will be populated by + * this function if the bitmap's colorspace is not sRGB. If populated the + * filter will convert colors from the bitmaps colorspace into sRGB. It + * is the callers responsibility to use this colorFilter when drawing + * this image into any destination that is presumed to be sRGB (i.e. a + * buffer that has no colorspace defined). + */ + sk_sp<SkImage> makeImage(sk_sp<SkColorFilter>* outputColorFilter); private: virtual ~Bitmap(); void* getStorage() const; diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp index e754daf7c42e..a087035fd8e5 100644 --- a/libs/hwui/hwui/Canvas.cpp +++ b/libs/hwui/hwui/Canvas.cpp @@ -158,7 +158,7 @@ private: }; void Canvas::drawText(const uint16_t* text, int start, int count, int contextCount, - float x, float y, int bidiFlags, const Paint& origPaint, Typeface* typeface) { + float x, float y, int bidiFlags, const Paint& origPaint, const Typeface* typeface) { // minikin may modify the original paint Paint paint(origPaint); @@ -207,7 +207,7 @@ private: }; void Canvas::drawTextOnPath(const uint16_t* text, int count, int bidiFlags, const SkPath& path, - float hOffset, float vOffset, const Paint& paint, Typeface* typeface) { + float hOffset, float vOffset, const Paint& paint, const Typeface* typeface) { Paint paintCopy(paint); minikin::Layout layout = MinikinUtils::doLayout( &paintCopy, bidiFlags, typeface, text, 0, count, count); diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index ac8a08169997..0b8155cc4887 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -98,15 +98,6 @@ public: static WARN_UNUSED_RESULT Canvas* create_recording_canvas(int width, int height, uirenderer::RenderNode* renderNode = nullptr); - enum class XformToSRGB { - // Transform any Bitmaps to the sRGB color space before drawing. - kImmediate, - - // Draw the Bitmap as is. This likely means that we are recording and that the - // transform can be handled at playback time. - kDefer, - }; - /** * Create a new Canvas object which delegates to an SkCanvas. * @@ -114,12 +105,10 @@ public: * delegated to this object. This function will call ref() on the * SkCanvas, and the returned Canvas will unref() it upon * destruction. - * @param xformToSRGB Indicates if bitmaps should be xformed to the sRGB - * color space before drawing. * @return new non-null Canvas Object. The type of DisplayList produced by this canvas is * determined based on Properties::getRenderPipelineType(). */ - static Canvas* create_canvas(SkCanvas* skiaCanvas, XformToSRGB xformToSRGB); + static Canvas* create_canvas(SkCanvas* skiaCanvas); /** * Provides a Skia SkCanvas interface that acts as a proxy to this Canvas. @@ -266,10 +255,10 @@ public: * and delegating the final draw to virtual drawGlyphs method. */ void drawText(const uint16_t* text, int start, int count, int contextCount, - float x, float y, int bidiFlags, const Paint& origPaint, Typeface* typeface); + float x, float y, int bidiFlags, const Paint& origPaint, const Typeface* typeface); void drawTextOnPath(const uint16_t* text, int count, int bidiFlags, const SkPath& path, - float hOffset, float vOffset, const Paint& paint, Typeface* typeface); + float hOffset, float vOffset, const Paint& paint, const Typeface* typeface); protected: void drawTextDecorations(float x, float y, float length, const SkPaint& paint); diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp index 415eef77f44e..5e7f1cf2da1c 100644 --- a/libs/hwui/hwui/MinikinUtils.cpp +++ b/libs/hwui/hwui/MinikinUtils.cpp @@ -27,7 +27,7 @@ namespace android { minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* minikinPaint, - const Paint* paint, Typeface* typeface) { + const Paint* paint, const Typeface* typeface) { const Typeface* resolvedFace = Typeface::resolveDefault(typeface); minikin::FontStyle resolved = resolvedFace->fStyle; @@ -39,10 +39,8 @@ minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* mini resolved.getItalic()); /* Prepare minikin Paint */ - // Note: it would be nice to handle fractional size values (it would improve smooth zoom - // behavior), but historically size has been treated as an int. - // TODO: explore whether to enable fractional sizes, possibly when linear text flag is set. - minikinPaint->size = (int)paint->getTextSize(); + minikinPaint->size = paint->isLinearText() ? + paint->getTextSize() : static_cast<int>(paint->getTextSize()); minikinPaint->scaleX = paint->getTextScaleX(); minikinPaint->skewX = paint->getTextSkewX(); minikinPaint->letterSpacing = paint->getLetterSpacing(); @@ -54,7 +52,7 @@ minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* mini } minikin::Layout MinikinUtils::doLayout(const Paint* paint, int bidiFlags, - Typeface* typeface, const uint16_t* buf, size_t start, size_t count, + const Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize) { minikin::MinikinPaint minikinPaint; minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, paint, typeface); @@ -64,16 +62,16 @@ minikin::Layout MinikinUtils::doLayout(const Paint* paint, int bidiFlags, return layout; } -float MinikinUtils::measureText(const Paint* paint, int bidiFlags, Typeface* typeface, +float MinikinUtils::measureText(const Paint* paint, int bidiFlags, const Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize, float *advances) { minikin::MinikinPaint minikinPaint; minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, paint, typeface); - Typeface* resolvedTypeface = Typeface::resolveDefault(typeface); + const Typeface* resolvedTypeface = Typeface::resolveDefault(typeface); return minikin::Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint, resolvedTypeface->fFontCollection, advances); } -bool MinikinUtils::hasVariationSelector(Typeface* typeface, uint32_t codepoint, uint32_t vs) { +bool MinikinUtils::hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs) { const Typeface* resolvedFace = Typeface::resolveDefault(typeface); return resolvedFace->fFontCollection->hasVariationSelector(codepoint, vs); } diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h index 0f22adc5d42b..bfd816fd3b58 100644 --- a/libs/hwui/hwui/MinikinUtils.h +++ b/libs/hwui/hwui/MinikinUtils.h @@ -35,16 +35,17 @@ namespace android { class MinikinUtils { public: ANDROID_API static minikin::FontStyle prepareMinikinPaint(minikin::MinikinPaint* minikinPaint, - const Paint* paint, Typeface* typeface); + const Paint* paint, const Typeface* typeface); ANDROID_API static minikin::Layout doLayout(const Paint* paint, int bidiFlags, - Typeface* typeface, const uint16_t* buf, size_t start, size_t count, + const Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize); - ANDROID_API static float measureText(const Paint* paint, int bidiFlags, Typeface* typeface, - const uint16_t* buf, size_t start, size_t count, size_t bufSize, float *advances); + ANDROID_API static float measureText(const Paint* paint, int bidiFlags, + const Typeface* typeface, const uint16_t* buf, size_t start, size_t count, + size_t bufSize, float *advances); - ANDROID_API static bool hasVariationSelector(Typeface* typeface, uint32_t codepoint, + ANDROID_API static bool hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs); ANDROID_API static float xOffsetForTextAlign(Paint* paint, const minikin::Layout& layout); diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h index a5d83a0ca018..f3779fddb620 100644 --- a/libs/hwui/hwui/Paint.h +++ b/libs/hwui/hwui/Paint.h @@ -17,6 +17,8 @@ #ifndef ANDROID_GRAPHICS_PAINT_H_ #define ANDROID_GRAPHICS_PAINT_H_ +#include "Typeface.h" + #include <cutils/compiler.h> #include <SkPaint.h> @@ -101,6 +103,14 @@ public: return mHyphenEdit; } + void setAndroidTypeface(Typeface* typeface) { + mTypeface = typeface; + } + + const Typeface* getAndroidTypeface() const { + return mTypeface; + } + private: float mLetterSpacing = 0; float mWordSpacing = 0; @@ -108,6 +118,10 @@ private: uint32_t mMinikinLangListId; minikin::FontVariant mFontVariant; uint32_t mHyphenEdit = 0; + // The native Typeface object has the same lifetime of the Java Typeface object. The Java Paint + // object holds a strong reference to the Java Typeface object. Thus, following pointer can + // never be a dangling pointer. Note that nullptr is valid: it means the default typeface. + const Typeface* mTypeface = nullptr; }; } // namespace android diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp index 67427433bb89..a5c2087490aa 100644 --- a/libs/hwui/hwui/PaintImpl.cpp +++ b/libs/hwui/hwui/PaintImpl.cpp @@ -27,7 +27,8 @@ Paint::Paint(const Paint& paint) : SkPaint(paint), mLetterSpacing(paint.mLetterSpacing), mWordSpacing(paint.mWordSpacing), mFontFeatureSettings(paint.mFontFeatureSettings), mMinikinLangListId(paint.mMinikinLangListId), mFontVariant(paint.mFontVariant), - mHyphenEdit(paint.mHyphenEdit) { + mHyphenEdit(paint.mHyphenEdit), + mTypeface(paint.mTypeface) { } Paint::Paint(const SkPaint& paint) : SkPaint(paint), @@ -46,6 +47,7 @@ Paint& Paint::operator=(const Paint& other) { mMinikinLangListId = other.mMinikinLangListId; mFontVariant = other.mFontVariant; mHyphenEdit = other.mHyphenEdit; + mTypeface = other.mTypeface; return *this; } @@ -56,7 +58,8 @@ bool operator==(const Paint& a, const Paint& b) { && a.mFontFeatureSettings == b.mFontFeatureSettings && a.mMinikinLangListId == b.mMinikinLangListId && a.mFontVariant == b.mFontVariant - && a.mHyphenEdit == b.mHyphenEdit; + && a.mHyphenEdit == b.mHyphenEdit + && a.mTypeface == b.mTypeface; } } diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp index f66bb045373c..0a388745b14c 100644 --- a/libs/hwui/hwui/Typeface.cpp +++ b/libs/hwui/hwui/Typeface.cpp @@ -14,12 +14,6 @@ * limitations under the License. */ -/** - * This is the implementation of the Typeface object. Historically, it has - * just been SkTypeface, but we are migrating to Minikin. For the time - * being, that choice is hidden under the USE_MINIKIN compile-time flag. - */ - #include "Typeface.h" #include <pthread.h> @@ -65,15 +59,15 @@ static minikin::FontStyle computeRelativeStyle(int baseWeight, SkTypeface::Style return computeMinikinStyle(weight, italic); } -Typeface* gDefaultTypeface = NULL; +const Typeface* gDefaultTypeface = NULL; -Typeface* Typeface::resolveDefault(Typeface* src) { - LOG_ALWAYS_FATAL_IF(gDefaultTypeface == nullptr); +const Typeface* Typeface::resolveDefault(const Typeface* src) { + LOG_ALWAYS_FATAL_IF(src == nullptr && gDefaultTypeface == nullptr); return src == nullptr ? gDefaultTypeface : src; } Typeface* Typeface::createRelative(Typeface* src, SkTypeface::Style style) { - Typeface* resolvedFace = Typeface::resolveDefault(src); + const Typeface* resolvedFace = Typeface::resolveDefault(src); Typeface* result = new Typeface; if (result != nullptr) { result->fFontCollection = resolvedFace->fFontCollection; @@ -85,7 +79,7 @@ Typeface* Typeface::createRelative(Typeface* src, SkTypeface::Style style) { } Typeface* Typeface::createAbsolute(Typeface* base, int weight, bool italic) { - Typeface* resolvedFace = Typeface::resolveDefault(base); + const Typeface* resolvedFace = Typeface::resolveDefault(base); Typeface* result = new Typeface(); if (result != nullptr) { result->fFontCollection = resolvedFace->fFontCollection; @@ -98,7 +92,7 @@ Typeface* Typeface::createAbsolute(Typeface* base, int weight, bool italic) { Typeface* Typeface::createFromTypefaceWithVariation(Typeface* src, const std::vector<minikin::FontVariation>& variations) { - Typeface* resolvedFace = Typeface::resolveDefault(src); + const Typeface* resolvedFace = Typeface::resolveDefault(src); Typeface* result = new Typeface(); if (result != nullptr) { result->fFontCollection = @@ -118,7 +112,7 @@ Typeface* Typeface::createFromTypefaceWithVariation(Typeface* src, } Typeface* Typeface::createWithDifferentBaseWeight(Typeface* src, int weight) { - Typeface* resolvedFace = Typeface::resolveDefault(src); + const Typeface* resolvedFace = Typeface::resolveDefault(src); Typeface* result = new Typeface; if (result != nullptr) { result->fFontCollection = resolvedFace->fFontCollection; @@ -172,7 +166,7 @@ Typeface* Typeface::createFromFamilies( return result; } -void Typeface::setDefault(Typeface* face) { +void Typeface::setDefault(const Typeface* face) { gDefaultTypeface = face; } diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h index db0b2cdeba00..38c623480196 100644 --- a/libs/hwui/hwui/Typeface.h +++ b/libs/hwui/hwui/Typeface.h @@ -41,7 +41,7 @@ struct ANDROID_API Typeface { // style used for constructing and querying Typeface objects SkTypeface::Style fSkiaStyle; - static Typeface* resolveDefault(Typeface* src); + static const Typeface* resolveDefault(const Typeface* src); // The following three functions create new Typeface from an existing Typeface with a different // style. There is a base weight concept which is used for calculating relative style from an @@ -78,7 +78,7 @@ struct ANDROID_API Typeface { std::vector<std::shared_ptr<minikin::FontFamily>>&& families, int weight, int italic); - static void setDefault(Typeface* face); + static void setDefault(const Typeface* face); // Sets roboto font as the default typeface for testing purpose. static void setRobotoTypefaceForTest(); diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp index ea302a154616..fcd72afe4fb9 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp @@ -17,6 +17,7 @@ #include "GLFunctorDrawable.h" #include "GlFunctorLifecycleListener.h" #include "RenderNode.h" +#include "SkAndroidFrameworkUtils.h" #include "SkClipStack.h" #include <private/hwui/DrawGlInfo.h> #include <GrContext.h> @@ -49,8 +50,6 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { return; } - canvas->flush(); - if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { canvas->clear(SK_ColorRED); return; @@ -72,33 +71,33 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { info.height = canvasInfo.height(); mat4.asColMajorf(&info.transform[0]); + bool clearStencilAfterFunctor = false; + //apply a simple clip with a scissor or a complex clip with a stencil SkRegion clipRegion; canvas->temporary_internal_getRgnClip(&clipRegion); if (CC_UNLIKELY(clipRegion.isComplex())) { - //It is only a temporary solution to use a scissor to draw the stencil. - //There is a bug 31489986 to implement efficiently non-rectangular clips. glDisable(GL_SCISSOR_TEST); - glDisable(GL_STENCIL_TEST); - glStencilMask(0xff); + glStencilMask(0x1); glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); - glEnable(GL_SCISSOR_TEST); - SkRegion::Cliperator it(clipRegion, ibounds); - while (!it.done()) { - setScissor(info.height, it.rect()); - glClearStencil(0x1); - glClear(GL_STENCIL_BUFFER_BIT); - it.next(); + bool stencilWritten = SkAndroidFrameworkUtils::clipWithStencil(canvas); + canvas->flush(); + if (stencilWritten) { + glStencilMask(0x1); + glStencilFunc(GL_EQUAL, 0x1, 0x1); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + clearStencilAfterFunctor = true; + glEnable(GL_STENCIL_TEST); + } else { + glDisable(GL_STENCIL_TEST); } - glDisable(GL_SCISSOR_TEST); - glStencilFunc(GL_EQUAL, 0x1, 0xff); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glEnable(GL_STENCIL_TEST); } else if (clipRegion.isEmpty()) { + canvas->flush(); glDisable(GL_STENCIL_TEST); glDisable(GL_SCISSOR_TEST); } else { + canvas->flush(); glDisable(GL_STENCIL_TEST); glEnable(GL_SCISSOR_TEST); setScissor(info.height, clipRegion.getBounds()); @@ -106,6 +105,15 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { (*mFunctor)(DrawGlInfo::kModeDraw, &info); + if (clearStencilAfterFunctor) { + //clear stencil buffer as it may be used by Skia + glDisable(GL_SCISSOR_TEST); + glDisable(GL_STENCIL_TEST); + glStencilMask(0x1); + glClearStencil(0); + glClear(GL_STENCIL_BUFFER_BIT); + } + canvas->getGrContext()->resetContext(); } diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index 4feeb2d6facb..17438e5e1cdc 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -28,7 +28,10 @@ namespace uirenderer { namespace skiapipeline { void LayerDrawable::onDraw(SkCanvas* canvas) { - DrawLayer(canvas->getGrContext(), canvas, mLayer.get()); + Layer* layer = mLayerUpdater->backingLayer(); + if (layer) { + DrawLayer(canvas->getGrContext(), canvas, layer); + } } bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer) { diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h index 431989519a70..d34d8e07c133 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.h +++ b/libs/hwui/pipeline/skia/LayerDrawable.h @@ -16,7 +16,7 @@ #pragma once -#include "Layer.h" +#include "DeferredLayerUpdater.h" #include <SkCanvas.h> #include <SkDrawable.h> @@ -30,18 +30,18 @@ namespace skiapipeline { */ class LayerDrawable : public SkDrawable { public: - explicit LayerDrawable(Layer* layer) - : mLayer(layer) {} + explicit LayerDrawable(DeferredLayerUpdater* layerUpdater) + : mLayerUpdater(layerUpdater) {} static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer); protected: virtual SkRect onGetBounds() override { - return SkRect::MakeWH(mLayer->getWidth(), mLayer->getHeight()); + return SkRect::MakeWH(mLayerUpdater->getWidth(), mLayerUpdater->getHeight()); } virtual void onDraw(SkCanvas* canvas) override; private: - sp<Layer> mLayer; + sp<DeferredLayerUpdater> mLayerUpdater; }; }; // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index 925db303461f..abba70e4bdd5 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -73,9 +73,11 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, // setup surface for fbo0 GrGLFramebufferInfo fboInfo; fboInfo.fFBOID = 0; + GrPixelConfig pixelConfig = + wideColorGamut ? kRGBA_half_GrPixelConfig : kRGBA_8888_GrPixelConfig; GrBackendRenderTarget backendRT(frame.width(), frame.height(), 0, STENCIL_BUFFER_SIZE, - kRGBA_8888_GrPixelConfig, fboInfo); + pixelConfig, fboInfo); SkSurfaceProps props(0, kUnknown_SkPixelGeometry); @@ -132,9 +134,24 @@ bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBi deferredLayer->updateTexImage(); deferredLayer->apply(); - SkCanvas canvas(*bitmap); + /* This intermediate surface is present to work around a bug in SwiftShader that + * prevents us from reading the contents of the layer's texture directly. The + * workaround involves first rendering that texture into an intermediate buffer and + * then reading from the intermediate buffer into the bitmap. + */ + sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), + SkBudgeted::kYes, bitmap->info()); + Layer* layer = deferredLayer->backingLayer(); - return LayerDrawable::DrawLayer(mRenderThread.getGrContext(), &canvas, layer); + if (LayerDrawable::DrawLayer(mRenderThread.getGrContext(), tmpSurface->getCanvas(), layer)) { + sk_sp<SkImage> tmpImage = tmpSurface->makeImageSnapshot(); + if (tmpImage->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) { + bitmap->notifyPixelsChanged(); + return true; + } + } + + return false; } static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight, @@ -303,12 +320,6 @@ sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr return nullptr; } - auto colorSpace = info.colorSpace(); - bool convertToSRGB = false; - if (colorSpace && (!colorSpace->isSRGB())) { - isSupported = false; - convertToSRGB = true; - } SkBitmap bitmap; if (isSupported) { @@ -317,7 +328,7 @@ sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr bitmap.allocPixels(SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(), nullptr)); bitmap.eraseColor(0); - if (info.colorType() == kRGBA_F16_SkColorType || convertToSRGB) { + if (info.colorType() == kRGBA_F16_SkColorType) { // Drawing RGBA_F16 onto ARGB_8888 is not supported skBitmap.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()), bitmap.getPixels(), bitmap.rowBytes(), 0, 0); diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp index 311419dd2b65..df9409297ef7 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp @@ -16,6 +16,7 @@ #include "SkiaOpenGLReadback.h" +#include "DeviceInfo.h" #include "Matrix.h" #include "Properties.h" #include <SkCanvas.h> @@ -54,28 +55,60 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4 externalTexture.fTarget = GL_TEXTURE_EXTERNAL_OES; externalTexture.fID = sourceTexId; - GrBackendTexture backendTexture(imgWidth, imgHeight, kRGBA_8888_GrPixelConfig, externalTexture); + GrPixelConfig pixelConfig; + switch (bitmap->colorType()) { + case kRGBA_F16_SkColorType: + pixelConfig = kRGBA_half_GrPixelConfig; + break; + case kN32_SkColorType: + default: + pixelConfig = kRGBA_8888_GrPixelConfig; + break; + } + + /* Ideally, we would call grContext->caps()->isConfigRenderable(...). We + * currently can't do that since some devices (i.e. SwiftShader) supports all + * the appropriate half float extensions, but only allow the buffer to be read + * back as full floats. We can relax this extension if Skia implements support + * for reading back float buffers (skbug.com/6945). + */ + if (pixelConfig == kRGBA_half_GrPixelConfig && + !DeviceInfo::get()->extensions().hasFloatTextures()) { + ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported"); + return CopyResult::DestinationInvalid; + } + + GrBackendTexture backendTexture(imgWidth, imgHeight, pixelConfig, externalTexture); CopyResult copyResult = CopyResult::UnknownError; sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), backendTexture, kTopLeft_GrSurfaceOrigin)); if (image) { + // Convert imgTransform matrix from right to left handed coordinate system. + // If we have a matrix transformation in right handed coordinate system + //|ScaleX, SkewX, TransX| same transform in left handed is |ScaleX, SkewX, TransX | + //|SkewY, ScaleY, TransY| |-SkewY, -ScaleY, 1-TransY| + //|0, 0, 1 | |0, 0, 1 | SkMatrix textureMatrix; - imgTransform.copyTo(textureMatrix); - - // remove the y-flip applied to the matrix - SkMatrix yFlip = SkMatrix::MakeScale(1, -1); - yFlip.postTranslate(0,1); - textureMatrix.preConcat(yFlip); - - // multiply by image size, because textureMatrix maps to [0..1] range - textureMatrix[SkMatrix::kMTransX] *= imgWidth; - textureMatrix[SkMatrix::kMTransY] *= imgHeight; - - // swap rotation and translation part of the matrix, because we convert from - // right-handed Cartesian to left-handed coordinate system. - std::swap(textureMatrix[SkMatrix::kMTransX], textureMatrix[SkMatrix::kMTransY]); - std::swap(textureMatrix[SkMatrix::kMSkewX], textureMatrix[SkMatrix::kMSkewY]); + textureMatrix.setIdentity(); + textureMatrix[SkMatrix::kMScaleX] = imgTransform[Matrix4::kScaleX]; + textureMatrix[SkMatrix::kMScaleY] = -imgTransform[Matrix4::kScaleY]; + textureMatrix[SkMatrix::kMSkewX] = imgTransform[Matrix4::kSkewX]; + textureMatrix[SkMatrix::kMSkewY] = -imgTransform[Matrix4::kSkewY]; + textureMatrix[SkMatrix::kMTransX] = imgTransform[Matrix4::kTranslateX]; + textureMatrix[SkMatrix::kMTransY] = 1-imgTransform[Matrix4::kTranslateY]; + + // textureMatrix maps 2D texture coordinates of the form (s, t, 1) with s and t in the + // inclusive range [0, 1] to the texture (see GLConsumer::getTransformMatrix comments). + // Convert textureMatrix to translate in real texture dimensions. Texture width and + // height are affected by the orientation (width and height swapped for 90/270 rotation). + if (textureMatrix[SkMatrix::kMSkewX] >= 0.5f || textureMatrix[SkMatrix::kMSkewX] <= -0.5f) { + textureMatrix[SkMatrix::kMTransX] *= imgHeight; + textureMatrix[SkMatrix::kMTransY] *= imgWidth; + } else { + textureMatrix[SkMatrix::kMTransX] *= imgWidth; + textureMatrix[SkMatrix::kMTransY] *= imgHeight; + } // convert to Skia data structures SkRect skiaSrcRect = srcRect.toSkRect(); diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 03792e0ed291..a8463ecc44d8 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -134,7 +134,13 @@ bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator, bool wideColorGamut) { SkSurface* layer = node->getLayerSurface(); if (!layer || layer->width() != node->getWidth() || layer->height() != node->getHeight()) { - SkImageInfo info = SkImageInfo::MakeN32Premul(node->getWidth(), node->getHeight()); + SkImageInfo info; + if (wideColorGamut) { + info = SkImageInfo::Make(node->getWidth(), node->getHeight(), kRGBA_F16_SkColorType, + kPremul_SkAlphaType); + } else { + info = SkImageInfo::MakeN32Premul(node->getWidth(), node->getHeight()); + } SkSurfaceProps props(0, kUnknown_SkPixelGeometry); SkASSERT(mRenderThread.getGrContext() != nullptr); // TODO: Handle wide color gamut requests @@ -161,7 +167,8 @@ void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { GrContext* context = thread.getGrContext(); if (context) { ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height()); - auto image = bitmap->makeImage(); + sk_sp<SkColorFilter> colorFilter; + auto image = bitmap->makeImage(&colorFilter); if (image.get() && !bitmap->isHardware()) { SkImage_pinAsTexture(image.get(), context); SkImage_unpinAsTexture(image.get(), context); diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index a0cce98c8d57..4c1d67351161 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -91,10 +91,9 @@ void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) { } void SkiaRecordingCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layerUpdater) { - if (layerUpdater != nullptr && layerUpdater->backingLayer() != nullptr) { - uirenderer::Layer* layer = layerUpdater->backingLayer(); + if (layerUpdater != nullptr) { // Create a ref-counted drawable, which is kept alive by sk_sp in SkLiteDL. - sk_sp<SkDrawable> drawable(new LayerDrawable(layer)); + sk_sp<SkDrawable> drawable(new LayerDrawable(layerUpdater)); drawDrawable(drawable.get()); } } @@ -145,10 +144,23 @@ void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) { // Recording Canvas draw operations: Bitmaps // ---------------------------------------------------------------------------- -inline static const SkPaint* nonAAPaint(const SkPaint* origPaint, SkPaint* tmpPaint) { - if (origPaint && origPaint->isAntiAlias()) { - *tmpPaint = *origPaint; +inline static const SkPaint* bitmapPaint(const SkPaint* origPaint, SkPaint* tmpPaint, + sk_sp<SkColorFilter> colorFilter) { + if ((origPaint && origPaint->isAntiAlias()) || colorFilter) { + if (origPaint) { + *tmpPaint = *origPaint; + } + + sk_sp<SkColorFilter> filter; + if (colorFilter && tmpPaint->getColorFilter()) { + filter = SkColorFilter::MakeComposeFilter(tmpPaint->refColorFilter(), colorFilter); + LOG_ALWAYS_FATAL_IF(!filter); + } else { + filter = colorFilter; + } + tmpPaint->setAntiAlias(false); + tmpPaint->setColorFilter(filter); return tmpPaint; } else { return origPaint; @@ -156,9 +168,10 @@ inline static const SkPaint* nonAAPaint(const SkPaint* origPaint, SkPaint* tmpPa } void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { - sk_sp<SkImage> image = bitmap.makeImage(); SkPaint tmpPaint; - mRecorder.drawImage(image, left, top, nonAAPaint(paint, &tmpPaint)); + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mRecorder.drawImage(image, left, top, bitmapPaint(paint, &tmpPaint, colorFilter)); // if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means // it is not safe to store a raw SkImage pointer, because the image object will be destroyed // when this function ends. @@ -167,36 +180,40 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, cons } } -void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix, +void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { SkAutoCanvasRestore acr(&mRecorder, true); concat(matrix); - sk_sp<SkImage> image = hwuiBitmap.makeImage(); + SkPaint tmpPaint; - mRecorder.drawImage(image, 0, 0, nonAAPaint(paint, &tmpPaint)); - if (!hwuiBitmap.isImmutable() && image.get() && !image->unique()) { + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mRecorder.drawImage(image, 0, 0, bitmapPaint(paint, &tmpPaint, colorFilter)); + if (!bitmap.isImmutable() && image.get() && !image->unique()) { mDisplayList->mMutableImages.push_back(image.get()); } } -void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop, +void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) { SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - sk_sp<SkImage> image = hwuiBitmap.makeImage(); + SkPaint tmpPaint; - mRecorder.drawImageRect(image, srcRect, dstRect, nonAAPaint(paint, &tmpPaint)); - if (!hwuiBitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mRecorder.drawImageRect(image, srcRect, dstRect, bitmapPaint(paint, &tmpPaint, colorFilter)); + if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() && !dstRect.isEmpty()) { mDisplayList->mMutableImages.push_back(image.get()); } } -void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk, +void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) { SkCanvas::Lattice lattice; - NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height()); + NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height()); lattice.fFlags = nullptr; int numFlags = 0; @@ -213,11 +230,13 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch lattice.fBounds = nullptr; SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - sk_sp<SkImage> image = hwuiBitmap.makeImage(); SkPaint tmpPaint; - mRecorder.drawImageLattice(image.get(), lattice, dst, nonAAPaint(paint, &tmpPaint)); - if (!hwuiBitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) { + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mRecorder.drawImageLattice(image.get(), lattice, dst, + bitmapPaint(paint, &tmpPaint, colorFilter)); + if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) { mDisplayList->mMutableImages.push_back(image.get()); } } diff --git a/libs/hwui/renderstate/OffscreenBufferPool.cpp b/libs/hwui/renderstate/OffscreenBufferPool.cpp index 2dfa6d4dc839..ea292d678c67 100644 --- a/libs/hwui/renderstate/OffscreenBufferPool.cpp +++ b/libs/hwui/renderstate/OffscreenBufferPool.cpp @@ -17,7 +17,6 @@ #include "OffscreenBufferPool.h" #include "Caches.h" -#include "Properties.h" #include "renderstate/RenderState.h" #include "utils/FatVector.h" #include "utils/TraceUtils.h" @@ -118,7 +117,8 @@ OffscreenBuffer::~OffscreenBuffer() { /////////////////////////////////////////////////////////////////////////////// OffscreenBufferPool::OffscreenBufferPool() - : mMaxSize(Properties::layerPoolSize) { + // 4 screen-sized RGBA_8888 textures + : mMaxSize(DeviceInfo::multiplyByResolution(4 * 4)) { } OffscreenBufferPool::~OffscreenBufferPool() { diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index 2c92924cc12c..ededffb0f4bb 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -53,6 +53,11 @@ void RenderState::onGLContextCreated() { mScissor = new Scissor(); mStencil = new Stencil(); + // Deferred because creation needs GL context for texture limits + if (!mLayerPool) { + mLayerPool = new OffscreenBufferPool(); + } + // This is delayed because the first access of Caches makes GL calls if (!mCaches) { mCaches = &Caches::createInstance(*this); @@ -67,7 +72,7 @@ static void layerLostGlContext(Layer* layer) { } void RenderState::onGLContextDestroyed() { - mLayerPool.clear(); + mLayerPool->clear(); // TODO: reset all cached state in state objects std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext); @@ -100,7 +105,7 @@ static void layerDestroyedVkContext(Layer* layer) { } void RenderState::onVkContextDestroyed() { - mLayerPool.clear(); + mLayerPool->clear(); std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerDestroyedVkContext); GpuMemoryTracker::onGpuContextDestroyed(); } @@ -116,10 +121,10 @@ void RenderState::flush(Caches::FlushMode mode) { case Caches::FlushMode::Moderate: // fall through case Caches::FlushMode::Layers: - mLayerPool.clear(); + if (mLayerPool) mLayerPool->clear(); break; } - mCaches->flush(mode); + if (mCaches) mCaches->flush(mode); } void RenderState::onBitmapDestroyed(uint32_t pixelRefId) { diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h index 4b7a86580621..df81e864a0b5 100644 --- a/libs/hwui/renderstate/RenderState.h +++ b/libs/hwui/renderstate/RenderState.h @@ -113,7 +113,7 @@ public: Scissor& scissor() { return *mScissor; } Stencil& stencil() { return *mStencil; } - OffscreenBufferPool& layerPool() { return mLayerPool; } + OffscreenBufferPool& layerPool() { return *mLayerPool; } GrContext* getGrContext() const; @@ -136,7 +136,7 @@ private: Scissor* mScissor = nullptr; Stencil* mStencil = nullptr; - OffscreenBufferPool mLayerPool; + OffscreenBufferPool* mLayerPool = nullptr; std::set<Layer*> mActiveLayers; std::set<DeferredLayerUpdater*> mActiveLayerUpdaters; diff --git a/libs/hwui/renderstate/Stencil.cpp b/libs/hwui/renderstate/Stencil.cpp index d25ad514e892..f59442196af1 100644 --- a/libs/hwui/renderstate/Stencil.cpp +++ b/libs/hwui/renderstate/Stencil.cpp @@ -47,7 +47,7 @@ uint8_t Stencil::getStencilSize() { */ GLenum Stencil::getLayerStencilFormat() { #if !DEBUG_STENCIL - const Extensions& extensions = Caches::getInstance().extensions(); + const Extensions& extensions = DeviceInfo::get()->extensions(); if (extensions.has4BitStencil()) { return GL_STENCIL_INDEX4_OES; } diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index 55694d046c2f..f6b23e1a0723 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -44,7 +44,7 @@ namespace renderthread { CacheManager::CacheManager(const DisplayInfo& display) : mMaxSurfaceArea(display.w * display.h) { mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2, - skiapipeline::VectorDrawableAtlas::StorageMode::allowSharedSurface); + skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface); } void CacheManager::reset(GrContext* context) { @@ -62,7 +62,8 @@ void CacheManager::reset(GrContext* context) { void CacheManager::destroy() { // cleanup any caches here as the GrContext is about to go away... mGrContext.reset(nullptr); - mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2); + mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2, + skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface); } void CacheManager::updateContextCacheSizes() { diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp index 4797dec8e89e..0f2dc034d125 100644 --- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp +++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp @@ -46,7 +46,8 @@ public: }); SkPaint paint; - sk_sp<SkImage> image = hwuiBitmap->makeImage(); + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = hwuiBitmap->makeImage(&colorFilter); sk_sp<SkShader> repeatShader = image->makeShader( SkShader::TileMode::kRepeat_TileMode, SkShader::TileMode::kRepeat_TileMode, diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp index c246ebaddcad..960b05340063 100644 --- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp +++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp @@ -75,7 +75,8 @@ public: void doFrame(int frameNr) override { } sk_sp<SkShader> createBitmapShader(Bitmap& bitmap) { - sk_sp<SkImage> image = bitmap.makeImage(); + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); return image->makeShader(SkShader::TileMode::kClamp_TileMode, SkShader::TileMode::kClamp_TileMode); } diff --git a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp index 919852f6b2d7..308fef303740 100644 --- a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp +++ b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp @@ -74,8 +74,8 @@ RENDERTHREAD_TEST(OffscreenBufferPool, construct) { OffscreenBufferPool pool; EXPECT_EQ(0u, pool.getCount()) << "pool must be created empty"; EXPECT_EQ(0u, pool.getSize()) << "pool must be created empty"; - EXPECT_EQ((uint32_t) Properties::layerPoolSize, pool.getMaxSize()) - << "pool must read size from Properties"; + // TODO: Does this really make sense as a test? + EXPECT_EQ(DeviceInfo::multiplyByResolution(4 * 4), pool.getMaxSize()); } RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, getPutClear) { diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp index c048dda4a2e9..d84b83d3f2dc 100644 --- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp +++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp @@ -45,8 +45,7 @@ OPENGL_PIPELINE_TEST(SkiaCanvasProxy, drawGlyphsViaPicture) { // record the same text draw into a SkPicture and replay it into a Recording canvas SkPictureRecorder recorder; SkCanvas* skCanvas = recorder.beginRecording(200, 200, NULL, 0); - std::unique_ptr<Canvas> pictCanvas(Canvas::create_canvas(skCanvas, - Canvas::XformToSRGB::kDefer)); + std::unique_ptr<Canvas> pictCanvas(Canvas::create_canvas(skCanvas)); TestUtils::drawUtf8ToCanvas(pictCanvas.get(), text, paint, 25, 25); sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture(); @@ -65,7 +64,7 @@ OPENGL_PIPELINE_TEST(SkiaCanvasProxy, drawGlyphsViaPicture) { TEST(SkiaCanvas, drawShadowLayer) { auto surface = SkSurface::MakeRasterN32Premul(10, 10); - SkiaCanvas canvas(surface->getCanvas(), Canvas::XformToSRGB::kDefer); + SkiaCanvas canvas(surface->getCanvas()); // clear to white canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrc); @@ -108,27 +107,14 @@ TEST(SkiaCanvas, colorSpaceXform) { // The result should be less than fully red, since we convert to Adobe RGB at draw time. ASSERT_EQ(0xFF0000DC, *adobeSkBitmap.getAddr32(0, 0)); - // Now try in kDefer mode. This is a little strange given that, in practice, all software - // canvases are kImmediate. - SkCanvas skCanvas(skBitmap); - SkiaCanvas deferCanvas(&skCanvas, Canvas::XformToSRGB::kDefer); - deferCanvas.drawBitmap(*adobeBitmap, 0, 0, nullptr); - // The result should be as before, since we deferred the conversion to sRGB. - ASSERT_EQ(0xFF0000DC, *skBitmap.getAddr32(0, 0)); - - // Test picture recording. We will kDefer the xform at recording time, but handle it when - // we playback to the software canvas. + // Test picture recording. SkPictureRecorder recorder; SkCanvas* skPicCanvas = recorder.beginRecording(1, 1, NULL, 0); - SkiaCanvas picCanvas(skPicCanvas, Canvas::XformToSRGB::kDefer); + SkiaCanvas picCanvas(skPicCanvas); picCanvas.drawBitmap(*adobeBitmap, 0, 0, nullptr); sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture(); - // Playback to a deferred canvas. The result should be as before. - deferCanvas.asSkCanvas()->drawPicture(picture); - ASSERT_EQ(0xFF0000DC, *skBitmap.getAddr32(0, 0)); - - // Playback to an immediate canvas. The result should be fully red. + // Playback to an software canvas. The result should be fully red. canvas.asSkCanvas()->drawPicture(picture); ASSERT_EQ(0xFF0000FF, *skBitmap.getAddr32(0, 0)); } @@ -155,7 +141,7 @@ TEST(SkiaCanvas, captureCanvasState) { // Create a picture canvas. SkPictureRecorder recorder; SkCanvas* skPicCanvas = recorder.beginRecording(1, 1, NULL, 0); - SkiaCanvas picCanvas(skPicCanvas, Canvas::XformToSRGB::kDefer); + SkiaCanvas picCanvas(skPicCanvas); state = picCanvas.captureCanvasState(); // Verify that we cannot get the CanvasState. diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp index c90b6f0e9cdd..345cfd647b11 100644 --- a/libs/hwui/tests/unit/TypefaceTests.cpp +++ b/libs/hwui/tests/unit/TypefaceTests.cpp @@ -70,7 +70,8 @@ TEST(TypefaceTest, resolveDefault_and_setDefaultTest) { RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); EXPECT_EQ(regular.get(), Typeface::resolveDefault(regular.get())); - Typeface* old = Typeface::resolveDefault(nullptr); // Keep the original to restore it later. + // Keep the original to restore it later. + const Typeface* old = Typeface::resolveDefault(nullptr); ASSERT_NE(nullptr, old); Typeface::setDefault(regular.get()); |