diff options
Diffstat (limited to 'libs')
110 files changed, 1795 insertions, 1191 deletions
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp index 02c85aa34f4b..3893041b05d9 100644 --- a/libs/androidfw/Android.bp +++ b/libs/androidfw/Android.bp @@ -155,6 +155,7 @@ cc_test { android: { srcs: [ "tests/BackupData_test.cpp", + "tests/BackupHelpers_test.cpp", "tests/ObbFile_test.cpp", "tests/PosixUtils_test.cpp", ], diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp index 8bfe2b6a259a..e80e9486c8b2 100644 --- a/libs/androidfw/BackupHelpers.cpp +++ b/libs/androidfw/BackupHelpers.cpp @@ -479,7 +479,7 @@ void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t siz } int write_tarfile(const String8& packageName, const String8& domain, - const String8& rootpath, const String8& filepath, off_t* outSize, + const String8& rootpath, const String8& filepath, off64_t* outSize, BackupDataWriter* writer) { // In the output stream everything is stored relative to the root diff --git a/libs/androidfw/include/androidfw/BackupHelpers.h b/libs/androidfw/include/androidfw/BackupHelpers.h index 2da247b77c0a..a0fa13662cb9 100644 --- a/libs/androidfw/include/androidfw/BackupHelpers.h +++ b/libs/androidfw/include/androidfw/BackupHelpers.h @@ -137,7 +137,7 @@ int back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapsh char const* const* files, char const* const *keys, int fileCount); int write_tarfile(const String8& packageName, const String8& domain, - const String8& rootPath, const String8& filePath, off_t* outSize, + const String8& rootPath, const String8& filePath, off64_t* outSize, BackupDataWriter* outputStream); class RestoreHelperBase diff --git a/libs/androidfw/tests/BackupHelpers_test.cpp b/libs/androidfw/tests/BackupHelpers_test.cpp new file mode 100644 index 000000000000..86b7fb361228 --- /dev/null +++ b/libs/androidfw/tests/BackupHelpers_test.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * 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. + */ + +#define LOG_TAG "BackupHelpers_test" +#include <androidfw/BackupHelpers.h> + +#include <gtest/gtest.h> + +#include <fcntl.h> +#include <utils/String8.h> +#include <android-base/file.h> + +namespace android { + +class BackupHelpersTest : public testing::Test { +protected: + + virtual void SetUp() { + } + virtual void TearDown() { + } +}; + +TEST_F(BackupHelpersTest, WriteTarFileWithSizeLessThan2GB) { + TemporaryFile tf; + // Allocate a 1 KB file. + off64_t fileSize = 1024; + ASSERT_EQ(0, posix_fallocate64(tf.fd, 0, fileSize)); + off64_t tarSize = 0; + int err = write_tarfile(/* packageName */ String8("test-pkg"), /* domain */ String8(""), /* rootpath */ String8(""), /* filePath */ String8(tf.path), /* outSize */ &tarSize, /* writer */ NULL); + ASSERT_EQ(err, 0); + // Returned tarSize includes 512 B for the header. + off64_t expectedTarSize = fileSize + 512; + ASSERT_EQ(tarSize, expectedTarSize); +} + +TEST_F(BackupHelpersTest, WriteTarFileWithSizeGreaterThan2GB) { + TemporaryFile tf; + // Allocate a 2 GB file. + off64_t fileSize = 2ll * 1024ll * 1024ll * 1024ll + 512ll; + ASSERT_EQ(0, posix_fallocate64(tf.fd, 0, fileSize)); + off64_t tarSize = 0; + int err = write_tarfile(/* packageName */ String8("test-pkg"), /* domain */ String8(""), /* rootpath */ String8(""), /* filePath */ String8(tf.path), /* outSize */ &tarSize, /* writer */ NULL); + ASSERT_EQ(err, 0); + // Returned tarSize includes 512 B for the header. + off64_t expectedTarSize = fileSize + 512; + ASSERT_EQ(tarSize, expectedTarSize); +} +} + diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index aa842ff6a7b7..9ae5ad97ed36 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -53,8 +53,6 @@ cc_defaults { host: { include_dirs: [ "external/vulkan-headers/include", - "frameworks/native/libs/math/include", - "frameworks/native/libs/ui/include", ], cflags: [ "-Wno-unused-variable", @@ -71,6 +69,10 @@ cc_defaults { "libminikin", ], + static_libs: [ + "libui-types", + ], + target: { android: { shared_libs: [ @@ -83,7 +85,6 @@ cc_defaults { "libGLESv2", "libGLESv3", "libvulkan", - "libui", "libnativedisplay", "libnativewindow", "libprotobuf-cpp-lite", @@ -152,6 +153,45 @@ cc_defaults { } // ------------------------ +// framework-graphics jar +// ------------------------ + +java_sdk_library { + name: "framework-graphics", + defaults: ["framework-module-defaults"], + visibility: [ + "//frameworks/base", // Framework + ], + + srcs: [ + ":framework-graphics-srcs", + ], + + permitted_packages: [ + "android.graphics", + ], + + // TODO: once framework-graphics is officially part of the + // UI-rendering module this line would no longer be + // needed. + installable: true, + + // Disable api_lint that the defaults enable + // TODO: enable this + api_lint: { + enabled: false, + }, +} + +filegroup { + name: "framework-graphics-srcs", + srcs: [ + "apex/java/**/*.java", + ], + path: "apex/java" +} + +// ------------------------ // APEX // ------------------------ @@ -346,6 +386,7 @@ cc_defaults { "libstatspull", "libstatssocket", "libpdfium", + "libbinder_ndk", ], static_libs: [ "libgif", @@ -457,6 +498,7 @@ cc_defaults { "service/GraphicsStatsService.cpp", "thread/CommonPool.cpp", "utils/GLUtils.cpp", + "utils/NdkUtils.cpp", "utils/StringUtils.cpp", "AutoBackendTextureRelease.cpp", "DeferredLayerUpdater.cpp", @@ -499,6 +541,11 @@ cc_library { "android_graphics_jni", ], export_header_lib_headers: ["android_graphics_apex_headers"], + target: { + android: { + version_script: "libhwui.map.txt", + } + }, } cc_library_static { @@ -516,6 +563,7 @@ cc_defaults { android: { shared_libs: [ "libgui", + "libui", ], } }, diff --git a/libs/hwui/AnimationContext.h b/libs/hwui/AnimationContext.h index 74d5e79c0b77..f8a2072ffbdb 100644 --- a/libs/hwui/AnimationContext.h +++ b/libs/hwui/AnimationContext.h @@ -77,8 +77,8 @@ class AnimationContext { PREVENT_COPY_AND_ASSIGN(AnimationContext); public: - ANDROID_API explicit AnimationContext(renderthread::TimeLord& clock); - ANDROID_API virtual ~AnimationContext(); + explicit AnimationContext(renderthread::TimeLord& clock); + virtual ~AnimationContext(); nsecs_t frameTimeMs() { return mFrameTimeMs; } bool hasAnimations() { @@ -87,22 +87,22 @@ public: // Will always add to the next frame list, which is swapped when // startFrame() is called - ANDROID_API void addAnimatingRenderNode(RenderNode& node); + void addAnimatingRenderNode(RenderNode& node); // Marks the start of a frame, which will update the frame time and move all // next frame animations into the current frame - ANDROID_API virtual void startFrame(TreeInfo::TraversalMode mode); + virtual void startFrame(TreeInfo::TraversalMode mode); // Runs any animations still left in mCurrentFrameAnimations that were not run // as part of the standard RenderNode:prepareTree pass. - ANDROID_API virtual void runRemainingAnimations(TreeInfo& info); + virtual void runRemainingAnimations(TreeInfo& info); - ANDROID_API virtual void callOnFinished(BaseRenderNodeAnimator* animator, + virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener); - ANDROID_API virtual void destroy(); + virtual void destroy(); - ANDROID_API virtual void pauseAnimators() {} + virtual void pauseAnimators() {} private: friend class AnimationHandle; diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h index ed7b6eb1cf4a..3c9f1ea1b6e3 100644 --- a/libs/hwui/Animator.h +++ b/libs/hwui/Animator.h @@ -39,10 +39,10 @@ class RenderProperties; class AnimationListener : public VirtualLightRefBase { public: - ANDROID_API virtual void onAnimationFinished(BaseRenderNodeAnimator*) = 0; + virtual void onAnimationFinished(BaseRenderNodeAnimator*) = 0; protected: - ANDROID_API virtual ~AnimationListener() {} + virtual ~AnimationListener() {} }; enum class RepeatMode { @@ -55,34 +55,34 @@ class BaseRenderNodeAnimator : public VirtualLightRefBase { PREVENT_COPY_AND_ASSIGN(BaseRenderNodeAnimator); public: - ANDROID_API void setStartValue(float value); - ANDROID_API void setInterpolator(Interpolator* interpolator); - ANDROID_API void setDuration(nsecs_t durationInMs); - ANDROID_API nsecs_t duration() { return mDuration; } - ANDROID_API void setStartDelay(nsecs_t startDelayInMs); - ANDROID_API nsecs_t startDelay() { return mStartDelay; } - ANDROID_API void setListener(AnimationListener* listener) { mListener = listener; } + void setStartValue(float value); + void setInterpolator(Interpolator* interpolator); + void setDuration(nsecs_t durationInMs); + nsecs_t duration() { return mDuration; } + void setStartDelay(nsecs_t startDelayInMs); + nsecs_t startDelay() { return mStartDelay; } + void setListener(AnimationListener* listener) { mListener = listener; } AnimationListener* listener() { return mListener.get(); } - ANDROID_API void setAllowRunningAsync(bool mayRunAsync) { mMayRunAsync = mayRunAsync; } + void setAllowRunningAsync(bool mayRunAsync) { mMayRunAsync = mayRunAsync; } bool mayRunAsync() { return mMayRunAsync; } - ANDROID_API void start(); - ANDROID_API virtual void reset(); - ANDROID_API void reverse(); + void start(); + virtual void reset(); + void reverse(); // Terminates the animation at its current progress. - ANDROID_API void cancel(); + void cancel(); // Terminates the animation and skip to the end of the animation. - ANDROID_API virtual void end(); + virtual void end(); void attach(RenderNode* target); virtual void onAttached() {} void detach() { mTarget = nullptr; } - ANDROID_API void pushStaging(AnimationContext& context); - ANDROID_API bool animate(AnimationContext& context); + void pushStaging(AnimationContext& context); + bool animate(AnimationContext& context); // Returns the remaining time in ms for the animation. Note this should only be called during // an animation on RenderThread. - ANDROID_API nsecs_t getRemainingPlayTime(); + nsecs_t getRemainingPlayTime(); bool isRunning() { return mPlayState == PlayState::Running || mPlayState == PlayState::Reversing; @@ -90,7 +90,7 @@ public: bool isFinished() { return mPlayState == PlayState::Finished; } float finalValue() { return mFinalValue; } - ANDROID_API virtual uint32_t dirtyMask() = 0; + virtual uint32_t dirtyMask() = 0; void forceEndNow(AnimationContext& context); RenderNode* target() { return mTarget; } @@ -196,9 +196,9 @@ public: ALPHA, }; - ANDROID_API RenderPropertyAnimator(RenderProperty property, float finalValue); + RenderPropertyAnimator(RenderProperty property, float finalValue); - ANDROID_API virtual uint32_t dirtyMask(); + virtual uint32_t dirtyMask(); protected: virtual float getValue(RenderNode* target) const override; @@ -221,10 +221,10 @@ private: class CanvasPropertyPrimitiveAnimator : public BaseRenderNodeAnimator { public: - ANDROID_API CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property, + CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property, float finalValue); - ANDROID_API virtual uint32_t dirtyMask(); + virtual uint32_t dirtyMask(); protected: virtual float getValue(RenderNode* target) const override; @@ -241,10 +241,10 @@ public: ALPHA, }; - ANDROID_API CanvasPropertyPaintAnimator(CanvasPropertyPaint* property, PaintField field, + CanvasPropertyPaintAnimator(CanvasPropertyPaint* property, PaintField field, float finalValue); - ANDROID_API virtual uint32_t dirtyMask(); + virtual uint32_t dirtyMask(); protected: virtual float getValue(RenderNode* target) const override; @@ -257,9 +257,9 @@ private: class RevealAnimator : public BaseRenderNodeAnimator { public: - ANDROID_API RevealAnimator(int centerX, int centerY, float startValue, float finalValue); + RevealAnimator(int centerX, int centerY, float startValue, float finalValue); - ANDROID_API virtual uint32_t dirtyMask(); + virtual uint32_t dirtyMask(); protected: virtual float getValue(RenderNode* target) const override; diff --git a/libs/hwui/AnimatorManager.h b/libs/hwui/AnimatorManager.h index 9575391a8b3f..a0df01d5962c 100644 --- a/libs/hwui/AnimatorManager.h +++ b/libs/hwui/AnimatorManager.h @@ -54,7 +54,7 @@ public: void animateNoDamage(TreeInfo& info); // Hard-ends all animators. May only be called on the UI thread. - ANDROID_API void endAllStagingAnimators(); + void endAllStagingAnimators(); // Hard-ends all animators that have been pushed. Used for cleanup if // the ActivityContext is being destroyed diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp index 8c37d73366c2..9d03ce5252a3 100644 --- a/libs/hwui/CanvasTransform.cpp +++ b/libs/hwui/CanvasTransform.cpp @@ -22,7 +22,6 @@ #include <SkGradientShader.h> #include <SkPaint.h> #include <SkShader.h> -#include <ui/ColorSpace.h> #include <algorithm> #include <cmath> diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h index 030a20f31c42..2faa9d012d66 100644 --- a/libs/hwui/DamageAccumulator.h +++ b/libs/hwui/DamageAccumulator.h @@ -58,7 +58,7 @@ public: // Returns the current dirty area, *NOT* transformed by pushed transforms void peekAtDirty(SkRect* dest) const; - ANDROID_API void computeCurrentTransform(Matrix4* outMatrix) const; + void computeCurrentTransform(Matrix4* outMatrix) const; void finish(SkRect* totalDirty); diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index c44c0d537fa7..05f3774d6951 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -44,11 +44,11 @@ class DeferredLayerUpdater : public VirtualLightRefBase, public IGpuContextCallb public: // Note that DeferredLayerUpdater assumes it is taking ownership of the layer // and will not call incrementRef on it as a result. - ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState); + explicit DeferredLayerUpdater(RenderState& renderState); - ANDROID_API ~DeferredLayerUpdater(); + ~DeferredLayerUpdater(); - ANDROID_API bool setSize(int width, int height) { + bool setSize(int width, int height) { if (mWidth != width || mHeight != height) { mWidth = width; mHeight = height; @@ -60,7 +60,7 @@ public: int getWidth() { return mWidth; } int getHeight() { return mHeight; } - ANDROID_API bool setBlend(bool blend) { + bool setBlend(bool blend) { if (blend != mBlend) { mBlend = blend; return true; @@ -68,18 +68,18 @@ public: return false; } - ANDROID_API void setSurfaceTexture(AutoTextureRelease&& consumer); + void setSurfaceTexture(AutoTextureRelease&& consumer); - ANDROID_API void updateTexImage() { mUpdateTexImage = true; } + void updateTexImage() { mUpdateTexImage = true; } - ANDROID_API void setTransform(const SkMatrix* matrix) { + void setTransform(const SkMatrix* matrix) { delete mTransform; mTransform = matrix ? new SkMatrix(*matrix) : nullptr; } SkMatrix* getTransform() { return mTransform; } - ANDROID_API void setPaint(const SkPaint* paint); + void setPaint(const SkPaint* paint); void apply(); diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp index c24224cbbd67..07594715a84c 100644 --- a/libs/hwui/DeviceInfo.cpp +++ b/libs/hwui/DeviceInfo.cpp @@ -15,6 +15,8 @@ */ #include <DeviceInfo.h> +#include <android/hardware_buffer.h> +#include <apex/display.h> #include <log/log.h> #include <utils/Errors.h> @@ -30,14 +32,47 @@ DeviceInfo* DeviceInfo::get() { DeviceInfo::DeviceInfo() { #if HWUI_NULL_GPU - mMaxTextureSize = NULL_GPU_MAX_TEXTURE_SIZE; + mMaxTextureSize = NULL_GPU_MAX_TEXTURE_SIZE; #else - mMaxTextureSize = -1; + mMaxTextureSize = -1; #endif - updateDisplayInfo(); } -DeviceInfo::~DeviceInfo() { - ADisplay_release(mDisplays); + +void DeviceInfo::updateDisplayInfo() { + if (Properties::isolatedProcess) { + return; + } + + ADisplay** displays; + int size = ADisplay_acquirePhysicalDisplays(&displays); + + if (size <= 0) { + LOG_ALWAYS_FATAL("Failed to acquire physical displays for WCG support!"); + } + + for (int i = 0; i < size; ++i) { + // Pick the first internal display for querying the display type + // In practice this is controlled by a sysprop so it doesn't really + // matter which display we use. + if (ADisplay_getDisplayType(displays[i]) == DISPLAY_TYPE_INTERNAL) { + // We get the dataspace from DisplayManager already. Allocate space + // for the result here but we don't actually care about using it. + ADataSpace dataspace; + AHardwareBuffer_Format pixelFormat; + ADisplay_getPreferredWideColorFormat(displays[i], &dataspace, &pixelFormat); + + if (pixelFormat == AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM) { + mWideColorType = SkColorType::kN32_SkColorType; + } else if (pixelFormat == AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT) { + mWideColorType = SkColorType::kRGBA_F16_SkColorType; + } else { + LOG_ALWAYS_FATAL("Unreachable: unsupported pixel format: %d", pixelFormat); + } + ADisplay_release(displays); + return; + } + } + LOG_ALWAYS_FATAL("Failed to find a valid physical display for WCG support!"); } int DeviceInfo::maxTextureSize() const { @@ -49,75 +84,29 @@ void DeviceInfo::setMaxTextureSize(int maxTextureSize) { DeviceInfo::get()->mMaxTextureSize = maxTextureSize; } +void DeviceInfo::setWideColorDataspace(ADataSpace dataspace) { + switch (dataspace) { + case ADATASPACE_DISPLAY_P3: + get()->mWideColorSpace = + SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDisplayP3); + break; + case ADATASPACE_SCRGB: + get()->mWideColorSpace = SkColorSpace::MakeSRGB(); + break; + case ADATASPACE_SRGB: + // when sRGB is returned, it means wide color gamut is not supported. + get()->mWideColorSpace = SkColorSpace::MakeSRGB(); + break; + default: + LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space."); + } +} + void DeviceInfo::onRefreshRateChanged(int64_t vsyncPeriod) { mVsyncPeriod = vsyncPeriod; } -void DeviceInfo::updateDisplayInfo() { - if (Properties::isolatedProcess) { - return; - } - - if (mCurrentConfig == nullptr) { - mDisplaysSize = ADisplay_acquirePhysicalDisplays(&mDisplays); - LOG_ALWAYS_FATAL_IF(mDisplays == nullptr || mDisplaysSize <= 0, - "Failed to get physical displays: no connected display: %d!", mDisplaysSize); - for (size_t i = 0; i < mDisplaysSize; i++) { - ADisplayType type = ADisplay_getDisplayType(mDisplays[i]); - if (type == ADisplayType::DISPLAY_TYPE_INTERNAL) { - mPhysicalDisplayIndex = i; - break; - } - } - LOG_ALWAYS_FATAL_IF(mPhysicalDisplayIndex < 0, "Failed to find a connected physical display!"); - - - // Since we now just got the primary display for the first time, then - // store the primary display metadata here. - ADisplay* primaryDisplay = mDisplays[mPhysicalDisplayIndex]; - mMaxRefreshRate = ADisplay_getMaxSupportedFps(primaryDisplay); - ADataSpace dataspace; - AHardwareBuffer_Format format; - ADisplay_getPreferredWideColorFormat(primaryDisplay, &dataspace, &format); - switch (dataspace) { - case ADATASPACE_DISPLAY_P3: - mWideColorSpace = - SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3); - break; - case ADATASPACE_SCRGB: - mWideColorSpace = SkColorSpace::MakeSRGB(); - break; - case ADATASPACE_SRGB: - // when sRGB is returned, it means wide color gamut is not supported. - mWideColorSpace = SkColorSpace::MakeSRGB(); - break; - default: - LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space."); - } - switch (format) { - case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: - mWideColorType = SkColorType::kN32_SkColorType; - break; - case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: - mWideColorType = SkColorType::kRGBA_F16_SkColorType; - break; - default: - LOG_ALWAYS_FATAL("Unreachable: unsupported pixel format."); - } - } - // This method may have been called when the display config changed, so - // sync with the current configuration. - ADisplay* primaryDisplay = mDisplays[mPhysicalDisplayIndex]; - status_t status = ADisplay_getCurrentConfig(primaryDisplay, &mCurrentConfig); - LOG_ALWAYS_FATAL_IF(status, "Failed to get display config, error %d", status); - - mWidth = ADisplayConfig_getWidth(mCurrentConfig); - mHeight = ADisplayConfig_getHeight(mCurrentConfig); - mDensity = ADisplayConfig_getDensity(mCurrentConfig); - mVsyncPeriod = static_cast<int64_t>(1000000000 / ADisplayConfig_getFps(mCurrentConfig)); - mCompositorOffset = ADisplayConfig_getCompositorOffsetNanos(mCurrentConfig); - mAppOffset = ADisplayConfig_getAppVsyncOffsetNanos(mCurrentConfig); -} +std::atomic<float> DeviceInfo::sDensity = 2.0; } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h index 16a22f4706f5..27be62269959 100644 --- a/libs/hwui/DeviceInfo.h +++ b/libs/hwui/DeviceInfo.h @@ -16,8 +16,10 @@ #ifndef DEVICEINFO_H #define DEVICEINFO_H -#include <apex/display.h> #include <SkImageInfo.h> +#include <android/data_space.h> + +#include <mutex> #include "utils/Macros.h" @@ -36,16 +38,37 @@ public: static float getMaxRefreshRate() { return get()->mMaxRefreshRate; } static int32_t getWidth() { return get()->mWidth; } static int32_t getHeight() { return get()->mHeight; } - static float getDensity() { return get()->mDensity; } + // Gets the density in density-independent pixels + static float getDensity() { return sDensity.load(); } static int64_t getVsyncPeriod() { return get()->mVsyncPeriod; } - static int64_t getCompositorOffset() { return get()->mCompositorOffset; } - static int64_t getAppOffset() { return get()->mAppOffset; } + static int64_t getCompositorOffset() { return get()->getCompositorOffsetInternal(); } + static int64_t getAppOffset() { return get()->mAppVsyncOffsetNanos; } + // Sets the density in density-independent pixels + static void setDensity(float density) { sDensity.store(density); } + static void setMaxRefreshRate(float refreshRate) { get()->mMaxRefreshRate = refreshRate; } + static void setWidth(int32_t width) { get()->mWidth = width; } + static void setHeight(int32_t height) { get()->mHeight = height; } + static void setRefreshRate(float refreshRate) { + get()->mVsyncPeriod = static_cast<int64_t>(1000000000 / refreshRate); + } + static void setPresentationDeadlineNanos(int64_t deadlineNanos) { + get()->mPresentationDeadlineNanos = deadlineNanos; + } + static void setAppVsyncOffsetNanos(int64_t offsetNanos) { + get()->mAppVsyncOffsetNanos = offsetNanos; + } + static void setWideColorDataspace(ADataSpace dataspace); // this value is only valid after the GPU has been initialized and there is a valid graphics // context or if you are using the HWUI_NULL_GPU int maxTextureSize() const; sk_sp<SkColorSpace> getWideColorSpace() const { return mWideColorSpace; } - SkColorType getWideColorType() const { return mWideColorType; } + SkColorType getWideColorType() { + static std::once_flag kFlag; + // lazily update display info from SF here, so that the call is performed by RenderThread. + std::call_once(kFlag, [&, this]() { updateDisplayInfo(); }); + return mWideColorType; + } // This method should be called whenever the display refresh rate changes. void onRefreshRateChanged(int64_t vsyncPeriod); @@ -54,24 +77,32 @@ private: friend class renderthread::RenderThread; static void setMaxTextureSize(int maxTextureSize); void updateDisplayInfo(); + int64_t getCompositorOffsetInternal() const { + // Assume that SF takes around a millisecond to latch buffers after + // waking up + return mVsyncPeriod - (mPresentationDeadlineNanos - 1000000); + } DeviceInfo(); - ~DeviceInfo(); + ~DeviceInfo() = default; int mMaxTextureSize; sk_sp<SkColorSpace> mWideColorSpace = SkColorSpace::MakeSRGB(); SkColorType mWideColorType = SkColorType::kN32_SkColorType; - ADisplayConfig* mCurrentConfig = nullptr; - ADisplay** mDisplays = nullptr; int mDisplaysSize = 0; int mPhysicalDisplayIndex = -1; float mMaxRefreshRate = 60.0; int32_t mWidth = 1080; int32_t mHeight = 1920; - float mDensity = 2.0; int64_t mVsyncPeriod = 16666666; - int64_t mCompositorOffset = 0; - int64_t mAppOffset = 0; + // Magically corresponds with an sf offset of 0 for a sane default. + int64_t mPresentationDeadlineNanos = 17666666; + int64_t mAppVsyncOffsetNanos = 0; + + // Density is not retrieved from the ADisplay apis, so this may potentially + // be called on multiple threads. + // Unit is density-independent pixels + static std::atomic<float> sDensity; }; } /* namespace uirenderer */ diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h index 51674fbd557e..dc30617009e7 100644 --- a/libs/hwui/FrameInfo.h +++ b/libs/hwui/FrameInfo.h @@ -69,7 +69,7 @@ enum { }; }; -class ANDROID_API UiFrameInfoBuilder { +class UiFrameInfoBuilder { public: explicit UiFrameInfoBuilder(int64_t* buffer) : mBuffer(buffer) { memset(mBuffer, 0, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t)); diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp index a3d552faeb0a..c2d2ff874816 100644 --- a/libs/hwui/HardwareBitmapUploader.cpp +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -16,12 +16,7 @@ #include "HardwareBitmapUploader.h" -#include "hwui/Bitmap.h" -#include "renderthread/EglManager.h" -#include "renderthread/VulkanManager.h" -#include "thread/ThreadBase.h" -#include "utils/TimeUtils.h" - +#include <EGL/egl.h> #include <EGL/eglext.h> #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> @@ -30,10 +25,18 @@ #include <SkCanvas.h> #include <SkImage.h> #include <utils/GLUtils.h> +#include <utils/NdkUtils.h> #include <utils/Trace.h> #include <utils/TraceUtils.h> + #include <thread> +#include "hwui/Bitmap.h" +#include "renderthread/EglManager.h" +#include "renderthread/VulkanManager.h" +#include "thread/ThreadBase.h" +#include "utils/TimeUtils.h" + namespace android::uirenderer { class AHBUploader; @@ -42,7 +45,7 @@ class AHBUploader; static sp<AHBUploader> sUploader = nullptr; struct FormatInfo { - PixelFormat pixelFormat; + AHardwareBuffer_Format bufferFormat; GLint format, type; VkFormat vkFormat; bool isSupported = false; @@ -71,10 +74,10 @@ public: } bool uploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format, - sp<GraphicBuffer> graphicBuffer) { + AHardwareBuffer* ahb) { ATRACE_CALL(); beginUpload(); - bool result = onUploadHardwareBitmap(bitmap, format, graphicBuffer); + bool result = onUploadHardwareBitmap(bitmap, format, ahb); endUpload(); return result; } @@ -93,7 +96,7 @@ private: virtual void onDestroy() = 0; virtual bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format, - sp<GraphicBuffer> graphicBuffer) = 0; + AHardwareBuffer* ahb) = 0; virtual void onBeginUpload() = 0; bool shouldTimeOutLocked() { @@ -165,16 +168,16 @@ private: } bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format, - sp<GraphicBuffer> graphicBuffer) override { + AHardwareBuffer* ahb) override { ATRACE_CALL(); EGLDisplay display = getUploadEglDisplay(); LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s", uirenderer::renderthread::EglManager::eglErrorString()); - // We use an EGLImage to access the content of the GraphicBuffer + // We use an EGLImage to access the content of the buffer // The EGL image is later bound to a 2D texture - EGLClientBuffer clientBuffer = (EGLClientBuffer)graphicBuffer->getNativeBuffer(); + const EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(ahb); AutoEglImage autoImage(display, clientBuffer); if (autoImage.image == EGL_NO_IMAGE_KHR) { ALOGW("Could not create EGL image, err =%s", @@ -272,13 +275,13 @@ private: } bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format, - sp<GraphicBuffer> graphicBuffer) override { + AHardwareBuffer* ahb) override { ATRACE_CALL(); std::lock_guard _lock{mLock}; - sk_sp<SkImage> image = SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(), - bitmap.pixmap(), reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get())); + sk_sp<SkImage> image = + SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(), ahb); return (image.get() != nullptr); } @@ -294,13 +297,17 @@ bool HardwareBitmapUploader::hasFP16Support() { // Gralloc shouldn't let us create a USAGE_HW_TEXTURE if GLES is unable to consume it, so // we don't need to double-check the GLES version/extension. std::call_once(sOnce, []() { - sp<GraphicBuffer> buffer = new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_FP16, - GraphicBuffer::USAGE_HW_TEXTURE | - GraphicBuffer::USAGE_SW_WRITE_NEVER | - GraphicBuffer::USAGE_SW_READ_NEVER, - "tempFp16Buffer"); - status_t error = buffer->initCheck(); - hasFP16Support = !error; + AHardwareBuffer_Desc desc = { + .width = 1, + .height = 1, + .layers = 1, + .format = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT, + .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | + AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER | + AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE, + }; + UniqueAHardwareBuffer buffer = allocateAHardwareBuffer(desc); + hasFP16Support = buffer != nullptr; }); return hasFP16Support; @@ -314,7 +321,7 @@ static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) { [[fallthrough]]; // ARGB_4444 is upconverted to RGBA_8888 case kARGB_4444_SkColorType: - formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; + formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; formatInfo.format = GL_RGBA; formatInfo.type = GL_UNSIGNED_BYTE; formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM; @@ -323,25 +330,25 @@ static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) { formatInfo.isSupported = HardwareBitmapUploader::hasFP16Support(); if (formatInfo.isSupported) { formatInfo.type = GL_HALF_FLOAT; - formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16; + formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT; formatInfo.vkFormat = VK_FORMAT_R16G16B16A16_SFLOAT; } else { formatInfo.type = GL_UNSIGNED_BYTE; - formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; + formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM; } formatInfo.format = GL_RGBA; break; case kRGB_565_SkColorType: formatInfo.isSupported = true; - formatInfo.pixelFormat = PIXEL_FORMAT_RGB_565; + formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM; formatInfo.format = GL_RGB; formatInfo.type = GL_UNSIGNED_SHORT_5_6_5; formatInfo.vkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16; break; case kGray_8_SkColorType: formatInfo.isSupported = usingGL; - formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; + formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; formatInfo.format = GL_LUMINANCE; formatInfo.type = GL_UNSIGNED_BYTE; formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM; @@ -394,28 +401,27 @@ sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sou } SkBitmap bitmap = makeHwCompatible(format, sourceBitmap); - sp<GraphicBuffer> buffer = new GraphicBuffer( - static_cast<uint32_t>(bitmap.width()), static_cast<uint32_t>(bitmap.height()), - format.pixelFormat, - GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER | - GraphicBuffer::USAGE_SW_READ_NEVER, - std::string("Bitmap::allocateHardwareBitmap pid [") + std::to_string(getpid()) + - "]"); - - status_t error = buffer->initCheck(); - if (error < 0) { - ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()"); + AHardwareBuffer_Desc desc = { + .width = static_cast<uint32_t>(bitmap.width()), + .height = static_cast<uint32_t>(bitmap.height()), + .layers = 1, + .format = format.bufferFormat, + .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER | + AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE, + }; + UniqueAHardwareBuffer ahb = allocateAHardwareBuffer(desc); + if (!ahb) { + ALOGW("allocateHardwareBitmap() failed in AHardwareBuffer_allocate()"); return nullptr; - } + }; createUploader(usingGL); - if (!sUploader->uploadHardwareBitmap(bitmap, format, buffer)) { + if (!sUploader->uploadHardwareBitmap(bitmap, format, ahb.get())) { return nullptr; } - return Bitmap::createFrom(buffer->toAHardwareBuffer(), bitmap.colorType(), - bitmap.refColorSpace(), bitmap.alphaType(), - Bitmap::computePalette(bitmap)); + return Bitmap::createFrom(ahb.get(), bitmap.colorType(), bitmap.refColorSpace(), + bitmap.alphaType(), Bitmap::computePalette(bitmap)); } void HardwareBitmapUploader::initialize() { diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h index 72243d23dd35..ad7a95a4fa03 100644 --- a/libs/hwui/HardwareBitmapUploader.h +++ b/libs/hwui/HardwareBitmapUploader.h @@ -20,7 +20,7 @@ namespace android::uirenderer { -class ANDROID_API HardwareBitmapUploader { +class HardwareBitmapUploader { public: static void initialize(); static void terminate(); diff --git a/libs/hwui/Interpolator.h b/libs/hwui/Interpolator.h index 452988fc8711..131cc3935f10 100644 --- a/libs/hwui/Interpolator.h +++ b/libs/hwui/Interpolator.h @@ -37,12 +37,12 @@ protected: Interpolator() {} }; -class ANDROID_API AccelerateDecelerateInterpolator : public Interpolator { +class AccelerateDecelerateInterpolator : public Interpolator { public: virtual float interpolate(float input) override; }; -class ANDROID_API AccelerateInterpolator : public Interpolator { +class AccelerateInterpolator : public Interpolator { public: explicit AccelerateInterpolator(float factor) : mFactor(factor), mDoubleFactor(factor * 2) {} virtual float interpolate(float input) override; @@ -52,7 +52,7 @@ private: const float mDoubleFactor; }; -class ANDROID_API AnticipateInterpolator : public Interpolator { +class AnticipateInterpolator : public Interpolator { public: explicit AnticipateInterpolator(float tension) : mTension(tension) {} virtual float interpolate(float input) override; @@ -61,7 +61,7 @@ private: const float mTension; }; -class ANDROID_API AnticipateOvershootInterpolator : public Interpolator { +class AnticipateOvershootInterpolator : public Interpolator { public: explicit AnticipateOvershootInterpolator(float tension) : mTension(tension) {} virtual float interpolate(float input) override; @@ -70,12 +70,12 @@ private: const float mTension; }; -class ANDROID_API BounceInterpolator : public Interpolator { +class BounceInterpolator : public Interpolator { public: virtual float interpolate(float input) override; }; -class ANDROID_API CycleInterpolator : public Interpolator { +class CycleInterpolator : public Interpolator { public: explicit CycleInterpolator(float cycles) : mCycles(cycles) {} virtual float interpolate(float input) override; @@ -84,7 +84,7 @@ private: const float mCycles; }; -class ANDROID_API DecelerateInterpolator : public Interpolator { +class DecelerateInterpolator : public Interpolator { public: explicit DecelerateInterpolator(float factor) : mFactor(factor) {} virtual float interpolate(float input) override; @@ -93,12 +93,12 @@ private: const float mFactor; }; -class ANDROID_API LinearInterpolator : public Interpolator { +class LinearInterpolator : public Interpolator { public: virtual float interpolate(float input) override { return input; } }; -class ANDROID_API OvershootInterpolator : public Interpolator { +class OvershootInterpolator : public Interpolator { public: explicit OvershootInterpolator(float tension) : mTension(tension) {} virtual float interpolate(float input) override; @@ -107,7 +107,7 @@ private: const float mTension; }; -class ANDROID_API PathInterpolator : public Interpolator { +class PathInterpolator : public Interpolator { public: explicit PathInterpolator(std::vector<float>&& x, std::vector<float>&& y) : mX(x), mY(y) {} virtual float interpolate(float input) override; @@ -117,7 +117,7 @@ private: std::vector<float> mY; }; -class ANDROID_API LUTInterpolator : public Interpolator { +class LUTInterpolator : public Interpolator { public: LUTInterpolator(float* values, size_t size); ~LUTInterpolator(); diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index 0c515a41689d..4c6e1a0a6eee 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -44,7 +44,7 @@ namespace uirenderer { // Classes /////////////////////////////////////////////////////////////////////////////// -class ANDROID_API Matrix4 { +class Matrix4 { public: float data[16]; diff --git a/libs/hwui/PathParser.h b/libs/hwui/PathParser.h index 878bb7c0f137..859697eb3e9b 100644 --- a/libs/hwui/PathParser.h +++ b/libs/hwui/PathParser.h @@ -30,17 +30,17 @@ namespace uirenderer { class PathParser { public: - struct ANDROID_API ParseResult { + struct ParseResult { bool failureOccurred = false; std::string failureMessage; }; /** * Parse the string literal and create a Skia Path. Return true on success. */ - ANDROID_API static void parseAsciiStringForSkPath(SkPath* outPath, ParseResult* result, - const char* pathStr, size_t strLength); - ANDROID_API static void getPathDataFromAsciiString(PathData* outData, ParseResult* result, - const char* pathStr, size_t strLength); + static void parseAsciiStringForSkPath(SkPath* outPath, ParseResult* result, + const char* pathStr, size_t strLength); + static void getPathDataFromAsciiString(PathData* outData, ParseResult* result, + const char* pathStr, size_t strLength); static void dump(const PathData& data); static void validateVerbAndPoints(char verb, size_t points, ParseResult* result); }; diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index d3ecb54d94f6..c8f6b3b7ff99 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -213,10 +213,10 @@ public: static int overrideSpotShadowStrength; static ProfileType getProfileType(); - ANDROID_API static RenderPipelineType peekRenderPipelineType(); - ANDROID_API static RenderPipelineType getRenderPipelineType(); + static RenderPipelineType peekRenderPipelineType(); + static RenderPipelineType getRenderPipelineType(); - ANDROID_API static bool enableHighContrastText; + static bool enableHighContrastText; // Should be used only by test apps static bool waitForGpuCompletion; @@ -235,17 +235,17 @@ public: static bool skpCaptureEnabled; // For experimentation b/68769804 - ANDROID_API static bool enableRTAnimations; + static bool enableRTAnimations; // Used for testing only to change the render pipeline. static void overrideRenderPipelineType(RenderPipelineType); static bool runningInEmulator; - ANDROID_API static bool debuggingEnabled; - ANDROID_API static bool isolatedProcess; + static bool debuggingEnabled; + static bool isolatedProcess; - ANDROID_API static int contextPriority; + static int contextPriority; static int defaultRenderAhead; diff --git a/libs/hwui/PropertyValuesAnimatorSet.h b/libs/hwui/PropertyValuesAnimatorSet.h index e4214b22d1cc..c04a0b9b0fe7 100644 --- a/libs/hwui/PropertyValuesAnimatorSet.h +++ b/libs/hwui/PropertyValuesAnimatorSet.h @@ -44,7 +44,7 @@ private: }; // TODO: This class should really be named VectorDrawableAnimator -class ANDROID_API PropertyValuesAnimatorSet : public BaseRenderNodeAnimator { +class PropertyValuesAnimatorSet : public BaseRenderNodeAnimator { public: friend class PropertyAnimatorSetListener; PropertyValuesAnimatorSet(); diff --git a/libs/hwui/PropertyValuesHolder.h b/libs/hwui/PropertyValuesHolder.h index 0a799d3c0b5c..bb26cbe7bc9b 100644 --- a/libs/hwui/PropertyValuesHolder.h +++ b/libs/hwui/PropertyValuesHolder.h @@ -28,7 +28,7 @@ namespace uirenderer { * When a fraction in [0f, 1f] is provided, the holder will calculate an interpolated value based * on its start and end value, and set the new value on the VectorDrawble's corresponding property. */ -class ANDROID_API PropertyValuesHolder { +class PropertyValuesHolder { public: virtual void setFraction(float fraction) = 0; virtual ~PropertyValuesHolder() {} @@ -49,19 +49,19 @@ public: } }; -class ANDROID_API ColorEvaluator : public Evaluator<SkColor> { +class ColorEvaluator : public Evaluator<SkColor> { public: virtual void evaluate(SkColor* outColor, const SkColor& from, const SkColor& to, float fraction) const override; }; -class ANDROID_API PathEvaluator : public Evaluator<PathData> { +class PathEvaluator : public Evaluator<PathData> { virtual void evaluate(PathData* out, const PathData& from, const PathData& to, float fraction) const override; }; template <typename T> -class ANDROID_API PropertyValuesHolderImpl : public PropertyValuesHolder { +class PropertyValuesHolderImpl : public PropertyValuesHolder { public: PropertyValuesHolderImpl(const T& startValue, const T& endValue) : mStartValue(startValue), mEndValue(endValue) {} @@ -85,7 +85,7 @@ protected: T mEndValue; }; -class ANDROID_API GroupPropertyValuesHolder : public PropertyValuesHolderImpl<float> { +class GroupPropertyValuesHolder : public PropertyValuesHolderImpl<float> { public: GroupPropertyValuesHolder(VectorDrawable::Group* ptr, int propertyId, float startValue, float endValue) @@ -99,7 +99,7 @@ private: int mPropertyId; }; -class ANDROID_API FullPathColorPropertyValuesHolder : public PropertyValuesHolderImpl<SkColor> { +class FullPathColorPropertyValuesHolder : public PropertyValuesHolderImpl<SkColor> { public: FullPathColorPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId, SkColor startValue, SkColor endValue) @@ -116,7 +116,7 @@ private: int mPropertyId; }; -class ANDROID_API FullPathPropertyValuesHolder : public PropertyValuesHolderImpl<float> { +class FullPathPropertyValuesHolder : public PropertyValuesHolderImpl<float> { public: FullPathPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId, float startValue, float endValue) @@ -132,7 +132,7 @@ private: int mPropertyId; }; -class ANDROID_API PathDataPropertyValuesHolder : public PropertyValuesHolderImpl<PathData> { +class PathDataPropertyValuesHolder : public PropertyValuesHolderImpl<PathData> { public: PathDataPropertyValuesHolder(VectorDrawable::Path* ptr, PathData* startValue, PathData* endValue) @@ -146,7 +146,7 @@ private: PathData mPathData; }; -class ANDROID_API RootAlphaPropertyValuesHolder : public PropertyValuesHolderImpl<float> { +class RootAlphaPropertyValuesHolder : public PropertyValuesHolderImpl<float> { public: RootAlphaPropertyValuesHolder(VectorDrawable::Tree* tree, float startValue, float endValue) : PropertyValuesHolderImpl(startValue, endValue), mTree(tree) { diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp index 39900e65cb8a..0dea354b7200 100644 --- a/libs/hwui/Readback.cpp +++ b/libs/hwui/Readback.cpp @@ -18,7 +18,6 @@ #include <sync/sync.h> #include <system/window.h> -#include <ui/GraphicBuffer.h> #include "DeferredLayerUpdater.h" #include "Properties.h" @@ -28,6 +27,7 @@ #include "renderthread/VulkanManager.h" #include "utils/Color.h" #include "utils/MathUtils.h" +#include "utils/NdkUtils.h" #include "utils/TraceUtils.h" using namespace android::uirenderer::renderthread; @@ -54,8 +54,7 @@ CopyResult Readback::copySurfaceInto(ANativeWindow* window, const Rect& srcRect, return CopyResult::SourceEmpty; } - std::unique_ptr<AHardwareBuffer, decltype(&AHardwareBuffer_release)> sourceBuffer( - rawSourceBuffer, AHardwareBuffer_release); + UniqueAHardwareBuffer sourceBuffer{rawSourceBuffer}; AHardwareBuffer_Desc description; AHardwareBuffer_describe(sourceBuffer.get(), &description); if (description.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) { diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index dc467c41baed..892d43a763a9 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -96,7 +96,7 @@ struct Restore final : Op { struct SaveLayer final : Op { static const auto kType = Type::SaveLayer; SaveLayer(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, - const SkImage* clipMask, const SkMatrix* clipMatrix, SkCanvas::SaveLayerFlags flags) { + SkCanvas::SaveLayerFlags flags) { if (bounds) { this->bounds = *bounds; } @@ -104,19 +104,14 @@ struct SaveLayer final : Op { this->paint = *paint; } this->backdrop = sk_ref_sp(backdrop); - this->clipMask = sk_ref_sp(clipMask); - this->clipMatrix = clipMatrix ? *clipMatrix : SkMatrix::I(); this->flags = flags; } SkRect bounds = kUnset; SkPaint paint; sk_sp<const SkImageFilter> backdrop; - sk_sp<const SkImage> clipMask; - SkMatrix clipMatrix; SkCanvas::SaveLayerFlags flags; void draw(SkCanvas* c, const SkMatrix&) const { - c->saveLayer({maybe_unset(bounds), &paint, backdrop.get(), clipMask.get(), - clipMatrix.isIdentity() ? nullptr : &clipMatrix, flags}); + c->saveLayer({maybe_unset(bounds), &paint, backdrop.get(), flags}); } }; struct SaveBehind final : Op { @@ -132,9 +127,9 @@ struct SaveBehind final : Op { struct Concat44 final : Op { static const auto kType = Type::Concat44; - Concat44(const SkScalar m[16]) { memcpy(colMajor, m, sizeof(colMajor)); } - SkScalar colMajor[16]; - void draw(SkCanvas* c, const SkMatrix&) const { c->experimental_concat44(colMajor); } + Concat44(const SkM44& m) : matrix(m) {} + SkM44 matrix; + void draw(SkCanvas* c, const SkMatrix&) const { c->concat(matrix); } }; struct Concat final : Op { static const auto kType = Type::Concat; @@ -448,14 +443,13 @@ struct DrawPoints final : Op { }; struct DrawVertices final : Op { static const auto kType = Type::DrawVertices; - DrawVertices(const SkVertices* v, int bc, SkBlendMode m, const SkPaint& p) - : vertices(sk_ref_sp(const_cast<SkVertices*>(v))), boneCount(bc), mode(m), paint(p) {} + DrawVertices(const SkVertices* v, SkBlendMode m, const SkPaint& p) + : vertices(sk_ref_sp(const_cast<SkVertices*>(v))), mode(m), paint(p) {} sk_sp<SkVertices> vertices; - int boneCount; SkBlendMode mode; SkPaint paint; void draw(SkCanvas* c, const SkMatrix&) const { - c->drawVertices(vertices, pod<SkVertices::Bone>(this), boneCount, mode, paint); + c->drawVertices(vertices, mode, paint); } }; struct DrawAtlas final : Op { @@ -565,17 +559,16 @@ void DisplayListData::restore() { this->push<Restore>(0); } void DisplayListData::saveLayer(const SkRect* bounds, const SkPaint* paint, - const SkImageFilter* backdrop, const SkImage* clipMask, - const SkMatrix* clipMatrix, SkCanvas::SaveLayerFlags flags) { - this->push<SaveLayer>(0, bounds, paint, backdrop, clipMask, clipMatrix, flags); + const SkImageFilter* backdrop, SkCanvas::SaveLayerFlags flags) { + this->push<SaveLayer>(0, bounds, paint, backdrop, flags); } void DisplayListData::saveBehind(const SkRect* subset) { this->push<SaveBehind>(0, subset); } -void DisplayListData::concat44(const SkScalar colMajor[16]) { - this->push<Concat44>(0, colMajor); +void DisplayListData::concat(const SkM44& m) { + this->push<Concat44>(0, m); } void DisplayListData::concat(const SkMatrix& matrix) { this->push<Concat>(0, matrix); @@ -686,11 +679,8 @@ void DisplayListData::drawPoints(SkCanvas::PointMode mode, size_t count, const S void* pod = this->push<DrawPoints>(count * sizeof(SkPoint), mode, count, paint); copy_v(pod, points, count); } -void DisplayListData::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[], - int boneCount, SkBlendMode mode, const SkPaint& paint) { - void* pod = this->push<DrawVertices>(boneCount * sizeof(SkVertices::Bone), vertices, boneCount, - mode, paint); - copy_v(pod, bones, boneCount); +void DisplayListData::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) { + this->push<DrawVertices>(0, vertices, mode, paint); } void DisplayListData::drawAtlas(const SkImage* atlas, const SkRSXform xforms[], const SkRect texs[], const SkColor colors[], int count, SkBlendMode xfermode, @@ -823,8 +813,7 @@ void RecordingCanvas::willSave() { fDL->save(); } SkCanvas::SaveLayerStrategy RecordingCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) { - fDL->saveLayer(rec.fBounds, rec.fPaint, rec.fBackdrop, rec.fClipMask, rec.fClipMatrix, - rec.fSaveLayerFlags); + fDL->saveLayer(rec.fBounds, rec.fPaint, rec.fBackdrop, rec.fSaveLayerFlags); return SkCanvas::kNoLayer_SaveLayerStrategy; } void RecordingCanvas::willRestore() { @@ -841,8 +830,8 @@ bool RecordingCanvas::onDoSaveBehind(const SkRect* subset) { return false; } -void RecordingCanvas::didConcat44(const SkScalar colMajor[16]) { - fDL->concat44(colMajor); +void RecordingCanvas::didConcat44(const SkM44& m) { + fDL->concat(m); } void RecordingCanvas::didConcat(const SkMatrix& matrix) { fDL->concat(matrix); @@ -929,24 +918,6 @@ void RecordingCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScala fDL->drawTextBlob(blob, x, y, paint); } -void RecordingCanvas::onDrawBitmap(const SkBitmap& bm, SkScalar x, SkScalar y, - const SkPaint* paint) { - fDL->drawImage(SkImage::MakeFromBitmap(bm), x, y, paint, BitmapPalette::Unknown); -} -void RecordingCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center, const SkRect& dst, - const SkPaint* paint) { - fDL->drawImageNine(SkImage::MakeFromBitmap(bm), center, dst, paint); -} -void RecordingCanvas::onDrawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst, - const SkPaint* paint, SrcRectConstraint constraint) { - fDL->drawImageRect(SkImage::MakeFromBitmap(bm), src, dst, paint, constraint, - BitmapPalette::Unknown); -} -void RecordingCanvas::onDrawBitmapLattice(const SkBitmap& bm, const SkCanvas::Lattice& lattice, - const SkRect& dst, const SkPaint* paint) { - fDL->drawImageLattice(SkImage::MakeFromBitmap(bm), lattice, dst, paint, BitmapPalette::Unknown); -} - void RecordingCanvas::drawImage(const sk_sp<SkImage>& image, SkScalar x, SkScalar y, const SkPaint* paint, BitmapPalette palette) { fDL->drawImage(image, x, y, paint, palette); @@ -1007,9 +978,8 @@ void RecordingCanvas::onDrawPoints(SkCanvas::PointMode mode, size_t count, const fDL->drawPoints(mode, count, pts, paint); } void RecordingCanvas::onDrawVerticesObject(const SkVertices* vertices, - const SkVertices::Bone bones[], int boneCount, SkBlendMode mode, const SkPaint& paint) { - fDL->drawVertices(vertices, bones, boneCount, mode, paint); + fDL->drawVertices(vertices, mode, paint); } void RecordingCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xforms[], const SkRect texs[], const SkColor colors[], int count, diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h index 7eb1ce3eb18a..63d120c4ca19 100644 --- a/libs/hwui/RecordingCanvas.h +++ b/libs/hwui/RecordingCanvas.h @@ -77,12 +77,11 @@ private: void flush(); void save(); - void saveLayer(const SkRect*, const SkPaint*, const SkImageFilter*, const SkImage*, - const SkMatrix*, SkCanvas::SaveLayerFlags); + void saveLayer(const SkRect*, const SkPaint*, const SkImageFilter*, SkCanvas::SaveLayerFlags); void saveBehind(const SkRect*); void restore(); - void concat44(const SkScalar colMajor[16]); + void concat(const SkM44&); void concat(const SkMatrix&); void setMatrix(const SkMatrix&); void scale(SkScalar, SkScalar); @@ -120,8 +119,7 @@ private: void drawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode, const SkPaint&); void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&); - void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode, - const SkPaint&); + void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&); void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, SkBlendMode, const SkRect*, const SkPaint*); void drawShadowRec(const SkPath&, const SkDrawShadowRec&); @@ -155,7 +153,7 @@ public: void onFlush() override; - void didConcat44(const SkScalar[16]) override; + void didConcat44(const SkM44&) override; void didConcat(const SkMatrix&) override; void didSetMatrix(const SkMatrix&) override; void didScale(SkScalar, SkScalar) override; @@ -182,13 +180,6 @@ public: void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override; - void onDrawBitmap(const SkBitmap&, SkScalar, SkScalar, const SkPaint*) override; - void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&, - const SkPaint*) override; - void onDrawBitmapNine(const SkBitmap&, const SkIRect&, const SkRect&, const SkPaint*) override; - void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*, - SrcRectConstraint) override; - void drawImage(const sk_sp<SkImage>& image, SkScalar left, SkScalar top, const SkPaint* paint, BitmapPalette pallete); @@ -206,8 +197,7 @@ public: void onDrawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode, const SkPaint&) override; void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; - void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, - SkBlendMode, const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override; void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, SkBlendMode, const SkRect*, const SkPaint*) override; void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override; diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index c0ec2174bb35..6d5e62e955bb 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -94,17 +94,17 @@ public: DISPLAY_LIST = 1 << 14, }; - ANDROID_API RenderNode(); - ANDROID_API virtual ~RenderNode(); + RenderNode(); + virtual ~RenderNode(); // See flags defined in DisplayList.java enum ReplayFlag { kReplayFlag_ClipChildren = 0x1 }; - ANDROID_API void setStagingDisplayList(DisplayList* newData); + void setStagingDisplayList(DisplayList* newData); - ANDROID_API void output(); - ANDROID_API int getUsageSize(); - ANDROID_API int getAllocatedSize(); + void output(); + int getUsageSize(); + int getAllocatedSize(); bool isRenderable() const { return mDisplayList && !mDisplayList->isEmpty(); } @@ -149,12 +149,12 @@ public: int getHeight() const { return properties().getHeight(); } - ANDROID_API virtual void prepareTree(TreeInfo& info); + virtual void prepareTree(TreeInfo& info); void destroyHardwareResources(TreeInfo* info = nullptr); void destroyLayers(); // UI thread only! - ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator); + void addAnimator(const sp<BaseRenderNodeAnimator>& animator); void removeAnimator(const sp<BaseRenderNodeAnimator>& animator); // This can only happen during pushStaging() @@ -179,7 +179,7 @@ public: // the frameNumber to appropriately batch/synchronize these transactions. // There is no other filtering/batching to ensure that only the "final" // state called once per frame. - class ANDROID_API PositionListener : public VirtualLightRefBase { + class PositionListener : public VirtualLightRefBase { public: virtual ~PositionListener() {} // Called when the RenderNode's position changes @@ -190,14 +190,14 @@ public: virtual void onPositionLost(RenderNode& node, const TreeInfo* info) = 0; }; - ANDROID_API void setPositionListener(PositionListener* listener) { + void setPositionListener(PositionListener* listener) { mStagingPositionListener = listener; mPositionListenerDirty = true; } // This is only modified in MODE_FULL, so it can be safely accessed // on the UI thread. - ANDROID_API bool hasParents() { return mParentCount; } + bool hasParents() { return mParentCount; } void onRemovedFromTree(TreeInfo* info); diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h index 24f6035b6708..ef4cd1f1eb62 100644 --- a/libs/hwui/RenderProperties.h +++ b/libs/hwui/RenderProperties.h @@ -69,7 +69,7 @@ enum ClippingFlags { CLIP_TO_CLIP_BOUNDS = 0x1 << 1, }; -class ANDROID_API LayerProperties { +class LayerProperties { public: bool setType(LayerType type) { if (RP_SET(mType, type)) { @@ -123,7 +123,7 @@ private: /* * Data structure that holds the properties for a RenderNode */ -class ANDROID_API RenderProperties { +class RenderProperties { public: RenderProperties(); virtual ~RenderProperties(); diff --git a/libs/hwui/RootRenderNode.h b/libs/hwui/RootRenderNode.h index 12de4ecac94b..1d3f5a8a51e0 100644 --- a/libs/hwui/RootRenderNode.h +++ b/libs/hwui/RootRenderNode.h @@ -27,16 +27,16 @@ namespace android::uirenderer { -class ANDROID_API RootRenderNode : public RenderNode { +class RootRenderNode : public RenderNode { public: - ANDROID_API explicit RootRenderNode(std::unique_ptr<ErrorHandler> errorHandler) + explicit RootRenderNode(std::unique_ptr<ErrorHandler> errorHandler) : RenderNode(), mErrorHandler(std::move(errorHandler)) {} - ANDROID_API virtual ~RootRenderNode() {} + virtual ~RootRenderNode() {} virtual void prepareTree(TreeInfo& info) override; - ANDROID_API void attachAnimatingNode(RenderNode* animatingNode); + void attachAnimatingNode(RenderNode* animatingNode); void attachPendingVectorDrawableAnimators(); @@ -53,9 +53,9 @@ public: void pushStagingVectorDrawableAnimators(AnimationContext* context); - ANDROID_API void destroy(); + void destroy(); - ANDROID_API void addVectorDrawableAnimator(PropertyValuesAnimatorSet* anim); + void addVectorDrawableAnimator(PropertyValuesAnimatorSet* anim); private: const std::unique_ptr<ErrorHandler> mErrorHandler; @@ -75,12 +75,11 @@ private: }; #ifdef __ANDROID__ // Layoutlib does not support Animations -class ANDROID_API ContextFactoryImpl : public IContextFactory { +class ContextFactoryImpl : public IContextFactory { public: - ANDROID_API explicit ContextFactoryImpl(RootRenderNode* rootNode) : mRootNode(rootNode) {} + explicit ContextFactoryImpl(RootRenderNode* rootNode) : mRootNode(rootNode) {} - ANDROID_API virtual AnimationContext* createAnimationContext( - renderthread::TimeLord& clock) override; + virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override; private: RootRenderNode* mRootNode; diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 941437998838..242b8b0d139e 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -40,6 +40,7 @@ #include <SkShader.h> #include <SkTemplates.h> #include <SkTextBlob.h> +#include <SkVertices.h> #include <memory> #include <optional> @@ -842,9 +843,4 @@ void SkiaCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) { LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw RenderNodes"); } -void SkiaCanvas::callDrawGLFunction(Functor* functor, - uirenderer::GlFunctorLifecycleListener* listener) { - LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw GL Content"); -} - } // namespace android diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h index 1eb089d8764c..1df2b2671659 100644 --- a/libs/hwui/SkiaCanvas.h +++ b/libs/hwui/SkiaCanvas.h @@ -57,8 +57,8 @@ public: LOG_ALWAYS_FATAL("SkiaCanvas does not produce a DisplayList"); return nullptr; } - virtual void insertReorderBarrier(bool enableReorder) override { - LOG_ALWAYS_FATAL("SkiaCanvas does not support reordering barriers"); + virtual void enableZ(bool enableZ) override { + LOG_ALWAYS_FATAL("SkiaCanvas does not support enableZ"); } virtual void setBitmap(const SkBitmap& bitmap) override; @@ -152,8 +152,6 @@ public: virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override; virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override; - virtual void callDrawGLFunction(Functor* functor, - uirenderer::GlFunctorLifecycleListener* listener) override; virtual void drawPicture(const SkPicture& picture) override; protected: diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h index e1b6f2adde74..ac7d41e0d600 100644 --- a/libs/hwui/VectorDrawable.h +++ b/libs/hwui/VectorDrawable.h @@ -97,7 +97,7 @@ private: bool* mStagingDirty; }; -class ANDROID_API Node { +class Node { public: class Properties { public: @@ -127,9 +127,9 @@ protected: PropertyChangedListener* mPropertyChangedListener = nullptr; }; -class ANDROID_API Path : public Node { +class Path : public Node { public: - struct ANDROID_API Data { + struct Data { std::vector<char> verbs; std::vector<size_t> verbSizes; std::vector<float> points; @@ -200,7 +200,7 @@ private: bool mStagingPropertiesDirty = true; }; -class ANDROID_API FullPath : public Path { +class FullPath : public Path { public: class FullPathProperties : public Properties { public: @@ -369,7 +369,7 @@ private: bool mAntiAlias = true; }; -class ANDROID_API ClipPath : public Path { +class ClipPath : public Path { public: ClipPath(const ClipPath& path) : Path(path) {} ClipPath(const char* path, size_t strLength) : Path(path, strLength) {} @@ -378,7 +378,7 @@ public: virtual void setAntiAlias(bool aa) {} }; -class ANDROID_API Group : public Node { +class Group : public Node { public: class GroupProperties : public Properties { public: @@ -498,7 +498,7 @@ private: std::vector<std::unique_ptr<Node> > mChildren; }; -class ANDROID_API Tree : public VirtualLightRefBase { +class Tree : public VirtualLightRefBase { public: explicit Tree(Group* rootNode) : mRootNode(rootNode) { mRootNode->setPropertyChangedListener(&mPropertyChangedListener); diff --git a/libs/hwui/apex/java/android/graphics/ColorMatrix.java b/libs/hwui/apex/java/android/graphics/ColorMatrix.java new file mode 100644 index 000000000000..6299b2c47ea1 --- /dev/null +++ b/libs/hwui/apex/java/android/graphics/ColorMatrix.java @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * 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. + */ + +package android.graphics; + +import java.util.Arrays; + +/** + * 4x5 matrix for transforming the color and alpha components of a Bitmap. + * The matrix can be passed as single array, and is treated as follows: + * + * <pre> + * [ a, b, c, d, e, + * f, g, h, i, j, + * k, l, m, n, o, + * p, q, r, s, t ]</pre> + * + * <p> + * When applied to a color <code>[R, G, B, A]</code>, the resulting color + * is computed as: + * </p> + * + * <pre> + * R’ = a*R + b*G + c*B + d*A + e; + * G’ = f*R + g*G + h*B + i*A + j; + * B’ = k*R + l*G + m*B + n*A + o; + * A’ = p*R + q*G + r*B + s*A + t;</pre> + * + * <p> + * That resulting color <code>[R’, G’, B’, A’]</code> + * then has each channel clamped to the <code>0</code> to <code>255</code> + * range. + * </p> + * + * <p> + * The sample ColorMatrix below inverts incoming colors by scaling each + * channel by <code>-1</code>, and then shifting the result up by + * <code>255</code> to remain in the standard color space. + * </p> + * + * <pre> + * [ -1, 0, 0, 0, 255, + * 0, -1, 0, 0, 255, + * 0, 0, -1, 0, 255, + * 0, 0, 0, 1, 0 ]</pre> + */ +@SuppressWarnings({ "MismatchedReadAndWriteOfArray", "PointlessArithmeticExpression" }) +public class ColorMatrix { + private final float[] mArray = new float[20]; + + /** + * Create a new colormatrix initialized to identity (as if reset() had + * been called). + */ + public ColorMatrix() { + reset(); + } + + /** + * Create a new colormatrix initialized with the specified array of values. + */ + public ColorMatrix(float[] src) { + System.arraycopy(src, 0, mArray, 0, 20); + } + + /** + * Create a new colormatrix initialized with the specified colormatrix. + */ + public ColorMatrix(ColorMatrix src) { + System.arraycopy(src.mArray, 0, mArray, 0, 20); + } + + /** + * Return the array of floats representing this colormatrix. + */ + public final float[] getArray() { return mArray; } + + /** + * Set this colormatrix to identity: + * <pre> + * [ 1 0 0 0 0 - red vector + * 0 1 0 0 0 - green vector + * 0 0 1 0 0 - blue vector + * 0 0 0 1 0 ] - alpha vector + * </pre> + */ + public void reset() { + final float[] a = mArray; + Arrays.fill(a, 0); + a[0] = a[6] = a[12] = a[18] = 1; + } + + /** + * Assign the src colormatrix into this matrix, copying all of its values. + */ + public void set(ColorMatrix src) { + System.arraycopy(src.mArray, 0, mArray, 0, 20); + } + + /** + * Assign the array of floats into this matrix, copying all of its values. + */ + public void set(float[] src) { + System.arraycopy(src, 0, mArray, 0, 20); + } + + /** + * Set this colormatrix to scale by the specified values. + */ + public void setScale(float rScale, float gScale, float bScale, + float aScale) { + final float[] a = mArray; + + for (int i = 19; i > 0; --i) { + a[i] = 0; + } + a[0] = rScale; + a[6] = gScale; + a[12] = bScale; + a[18] = aScale; + } + + /** + * Set the rotation on a color axis by the specified values. + * <p> + * <code>axis=0</code> correspond to a rotation around the RED color + * <code>axis=1</code> correspond to a rotation around the GREEN color + * <code>axis=2</code> correspond to a rotation around the BLUE color + * </p> + */ + public void setRotate(int axis, float degrees) { + reset(); + double radians = degrees * Math.PI / 180d; + float cosine = (float) Math.cos(radians); + float sine = (float) Math.sin(radians); + switch (axis) { + // Rotation around the red color + case 0: + mArray[6] = mArray[12] = cosine; + mArray[7] = sine; + mArray[11] = -sine; + break; + // Rotation around the green color + case 1: + mArray[0] = mArray[12] = cosine; + mArray[2] = -sine; + mArray[10] = sine; + break; + // Rotation around the blue color + case 2: + mArray[0] = mArray[6] = cosine; + mArray[1] = sine; + mArray[5] = -sine; + break; + default: + throw new RuntimeException(); + } + } + + /** + * Set this colormatrix to the concatenation of the two specified + * colormatrices, such that the resulting colormatrix has the same effect + * as applying matB and then applying matA. + * <p> + * It is legal for either matA or matB to be the same colormatrix as this. + * </p> + */ + public void setConcat(ColorMatrix matA, ColorMatrix matB) { + float[] tmp; + if (matA == this || matB == this) { + tmp = new float[20]; + } else { + tmp = mArray; + } + + final float[] a = matA.mArray; + final float[] b = matB.mArray; + int index = 0; + for (int j = 0; j < 20; j += 5) { + for (int i = 0; i < 4; i++) { + tmp[index++] = a[j + 0] * b[i + 0] + a[j + 1] * b[i + 5] + + a[j + 2] * b[i + 10] + a[j + 3] * b[i + 15]; + } + tmp[index++] = a[j + 0] * b[4] + a[j + 1] * b[9] + + a[j + 2] * b[14] + a[j + 3] * b[19] + + a[j + 4]; + } + + if (tmp != mArray) { + System.arraycopy(tmp, 0, mArray, 0, 20); + } + } + + /** + * Concat this colormatrix with the specified prematrix. + * <p> + * This is logically the same as calling setConcat(this, prematrix); + * </p> + */ + public void preConcat(ColorMatrix prematrix) { + setConcat(this, prematrix); + } + + /** + * Concat this colormatrix with the specified postmatrix. + * <p> + * This is logically the same as calling setConcat(postmatrix, this); + * </p> + */ + public void postConcat(ColorMatrix postmatrix) { + setConcat(postmatrix, this); + } + + /////////////////////////////////////////////////////////////////////////// + + /** + * Set the matrix to affect the saturation of colors. + * + * @param sat A value of 0 maps the color to gray-scale. 1 is identity. + */ + public void setSaturation(float sat) { + reset(); + float[] m = mArray; + + final float invSat = 1 - sat; + final float R = 0.213f * invSat; + final float G = 0.715f * invSat; + final float B = 0.072f * invSat; + + m[0] = R + sat; m[1] = G; m[2] = B; + m[5] = R; m[6] = G + sat; m[7] = B; + m[10] = R; m[11] = G; m[12] = B + sat; + } + + /** + * Set the matrix to convert RGB to YUV + */ + public void setRGB2YUV() { + reset(); + float[] m = mArray; + // these coefficients match those in libjpeg + m[0] = 0.299f; m[1] = 0.587f; m[2] = 0.114f; + m[5] = -0.16874f; m[6] = -0.33126f; m[7] = 0.5f; + m[10] = 0.5f; m[11] = -0.41869f; m[12] = -0.08131f; + } + + /** + * Set the matrix to convert from YUV to RGB + */ + public void setYUV2RGB() { + reset(); + float[] m = mArray; + // these coefficients match those in libjpeg + m[2] = 1.402f; + m[5] = 1; m[6] = -0.34414f; m[7] = -0.71414f; + m[10] = 1; m[11] = 1.772f; m[12] = 0; + } + + @Override + public boolean equals(Object obj) { + // if (obj == this) return true; -- NaN value would mean matrix != itself + if (!(obj instanceof ColorMatrix)) { + return false; + } + + // we don't use Arrays.equals(), since that considers NaN == NaN + final float[] other = ((ColorMatrix) obj).mArray; + for (int i = 0; i < 20; i++) { + if (other[i] != mArray[i]) { + return false; + } + } + return true; + } +} diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp index a114e2f42157..b933813550d4 100644 --- a/libs/hwui/apex/jni_runtime.cpp +++ b/libs/hwui/apex/jni_runtime.cpp @@ -61,6 +61,7 @@ extern int register_android_graphics_Path(JNIEnv* env); extern int register_android_graphics_PathMeasure(JNIEnv* env); extern int register_android_graphics_Picture(JNIEnv*); extern int register_android_graphics_Region(JNIEnv* env); +extern int register_android_graphics_TextureLayer(JNIEnv* env); extern int register_android_graphics_animation_NativeInterpolatorFactory(JNIEnv* env); extern int register_android_graphics_animation_RenderNodeAnimator(JNIEnv* env); extern int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env); @@ -76,7 +77,6 @@ extern int register_android_graphics_text_LineBreaker(JNIEnv *env); extern int register_android_util_PathParser(JNIEnv* env); extern int register_android_view_DisplayListCanvas(JNIEnv* env); extern int register_android_view_RenderNode(JNIEnv* env); -extern int register_android_view_TextureLayer(JNIEnv* env); extern int register_android_view_ThreadedRenderer(JNIEnv* env); #ifdef NDEBUG @@ -123,6 +123,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_graphics_Picture), REG_JNI(register_android_graphics_Region), REG_JNI(register_android_graphics_Shader), + REG_JNI(register_android_graphics_TextureLayer), REG_JNI(register_android_graphics_Typeface), REG_JNI(register_android_graphics_YuvImage), REG_JNI(register_android_graphics_animation_NativeInterpolatorFactory), @@ -140,7 +141,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_util_PathParser), REG_JNI(register_android_view_RenderNode), REG_JNI(register_android_view_DisplayListCanvas), - REG_JNI(register_android_view_TextureLayer), REG_JNI(register_android_view_ThreadedRenderer), }; diff --git a/libs/hwui/api/current.txt b/libs/hwui/api/current.txt new file mode 100644 index 000000000000..c396a2032eed --- /dev/null +++ b/libs/hwui/api/current.txt @@ -0,0 +1,23 @@ +// Signature format: 2.0 +package android.graphics { + + public class ColorMatrix { + ctor public ColorMatrix(); + ctor public ColorMatrix(float[]); + ctor public ColorMatrix(android.graphics.ColorMatrix); + method public final float[] getArray(); + method public void postConcat(android.graphics.ColorMatrix); + method public void preConcat(android.graphics.ColorMatrix); + method public void reset(); + method public void set(android.graphics.ColorMatrix); + method public void set(float[]); + method public void setConcat(android.graphics.ColorMatrix, android.graphics.ColorMatrix); + method public void setRGB2YUV(); + method public void setRotate(int, float); + method public void setSaturation(float); + method public void setScale(float, float, float, float); + method public void setYUV2RGB(); + } + +} + diff --git a/libs/hwui/api/module-lib-current.txt b/libs/hwui/api/module-lib-current.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/libs/hwui/api/module-lib-current.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/libs/hwui/api/module-lib-removed.txt b/libs/hwui/api/module-lib-removed.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/libs/hwui/api/module-lib-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/libs/hwui/api/removed.txt b/libs/hwui/api/removed.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/libs/hwui/api/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/libs/hwui/api/system-current.txt b/libs/hwui/api/system-current.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/libs/hwui/api/system-current.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/libs/hwui/api/system-removed.txt b/libs/hwui/api/system-removed.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/libs/hwui/api/system-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h index f0aa35acf71b..f81a5a40b44e 100644 --- a/libs/hwui/hwui/AnimatedImageDrawable.h +++ b/libs/hwui/hwui/AnimatedImageDrawable.h @@ -44,7 +44,7 @@ public: * This class can be drawn into Canvas.h and maintains the state needed to drive * the animation from the RenderThread. */ -class ANDROID_API AnimatedImageDrawable : public SkDrawable { +class AnimatedImageDrawable : public SkDrawable { public: // bytesUsed includes the approximate sizes of the SkAnimatedImage and the SkPictures in the // Snapshots. diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 56d951cdb338..c0a24438987a 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -33,7 +33,6 @@ #ifndef _WIN32 #include <binder/IServiceManager.h> #endif -#include <ui/PixelFormat.h> #include <SkCanvas.h> #include <SkImagePriv.h> @@ -132,15 +131,8 @@ sk_sp<Bitmap> Bitmap::allocateHeapBitmap(size_t size, const SkImageInfo& info, s return sk_sp<Bitmap>(new Bitmap(addr, size, info, rowBytes)); } -void FreePixelRef(void* addr, void* context) { - auto pixelRef = (SkPixelRef*)context; - pixelRef->unref(); -} - sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) { - pixelRef.ref(); - return sk_sp<Bitmap>(new Bitmap((void*)pixelRef.pixels(), (void*)&pixelRef, FreePixelRef, info, - pixelRef.rowBytes())); + return sk_sp<Bitmap>(new Bitmap(pixelRef, info)); } @@ -233,14 +225,12 @@ Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBy mPixelStorage.heap.size = size; } -Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info, - size_t rowBytes) - : SkPixelRef(info.width(), info.height(), address, rowBytes) +Bitmap::Bitmap(SkPixelRef& pixelRef, const SkImageInfo& info) + : SkPixelRef(info.width(), info.height(), pixelRef.pixels(), pixelRef.rowBytes()) , mInfo(validateAlpha(info)) - , mPixelStorageType(PixelStorageType::External) { - mPixelStorage.external.address = address; - mPixelStorage.external.context = context; - mPixelStorage.external.freeFunc = freeFunc; + , mPixelStorageType(PixelStorageType::WrappedPixelRef) { + pixelRef.ref(); + mPixelStorage.wrapped.pixelRef = &pixelRef; } Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes) @@ -269,9 +259,8 @@ Bitmap::Bitmap(AHardwareBuffer* buffer, const SkImageInfo& info, size_t rowBytes Bitmap::~Bitmap() { switch (mPixelStorageType) { - case PixelStorageType::External: - mPixelStorage.external.freeFunc(mPixelStorage.external.address, - mPixelStorage.external.context); + case PixelStorageType::WrappedPixelRef: + mPixelStorage.wrapped.pixelRef->unref(); break; case PixelStorageType::Ashmem: #ifndef _WIN32 // ashmem not implemented on Windows @@ -303,19 +292,6 @@ void Bitmap::setHasHardwareMipMap(bool hasMipMap) { mHasHardwareMipMap = hasMipMap; } -void* Bitmap::getStorage() const { - switch (mPixelStorageType) { - case PixelStorageType::External: - return mPixelStorage.external.address; - case PixelStorageType::Ashmem: - return mPixelStorage.ashmem.address; - case PixelStorageType::Heap: - return mPixelStorage.heap.address; - case PixelStorageType::Hardware: - return nullptr; - } -} - int Bitmap::getAshmemFd() const { switch (mPixelStorageType) { case PixelStorageType::Ashmem: diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h index b8b59947a57b..6ece7ef9f329 100644 --- a/libs/hwui/hwui/Bitmap.h +++ b/libs/hwui/hwui/Bitmap.h @@ -32,7 +32,7 @@ class SkWStream; namespace android { enum class PixelStorageType { - External, + WrappedPixelRef, Heap, Ashmem, Hardware, @@ -56,7 +56,7 @@ class PixelStorage; typedef void (*FreeFunc)(void* addr, void* context); -class ANDROID_API Bitmap : public SkPixelRef { +class Bitmap : public SkPixelRef { public: /* The allocate factories not only construct the Bitmap object but also allocate the * backing store whose type is determined by the specific method that is called. @@ -71,6 +71,7 @@ public: static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& bitmap); static sk_sp<Bitmap> allocateHeapBitmap(SkBitmap* bitmap); static sk_sp<Bitmap> allocateHeapBitmap(const SkImageInfo& info); + static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& i, size_t rowBytes); /* The createFrom factories construct a new Bitmap object by wrapping the already allocated * memory that is provided as an input param. @@ -160,11 +161,9 @@ public: int32_t quality, SkWStream* stream); private: static sk_sp<Bitmap> allocateAshmemBitmap(size_t size, const SkImageInfo& i, size_t rowBytes); - static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& i, size_t rowBytes); Bitmap(void* address, size_t allocSize, const SkImageInfo& info, size_t rowBytes); - Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info, - size_t rowBytes); + Bitmap(SkPixelRef& pixelRef, const SkImageInfo& info); Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes); #ifdef __ANDROID__ // Layoutlib does not support hardware acceleration Bitmap(AHardwareBuffer* buffer, const SkImageInfo& info, size_t rowBytes, @@ -178,7 +177,6 @@ private: #endif virtual ~Bitmap(); - void* getStorage() const; SkImageInfo mInfo; @@ -191,10 +189,8 @@ private: union { struct { - void* address; - void* context; - FreeFunc freeFunc; - } external; + SkPixelRef* pixelRef; + } wrapped; struct { void* address; int fd; diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index 27dfed305a94..333567b0cf91 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -20,7 +20,6 @@ #include <utils/Functor.h> #include <androidfw/ResourceTypes.h> -#include "GlFunctorLifecycleListener.h" #include "Properties.h" #include "utils/Macros.h" @@ -144,7 +143,7 @@ public: virtual void resetRecording(int width, int height, uirenderer::RenderNode* renderNode = nullptr) = 0; virtual uirenderer::DisplayList* finishRecording() = 0; - virtual void insertReorderBarrier(bool enableReorder) = 0; + virtual void enableZ(bool enableZ) = 0; bool isHighContrastText() const { return uirenderer::Properties::enableHighContrastText; } @@ -162,8 +161,7 @@ public: virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0; virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0; - virtual void callDrawGLFunction(Functor* functor, - uirenderer::GlFunctorLifecycleListener* listener) = 0; + virtual void drawWebViewFunctor(int /*functor*/) { LOG_ALWAYS_FATAL("Not supported"); } diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h index cbf409504675..0eacde9a467e 100644 --- a/libs/hwui/hwui/MinikinUtils.h +++ b/libs/hwui/hwui/MinikinUtils.h @@ -39,30 +39,30 @@ namespace android { class MinikinUtils { public: - ANDROID_API static minikin::MinikinPaint prepareMinikinPaint(const Paint* paint, + static minikin::MinikinPaint prepareMinikinPaint(const Paint* paint, const Typeface* typeface); - ANDROID_API static minikin::Layout doLayout(const Paint* paint, minikin::Bidi bidiFlags, + static minikin::Layout doLayout(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface, const uint16_t* buf, size_t bufSize, size_t start, size_t count, size_t contextStart, size_t contextCount, minikin::MeasuredText* mt); - ANDROID_API static float measureText(const Paint* paint, minikin::Bidi bidiFlags, + static float measureText(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize, float* advances); - ANDROID_API static bool hasVariationSelector(const Typeface* typeface, uint32_t codepoint, + static bool hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs); - ANDROID_API static float xOffsetForTextAlign(Paint* paint, const minikin::Layout& layout); + static float xOffsetForTextAlign(Paint* paint, const minikin::Layout& layout); - ANDROID_API static float hOffsetForTextAlign(Paint* paint, const minikin::Layout& layout, + static float hOffsetForTextAlign(Paint* paint, const minikin::Layout& layout, const SkPath& path); // f is a functor of type void f(size_t start, size_t end); template <typename F> - ANDROID_API static void forFontRun(const minikin::Layout& layout, Paint* paint, F& f) { + static void forFontRun(const minikin::Layout& layout, Paint* paint, F& f) { float saveSkewX = paint->getSkFont().getSkewX(); bool savefakeBold = paint->getSkFont().isEmbolden(); const minikin::MinikinFont* curFont = nullptr; diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h index 281ecd27d780..e75e9e7c6933 100644 --- a/libs/hwui/hwui/Paint.h +++ b/libs/hwui/hwui/Paint.h @@ -32,7 +32,7 @@ namespace android { -class ANDROID_API Paint : public SkPaint { +class Paint : public SkPaint { public: // Default values for underlined and strikethrough text, // as defined by Skia in SkTextFormatParams.h. diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp index c0663a9bc699..eb9885a4436a 100755 --- a/libs/hwui/jni/Bitmap.cpp +++ b/libs/hwui/jni/Bitmap.cpp @@ -19,12 +19,19 @@ #include <utils/Color.h> #ifdef __ANDROID__ // Layoutlib does not support graphic buffer, parcel or render thread +#include <android-base/unique_fd.h> +#include <android/binder_parcel.h> +#include <android/binder_parcel_jni.h> +#include <android/binder_parcel_platform.h> +#include <android/binder_parcel_utils.h> #include <private/android/AHardwareBufferHelpers.h> -#include <binder/Parcel.h> +#include <cutils/ashmem.h> #include <dlfcn.h> #include <renderthread/RenderProxy.h> +#include <sys/mman.h> #endif +#include <inttypes.h> #include <string.h> #include <memory> #include <string> @@ -567,152 +574,296 @@ static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle, /////////////////////////////////////////////////////////////////////////////// +// TODO: Move somewhere else #ifdef __ANDROID__ // Layoutlib does not support parcel -static struct parcel_offsets_t -{ - jclass clazz; - jfieldID mNativePtr; -} gParcelOffsets; - -static Parcel* parcelForJavaObject(JNIEnv* env, jobject obj) { - if (obj) { - Parcel* p = (Parcel*)env->GetLongField(obj, gParcelOffsets.mNativePtr); - if (p != NULL) { - return p; + +class ScopedParcel { +public: + explicit ScopedParcel(JNIEnv* env, jobject parcel) { + mParcel = AParcel_fromJavaParcel(env, parcel); + } + + ~ScopedParcel() { AParcel_delete(mParcel); } + + int32_t readInt32() { + int32_t temp = 0; + // TODO: This behavior-matches what android::Parcel does + // but this should probably be better + if (AParcel_readInt32(mParcel, &temp) != STATUS_OK) { + temp = 0; } - jniThrowException(env, "java/lang/IllegalStateException", "Parcel has been finalized!"); + return temp; + } + + uint32_t readUint32() { + uint32_t temp = 0; + // TODO: This behavior-matches what android::Parcel does + // but this should probably be better + if (AParcel_readUint32(mParcel, &temp) != STATUS_OK) { + temp = 0; + } + return temp; + } + + void writeInt32(int32_t value) { AParcel_writeInt32(mParcel, value); } + + void writeUint32(uint32_t value) { AParcel_writeUint32(mParcel, value); } + + bool allowFds() const { return AParcel_getAllowFds(mParcel); } + + std::optional<sk_sp<SkData>> readData() { + struct Data { + void* ptr = nullptr; + size_t size = 0; + } data; + auto error = AParcel_readByteArray(mParcel, &data, + [](void* arrayData, int32_t length, + int8_t** outBuffer) -> bool { + Data* data = reinterpret_cast<Data*>(arrayData); + if (length > 0) { + data->ptr = sk_malloc_canfail(length); + if (!data->ptr) { + return false; + } + *outBuffer = + reinterpret_cast<int8_t*>(data->ptr); + data->size = length; + } + return true; + }); + if (error != STATUS_OK || data.size <= 0) { + sk_free(data.ptr); + return std::nullopt; + } else { + return SkData::MakeFromMalloc(data.ptr, data.size); + } + } + + void writeData(const std::optional<sk_sp<SkData>>& optData) { + if (optData) { + const auto& data = *optData; + AParcel_writeByteArray(mParcel, reinterpret_cast<const int8_t*>(data->data()), + data->size()); + } else { + AParcel_writeByteArray(mParcel, nullptr, -1); + } + } + + AParcel* get() { return mParcel; } + +private: + AParcel* mParcel; +}; + +enum class BlobType : int32_t { + IN_PLACE, + ASHMEM, +}; + +#define ON_ERROR_RETURN(X) \ + if ((error = (X)) != STATUS_OK) return error + +template <typename T, typename U> +static binder_status_t readBlob(AParcel* parcel, T inPlaceCallback, U ashmemCallback) { + binder_status_t error = STATUS_OK; + BlobType type; + static_assert(sizeof(BlobType) == sizeof(int32_t)); + ON_ERROR_RETURN(AParcel_readInt32(parcel, (int32_t*)&type)); + if (type == BlobType::IN_PLACE) { + struct Data { + std::unique_ptr<int8_t[]> ptr = nullptr; + int32_t size = 0; + } data; + ON_ERROR_RETURN( + AParcel_readByteArray(parcel, &data, + [](void* arrayData, int32_t length, int8_t** outBuffer) { + Data* data = reinterpret_cast<Data*>(arrayData); + if (length > 0) { + data->ptr = std::make_unique<int8_t[]>(length); + data->size = length; + *outBuffer = data->ptr.get(); + } + return data->ptr != nullptr; + })); + inPlaceCallback(std::move(data.ptr), data.size); + return STATUS_OK; + } else if (type == BlobType::ASHMEM) { + int rawFd = -1; + int32_t size = 0; + ON_ERROR_RETURN(AParcel_readInt32(parcel, &size)); + ON_ERROR_RETURN(AParcel_readParcelFileDescriptor(parcel, &rawFd)); + android::base::unique_fd fd(rawFd); + ashmemCallback(std::move(fd), size); + return STATUS_OK; + } else { + // Although the above if/else was "exhaustive" guard against unknown types + return STATUS_UNKNOWN_ERROR; } - return NULL; } -#endif + +static constexpr size_t BLOB_INPLACE_LIMIT = 12 * 1024; +// Fail fast if we can't use ashmem and the size exceeds this limit - the binder transaction +// wouldn't go through, anyway +// TODO: Can we get this from somewhere? +static constexpr size_t BLOB_MAX_INPLACE_LIMIT = 1 * 1024 * 1024; +static constexpr bool shouldUseAshmem(AParcel* parcel, int32_t size) { + return size > BLOB_INPLACE_LIMIT && AParcel_getAllowFds(parcel); +} + +static binder_status_t writeBlobFromFd(AParcel* parcel, int32_t size, int fd) { + binder_status_t error = STATUS_OK; + ON_ERROR_RETURN(AParcel_writeInt32(parcel, static_cast<int32_t>(BlobType::ASHMEM))); + ON_ERROR_RETURN(AParcel_writeInt32(parcel, size)); + ON_ERROR_RETURN(AParcel_writeParcelFileDescriptor(parcel, fd)); + return STATUS_OK; +} + +static binder_status_t writeBlob(AParcel* parcel, const int32_t size, const void* data, bool immutable) { + if (size <= 0 || data == nullptr) { + return STATUS_NOT_ENOUGH_DATA; + } + binder_status_t error = STATUS_OK; + if (shouldUseAshmem(parcel, size)) { + // Create new ashmem region with read/write priv + base::unique_fd fd(ashmem_create_region("bitmap", size)); + if (fd.get() < 0) { + return STATUS_NO_MEMORY; + } + + { + void* dest = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0); + if (dest == MAP_FAILED) { + return STATUS_NO_MEMORY; + } + memcpy(dest, data, size); + munmap(dest, size); + } + + if (immutable && ashmem_set_prot_region(fd.get(), PROT_READ) < 0) { + return STATUS_UNKNOWN_ERROR; + } + // Workaround b/149851140 in AParcel_writeParcelFileDescriptor + int rawFd = fd.release(); + error = writeBlobFromFd(parcel, size, rawFd); + close(rawFd); + return error; + } else { + if (size > BLOB_MAX_INPLACE_LIMIT) { + return STATUS_FAILED_TRANSACTION; + } + ON_ERROR_RETURN(AParcel_writeInt32(parcel, static_cast<int32_t>(BlobType::IN_PLACE))); + ON_ERROR_RETURN(AParcel_writeByteArray(parcel, static_cast<const int8_t*>(data), size)); + return STATUS_OK; + } +} + +#undef ON_ERROR_RETURN + +#endif // __ANDROID__ // Layoutlib does not support parcel // This is the maximum possible size because the SkColorSpace must be // representable (and therefore serializable) using a matrix and numerical // transfer function. If we allow more color space representations in the // framework, we may need to update this maximum size. -static constexpr uint32_t kMaxColorSpaceSerializedBytes = 80; +static constexpr size_t kMaxColorSpaceSerializedBytes = 80; + +static constexpr auto RuntimeException = "java/lang/RuntimeException"; + +static bool validateImageInfo(const SkImageInfo& info, int32_t rowBytes) { + // TODO: Can we avoid making a SkBitmap for this? + return SkBitmap().setInfo(info, rowBytes); +} static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { #ifdef __ANDROID__ // Layoutlib does not support parcel if (parcel == NULL) { - SkDebugf("-------- unparcel parcel is NULL\n"); + jniThrowNullPointerException(env, "parcel cannot be null"); return NULL; } - android::Parcel* p = parcelForJavaObject(env, parcel); + ScopedParcel p(env, parcel); - const bool isMutable = p->readInt32() != 0; - const SkColorType colorType = (SkColorType)p->readInt32(); - const SkAlphaType alphaType = (SkAlphaType)p->readInt32(); - const uint32_t colorSpaceSize = p->readUint32(); + const bool isMutable = p.readInt32(); + const SkColorType colorType = static_cast<SkColorType>(p.readInt32()); + const SkAlphaType alphaType = static_cast<SkAlphaType>(p.readInt32()); sk_sp<SkColorSpace> colorSpace; - if (colorSpaceSize > 0) { - if (colorSpaceSize > kMaxColorSpaceSerializedBytes) { + const auto optColorSpaceData = p.readData(); + if (optColorSpaceData) { + const auto& colorSpaceData = *optColorSpaceData; + if (colorSpaceData->size() > kMaxColorSpaceSerializedBytes) { ALOGD("Bitmap_createFromParcel: Serialized SkColorSpace is larger than expected: " - "%d bytes\n", colorSpaceSize); + "%zu bytes (max: %zu)\n", + colorSpaceData->size(), kMaxColorSpaceSerializedBytes); } - const void* data = p->readInplace(colorSpaceSize); - if (data) { - colorSpace = SkColorSpace::Deserialize(data, colorSpaceSize); - } else { - ALOGD("Bitmap_createFromParcel: Unable to read serialized SkColorSpace data\n"); - } + colorSpace = SkColorSpace::Deserialize(colorSpaceData->data(), colorSpaceData->size()); } - const int width = p->readInt32(); - const int height = p->readInt32(); - const int rowBytes = p->readInt32(); - const int density = p->readInt32(); + const int32_t width = p.readInt32(); + const int32_t height = p.readInt32(); + const int32_t rowBytes = p.readInt32(); + const int32_t density = p.readInt32(); if (kN32_SkColorType != colorType && kRGBA_F16_SkColorType != colorType && kRGB_565_SkColorType != colorType && kARGB_4444_SkColorType != colorType && kAlpha_8_SkColorType != colorType) { - SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType); + jniThrowExceptionFmt(env, RuntimeException, + "Bitmap_createFromParcel unknown colortype: %d\n", colorType); return NULL; } - std::unique_ptr<SkBitmap> bitmap(new SkBitmap); - if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, colorSpace), - rowBytes)) { + auto imageInfo = SkImageInfo::Make(width, height, colorType, alphaType, colorSpace); + size_t allocationSize = 0; + if (!validateImageInfo(imageInfo, rowBytes)) { + jniThrowRuntimeException(env, "Received bad SkImageInfo"); return NULL; } - - // Read the bitmap blob. - size_t size = bitmap->computeByteSize(); - android::Parcel::ReadableBlob blob; - android::status_t status = p->readBlob(size, &blob); - if (status) { - doThrowRE(env, "Could not read bitmap blob."); + if (!Bitmap::computeAllocationSize(rowBytes, height, &allocationSize)) { + jniThrowExceptionFmt(env, RuntimeException, + "Received bad bitmap size: width=%d, height=%d, rowBytes=%d", width, + height, rowBytes); return NULL; } - - // Map the bitmap in place from the ashmem region if possible otherwise copy. sk_sp<Bitmap> nativeBitmap; - // If the blob is mutable we have ownership of the region and can always use it - // If the blob is immutable _and_ we're immutable, we can then still use it - if (blob.fd() >= 0 && (blob.isMutable() || !isMutable)) { -#if DEBUG_PARCEL - ALOGD("Bitmap.createFromParcel: mapped contents of bitmap from %s blob " - "(fds %s)", - blob.isMutable() ? "mutable" : "immutable", - p->allowFds() ? "allowed" : "forbidden"); -#endif - // Dup the file descriptor so we can keep a reference to it after the Parcel - // is disposed. - int dupFd = fcntl(blob.fd(), F_DUPFD_CLOEXEC, 0); - if (dupFd < 0) { - ALOGE("Error allocating dup fd. Error:%d", errno); - blob.release(); - doThrowRE(env, "Could not allocate dup blob fd."); - return NULL; - } - - // Map the pixels in place and take ownership of the ashmem region. We must also respect the - // rowBytes value already set on the bitmap instead of attempting to compute our own. - nativeBitmap = Bitmap::createFrom(bitmap->info(), bitmap->rowBytes(), dupFd, - const_cast<void*>(blob.data()), size, !isMutable); - if (!nativeBitmap) { - close(dupFd); - blob.release(); - doThrowRE(env, "Could not allocate ashmem pixel ref."); - return NULL; - } - - // Clear the blob handle, don't release it. - blob.clear(); - } else { -#if DEBUG_PARCEL - if (blob.fd() >= 0) { - ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap " - "from immutable blob (fds %s)", - p->allowFds() ? "allowed" : "forbidden"); - } else { - ALOGD("Bitmap.createFromParcel: copied contents from %s blob " - "(fds %s)", - blob.isMutable() ? "mutable" : "immutable", - p->allowFds() ? "allowed" : "forbidden"); - } -#endif - - // Copy the pixels into a new buffer. - nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get()); - if (!nativeBitmap) { - blob.release(); - doThrowRE(env, "Could not allocate java pixel ref."); - return NULL; - } - memcpy(bitmap->getPixels(), blob.data(), size); - - // Release the blob handle. - blob.release(); + binder_status_t error = readBlob( + p.get(), + // In place callback + [&](std::unique_ptr<int8_t[]> buffer, int32_t size) { + nativeBitmap = Bitmap::allocateHeapBitmap(allocationSize, imageInfo, rowBytes); + if (nativeBitmap) { + memcpy(nativeBitmap->pixels(), buffer.get(), size); + } + }, + // Ashmem callback + [&](android::base::unique_fd fd, int32_t size) { + int flags = PROT_READ; + if (isMutable) { + flags |= PROT_WRITE; + } + void* addr = mmap(nullptr, size, flags, MAP_SHARED, fd.get(), 0); + if (addr == MAP_FAILED) { + const int err = errno; + ALOGW("mmap failed, error %d (%s)", err, strerror(err)); + return; + } + nativeBitmap = + Bitmap::createFrom(imageInfo, rowBytes, fd.release(), addr, size, !isMutable); + }); + if (error != STATUS_OK) { + // TODO: Stringify the error, see signalExceptionForError in android_util_Binder.cpp + jniThrowExceptionFmt(env, RuntimeException, "Failed to read from Parcel, error=%d", error); + return nullptr; + } + if (!nativeBitmap) { + jniThrowRuntimeException(env, "Could not allocate java pixel ref."); + return nullptr; } - return createBitmap(env, nativeBitmap.release(), - getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); + return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable), nullptr, + nullptr, density); #else - doThrowRE(env, "Cannot use parcels outside of Android"); + jniThrowRuntimeException(env, "Cannot use parcels outside of Android"); return NULL; #endif } @@ -725,48 +876,38 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, return JNI_FALSE; } - android::Parcel* p = parcelForJavaObject(env, parcel); + ScopedParcel p(env, parcel); SkBitmap bitmap; auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle); bitmapWrapper->getSkBitmap(&bitmap); - p->writeInt32(!bitmap.isImmutable()); - p->writeInt32(bitmap.colorType()); - p->writeInt32(bitmap.alphaType()); + p.writeInt32(!bitmap.isImmutable()); + p.writeInt32(bitmap.colorType()); + p.writeInt32(bitmap.alphaType()); SkColorSpace* colorSpace = bitmap.colorSpace(); if (colorSpace != nullptr) { - sk_sp<SkData> data = colorSpace->serialize(); - size_t size = data->size(); - p->writeUint32(size); - if (size > 0) { - if (size > kMaxColorSpaceSerializedBytes) { - ALOGD("Bitmap_writeToParcel: Serialized SkColorSpace is larger than expected: " - "%zu bytes\n", size); - } - - p->write(data->data(), size); - } + p.writeData(colorSpace->serialize()); } else { - p->writeUint32(0); + p.writeData(std::nullopt); } - p->writeInt32(bitmap.width()); - p->writeInt32(bitmap.height()); - p->writeInt32(bitmap.rowBytes()); - p->writeInt32(density); + p.writeInt32(bitmap.width()); + p.writeInt32(bitmap.height()); + p.writeInt32(bitmap.rowBytes()); + p.writeInt32(density); // Transfer the underlying ashmem region if we have one and it's immutable. - android::status_t status; + binder_status_t status; int fd = bitmapWrapper->bitmap().getAshmemFd(); - if (fd >= 0 && bitmap.isImmutable() && p->allowFds()) { + if (fd >= 0 && p.allowFds() && bitmap.isImmutable()) { #if DEBUG_PARCEL ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as " - "immutable blob (fds %s)", - p->allowFds() ? "allowed" : "forbidden"); + "immutable blob (fds %s)", + p.allowFds() ? "allowed" : "forbidden"); #endif - status = p->writeDupImmutableBlobFileDescriptor(fd); - if (status) { + status = writeBlobFromFd(p.get(), bitmapWrapper->bitmap().getAllocationByteCount(), fd); + if (status != STATUS_OK) { doThrowRE(env, "Could not write bitmap blob file descriptor."); return JNI_FALSE; } @@ -776,26 +917,15 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, // Copy the bitmap to a new blob. #if DEBUG_PARCEL ALOGD("Bitmap.writeToParcel: copying bitmap into new blob (fds %s)", - p->allowFds() ? "allowed" : "forbidden"); + p.allowFds() ? "allowed" : "forbidden"); #endif - const bool mutableCopy = !bitmap.isImmutable(); size_t size = bitmap.computeByteSize(); - android::Parcel::WritableBlob blob; - status = p->writeBlob(size, mutableCopy, &blob); + status = writeBlob(p.get(), size, bitmap.getPixels(), bitmap.isImmutable()); if (status) { doThrowRE(env, "Could not copy bitmap to parcel blob."); return JNI_FALSE; } - - const void* pSrc = bitmap.getPixels(); - if (pSrc == NULL) { - memset(blob.data(), 0, size); - } else { - memcpy(blob.data(), pSrc, size); - } - - blob.release(); return JNI_TRUE; #else doThrowRE(env, "Cannot use parcels outside of Android"); @@ -1074,13 +1204,16 @@ static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject har static jobject Bitmap_getHardwareBuffer(JNIEnv* env, jobject, jlong bitmapPtr) { #ifdef __ANDROID__ // Layoutlib does not support graphic buffer LocalScopedBitmap bitmapHandle(bitmapPtr); - LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(), + if (!bitmapHandle->isHardware()) { + jniThrowException(env, "java/lang/IllegalStateException", "Hardware config is only supported config in Bitmap_getHardwareBuffer"); + return nullptr; + } Bitmap& bitmap = bitmapHandle->bitmap(); return AHardwareBuffer_toHardwareBuffer(env, bitmap.hardwareBuffer()); #else - return NULL; + return nullptr; #endif } @@ -1091,6 +1224,14 @@ static jboolean Bitmap_isImmutable(CRITICAL_JNI_PARAMS_COMMA jlong bitmapHandle) return bitmapHolder->bitmap().isImmutable() ? JNI_TRUE : JNI_FALSE; } +static jboolean Bitmap_isBackedByAshmem(CRITICAL_JNI_PARAMS_COMMA jlong bitmapHandle) { + LocalScopedBitmap bitmapHolder(bitmapHandle); + if (!bitmapHolder.valid()) return JNI_FALSE; + + return bitmapHolder->bitmap().pixelStorageType() == PixelStorageType::Ashmem ? JNI_TRUE + : JNI_FALSE; +} + static void Bitmap_setImmutable(JNIEnv* env, jobject, jlong bitmapHandle) { LocalScopedBitmap bitmapHolder(bitmapHandle); if (!bitmapHolder.valid()) return; @@ -1157,12 +1298,11 @@ static const JNINativeMethod gBitmapMethods[] = { { "nativeSetImmutable", "(J)V", (void*)Bitmap_setImmutable}, // ------------ @CriticalNative ---------------- - { "nativeIsImmutable", "(J)Z", (void*)Bitmap_isImmutable} + { "nativeIsImmutable", "(J)Z", (void*)Bitmap_isImmutable}, + { "nativeIsBackedByAshmem", "(J)Z", (void*)Bitmap_isBackedByAshmem} }; -const char* const kParcelPathName = "android/os/Parcel"; - int register_android_graphics_Bitmap(JNIEnv* env) { gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap")); @@ -1180,9 +1320,6 @@ int register_android_graphics_Bitmap(JNIEnv* env) AHardwareBuffer_toHardwareBuffer = (AHB_to_HB)dlsym(handle_, "AHardwareBuffer_toHardwareBuffer"); LOG_ALWAYS_FATAL_IF(AHardwareBuffer_toHardwareBuffer == nullptr, " Failed to find required symbol AHardwareBuffer_toHardwareBuffer!"); - - gParcelOffsets.clazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, kParcelPathName)); - gParcelOffsets.mNativePtr = GetFieldIDOrDie(env, gParcelOffsets.clazz, "mNativePtr", "J"); #endif return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods, NELEM(gBitmapMethods)); diff --git a/libs/hwui/jni/BitmapFactory.cpp b/libs/hwui/jni/BitmapFactory.cpp index e8e89d81bdb7..7d2583a2ac01 100644 --- a/libs/hwui/jni/BitmapFactory.cpp +++ b/libs/hwui/jni/BitmapFactory.cpp @@ -3,12 +3,11 @@ #include "BitmapFactory.h" #include "CreateJavaOutputStreamAdaptor.h" +#include "FrontBufferedStream.h" #include "GraphicsJNI.h" #include "MimeType.h" #include "NinePatchPeeker.h" #include "SkAndroidCodec.h" -#include "SkBRDAllocator.h" -#include "SkFrontBufferedStream.h" #include "SkMath.h" #include "SkPixelRef.h" #include "SkStream.h" @@ -510,8 +509,8 @@ static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteA std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage)); if (stream.get()) { - std::unique_ptr<SkStreamRewindable> bufferedStream( - SkFrontBufferedStream::Make(std::move(stream), SkCodec::MinBufferedBytesNeeded())); + std::unique_ptr<SkStreamRewindable> bufferedStream(skia::FrontBufferedStream::Make( + std::move(stream), SkCodec::MinBufferedBytesNeeded())); SkASSERT(bufferedStream.get() != NULL); bitmap = doDecode(env, std::move(bufferedStream), padding, options, inBitmapHandle, colorSpaceHandle); @@ -565,8 +564,8 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi // Use a buffered stream. Although an SkFILEStream can be rewound, this // ensures that SkImageDecoder::Factory never rewinds beyond the // current position of the file descriptor. - std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Make(std::move(fileStream), - SkCodec::MinBufferedBytesNeeded())); + std::unique_ptr<SkStreamRewindable> stream(skia::FrontBufferedStream::Make( + std::move(fileStream), SkCodec::MinBufferedBytesNeeded())); return doDecode(env, std::move(stream), padding, bitmapFactoryOptions, inBitmapHandle, colorSpaceHandle); diff --git a/libs/hwui/jni/BitmapRegionDecoder.cpp b/libs/hwui/jni/BitmapRegionDecoder.cpp index 712351382d97..4cc05ef6f13b 100644 --- a/libs/hwui/jni/BitmapRegionDecoder.cpp +++ b/libs/hwui/jni/BitmapRegionDecoder.cpp @@ -22,8 +22,8 @@ #include "GraphicsJNI.h" #include "Utils.h" +#include "BitmapRegionDecoder.h" #include "SkBitmap.h" -#include "SkBitmapRegionDecoder.h" #include "SkCodec.h" #include "SkData.h" #include "SkStream.h" @@ -36,10 +36,8 @@ using namespace android; -static jobject createBitmapRegionDecoder(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream) { - std::unique_ptr<SkBitmapRegionDecoder> brd( - SkBitmapRegionDecoder::Create(stream.release(), - SkBitmapRegionDecoder::kAndroidCodec_Strategy)); +static jobject createBitmapRegionDecoder(JNIEnv* env, sk_sp<SkData> data) { + auto brd = skia::BitmapRegionDecoder::Make(std::move(data)); if (!brd) { doThrowIOE(env, "Image format not supported"); return nullObjectReturn("CreateBitmapRegionDecoder returned null"); @@ -49,21 +47,13 @@ static jobject createBitmapRegionDecoder(JNIEnv* env, std::unique_ptr<SkStreamRe } static jobject nativeNewInstanceFromByteArray(JNIEnv* env, jobject, jbyteArray byteArray, - jint offset, jint length, jboolean isShareable) { - /* If isShareable we could decide to just wrap the java array and - share it, but that means adding a globalref to the java array object - For now we just always copy the array's data if isShareable. - */ + jint offset, jint length) { AutoJavaByteArray ar(env, byteArray); - std::unique_ptr<SkMemoryStream> stream(new SkMemoryStream(ar.ptr() + offset, length, true)); - - // the decoder owns the stream. - jobject brd = createBitmapRegionDecoder(env, std::move(stream)); - return brd; + return createBitmapRegionDecoder(env, SkData::MakeWithCopy(ar.ptr() + offset, length)); } static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz, - jobject fileDescriptor, jboolean isShareable) { + jobject fileDescriptor) { NPE_CHECK_RETURN_ZERO(env, fileDescriptor); jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor); @@ -74,41 +64,28 @@ static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz, return nullObjectReturn("fstat return -1"); } - sk_sp<SkData> data(SkData::MakeFromFD(descriptor)); - std::unique_ptr<SkMemoryStream> stream(new SkMemoryStream(std::move(data))); - - // the decoder owns the stream. - jobject brd = createBitmapRegionDecoder(env, std::move(stream)); - return brd; + return createBitmapRegionDecoder(env, SkData::MakeFromFD(descriptor)); } -static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz, - jobject is, // InputStream - jbyteArray storage, // byte[] - jboolean isShareable) { - jobject brd = NULL; - // for now we don't allow shareable with java inputstreams - std::unique_ptr<SkStreamRewindable> stream(CopyJavaInputStream(env, is, storage)); - - if (stream) { - // the decoder owns the stream. - brd = createBitmapRegionDecoder(env, std::move(stream)); +static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz, jobject is, // InputStream + jbyteArray storage) { // byte[] + jobject brd = nullptr; + sk_sp<SkData> data = CopyJavaInputStream(env, is, storage); + + if (data) { + brd = createBitmapRegionDecoder(env, std::move(data)); } return brd; } -static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz, - jlong native_asset, // Asset - jboolean isShareable) { +static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz, jlong native_asset) { Asset* asset = reinterpret_cast<Asset*>(native_asset); - std::unique_ptr<SkMemoryStream> stream(CopyAssetToStream(asset)); - if (NULL == stream) { - return NULL; + sk_sp<SkData> data = CopyAssetToData(asset); + if (!data) { + return nullptr; } - // the decoder owns the stream. - jobject brd = createBitmapRegionDecoder(env, std::move(stream)); - return brd; + return createBitmapRegionDecoder(env, data); } /* @@ -158,7 +135,7 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in recycledBytes = recycledBitmap->getAllocationByteCount(); } - SkBitmapRegionDecoder* brd = reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle); + auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle); SkColorType decodeColorType = brd->computeOutputColorType(colorType); if (decodeColorType == kRGBA_F16_SkColorType && isHardware && !uirenderer::HardwareBitmapUploader::hasFP16Support()) { @@ -166,7 +143,7 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in } // Set up the pixel allocator - SkBRDAllocator* allocator = nullptr; + skia::BRDAllocator* allocator = nullptr; RecyclingClippingPixelAllocator recycleAlloc(recycledBitmap, recycledBytes); HeapAllocator heapAlloc; if (javaBitmap) { @@ -230,20 +207,17 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in } static jint nativeGetHeight(JNIEnv* env, jobject, jlong brdHandle) { - SkBitmapRegionDecoder* brd = - reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle); + auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle); return static_cast<jint>(brd->height()); } static jint nativeGetWidth(JNIEnv* env, jobject, jlong brdHandle) { - SkBitmapRegionDecoder* brd = - reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle); + auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle); return static_cast<jint>(brd->width()); } static void nativeClean(JNIEnv* env, jobject, jlong brdHandle) { - SkBitmapRegionDecoder* brd = - reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle); + auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle); delete brd; } @@ -261,22 +235,22 @@ static const JNINativeMethod gBitmapRegionDecoderMethods[] = { { "nativeClean", "(J)V", (void*)nativeClean}, { "nativeNewInstance", - "([BIIZ)Landroid/graphics/BitmapRegionDecoder;", + "([BII)Landroid/graphics/BitmapRegionDecoder;", (void*)nativeNewInstanceFromByteArray }, { "nativeNewInstance", - "(Ljava/io/InputStream;[BZ)Landroid/graphics/BitmapRegionDecoder;", + "(Ljava/io/InputStream;[B)Landroid/graphics/BitmapRegionDecoder;", (void*)nativeNewInstanceFromStream }, { "nativeNewInstance", - "(Ljava/io/FileDescriptor;Z)Landroid/graphics/BitmapRegionDecoder;", + "(Ljava/io/FileDescriptor;)Landroid/graphics/BitmapRegionDecoder;", (void*)nativeNewInstanceFromFileDescriptor }, { "nativeNewInstance", - "(JZ)Landroid/graphics/BitmapRegionDecoder;", + "(J)Landroid/graphics/BitmapRegionDecoder;", (void*)nativeNewInstanceFromAsset }, }; diff --git a/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp index f1c6b29204b2..785a5dc995ab 100644 --- a/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp +++ b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp @@ -177,8 +177,12 @@ SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream, jbyteArray s return JavaInputStreamAdaptor::Create(env, stream, storage, swallowExceptions); } -static SkMemoryStream* adaptor_to_mem_stream(SkStream* stream) { - SkASSERT(stream != NULL); +sk_sp<SkData> CopyJavaInputStream(JNIEnv* env, jobject inputStream, jbyteArray storage) { + std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, inputStream, storage)); + if (!stream) { + return nullptr; + } + size_t bufferSize = 4096; size_t streamLen = 0; size_t len; @@ -194,18 +198,7 @@ static SkMemoryStream* adaptor_to_mem_stream(SkStream* stream) { } data = (char*)sk_realloc_throw(data, streamLen); - SkMemoryStream* streamMem = new SkMemoryStream(); - streamMem->setMemoryOwned(data, streamLen); - return streamMem; -} - -SkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream, - jbyteArray storage) { - std::unique_ptr<SkStream> adaptor(CreateJavaInputStreamAdaptor(env, stream, storage)); - if (NULL == adaptor.get()) { - return NULL; - } - return adaptor_to_mem_stream(adaptor.get()); + return SkData::MakeFromMalloc(data, streamLen); } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/jni/CreateJavaOutputStreamAdaptor.h b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.h index 849418da01a1..bae40f1e8d2f 100644 --- a/libs/hwui/jni/CreateJavaOutputStreamAdaptor.h +++ b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.h @@ -2,6 +2,7 @@ #define _ANDROID_GRAPHICS_CREATE_JAVA_OUTPUT_STREAM_ADAPTOR_H_ #include "jni.h" +#include "SkData.h" class SkMemoryStream; class SkStream; @@ -27,15 +28,14 @@ SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream, jbyteArray s bool swallowExceptions = true); /** - * Copy a Java InputStream. The result will be rewindable. + * Copy a Java InputStream to an SkData. * @param env JNIEnv object. * @param stream Pointer to Java InputStream. * @param storage Java byte array for retrieving data from the * Java InputStream. - * @return SkStreamRewindable The data in stream will be copied - * to a new SkStreamRewindable. + * @return SkData containing the stream's data. */ -SkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream, jbyteArray storage); +sk_sp<SkData> CopyJavaInputStream(JNIEnv* env, jobject stream, jbyteArray storage); SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream, jbyteArray storage); diff --git a/libs/hwui/jni/Graphics.cpp b/libs/hwui/jni/Graphics.cpp index f76ecb4c9c8a..ecbb55ec878d 100644 --- a/libs/hwui/jni/Graphics.cpp +++ b/libs/hwui/jni/Graphics.cpp @@ -470,7 +470,7 @@ SkRegion* GraphicsJNI::getNativeRegion(JNIEnv* env, jobject region) /////////////////////////////////////////////////////////////////////////////////////////// -jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap) +jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, skia::BitmapRegionDecoder* bitmap) { ALOG_ASSERT(bitmap != NULL); diff --git a/libs/hwui/jni/GraphicsJNI.h b/libs/hwui/jni/GraphicsJNI.h index b58a740a4c27..79ab617411e3 100644 --- a/libs/hwui/jni/GraphicsJNI.h +++ b/libs/hwui/jni/GraphicsJNI.h @@ -4,8 +4,8 @@ #include <cutils/compiler.h> #include "Bitmap.h" +#include "BRDAllocator.h" #include "SkBitmap.h" -#include "SkBRDAllocator.h" #include "SkCodec.h" #include "SkPixelRef.h" #include "SkMallocPixelRef.h" @@ -17,10 +17,12 @@ #include "graphics_jni_helpers.h" -class SkBitmapRegionDecoder; class SkCanvas; namespace android { +namespace skia { + class BitmapRegionDecoder; +} class Paint; struct Typeface; } @@ -103,7 +105,8 @@ public: static jobject createRegion(JNIEnv* env, SkRegion* region); - static jobject createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap); + static jobject createBitmapRegionDecoder(JNIEnv* env, + android::skia::BitmapRegionDecoder* bitmap); /** * Given a bitmap we natively allocate a memory block to store the contents @@ -154,7 +157,7 @@ private: static JavaVM* mJavaVM; }; -class HeapAllocator : public SkBRDAllocator { +class HeapAllocator : public android::skia::BRDAllocator { public: HeapAllocator() { }; ~HeapAllocator() { }; @@ -181,7 +184,7 @@ private: * the decoded output to fit in the recycled bitmap if necessary. * This allocator implements that behavior. * - * Skia's SkBitmapRegionDecoder expects the memory that + * Skia's BitmapRegionDecoder expects the memory that * is allocated to be large enough to decode the entire region * that is requested. It will decode directly into the memory * that is provided. @@ -200,7 +203,7 @@ private: * reuse it again, given that it still may be in use from our * first allocation. */ -class RecyclingClippingPixelAllocator : public SkBRDAllocator { +class RecyclingClippingPixelAllocator : public android::skia::BRDAllocator { public: RecyclingClippingPixelAllocator(android::Bitmap* recycledBitmap, diff --git a/libs/hwui/jni/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp index 41d939bd6373..1f4fd230e55e 100644 --- a/libs/hwui/jni/ImageDecoder.cpp +++ b/libs/hwui/jni/ImageDecoder.cpp @@ -27,9 +27,9 @@ #include <hwui/ImageDecoder.h> #include <HardwareBitmapUploader.h> +#include <FrontBufferedStream.h> #include <SkAndroidCodec.h> #include <SkEncodedImageFormat.h> -#include <SkFrontBufferedStream.h> #include <SkStream.h> #include <androidfw/Asset.h> @@ -187,8 +187,7 @@ static jobject ImageDecoder_nCreateInputStream(JNIEnv* env, jobject /*clazz*/, } std::unique_ptr<SkStream> bufferedStream( - SkFrontBufferedStream::Make(std::move(stream), - SkCodec::MinBufferedBytesNeeded())); + skia::FrontBufferedStream::Make(std::move(stream), SkCodec::MinBufferedBytesNeeded())); return native_create(env, std::move(bufferedStream), source, preferAnimation); } diff --git a/libs/hwui/jni/Movie.cpp b/libs/hwui/jni/Movie.cpp index ede0ca8cda5b..bb8c99a73edf 100644 --- a/libs/hwui/jni/Movie.cpp +++ b/libs/hwui/jni/Movie.cpp @@ -1,7 +1,7 @@ #include "CreateJavaOutputStreamAdaptor.h" +#include "FrontBufferedStream.h" #include "GraphicsJNI.h" #include <nativehelper/ScopedLocalRef.h> -#include "SkFrontBufferedStream.h" #include "Movie.h" #include "SkStream.h" #include "SkUtils.h" @@ -100,10 +100,8 @@ static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) { // Need to buffer enough input to be able to rewind as much as might be read by a decoder // trying to determine the stream's format. The only decoder for movies is GIF, which // will only read 6. - // FIXME: Get this number from SkImageDecoder - // bufferedStream takes ownership of strm - std::unique_ptr<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Make( - std::unique_ptr<SkStream>(strm), 6)); + std::unique_ptr<SkStreamRewindable> bufferedStream( + android::skia::FrontBufferedStream::Make(std::unique_ptr<SkStream>(strm), 6)); SkASSERT(bufferedStream.get() != NULL); Movie* moov = Movie::DecodeStream(bufferedStream.get()); diff --git a/libs/hwui/jni/Utils.cpp b/libs/hwui/jni/Utils.cpp index 34fd6687d52c..ac2f5b77d23a 100644 --- a/libs/hwui/jni/Utils.cpp +++ b/libs/hwui/jni/Utils.cpp @@ -114,7 +114,7 @@ size_t AssetStreamAdaptor::read(void* buffer, size_t size) { return amount; } -SkMemoryStream* android::CopyAssetToStream(Asset* asset) { +sk_sp<SkData> android::CopyAssetToData(Asset* asset) { if (NULL == asset) { return NULL; } @@ -138,7 +138,7 @@ SkMemoryStream* android::CopyAssetToStream(Asset* asset) { return NULL; } - return new SkMemoryStream(std::move(data)); + return data; } jobject android::nullObjectReturn(const char msg[]) { diff --git a/libs/hwui/jni/Utils.h b/libs/hwui/jni/Utils.h index f628cc3c85ed..6cdf44d85a5a 100644 --- a/libs/hwui/jni/Utils.h +++ b/libs/hwui/jni/Utils.h @@ -46,12 +46,11 @@ private: }; /** - * Make a deep copy of the asset, and return it as a stream, or NULL if there + * Make a deep copy of the asset, and return it as an SkData, or NULL if there * was an error. - * FIXME: If we could "ref/reopen" the asset, we may not need to copy it here. */ -SkMemoryStream* CopyAssetToStream(Asset*); +sk_sp<SkData> CopyAssetToData(Asset*); /** Restore the file descriptor's offset in our destructor */ diff --git a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp index 54822f1f07e2..7c1422de0984 100644 --- a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp +++ b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp @@ -67,39 +67,7 @@ private: JavaVM* mVm; jobject mRunnable; }; - -class GlFunctorReleasedCallbackBridge : public GlFunctorLifecycleListener { -public: - GlFunctorReleasedCallbackBridge(JNIEnv* env, jobject javaCallback) { - mLooper = Looper::getForThread(); - mMessage = new InvokeRunnableMessage(env, javaCallback); - } - - virtual void onGlFunctorReleased(Functor* functor) override { - mLooper->sendMessage(mMessage, 0); - } - -private: - sp<Looper> mLooper; - sp<InvokeRunnableMessage> mMessage; -}; -#endif - -// ---------------- @FastNative ----------------------------- - -static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz, - jlong canvasPtr, jlong functorPtr, jobject releasedCallback) { -#ifdef __ANDROID__ // Layoutlib does not support GL - Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr); - Functor* functor = reinterpret_cast<Functor*>(functorPtr); - sp<GlFunctorReleasedCallbackBridge> bridge; - if (releasedCallback) { - bridge = new GlFunctorReleasedCallbackBridge(env, releasedCallback); - } - canvas->callDrawGLFunction(functor, bridge.get()); #endif -} - // ---------------- @CriticalNative ------------------------- @@ -124,10 +92,10 @@ static jint android_view_DisplayListCanvas_getMaxTextureSize(CRITICAL_JNI_PARAMS #endif } -static void android_view_DisplayListCanvas_insertReorderBarrier(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, +static void android_view_DisplayListCanvas_enableZ(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jboolean reorderEnable) { Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr); - canvas->insertReorderBarrier(reorderEnable); + canvas->enableZ(reorderEnable); } static jlong android_view_DisplayListCanvas_finishRecording(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr) { @@ -183,18 +151,12 @@ static void android_view_DisplayListCanvas_drawWebViewFunctor(CRITICAL_JNI_PARAM const char* const kClassPathName = "android/graphics/RecordingCanvas"; static JNINativeMethod gMethods[] = { - - // ------------ @FastNative ------------------ - - { "nCallDrawGLFunction", "(JJLjava/lang/Runnable;)V", - (void*) android_view_DisplayListCanvas_callDrawGLFunction }, - // ------------ @CriticalNative -------------- { "nCreateDisplayListCanvas", "(JII)J", (void*) android_view_DisplayListCanvas_createDisplayListCanvas }, { "nResetDisplayListCanvas", "(JJII)V", (void*) android_view_DisplayListCanvas_resetDisplayListCanvas }, { "nGetMaximumTextureWidth", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureSize }, { "nGetMaximumTextureHeight", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureSize }, - { "nInsertReorderBarrier", "(JZ)V", (void*) android_view_DisplayListCanvas_insertReorderBarrier }, + { "nEnableZ", "(JZ)V", (void*) android_view_DisplayListCanvas_enableZ }, { "nFinishRecording", "(J)J", (void*) android_view_DisplayListCanvas_finishRecording }, { "nDrawRenderNode", "(JJ)V", (void*) android_view_DisplayListCanvas_drawRenderNode }, { "nDrawTextureLayer", "(JJ)V", (void*) android_view_DisplayListCanvas_drawTextureLayer }, diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp index 9815e85db880..42743db3061c 100644 --- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp +++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp @@ -256,12 +256,6 @@ static void android_view_ThreadedRenderer_registerVectorDrawableAnimator(JNIEnv* rootRenderNode->addVectorDrawableAnimator(animator); } -static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz, - jlong functorPtr, jboolean waitForCompletion) { - Functor* functor = reinterpret_cast<Functor*>(functorPtr); - RenderProxy::invokeFunctor(functor, waitForCompletion); -} - static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz, jlong proxyPtr) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); @@ -593,6 +587,28 @@ static void android_view_ThreadedRenderer_preload(JNIEnv*, jclass) { RenderProxy::preload(); } +// Plumbs the display density down to DeviceInfo. +static void android_view_ThreadedRenderer_setDisplayDensityDpi(JNIEnv*, jclass, jint densityDpi) { + // Convert from dpi to density-independent pixels. + const float density = densityDpi / 160.0; + DeviceInfo::setDensity(density); +} + +static void android_view_ThreadedRenderer_initDisplayInfo(JNIEnv*, jclass, jint physicalWidth, + jint physicalHeight, jfloat refreshRate, + jfloat maxRefreshRate, + jint wideColorDataspace, + jlong appVsyncOffsetNanos, + jlong presentationDeadlineNanos) { + DeviceInfo::setWidth(physicalWidth); + DeviceInfo::setHeight(physicalHeight); + DeviceInfo::setRefreshRate(refreshRate); + DeviceInfo::setMaxRefreshRate(maxRefreshRate); + DeviceInfo::setWideColorDataspace(static_cast<ADataSpace>(wideColorDataspace)); + DeviceInfo::setAppVsyncOffsetNanos(appVsyncOffsetNanos); + DeviceInfo::setPresentationDeadlineNanos(presentationDeadlineNanos); +} + // ---------------------------------------------------------------------------- // HardwareRendererObserver // ---------------------------------------------------------------------------- @@ -637,67 +653,82 @@ static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, job const char* const kClassPathName = "android/graphics/HardwareRenderer"; static const JNINativeMethod gMethods[] = { - { "nRotateProcessStatsBuffer", "()V", (void*) android_view_ThreadedRenderer_rotateProcessStatsBuffer }, - { "nSetProcessStatsBuffer", "(I)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer }, - { "nGetRenderThreadTid", "(J)I", (void*) android_view_ThreadedRenderer_getRenderThreadTid }, - { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode }, - { "nCreateProxy", "(ZZJ)J", (void*) android_view_ThreadedRenderer_createProxy }, - { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy }, - { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties }, - { "nSetName", "(JLjava/lang/String;)V", (void*) android_view_ThreadedRenderer_setName }, - { "nSetSurface", "(JLandroid/view/Surface;Z)V", (void*) android_view_ThreadedRenderer_setSurface }, - { "nPause", "(J)Z", (void*) android_view_ThreadedRenderer_pause }, - { "nSetStopped", "(JZ)V", (void*) android_view_ThreadedRenderer_setStopped }, - { "nSetLightAlpha", "(JFF)V", (void*) android_view_ThreadedRenderer_setLightAlpha }, - { "nSetLightGeometry", "(JFFFF)V", (void*) android_view_ThreadedRenderer_setLightGeometry }, - { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque }, - { "nSetWideGamut", "(JZ)V", (void*) android_view_ThreadedRenderer_setWideGamut }, - { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame }, - { "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy }, - { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode }, - { "nRegisterVectorDrawableAnimator", "(JJ)V", (void*) android_view_ThreadedRenderer_registerVectorDrawableAnimator }, - { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor }, - { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer }, - { "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer }, - { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto }, - { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate }, - { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate }, - { "nDetachSurfaceTexture", "(JJ)V", (void*) android_view_ThreadedRenderer_detachSurfaceTexture }, - { "nDestroyHardwareResources", "(J)V", (void*) android_view_ThreadedRenderer_destroyHardwareResources }, - { "nTrimMemory", "(I)V", (void*) android_view_ThreadedRenderer_trimMemory }, - { "nOverrideProperty", "(Ljava/lang/String;Ljava/lang/String;)V", (void*) android_view_ThreadedRenderer_overrideProperty }, - { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence }, - { "nStopDrawing", "(J)V", (void*) android_view_ThreadedRenderer_stopDrawing }, - { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending }, - { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo }, - { "setupShadersDiskCache", "(Ljava/lang/String;Ljava/lang/String;)V", - (void*) android_view_ThreadedRenderer_setupShadersDiskCache }, - { "nAddRenderNode", "(JJZ)V", (void*) android_view_ThreadedRenderer_addRenderNode}, - { "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode}, - { "nDrawRenderNode", "(JJ)V", (void*) android_view_ThreadedRendererd_drawRenderNode}, - { "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds}, - { "nSetPictureCaptureCallback", "(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V", - (void*) android_view_ThreadedRenderer_setPictureCapturedCallbackJNI }, - { "nSetFrameCallback", "(JLandroid/graphics/HardwareRenderer$FrameDrawingCallback;)V", - (void*)android_view_ThreadedRenderer_setFrameCallback}, - { "nSetFrameCompleteCallback", "(JLandroid/graphics/HardwareRenderer$FrameCompleteCallback;)V", - (void*)android_view_ThreadedRenderer_setFrameCompleteCallback }, - { "nAddObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_addObserver }, - { "nRemoveObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_removeObserver }, - { "nCopySurfaceInto", "(Landroid/view/Surface;IIIIJ)I", - (void*)android_view_ThreadedRenderer_copySurfaceInto }, - { "nCreateHardwareBitmap", "(JII)Landroid/graphics/Bitmap;", - (void*)android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode }, - { "disableVsync", "()V", (void*)android_view_ThreadedRenderer_disableVsync }, - { "nSetHighContrastText", "(Z)V", (void*)android_view_ThreadedRenderer_setHighContrastText }, - { "nHackySetRTAnimationsEnabled", "(Z)V", - (void*)android_view_ThreadedRenderer_hackySetRTAnimationsEnabled }, - { "nSetDebuggingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDebuggingEnabled }, - { "nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess }, - { "nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority }, - { "nAllocateBuffers", "(J)V", (void*)android_view_ThreadedRenderer_allocateBuffers }, - { "nSetForceDark", "(JZ)V", (void*)android_view_ThreadedRenderer_setForceDark }, - { "preload", "()V", (void*)android_view_ThreadedRenderer_preload }, + {"nRotateProcessStatsBuffer", "()V", + (void*)android_view_ThreadedRenderer_rotateProcessStatsBuffer}, + {"nSetProcessStatsBuffer", "(I)V", + (void*)android_view_ThreadedRenderer_setProcessStatsBuffer}, + {"nGetRenderThreadTid", "(J)I", (void*)android_view_ThreadedRenderer_getRenderThreadTid}, + {"nCreateRootRenderNode", "()J", (void*)android_view_ThreadedRenderer_createRootRenderNode}, + {"nCreateProxy", "(ZZJ)J", (void*)android_view_ThreadedRenderer_createProxy}, + {"nDeleteProxy", "(J)V", (void*)android_view_ThreadedRenderer_deleteProxy}, + {"nLoadSystemProperties", "(J)Z", + (void*)android_view_ThreadedRenderer_loadSystemProperties}, + {"nSetName", "(JLjava/lang/String;)V", (void*)android_view_ThreadedRenderer_setName}, + {"nSetSurface", "(JLandroid/view/Surface;Z)V", + (void*)android_view_ThreadedRenderer_setSurface}, + {"nPause", "(J)Z", (void*)android_view_ThreadedRenderer_pause}, + {"nSetStopped", "(JZ)V", (void*)android_view_ThreadedRenderer_setStopped}, + {"nSetLightAlpha", "(JFF)V", (void*)android_view_ThreadedRenderer_setLightAlpha}, + {"nSetLightGeometry", "(JFFFF)V", (void*)android_view_ThreadedRenderer_setLightGeometry}, + {"nSetOpaque", "(JZ)V", (void*)android_view_ThreadedRenderer_setOpaque}, + {"nSetWideGamut", "(JZ)V", (void*)android_view_ThreadedRenderer_setWideGamut}, + {"nSyncAndDrawFrame", "(J[JI)I", (void*)android_view_ThreadedRenderer_syncAndDrawFrame}, + {"nDestroy", "(JJ)V", (void*)android_view_ThreadedRenderer_destroy}, + {"nRegisterAnimatingRenderNode", "(JJ)V", + (void*)android_view_ThreadedRenderer_registerAnimatingRenderNode}, + {"nRegisterVectorDrawableAnimator", "(JJ)V", + (void*)android_view_ThreadedRenderer_registerVectorDrawableAnimator}, + {"nCreateTextureLayer", "(J)J", (void*)android_view_ThreadedRenderer_createTextureLayer}, + {"nBuildLayer", "(JJ)V", (void*)android_view_ThreadedRenderer_buildLayer}, + {"nCopyLayerInto", "(JJJ)Z", (void*)android_view_ThreadedRenderer_copyLayerInto}, + {"nPushLayerUpdate", "(JJ)V", (void*)android_view_ThreadedRenderer_pushLayerUpdate}, + {"nCancelLayerUpdate", "(JJ)V", (void*)android_view_ThreadedRenderer_cancelLayerUpdate}, + {"nDetachSurfaceTexture", "(JJ)V", + (void*)android_view_ThreadedRenderer_detachSurfaceTexture}, + {"nDestroyHardwareResources", "(J)V", + (void*)android_view_ThreadedRenderer_destroyHardwareResources}, + {"nTrimMemory", "(I)V", (void*)android_view_ThreadedRenderer_trimMemory}, + {"nOverrideProperty", "(Ljava/lang/String;Ljava/lang/String;)V", + (void*)android_view_ThreadedRenderer_overrideProperty}, + {"nFence", "(J)V", (void*)android_view_ThreadedRenderer_fence}, + {"nStopDrawing", "(J)V", (void*)android_view_ThreadedRenderer_stopDrawing}, + {"nNotifyFramePending", "(J)V", (void*)android_view_ThreadedRenderer_notifyFramePending}, + {"nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", + (void*)android_view_ThreadedRenderer_dumpProfileInfo}, + {"setupShadersDiskCache", "(Ljava/lang/String;Ljava/lang/String;)V", + (void*)android_view_ThreadedRenderer_setupShadersDiskCache}, + {"nAddRenderNode", "(JJZ)V", (void*)android_view_ThreadedRenderer_addRenderNode}, + {"nRemoveRenderNode", "(JJ)V", (void*)android_view_ThreadedRenderer_removeRenderNode}, + {"nDrawRenderNode", "(JJ)V", (void*)android_view_ThreadedRendererd_drawRenderNode}, + {"nSetContentDrawBounds", "(JIIII)V", + (void*)android_view_ThreadedRenderer_setContentDrawBounds}, + {"nSetPictureCaptureCallback", + "(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V", + (void*)android_view_ThreadedRenderer_setPictureCapturedCallbackJNI}, + {"nSetFrameCallback", "(JLandroid/graphics/HardwareRenderer$FrameDrawingCallback;)V", + (void*)android_view_ThreadedRenderer_setFrameCallback}, + {"nSetFrameCompleteCallback", + "(JLandroid/graphics/HardwareRenderer$FrameCompleteCallback;)V", + (void*)android_view_ThreadedRenderer_setFrameCompleteCallback}, + {"nAddObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_addObserver}, + {"nRemoveObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_removeObserver}, + {"nCopySurfaceInto", "(Landroid/view/Surface;IIIIJ)I", + (void*)android_view_ThreadedRenderer_copySurfaceInto}, + {"nCreateHardwareBitmap", "(JII)Landroid/graphics/Bitmap;", + (void*)android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode}, + {"disableVsync", "()V", (void*)android_view_ThreadedRenderer_disableVsync}, + {"nSetHighContrastText", "(Z)V", (void*)android_view_ThreadedRenderer_setHighContrastText}, + {"nHackySetRTAnimationsEnabled", "(Z)V", + (void*)android_view_ThreadedRenderer_hackySetRTAnimationsEnabled}, + {"nSetDebuggingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDebuggingEnabled}, + {"nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess}, + {"nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority}, + {"nAllocateBuffers", "(J)V", (void*)android_view_ThreadedRenderer_allocateBuffers}, + {"nSetForceDark", "(JZ)V", (void*)android_view_ThreadedRenderer_setForceDark}, + {"nSetDisplayDensityDpi", "(I)V", + (void*)android_view_ThreadedRenderer_setDisplayDensityDpi}, + {"nInitDisplayInfo", "(IIFFIJJ)V", (void*)android_view_ThreadedRenderer_initDisplayInfo}, + {"preload", "()V", (void*)android_view_ThreadedRenderer_preload}, }; static JavaVM* mJvm = nullptr; diff --git a/libs/hwui/jni/android_graphics_TextureLayer.cpp b/libs/hwui/jni/android_graphics_TextureLayer.cpp index bd20269d3751..4dbb24ce4347 100644 --- a/libs/hwui/jni/android_graphics_TextureLayer.cpp +++ b/libs/hwui/jni/android_graphics_TextureLayer.cpp @@ -67,7 +67,7 @@ static void TextureLayer_updateSurfaceTexture(JNIEnv* env, jobject clazz, // JNI Glue // ---------------------------------------------------------------------------- -const char* const kClassPathName = "android/view/TextureLayer"; +const char* const kClassPathName = "android/graphics/TextureLayer"; static const JNINativeMethod gMethods[] = { { "nPrepare", "(JIIZ)Z", (void*) TextureLayer_prepare }, @@ -78,7 +78,7 @@ static const JNINativeMethod gMethods[] = { { "nUpdateSurfaceTexture", "(J)V", (void*) TextureLayer_updateSurfaceTexture }, }; -int register_android_view_TextureLayer(JNIEnv* env) { +int register_android_graphics_TextureLayer(JNIEnv* env) { return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); } diff --git a/libs/hwui/libhwui.map.txt b/libs/hwui/libhwui.map.txt new file mode 100644 index 000000000000..73de0d12a60b --- /dev/null +++ b/libs/hwui/libhwui.map.txt @@ -0,0 +1,70 @@ +LIBHWUI { + global: + /* listing of all C APIs to be exposed by libhwui to consumers outside of the module */ + ABitmap_getInfoFromJava; + ABitmap_acquireBitmapFromJava; + ABitmap_copy; + ABitmap_acquireRef; + ABitmap_releaseRef; + ABitmap_getInfo; + ABitmap_getDataSpace; + ABitmap_getPixels; + ABitmap_notifyPixelsChanged; + ABitmapConfig_getFormatFromConfig; + ABitmapConfig_getConfigFromFormat; + ABitmap_compress; + ABitmap_getHardwareBuffer; + ACanvas_isSupportedPixelFormat; + ACanvas_getNativeHandleFromJava; + ACanvas_createCanvas; + ACanvas_destroyCanvas; + ACanvas_setBuffer; + ACanvas_clipRect; + ACanvas_clipOutRect; + ACanvas_drawRect; + ACanvas_drawBitmap; + init_android_graphics; + register_android_graphics_classes; + register_android_graphics_GraphicsStatsService; + zygote_preload_graphics; + AMatrix_getContents; + APaint_createPaint; + APaint_destroyPaint; + APaint_setBlendMode; + ARegionIterator_acquireIterator; + ARegionIterator_releaseIterator; + ARegionIterator_isComplex; + ARegionIterator_isDone; + ARegionIterator_next; + ARegionIterator_getRect; + ARegionIterator_getTotalBounds; + ARenderThread_dumpGraphicsMemory; + local: + *; +}; + +LIBHWUI_PLATFORM { + global: + extern "C++" { + /* required by libwebviewchromium_plat_support */ + android::uirenderer::ColorSpaceToADataSpace*; + android::uirenderer::WebViewFunctor_*; + GraphicsJNI::getNativeCanvas*; + SkCanvasStateUtils::ReleaseCanvasState*; + SkColorSpace::toXYZD50*; + SkColorSpace::transferFn*; + /* required by libjnigraphics */ + android::ImageDecoder::*; + android::uirenderer::DataSpaceToColorSpace*; + android::uirenderer::ColorSpaceToADataSpace*; + getMimeType*; + SkAndroidCodec::*; + SkCodec::MakeFromStream*; + SkColorInfo::*; + SkFILEStream::SkFILEStream*; + SkImageInfo::*; + SkMemoryStream::SkMemoryStream*; + }; + local: + *; +}; diff --git a/libs/hwui/pipeline/skia/FunctorDrawable.h b/libs/hwui/pipeline/skia/FunctorDrawable.h index cf2f93b95e71..988a896b6267 100644 --- a/libs/hwui/pipeline/skia/FunctorDrawable.h +++ b/libs/hwui/pipeline/skia/FunctorDrawable.h @@ -16,8 +16,6 @@ #pragma once -#include "GlFunctorLifecycleListener.h" - #include <SkCanvas.h> #include <SkDrawable.h> @@ -36,44 +34,21 @@ namespace skiapipeline { */ class FunctorDrawable : public SkDrawable { public: - FunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas) - : mBounds(canvas->getLocalClipBounds()) - , mAnyFunctor(std::in_place_type<LegacyFunctor>, functor, listener) {} - FunctorDrawable(int functor, SkCanvas* canvas) : mBounds(canvas->getLocalClipBounds()) - , mAnyFunctor(std::in_place_type<NewFunctor>, functor) {} + , mWebViewHandle(WebViewFunctorManager::instance().handleFor(functor)) {} virtual ~FunctorDrawable() {} virtual void syncFunctor(const WebViewSyncData& data) const { - if (mAnyFunctor.index() == 0) { - std::get<0>(mAnyFunctor).handle->sync(data); - } else { - (*(std::get<1>(mAnyFunctor).functor))(DrawGlInfo::kModeSync, nullptr); - } + mWebViewHandle->sync(data); } protected: virtual SkRect onGetBounds() override { return mBounds; } const SkRect mBounds; - - struct LegacyFunctor { - explicit LegacyFunctor(Functor* functor, GlFunctorLifecycleListener* listener) - : functor(functor), listener(listener) {} - Functor* functor; - sp<GlFunctorLifecycleListener> listener; - }; - - struct NewFunctor { - explicit NewFunctor(int functor) { - handle = WebViewFunctorManager::instance().handleFor(functor); - } - sp<WebViewFunctor::Handle> handle; - }; - - std::variant<NewFunctor, LegacyFunctor> mAnyFunctor; + sp<WebViewFunctor::Handle> mWebViewHandle; }; } // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp index aa8849b642b1..f502fc34f7b7 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp @@ -18,7 +18,6 @@ #include <GrContext.h> #include <private/hwui/DrawGlInfo.h> #include "FunctorDrawable.h" -#include "GlFunctorLifecycleListener.h" #include "GrBackendSurface.h" #include "GrRenderTarget.h" #include "GrRenderTargetContext.h" @@ -26,20 +25,12 @@ #include "SkAndroidFrameworkUtils.h" #include "SkClipStack.h" #include "SkRect.h" -#include "include/private/SkM44.h" +#include "SkM44.h" namespace android { namespace uirenderer { namespace skiapipeline { -GLFunctorDrawable::~GLFunctorDrawable() { - if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) { - if (lp->listener) { - lp->listener->onGlFunctorReleased(lp->functor); - } - } -} - static void setScissor(int viewportHeight, const SkIRect& clip) { SkASSERT(!clip.isEmpty()); // transform to Y-flipped GL space, and prevent negatives @@ -93,7 +84,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { SkIRect surfaceBounds = canvas->internal_private_getTopLayerBounds(); SkIRect clipBounds = canvas->getDeviceClipBounds(); - SkM44 mat4(canvas->experimental_getLocalToDevice()); + SkM44 mat4(canvas->getLocalToDevice()); SkRegion clipRegion; canvas->temporary_internal_getRgnClip(&clipRegion); @@ -195,11 +186,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { setScissor(info.height, clipRegion.getBounds()); } - if (mAnyFunctor.index() == 0) { - std::get<0>(mAnyFunctor).handle->drawGl(info); - } else { - (*(std::get<1>(mAnyFunctor).functor))(DrawGlInfo::kModeDraw, &info); - } + mWebViewHandle->drawGl(info); if (clearStencilAfterFunctor) { // clear stencil buffer as it may be used by Skia diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.h b/libs/hwui/pipeline/skia/GLFunctorDrawable.h index 2ea4f67428bc..4092e8dfa3a5 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.h +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.h @@ -33,7 +33,7 @@ class GLFunctorDrawable : public FunctorDrawable { public: using FunctorDrawable::FunctorDrawable; - virtual ~GLFunctorDrawable(); + virtual ~GLFunctorDrawable() {} protected: void onDraw(SkCanvas* canvas) override; diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h index 0898017d52a1..5b8e668a56f4 100644 --- a/libs/hwui/pipeline/skia/ShaderCache.h +++ b/libs/hwui/pipeline/skia/ShaderCache.h @@ -37,7 +37,7 @@ public: * "get" returns a pointer to the singleton ShaderCache object. This * singleton object will never be destroyed. */ - ANDROID_API static ShaderCache& get(); + static ShaderCache& get(); /** * initShaderDiskCache" loads the serialized cache contents from disk, diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 5088494d6a07..89a1c713ef62 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -145,7 +145,7 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque) if (cachedContext.get() != currentContext) { if (cachedContext.get()) { ATRACE_NAME("flush layers (context changed)"); - cachedContext->flush(); + cachedContext->flushAndSubmit(); } cachedContext.reset(SkSafeRef(currentContext)); } @@ -153,7 +153,7 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque) if (cachedContext.get()) { ATRACE_NAME("flush layers"); - cachedContext->flush(); + cachedContext->flushAndSubmit(); } } @@ -450,7 +450,7 @@ void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& cli } ATRACE_NAME("flush commands"); - surface->getCanvas()->flush(); + surface->flushAndSubmit(); Properties::skpCaptureEnabled = previousSkpEnabled; } diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index d67cf8c9c73f..e292cbdd101f 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -57,7 +57,7 @@ void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, in uirenderer::DisplayList* SkiaRecordingCanvas::finishRecording() { // close any existing chunks if necessary - insertReorderBarrier(false); + enableZ(false); mRecorder.restoreToCount(1); return mDisplayList.release(); } @@ -85,8 +85,8 @@ void SkiaRecordingCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x, drawDrawable(mDisplayList->allocateDrawable<AnimatedCircle>(x, y, radius, paint)); } -void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) { - if (mCurrentBarrier && enableReorder) { +void SkiaRecordingCanvas::enableZ(bool enableZ) { + if (mCurrentBarrier && enableZ) { // Already in a re-order section, nothing to do return; } @@ -98,7 +98,7 @@ void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) { mCurrentBarrier = nullptr; drawDrawable(drawable); } - if (enableReorder) { + if (enableZ) { mCurrentBarrier = mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(mDisplayList.get()); drawDrawable(mCurrentBarrier); @@ -132,23 +132,6 @@ void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) { } } - -void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor, - uirenderer::GlFunctorLifecycleListener* listener) { -#ifdef __ANDROID__ // Layoutlib does not support GL, Vulcan etc. - FunctorDrawable* functorDrawable; - if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { - functorDrawable = mDisplayList->allocateDrawable<VkInteropFunctorDrawable>( - functor, listener, asSkCanvas()); - } else { - functorDrawable = - mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, listener, asSkCanvas()); - } - mDisplayList->mChildFunctors.push_back(functorDrawable); - drawDrawable(functorDrawable); -#endif -} - void SkiaRecordingCanvas::drawWebViewFunctor(int functor) { #ifdef __ANDROID__ // Layoutlib does not support GL, Vulcan etc. FunctorDrawable* functorDrawable; diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h index bd5274c94e75..83e934974afd 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h @@ -69,11 +69,10 @@ public: virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override; - virtual void insertReorderBarrier(bool enableReorder) override; + virtual void enableZ(bool enableZ) override; virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override; virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override; - virtual void callDrawGLFunction(Functor* functor, - uirenderer::GlFunctorLifecycleListener* listener) override; + void drawWebViewFunctor(int functor) override; private: diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp index 68f111752a4c..50b45e6eb7ec 100644 --- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp @@ -20,7 +20,7 @@ #include <GrBackendDrawableInfo.h> #include <SkAndroidFrameworkUtils.h> #include <SkImage.h> -#include "include/private/SkM44.h" +#include <SkM44.h> #include <utils/Color.h> #include <utils/Trace.h> #include <utils/TraceUtils.h> @@ -121,12 +121,7 @@ std::unique_ptr<FunctorDrawable::GpuDrawHandler> VkFunctorDrawable::onSnapGpuDra return nullptr; } std::unique_ptr<VkFunctorDrawHandler> draw; - if (mAnyFunctor.index() == 0) { - return std::make_unique<VkFunctorDrawHandler>(std::get<0>(mAnyFunctor).handle, matrix, clip, - image_info); - } else { - LOG_ALWAYS_FATAL("Not implemented"); - } + return std::make_unique<VkFunctorDrawHandler>(mWebViewHandle, matrix, clip, image_info); } } // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkFunctorDrawable.h index d3f97773b91d..fbfc6e76595e 100644 --- a/libs/hwui/pipeline/skia/VkFunctorDrawable.h +++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.h @@ -19,7 +19,6 @@ #include "FunctorDrawable.h" #include <SkImageInfo.h> -#include <ui/GraphicBuffer.h> #include <utils/RefBase.h> namespace android { diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp index 241d3708def5..403d9075dbd1 100644 --- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp @@ -15,23 +15,24 @@ */ #include "VkInteropFunctorDrawable.h" -#include <private/hwui/DrawGlInfo.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <GLES3/gl3.h> +#include <private/hwui/DrawGlInfo.h> #include <utils/Color.h> +#include <utils/GLUtils.h> #include <utils/Trace.h> #include <utils/TraceUtils.h> + #include <thread> + #include "renderthread/EglManager.h" #include "thread/ThreadBase.h" #include "utils/TimeUtils.h" -#include <EGL/eglext.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#include <GLES3/gl3.h> - -#include <utils/GLUtils.h> - namespace android { namespace uirenderer { namespace skiapipeline { @@ -75,20 +76,23 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { SkImageInfo surfaceInfo = canvas->imageInfo(); - if (!mFrameBuffer.get() || mFBInfo != surfaceInfo) { + if (mFrameBuffer == nullptr || mFBInfo != surfaceInfo) { // Buffer will be used as an OpenGL ES render target. - mFrameBuffer = new GraphicBuffer( - // TODO: try to reduce the size of the buffer: possibly by using clip bounds. - static_cast<uint32_t>(surfaceInfo.width()), - static_cast<uint32_t>(surfaceInfo.height()), - ColorTypeToPixelFormat(surfaceInfo.colorType()), - GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER | - GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_HW_RENDER, - std::string("VkInteropFunctorDrawable::onDraw pid [") + std::to_string(getpid()) + - "]"); - status_t error = mFrameBuffer->initCheck(); - if (error < 0) { - ALOGW("VkInteropFunctorDrawable::onDraw() failed in GraphicBuffer.create()"); + AHardwareBuffer_Desc desc = { + .width = static_cast<uint32_t>(surfaceInfo.width()), + .height = static_cast<uint32_t>(surfaceInfo.height()), + .layers = 1, + .format = ColorTypeToBufferFormat(surfaceInfo.colorType()), + .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | + AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER | + AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | + AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, + }; + + mFrameBuffer = allocateAHardwareBuffer(desc); + + if (!mFrameBuffer) { + ALOGW("VkInteropFunctorDrawable::onDraw() failed in AHardwareBuffer_allocate()"); return; } @@ -106,7 +110,7 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { uirenderer::renderthread::EglManager::eglErrorString()); // We use an EGLImage to access the content of the GraphicBuffer // The EGL image is later bound to a 2D texture - EGLClientBuffer clientBuffer = (EGLClientBuffer)mFrameBuffer->getNativeBuffer(); + const EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(mFrameBuffer.get()); AutoEglImage autoImage(display, clientBuffer); if (autoImage.image == EGL_NO_IMAGE_KHR) { ALOGW("Could not create EGL image, err =%s", @@ -121,7 +125,7 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { glBindTexture(GL_TEXTURE_2D, 0); DrawGlInfo info; - SkM44 mat4(canvas->experimental_getLocalToDevice()); + SkM44 mat4(canvas->getLocalToDevice()); SkIRect clipBounds = canvas->getDeviceClipBounds(); info.clipLeft = clipBounds.fLeft; @@ -151,11 +155,7 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); - if (mAnyFunctor.index() == 0) { - std::get<0>(mAnyFunctor).handle->drawGl(info); - } else { - (*(std::get<1>(mAnyFunctor).functor))(DrawGlInfo::kModeDraw, &info); - } + mWebViewHandle->drawGl(info); EGLSyncKHR glDrawFinishedFence = eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL); @@ -179,22 +179,13 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { // drawing into the offscreen surface, so we need to reset it here. canvas->resetMatrix(); - auto functorImage = SkImage::MakeFromAHardwareBuffer( - reinterpret_cast<AHardwareBuffer*>(mFrameBuffer.get()), kPremul_SkAlphaType, - canvas->imageInfo().refColorSpace(), kBottomLeft_GrSurfaceOrigin); + auto functorImage = SkImage::MakeFromAHardwareBuffer(mFrameBuffer.get(), kPremul_SkAlphaType, + canvas->imageInfo().refColorSpace(), + kBottomLeft_GrSurfaceOrigin); canvas->drawImage(functorImage, 0, 0, &paint); canvas->restore(); } -VkInteropFunctorDrawable::~VkInteropFunctorDrawable() { - if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) { - if (lp->listener) { - ScopedDrawRequest _drawRequest{}; - lp->listener->onGlFunctorReleased(lp->functor); - } - } -} - void VkInteropFunctorDrawable::syncFunctor(const WebViewSyncData& data) const { ScopedDrawRequest _drawRequest{}; FunctorDrawable::syncFunctor(data); diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h index c47ee114263f..e6ea175929c0 100644 --- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h +++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h @@ -16,11 +16,12 @@ #pragma once -#include "FunctorDrawable.h" - -#include <ui/GraphicBuffer.h> +#include <android/hardware_buffer.h> +#include <utils/NdkUtils.h> #include <utils/RefBase.h> +#include "FunctorDrawable.h" + namespace android { namespace uirenderer { @@ -34,7 +35,7 @@ class VkInteropFunctorDrawable : public FunctorDrawable { public: using FunctorDrawable::FunctorDrawable; - virtual ~VkInteropFunctorDrawable(); + virtual ~VkInteropFunctorDrawable() {} static void vkInvokeFunctor(Functor* functor); @@ -45,7 +46,7 @@ protected: private: // Variables below describe/store temporary offscreen buffer used for Vulkan pipeline. - sp<GraphicBuffer> mFrameBuffer; + UniqueAHardwareBuffer mFrameBuffer; SkImageInfo mFBInfo; }; diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index 1e5877356e8d..b57dee4897ac 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -101,7 +101,7 @@ void CacheManager::trimMemory(TrimMemoryMode mode) { return; } - mGrContext->flush(); + mGrContext->flushAndSubmit(); switch (mode) { case TrimMemoryMode::Complete: @@ -122,14 +122,15 @@ void CacheManager::trimMemory(TrimMemoryMode mode) { // We must sync the cpu to make sure deletions of resources still queued up on the GPU actually // happen. - mGrContext->flush(kSyncCpu_GrFlushFlag, 0, nullptr); + mGrContext->flush({}); + mGrContext->submit(true); } void CacheManager::trimStaleResources() { if (!mGrContext) { return; } - mGrContext->flush(); + mGrContext->flushAndSubmit(); mGrContext->purgeResourcesNotUsedInMs(std::chrono::seconds(30)); } diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 0f1b8aebf56c..0306eeccc5d4 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -170,9 +170,9 @@ public: } // Used to queue up work that needs to be completed before this frame completes - ANDROID_API void enqueueFrameWork(std::function<void()>&& func); + void enqueueFrameWork(std::function<void()>&& func); - ANDROID_API int64_t getFrameNumber(); + int64_t getFrameNumber(); void waitOnFences(); diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 5e0471c08d67..c7013531c07f 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -136,7 +136,7 @@ void EglManager::initialize() { LOG_ALWAYS_FATAL_IF(!DeviceInfo::get()->getWideColorSpace()->toXYZD50(&wideColorGamut), "Could not get gamut matrix from wideColorSpace"); bool hasWideColorSpaceExtension = false; - if (memcmp(&wideColorGamut, &SkNamedGamut::kDCIP3, sizeof(wideColorGamut)) == 0) { + if (memcmp(&wideColorGamut, &SkNamedGamut::kDisplayP3, sizeof(wideColorGamut)) == 0) { hasWideColorSpaceExtension = EglExtensions.displayP3; } else if (memcmp(&wideColorGamut, &SkNamedGamut::kSRGB, sizeof(wideColorGamut)) == 0) { hasWideColorSpaceExtension = EglExtensions.scRGB; @@ -208,8 +208,12 @@ EGLConfig EglManager::loadFP16Config(EGLDisplay display, SwapBehavior swapBehavi return config; } +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); + void EglManager::initExtensions() { auto extensions = StringUtils::split(eglQueryString(mEglDisplay, EGL_EXTENSIONS)); + auto extensionsAndroid = + StringUtils::split(eglQueryStringImplementationANDROID(mEglDisplay, EGL_EXTENSIONS)); // For our purposes we don't care if EGL_BUFFER_AGE is a result of // EGL_EXT_buffer_age or EGL_KHR_partial_update as our usage is covered @@ -228,9 +232,12 @@ void EglManager::initExtensions() { EglExtensions.displayP3 = extensions.has("EGL_EXT_gl_colorspace_display_p3_passthrough"); EglExtensions.contextPriority = extensions.has("EGL_IMG_context_priority"); EglExtensions.surfacelessContext = extensions.has("EGL_KHR_surfaceless_context"); - EglExtensions.nativeFenceSync = extensions.has("EGL_ANDROID_native_fence_sync"); EglExtensions.fenceSync = extensions.has("EGL_KHR_fence_sync"); EglExtensions.waitSync = extensions.has("EGL_KHR_wait_sync"); + + // EGL_ANDROID_native_fence_sync is not exposed to applications, so access + // this through the private Android-specific query instead. + EglExtensions.nativeFenceSync = extensionsAndroid.has("EGL_ANDROID_native_fence_sync"); } bool EglManager::hasEglContext() { @@ -337,7 +344,7 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window, skcms_Matrix3x3 colorGamut; LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&colorGamut), "Could not get gamut matrix from color space"); - if (memcmp(&colorGamut, &SkNamedGamut::kDCIP3, sizeof(colorGamut)) == 0) { + if (memcmp(&colorGamut, &SkNamedGamut::kDisplayP3, sizeof(colorGamut)) == 0) { attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT; } else if (memcmp(&colorGamut, &SkNamedGamut::kSRGB, sizeof(colorGamut)) == 0) { attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT; diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h index a893e245b214..f67fb31db951 100644 --- a/libs/hwui/renderthread/EglManager.h +++ b/libs/hwui/renderthread/EglManager.h @@ -21,7 +21,6 @@ #include <SkImageInfo.h> #include <SkRect.h> #include <cutils/compiler.h> -#include <ui/GraphicBuffer.h> #include <utils/StrongPointer.h> #include "IRenderPipeline.h" diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp index dcf1fc189588..c29cc11fa7ea 100644 --- a/libs/hwui/renderthread/ReliableSurface.cpp +++ b/libs/hwui/renderthread/ReliableSurface.cpp @@ -149,21 +149,25 @@ ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer(int error) { return AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get()); } - AHardwareBuffer_Desc desc; - desc.usage = mUsage; - desc.format = mFormat; - desc.width = 1; - desc.height = 1; - desc.layers = 1; - desc.rfu0 = 0; - desc.rfu1 = 0; - AHardwareBuffer* newBuffer = nullptr; - int err = AHardwareBuffer_allocate(&desc, &newBuffer); - if (err) { + AHardwareBuffer_Desc desc = AHardwareBuffer_Desc{ + .usage = mUsage, + .format = mFormat, + .width = 1, + .height = 1, + .layers = 1, + .rfu0 = 0, + .rfu1 = 0, + }; + + AHardwareBuffer* newBuffer; + int result = AHardwareBuffer_allocate(&desc, &newBuffer); + + if (result != NO_ERROR) { // Allocate failed, that sucks - ALOGW("Failed to allocate scratch buffer, error=%d", err); + ALOGW("Failed to allocate scratch buffer, error=%d", result); return nullptr; } + mScratchBuffer.reset(newBuffer); return AHardwareBuffer_to_ANativeWindowBuffer(newBuffer); } diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h index f699eb1fe6b3..41969e776fc8 100644 --- a/libs/hwui/renderthread/ReliableSurface.h +++ b/libs/hwui/renderthread/ReliableSurface.h @@ -21,6 +21,7 @@ #include <apex/window.h> #include <utils/Errors.h> #include <utils/Macros.h> +#include <utils/NdkUtils.h> #include <utils/StrongPointer.h> #include <memory> @@ -67,8 +68,7 @@ private: uint64_t mUsage = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER; AHardwareBuffer_Format mFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; - std::unique_ptr<AHardwareBuffer, void (*)(AHardwareBuffer*)> mScratchBuffer{ - nullptr, AHardwareBuffer_release}; + UniqueAHardwareBuffer mScratchBuffer; ANativeWindowBuffer* mReservedBuffer = nullptr; base::unique_fd mReservedFenceFd; bool mHasDequeuedBuffer = false; diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index b66a13d1efda..b764f74bf116 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -128,20 +128,6 @@ void RenderProxy::destroy() { mRenderThread.queue().runSync([=]() { mContext->destroy(); }); } -void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) { - ATRACE_CALL(); - RenderThread& thread = RenderThread::getInstance(); - auto invoke = [&thread, functor]() { CanvasContext::invokeFunctor(thread, functor); }; - if (waitForCompletion) { - // waitForCompletion = true is expected to be fairly rare and only - // happen in destruction. Thus it should be fine to temporarily - // create a Mutex - thread.queue().runSync(std::move(invoke)); - } else { - thread.queue().post(std::move(invoke)); - } -} - void RenderProxy::destroyFunctor(int functor) { ATRACE_CALL(); RenderThread& thread = RenderThread::getInstance(); diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 3baeb2f7a476..16eabadc064c 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -60,69 +60,67 @@ enum { * references RenderProxy fields. This is safe as RenderProxy cannot * be deleted if it is blocked inside a call. */ -class ANDROID_API RenderProxy { +class RenderProxy { public: - ANDROID_API RenderProxy(bool opaque, RenderNode* rootNode, IContextFactory* contextFactory); - ANDROID_API virtual ~RenderProxy(); + RenderProxy(bool opaque, RenderNode* rootNode, IContextFactory* contextFactory); + virtual ~RenderProxy(); // Won't take effect until next EGLSurface creation - ANDROID_API void setSwapBehavior(SwapBehavior swapBehavior); - ANDROID_API bool loadSystemProperties(); - ANDROID_API void setName(const char* name); - - ANDROID_API void setSurface(ANativeWindow* window, bool enableTimeout = true); - ANDROID_API void allocateBuffers(); - ANDROID_API bool pause(); - ANDROID_API void setStopped(bool stopped); - ANDROID_API void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); - ANDROID_API void setLightGeometry(const Vector3& lightCenter, float lightRadius); - ANDROID_API void setOpaque(bool opaque); - ANDROID_API void setWideGamut(bool wideGamut); - ANDROID_API int64_t* frameInfo(); - ANDROID_API int syncAndDrawFrame(); - ANDROID_API void destroy(); - - ANDROID_API static void invokeFunctor(Functor* functor, bool waitForCompletion); + void setSwapBehavior(SwapBehavior swapBehavior); + bool loadSystemProperties(); + void setName(const char* name); + + void setSurface(ANativeWindow* window, bool enableTimeout = true); + void allocateBuffers(); + bool pause(); + void setStopped(bool stopped); + void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); + void setLightGeometry(const Vector3& lightCenter, float lightRadius); + void setOpaque(bool opaque); + void setWideGamut(bool wideGamut); + int64_t* frameInfo(); + int syncAndDrawFrame(); + void destroy(); + static void destroyFunctor(int functor); - ANDROID_API DeferredLayerUpdater* createTextureLayer(); - ANDROID_API void buildLayer(RenderNode* node); - ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap); - ANDROID_API void pushLayerUpdate(DeferredLayerUpdater* layer); - ANDROID_API void cancelLayerUpdate(DeferredLayerUpdater* layer); - ANDROID_API void detachSurfaceTexture(DeferredLayerUpdater* layer); + DeferredLayerUpdater* createTextureLayer(); + void buildLayer(RenderNode* node); + bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap); + void pushLayerUpdate(DeferredLayerUpdater* layer); + void cancelLayerUpdate(DeferredLayerUpdater* layer); + void detachSurfaceTexture(DeferredLayerUpdater* layer); - ANDROID_API void destroyHardwareResources(); - ANDROID_API static void trimMemory(int level); - ANDROID_API static void overrideProperty(const char* name, const char* value); + void destroyHardwareResources(); + static void trimMemory(int level); + static void overrideProperty(const char* name, const char* value); - ANDROID_API void fence(); - ANDROID_API static int maxTextureSize(); - ANDROID_API void stopDrawing(); - ANDROID_API void notifyFramePending(); + void fence(); + static int maxTextureSize(); + void stopDrawing(); + void notifyFramePending(); - ANDROID_API void dumpProfileInfo(int fd, int dumpFlags); + void dumpProfileInfo(int fd, int dumpFlags); // Not exported, only used for testing void resetProfileInfo(); uint32_t frameTimePercentile(int p); - ANDROID_API static void dumpGraphicsMemory(int fd); + static void dumpGraphicsMemory(int fd); - ANDROID_API static void rotateProcessStatsBuffer(); - ANDROID_API static void setProcessStatsBuffer(int fd); - ANDROID_API int getRenderThreadTid(); + static void rotateProcessStatsBuffer(); + static void setProcessStatsBuffer(int fd); + int getRenderThreadTid(); - ANDROID_API void addRenderNode(RenderNode* node, bool placeFront); - ANDROID_API void removeRenderNode(RenderNode* node); - ANDROID_API void drawRenderNode(RenderNode* node); - ANDROID_API void setContentDrawBounds(int left, int top, int right, int bottom); - ANDROID_API void setPictureCapturedCallback( - const std::function<void(sk_sp<SkPicture>&&)>& callback); - ANDROID_API void setFrameCallback(std::function<void(int64_t)>&& callback); - ANDROID_API void setFrameCompleteCallback(std::function<void(int64_t)>&& callback); + void addRenderNode(RenderNode* node, bool placeFront); + void removeRenderNode(RenderNode* node); + void drawRenderNode(RenderNode* node); + void setContentDrawBounds(int left, int top, int right, int bottom); + void setPictureCapturedCallback(const std::function<void(sk_sp<SkPicture>&&)>& callback); + void setFrameCallback(std::function<void(int64_t)>&& callback); + void setFrameCompleteCallback(std::function<void(int64_t)>&& callback); - ANDROID_API void addFrameMetricsObserver(FrameMetricsObserver* observer); - ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer); - ANDROID_API void setForceDark(bool enable); + void addFrameMetricsObserver(FrameMetricsObserver* observer); + void removeFrameMetricsObserver(FrameMetricsObserver* observer); + void setForceDark(bool enable); /** * Sets a render-ahead depth on the backing renderer. This will increase latency by @@ -139,17 +137,17 @@ public: * * @param renderAhead How far to render ahead, must be in the range [0..2] */ - ANDROID_API void setRenderAheadDepth(int renderAhead); + void setRenderAheadDepth(int renderAhead); - ANDROID_API static int copySurfaceInto(ANativeWindow* window, int left, int top, int right, + static int copySurfaceInto(ANativeWindow* window, int left, int top, int right, int bottom, SkBitmap* bitmap); - ANDROID_API static void prepareToDraw(Bitmap& bitmap); + static void prepareToDraw(Bitmap& bitmap); static int copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap); - ANDROID_API static void disableVsync(); + static void disableVsync(); - ANDROID_API static void preload(); + static void preload(); private: RenderThread& mRenderThread; diff --git a/libs/hwui/renderthread/RenderTask.h b/libs/hwui/renderthread/RenderTask.h index c56a3578ad58..3e3a381d65fe 100644 --- a/libs/hwui/renderthread/RenderTask.h +++ b/libs/hwui/renderthread/RenderTask.h @@ -45,12 +45,12 @@ namespace renderthread { * malloc/free churn of small objects? */ -class ANDROID_API RenderTask { +class RenderTask { public: - ANDROID_API RenderTask() : mNext(nullptr), mRunAt(0) {} - ANDROID_API virtual ~RenderTask() {} + RenderTask() : mNext(nullptr), mRunAt(0) {} + virtual ~RenderTask() {} - ANDROID_API virtual void run() = 0; + virtual void run() = 0; RenderTask* mNext; nsecs_t mRunAt; // nano-seconds on the SYSTEM_TIME_MONOTONIC clock diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 8be46a6d16e1..2c295bcd8105 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -88,7 +88,7 @@ class RenderThread : private ThreadBase { public: // Sets a callback that fires before any RenderThread setup has occurred. - ANDROID_API static void setOnStartHook(JVMAttachHook onStartHook); + static void setOnStartHook(JVMAttachHook onStartHook); static JVMAttachHook getOnStartHook(); WorkQueue& queue() { return ThreadBase::queue(); } diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index ba70afc8b8d2..3cb16074dd5e 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -459,7 +459,7 @@ Frame VulkanManager::dequeueNextBuffer(VulkanSurface* surface) { // The following flush blocks the GPU immediately instead of waiting for other // drawing ops. It seems dequeue_fence is not respected otherwise. // TODO: remove the flush after finding why backendSemaphore is not working. - bufferInfo->skSurface->flush(); + bufferInfo->skSurface->flushAndSubmit(); } } } @@ -525,9 +525,15 @@ void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) int fenceFd = -1; DestroySemaphoreInfo* destroyInfo = new DestroySemaphoreInfo(mDestroySemaphore, mDevice, semaphore); + GrFlushInfo flushInfo; + flushInfo.fNumSemaphores = 1; + flushInfo.fSignalSemaphores = &backendSemaphore; + flushInfo.fFinishedProc = destroy_semaphore; + flushInfo.fFinishedContext = destroyInfo; GrSemaphoresSubmitted submitted = bufferInfo->skSurface->flush( - SkSurface::BackendSurfaceAccess::kPresent, kNone_GrFlushFlags, 1, &backendSemaphore, - destroy_semaphore, destroyInfo); + SkSurface::BackendSurfaceAccess::kPresent, flushInfo); + ALOGE_IF(!bufferInfo->skSurface->getContext(), "Surface is not backed by gpu"); + bufferInfo->skSurface->getContext()->submit(); if (submitted == GrSemaphoresSubmitted::kYes) { VkSemaphoreGetFdInfoKHR getFdInfo; getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR; @@ -612,7 +618,7 @@ status_t VulkanManager::fenceWait(int fence, GrContext* grContext) { // Skia takes ownership of the semaphore and will delete it once the wait has finished. grContext->wait(1, &beSemaphore); - grContext->flush(); + grContext->flushAndSubmit(); return OK; } @@ -648,8 +654,13 @@ status_t VulkanManager::createReleaseFence(int* nativeFence, GrContext* grContex // Even if Skia fails to submit the semaphore, it will still call the destroy_semaphore callback // which will remove its ref to the semaphore. The VulkanManager must still release its ref, // when it is done with the semaphore. - GrSemaphoresSubmitted submitted = grContext->flush(kNone_GrFlushFlags, 1, &backendSemaphore, - destroy_semaphore, destroyInfo); + GrFlushInfo flushInfo; + flushInfo.fNumSemaphores = 1; + flushInfo.fSignalSemaphores = &backendSemaphore; + flushInfo.fFinishedProc = destroy_semaphore; + flushInfo.fFinishedContext = destroyInfo; + GrSemaphoresSubmitted submitted = grContext->flush(flushInfo); + grContext->submit(); if (submitted == GrSemaphoresSubmitted::kNo) { ALOGE("VulkanManager::createReleaseFence: Failed to submit semaphore"); diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp index a7ea21d8c4de..1da09b454da7 100644 --- a/libs/hwui/renderthread/VulkanSurface.cpp +++ b/libs/hwui/renderthread/VulkanSurface.cpp @@ -200,16 +200,16 @@ bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode "Could not get gamut matrix from color space"); if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) { outWindowInfo->dataspace = HAL_DATASPACE_V0_SCRGB; - } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDCIP3, sizeof(surfaceGamut)) == 0) { + } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDisplayP3, sizeof(surfaceGamut)) == 0) { outWindowInfo->dataspace = HAL_DATASPACE_DISPLAY_P3; } else { LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space."); } } - outWindowInfo->pixelFormat = ColorTypeToPixelFormat(colorType); + outWindowInfo->bufferFormat = ColorTypeToBufferFormat(colorType); VkFormat vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM; - if (outWindowInfo->pixelFormat == PIXEL_FORMAT_RGBA_FP16) { + if (outWindowInfo->bufferFormat == AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT) { vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT; } @@ -263,10 +263,10 @@ bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) { ATRACE_CALL(); - int err = native_window_set_buffers_format(window, windowInfo.pixelFormat); + int err = native_window_set_buffers_format(window, windowInfo.bufferFormat); if (err != 0) { ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)", - windowInfo.pixelFormat, strerror(-err), err); + windowInfo.bufferFormat, strerror(-err), err); return false; } diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h index bd2362612a13..40a44b11c0bc 100644 --- a/libs/hwui/renderthread/VulkanSurface.h +++ b/libs/hwui/renderthread/VulkanSurface.h @@ -17,8 +17,6 @@ #include <system/graphics.h> #include <system/window.h> -#include <ui/BufferQueueDefs.h> -#include <ui/PixelFormat.h> #include <vulkan/vulkan.h> #include <SkRefCnt.h> @@ -91,7 +89,7 @@ private: struct WindowInfo { SkISize size; - PixelFormat pixelFormat; + uint32_t bufferFormat; android_dataspace dataspace; int transform; size_t bufferCount; @@ -111,8 +109,13 @@ private: static bool UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo); void releaseBuffers(); + // TODO: This number comes from ui/BufferQueueDefs. We're not pulling the + // header in so that we don't need to depend on libui, but we should share + // this constant somewhere. But right now it's okay to keep here because we + // can't safely change the slot count anyways. + static constexpr size_t kNumBufferSlots = 64; // TODO: Just use a vector? - NativeBufferInfo mNativeBuffers[android::BufferQueueDefs::NUM_BUFFER_SLOTS]; + NativeBufferInfo mNativeBuffers[kNumBufferSlots]; sp<ANativeWindow> mNativeWindow; WindowInfo mWindowInfo; diff --git a/libs/hwui/service/GraphicsStatsService.h b/libs/hwui/service/GraphicsStatsService.h index 59e21d039c9d..4063f749f808 100644 --- a/libs/hwui/service/GraphicsStatsService.h +++ b/libs/hwui/service/GraphicsStatsService.h @@ -44,18 +44,16 @@ public: ProtobufStatsd, }; - ANDROID_API static void saveBuffer(const std::string& path, const std::string& package, - int64_t versionCode, int64_t startTime, int64_t endTime, - const ProfileData* data); - - ANDROID_API static Dump* createDump(int outFd, DumpType type); - ANDROID_API static void addToDump(Dump* dump, const std::string& path, - const std::string& package, int64_t versionCode, - int64_t startTime, int64_t endTime, const ProfileData* data); - ANDROID_API static void addToDump(Dump* dump, const std::string& path); - ANDROID_API static void finishDump(Dump* dump); - ANDROID_API static void finishDumpInMemory(Dump* dump, AStatsEventList* data, - bool lastFullDay); + static void saveBuffer(const std::string& path, const std::string& package, int64_t versionCode, + int64_t startTime, int64_t endTime, const ProfileData* data); + + static Dump* createDump(int outFd, DumpType type); + static void addToDump(Dump* dump, const std::string& path, const std::string& package, + int64_t versionCode, int64_t startTime, int64_t endTime, + const ProfileData* data); + static void addToDump(Dump* dump, const std::string& path); + static void finishDump(Dump* dump); + static void finishDumpInMemory(Dump* dump, AStatsEventList* data, bool lastFullDay); // Visible for testing static bool parseFromFile(const std::string& path, protos::GraphicsStatsProto* output); diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index 91a808df3657..36c5a8c1b3de 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -287,18 +287,6 @@ public: static std::unique_ptr<uint16_t[]> asciiToUtf16(const char* str); - class MockFunctor : public Functor { - public: - virtual status_t operator()(int what, void* data) { - mLastMode = what; - return DrawGlInfo::kStatusDone; - } - int getLastMode() const { return mLastMode; } - - private: - int mLastMode = -1; - }; - static SkColor getColor(const sk_sp<SkSurface>& surface, int x, int y); static SkRect getClipBounds(const SkCanvas* canvas); @@ -311,30 +299,32 @@ public: int glesDraw = 0; }; - static void expectOnRenderThread() { EXPECT_EQ(gettid(), TestUtils::getRenderThreadTid()); } + static void expectOnRenderThread(const std::string_view& function = "unknown") { + EXPECT_EQ(gettid(), TestUtils::getRenderThreadTid()) << "Called on wrong thread: " << function; + } static WebViewFunctorCallbacks createMockFunctor(RenderMode mode) { auto callbacks = WebViewFunctorCallbacks{ .onSync = [](int functor, void* client_data, const WebViewSyncData& data) { - expectOnRenderThread(); + expectOnRenderThread("onSync"); sMockFunctorCounts[functor].sync++; }, .onContextDestroyed = [](int functor, void* client_data) { - expectOnRenderThread(); + expectOnRenderThread("onContextDestroyed"); sMockFunctorCounts[functor].contextDestroyed++; }, .onDestroyed = [](int functor, void* client_data) { - expectOnRenderThread(); + expectOnRenderThread("onDestroyed"); sMockFunctorCounts[functor].destroyed++; }, }; switch (mode) { case RenderMode::OpenGL_ES: callbacks.gles.draw = [](int functor, void* client_data, const DrawGlInfo& params) { - expectOnRenderThread(); + expectOnRenderThread("draw"); sMockFunctorCounts[functor].glesDraw++; }; break; diff --git a/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp b/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp index f4fce277454d..edadf78db051 100644 --- a/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp +++ b/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp @@ -56,9 +56,9 @@ public: (float)magnifier->height(), 0, 0, (float)props.getWidth(), (float)props.getHeight(), nullptr); }); - canvas.insertReorderBarrier(true); + canvas.enableZ(true); canvas.drawRenderNode(zoomImageView.get()); - canvas.insertReorderBarrier(false); + canvas.enableZ(false); } void doFrame(int frameNr) override { diff --git a/libs/hwui/tests/common/scenes/RecentsAnimation.cpp b/libs/hwui/tests/common/scenes/RecentsAnimation.cpp index 3480a0f18407..1c2507867f6e 100644 --- a/libs/hwui/tests/common/scenes/RecentsAnimation.cpp +++ b/libs/hwui/tests/common/scenes/RecentsAnimation.cpp @@ -36,7 +36,7 @@ public: int cardsize = std::min(width, height) - dp(64); renderer.drawColor(Color::White, SkBlendMode::kSrcOver); - renderer.insertReorderBarrier(true); + renderer.enableZ(true); int x = dp(32); for (int i = 0; i < 4; i++) { @@ -52,7 +52,7 @@ public: mCards.push_back(card); } - renderer.insertReorderBarrier(false); + renderer.enableZ(false); } void doFrame(int frameNr) override { diff --git a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp index 80b5cc191089..f37bcbc3ee1b 100644 --- a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp +++ b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp @@ -29,7 +29,7 @@ public: sp<RenderNode> card; void createContent(int width, int height, Canvas& canvas) override { canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); - canvas.insertReorderBarrier(true); + canvas.enableZ(true); card = TestUtils::createNode(50, 50, 250, 250, [](RenderProperties& props, Canvas& canvas) { canvas.drawColor(0xFFFF00FF, SkBlendMode::kSrcOver); @@ -47,7 +47,7 @@ public: }); canvas.drawRenderNode(card.get()); - canvas.insertReorderBarrier(false); + canvas.enableZ(false); } void doFrame(int frameNr) override { int curFrame = frameNr % 150; diff --git a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp index 314e922e9f38..163745b04ed2 100644 --- a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp +++ b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp @@ -27,7 +27,7 @@ public: std::vector<sp<RenderNode> > cards; void createContent(int width, int height, Canvas& canvas) override { canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); - canvas.insertReorderBarrier(true); + canvas.enableZ(true); int ci = 0; for (int x = 0; x < width; x += mSpacing) { @@ -45,7 +45,7 @@ public: } } - canvas.insertReorderBarrier(false); + canvas.enableZ(false); } void doFrame(int frameNr) override { int curFrame = frameNr % 50; diff --git a/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp b/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp index bdc991ba1890..c13e80e8c204 100644 --- a/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp +++ b/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp @@ -29,7 +29,7 @@ public: std::vector<sp<RenderNode> > cards; void createContent(int width, int height, Canvas& canvas) override { canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); - canvas.insertReorderBarrier(true); + canvas.enableZ(true); for (int x = dp(8); x < (width - dp(58)); x += dp(58)) { for (int y = dp(8); y < (height - dp(58)); y += dp(58)) { @@ -39,7 +39,7 @@ public: } } - canvas.insertReorderBarrier(false); + canvas.enableZ(false); } void doFrame(int frameNr) override { int curFrame = frameNr % 150; diff --git a/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp b/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp index a12fd4d69280..772b98e32220 100644 --- a/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp +++ b/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp @@ -29,7 +29,7 @@ public: std::vector<sp<RenderNode> > cards; void createContent(int width, int height, Canvas& canvas) override { canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); - canvas.insertReorderBarrier(true); + canvas.enableZ(true); for (int x = dp(16); x < (width - dp(116)); x += dp(116)) { for (int y = dp(16); y < (height - dp(116)); y += dp(116)) { @@ -39,7 +39,7 @@ public: } } - canvas.insertReorderBarrier(false); + canvas.enableZ(false); } void doFrame(int frameNr) override { int curFrame = frameNr % 150; diff --git a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp index 9f599100200e..0019da5fd80b 100644 --- a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp +++ b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp @@ -29,7 +29,7 @@ public: std::vector<sp<RenderNode> > cards; void createContent(int width, int height, Canvas& canvas) override { canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); - canvas.insertReorderBarrier(true); + canvas.enableZ(true); int outset = 50; for (int i = 0; i < 10; i++) { @@ -39,7 +39,7 @@ public: cards.push_back(card); } - canvas.insertReorderBarrier(false); + canvas.enableZ(false); } void doFrame(int frameNr) override { int curFrame = frameNr % 10; diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp index bac887053d2f..1b0a07a98b3f 100644 --- a/libs/hwui/tests/common/scenes/TvApp.cpp +++ b/libs/hwui/tests/common/scenes/TvApp.cpp @@ -67,7 +67,7 @@ public: mBg = createBitmapNode(canvas, 0xFF9C27B0, 0, 0, width, height); canvas.drawRenderNode(mBg.get()); - canvas.insertReorderBarrier(true); + canvas.enableZ(true); mSingleBitmap = mAllocator(dp(160), dp(120), kRGBA_8888_SkColorType, [](SkBitmap& skBitmap) { skBitmap.eraseColor(0xFF0000FF); }); @@ -80,7 +80,7 @@ public: mCards.push_back(card); } } - canvas.insertReorderBarrier(false); + canvas.enableZ(false); } void doFrame(int frameNr) override { diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp index 4ce6c32470ea..d393c693c774 100644 --- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp +++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp @@ -133,14 +133,14 @@ void BM_DisplayListCanvas_basicViewGroupDraw(benchmark::State& benchState) { int clipRestoreCount = canvas->save(SaveFlags::MatrixClip); canvas->clipRect(1, 1, 199, 199, SkClipOp::kIntersect); - canvas->insertReorderBarrier(true); + canvas->enableZ(true); // Draw child loop for (int i = 0; i < benchState.range(0); i++) { canvas->drawRenderNode(child.get()); } - canvas->insertReorderBarrier(false); + canvas->enableZ(false); canvas->restoreToCount(clipRestoreCount); delete canvas->finishRecording(); diff --git a/libs/hwui/tests/scripts/prep_generic.sh b/libs/hwui/tests/scripts/prep_generic.sh index 223bf373c65a..89826ff69463 100755 --- a/libs/hwui/tests/scripts/prep_generic.sh +++ b/libs/hwui/tests/scripts/prep_generic.sh @@ -28,11 +28,17 @@ # performance between different device models. # Fun notes for maintaining this file: -# `expr` can deal with ints > INT32_MAX, but if compares cannot. This is why we use MHz. -# `expr` can sometimes evaluate right-to-left. This is why we use parens. +# $((arithmetic expressions)) can deal with ints > INT32_MAX, but if compares cannot. This is +# why we use MHz. +# $((arithmetic expressions)) can sometimes evaluate right-to-left. This is why we use parens. # Everything below the initial host-check isn't bash - Android uses mksh # mksh allows `\n` in an echo, bash doesn't # can't use `awk` +# can't use `sed` +# can't use `cut` on < L +# can't use `expr` on < L + +ARG_CORES=${1:-big} CPU_TARGET_FREQ_PERCENT=50 GPU_TARGET_FREQ_PERCENT=50 @@ -43,7 +49,7 @@ if [ "`command -v getprop`" == "" ]; then echo "Pushing $0 and running it on device..." dest=/data/local/tmp/`basename $0` adb push $0 ${dest} - adb shell ${dest} + adb shell ${dest} $@ adb shell rm ${dest} exit else @@ -56,7 +62,7 @@ if [ "`command -v getprop`" == "" ]; then fi # require root -if [ "`id -u`" -ne "0" ]; then +if [[ `id` != "uid=0"* ]]; then echo "Not running as root, cannot lock clocks, aborting" exit -1 fi @@ -64,74 +70,175 @@ fi DEVICE=`getprop ro.product.device` MODEL=`getprop ro.product.model` -# Find CPU max frequency, and lock big cores to an available frequency -# that's >= $CPU_TARGET_FREQ_PERCENT% of max. Disable other cores. +if [ "$ARG_CORES" == "big" ]; then + CPU_IDEAL_START_FREQ_KHZ=0 +elif [ "$ARG_CORES" == "little" ]; then + CPU_IDEAL_START_FREQ_KHZ=100000000 ## finding min of max freqs, so start at 100M KHz (100 GHz) +else + echo "Invalid argument \$1 for ARG_CORES, should be 'big' or 'little', but was $ARG_CORES" + exit -1 +fi + +function_core_check() { + if [ "$ARG_CORES" == "big" ]; then + [ $1 -gt $2 ] + elif [ "$ARG_CORES" == "little" ]; then + [ $1 -lt $2 ] + else + echo "Invalid argument \$1 for ARG_CORES, should be 'big' or 'little', but was $ARG_CORES" + exit -1 + fi +} + +function_setup_go() { + if [ -f /d/fpsgo/common/force_onoff ]; then + # Disable fpsgo + echo 0 > /d/fpsgo/common/force_onoff + fpsgoState=`cat /d/fpsgo/common/force_onoff` + if [ "$fpsgoState" != "0" ] && [ "$fpsgoState" != "force off" ]; then + echo "Failed to disable fpsgo" + exit -1 + fi + fi +} + +# Find the min or max (little vs big) of CPU max frequency, and lock cores of the selected type to +# an available frequency that's >= $CPU_TARGET_FREQ_PERCENT% of max. Disable other cores. function_lock_cpu() { CPU_BASE=/sys/devices/system/cpu GOV=cpufreq/scaling_governor + # Options to make clock locking on go devices more sticky. + function_setup_go + # Find max CPU freq, and associated list of available freqs - cpuMaxFreq=0 + cpuIdealFreq=$CPU_IDEAL_START_FREQ_KHZ cpuAvailFreqCmpr=0 cpuAvailFreq=0 enableIndices='' disableIndices='' cpu=0 - while [ -f ${CPU_BASE}/cpu${cpu}/online ]; do - # enable core, so we can find its frequencies - echo 1 > ${CPU_BASE}/cpu${cpu}/online + while [ -d ${CPU_BASE}/cpu${cpu}/cpufreq ]; do + # Try to enable core, so we can find its frequencies. + # Note: In cases where the online file is inaccessible, it represents a + # core which cannot be turned off, so we simply assume it is enabled if + # this command fails. + if [ -f "$CPU_BASE/cpu$cpu/online" ]; then + echo 1 > ${CPU_BASE}/cpu${cpu}/online || true + fi + + # set userspace governor on all CPUs to ensure freq scaling is disabled + echo userspace > ${CPU_BASE}/cpu${cpu}/${GOV} maxFreq=`cat ${CPU_BASE}/cpu$cpu/cpufreq/cpuinfo_max_freq` availFreq=`cat ${CPU_BASE}/cpu$cpu/cpufreq/scaling_available_frequencies` availFreqCmpr=${availFreq// /-} - if [ ${maxFreq} -gt ${cpuMaxFreq} ]; then - # new highest max freq, look for cpus with same max freq and same avail freq list - cpuMaxFreq=${maxFreq} + if (function_core_check $maxFreq $cpuIdealFreq); then + # new min/max of max freq, look for cpus with same max freq and same avail freq list + cpuIdealFreq=${maxFreq} cpuAvailFreq=${availFreq} cpuAvailFreqCmpr=${availFreqCmpr} - if [ -z ${disableIndices} ]; then + if [ -z "$disableIndices" ]; then disableIndices="$enableIndices" else disableIndices="$disableIndices $enableIndices" fi enableIndices=${cpu} - elif [ ${maxFreq} == ${cpuMaxFreq} ] && [ ${availFreqCmpr} == ${cpuAvailFreqCmpr} ]; then + elif [ ${maxFreq} == ${cpuIdealFreq} ] && [ ${availFreqCmpr} == ${cpuAvailFreqCmpr} ]; then enableIndices="$enableIndices $cpu" else - disableIndices="$disableIndices $cpu" + if [ -z "$disableIndices" ]; then + disableIndices="$cpu" + else + disableIndices="$disableIndices $cpu" + fi fi + cpu=$(($cpu + 1)) done + # check that some CPUs will be enabled + if [ -z "$enableIndices" ]; then + echo "Failed to find any $ARG_CORES cores to enable, aborting." + exit -1 + fi + # Chose a frequency to lock to that's >= $CPU_TARGET_FREQ_PERCENT% of max # (below, 100M = 1K for KHz->MHz * 100 for %) - TARGET_FREQ_MHZ=`expr \( ${cpuMaxFreq} \* ${CPU_TARGET_FREQ_PERCENT} \) \/ 100000` + TARGET_FREQ_MHZ=$(( ($cpuIdealFreq * $CPU_TARGET_FREQ_PERCENT) / 100000 )) chosenFreq=0 + chosenFreqDiff=100000000 for freq in ${cpuAvailFreq}; do - freqMhz=`expr ${freq} \/ 1000` + freqMhz=$(( ${freq} / 1000 )) if [ ${freqMhz} -ge ${TARGET_FREQ_MHZ} ]; then - chosenFreq=${freq} - break + newChosenFreqDiff=$(( $freq - $TARGET_FREQ_MHZ )) + if [ $newChosenFreqDiff -lt $chosenFreqDiff ]; then + chosenFreq=${freq} + chosenFreqDiff=$(( $chosenFreq - $TARGET_FREQ_MHZ )) + fi fi done + # Lock wembley clocks using high-priority op code method. + # This block depends on the shell utility awk, which is only available on API 27+ + if [ "$DEVICE" == "wembley" ]; then + # Get list of available frequencies to lock to by parsing the op-code list. + AVAIL_OP_FREQS=`cat /proc/cpufreq/MT_CPU_DVFS_LL/cpufreq_oppidx \ + | awk '{print $2}' \ + | tail -n +3 \ + | while read line; do + echo "${line:1:${#line}-2}" + done` + + # Compute the closest available frequency to the desired frequency, $chosenFreq. + # This assumes the op codes listen in /proc/cpufreq/MT_CPU_DVFS_LL/cpufreq_oppidx are listed + # in order and 0-indexed. + opCode=-1 + opFreq=0 + currOpCode=-1 + for currOpFreq in $AVAIL_OP_FREQS; do + currOpCode=$((currOpCode + 1)) + + prevDiff=$((chosenFreq-opFreq)) + prevDiff=`function_abs $prevDiff` + currDiff=$((chosenFreq-currOpFreq)) + currDiff=`function_abs $currDiff` + if [ $currDiff -lt $prevDiff ]; then + opCode="$currOpCode" + opFreq="$currOpFreq" + fi + done + + echo "$opCode" > /proc/ppm/policy/ut_fix_freq_idx + fi + # enable 'big' CPUs for cpu in ${enableIndices}; do freq=${CPU_BASE}/cpu$cpu/cpufreq - echo 1 > ${CPU_BASE}/cpu${cpu}/online - echo userspace > ${CPU_BASE}/cpu${cpu}/${GOV} + # Try to enable core, so we can find its frequencies. + # Note: In cases where the online file is inaccessible, it represents a + # core which cannot be turned off, so we simply assume it is enabled if + # this command fails. + if [ -f "$CPU_BASE/cpu$cpu/online" ]; then + echo 1 > ${CPU_BASE}/cpu${cpu}/online || true + fi + + # scaling_max_freq must be set before scaling_min_freq echo ${chosenFreq} > ${freq}/scaling_max_freq echo ${chosenFreq} > ${freq}/scaling_min_freq echo ${chosenFreq} > ${freq}/scaling_setspeed + # Give system a bit of time to propagate the change to scaling_setspeed. + sleep 0.1 + # validate setting the freq worked obsCur=`cat ${freq}/scaling_cur_freq` obsMin=`cat ${freq}/scaling_min_freq` obsMax=`cat ${freq}/scaling_max_freq` - if [ obsCur -ne ${chosenFreq} ] || [ obsMin -ne ${chosenFreq} ] || [ obsMax -ne ${chosenFreq} ]; then + if [ "$obsCur" -ne "$chosenFreq" ] || [ "$obsMin" -ne "$chosenFreq" ] || [ "$obsMax" -ne "$chosenFreq" ]; then echo "Failed to set CPU$cpu to $chosenFreq Hz! Aborting..." echo "scaling_cur_freq = $obsCur" echo "scaling_min_freq = $obsMin" @@ -145,8 +252,20 @@ function_lock_cpu() { echo 0 > ${CPU_BASE}/cpu${cpu}/online done - echo "\nLocked CPUs ${enableIndices// /,} to $chosenFreq / $maxFreq KHz" + echo "==================================" + echo "Locked CPUs ${enableIndices// /,} to $chosenFreq / $cpuIdealFreq KHz" echo "Disabled CPUs ${disableIndices// /,}" + echo "==================================" +} + +# Returns the absolute value of the first arg passed to this helper. +function_abs() { + n=$1 + if [ $n -lt 0 ]; then + echo "$((n * -1 ))" + else + echo "$n" + fi } # If we have a Qualcomm GPU, find its max frequency, and lock to @@ -154,12 +273,12 @@ function_lock_cpu() { function_lock_gpu_kgsl() { if [ ! -d /sys/class/kgsl/kgsl-3d0/ ]; then # not kgsl, abort - echo "\nCurrently don't support locking GPU clocks of $MODEL ($DEVICE)" + echo "Currently don't support locking GPU clocks of $MODEL ($DEVICE)" return -1 fi if [ ${DEVICE} == "walleye" ] || [ ${DEVICE} == "taimen" ]; then # Workaround crash - echo "\nUnable to lock GPU clocks of $MODEL ($DEVICE)" + echo "Unable to lock GPU clocks of $MODEL ($DEVICE)" return -1 fi @@ -174,13 +293,13 @@ function_lock_gpu_kgsl() { done # (below, 100M = 1M for MHz * 100 for %) - TARGET_FREQ_MHZ=`expr \( ${gpuMaxFreq} \* ${GPU_TARGET_FREQ_PERCENT} \) \/ 100000000` + TARGET_FREQ_MHZ=$(( (${gpuMaxFreq} * ${GPU_TARGET_FREQ_PERCENT}) / 100000000 )) chosenFreq=${gpuMaxFreq} index=0 chosenIndex=0 for freq in ${gpuAvailFreq}; do - freqMhz=`expr ${freq} \/ 1000000` + freqMhz=$(( ${freq} / 1000000 )) if [ ${freqMhz} -ge ${TARGET_FREQ_MHZ} ] && [ ${chosenFreq} -ge ${freq} ]; then # note avail freq are generally in reverse order, so we don't break out of this loop chosenFreq=${freq} @@ -190,7 +309,7 @@ function_lock_gpu_kgsl() { done lastIndex=$(($index - 1)) - firstFreq=`echo $gpuAvailFreq | cut -d" " -f1` + firstFreq=`function_cut_first_from_space_seperated_list $gpuAvailFreq` if [ ${gpuMaxFreq} != ${firstFreq} ]; then # pwrlevel is index of desired freq among available frequencies, from highest to lowest. @@ -226,24 +345,40 @@ function_lock_gpu_kgsl() { echo "index = $chosenIndex" exit -1 fi - echo "\nLocked GPU to $chosenFreq / $gpuMaxFreq Hz" + echo "Locked GPU to $chosenFreq / $gpuMaxFreq Hz" +} + +# cut is not available on some devices (Nexus 5 running LRX22C). +function_cut_first_from_space_seperated_list() { + list=$1 + + for freq in $list; do + echo $freq + break + done } # kill processes that manage thermals / scaling -stop thermal-engine -stop perfd -stop vendor.thermal-engine -stop vendor.perfd +stop thermal-engine || true +stop perfd || true +stop vendor.thermal-engine || true +stop vendor.perfd || true +setprop vendor.powerhal.init 0 || true +setprop ctl.interface_restart android.hardware.power@1.0::IPower/default || true function_lock_cpu -function_lock_gpu_kgsl +if [ "$DEVICE" -ne "wembley" ]; then + function_lock_gpu_kgsl +else + echo "Unable to lock gpu clocks of $MODEL ($DEVICE)." +fi # Memory bus - hardcoded per-device for now if [ ${DEVICE} == "marlin" ] || [ ${DEVICE} == "sailfish" ]; then echo 13763 > /sys/class/devfreq/soc:qcom,gpubw/max_freq else - echo "\nUnable to lock memory bus of $MODEL ($DEVICE)." + echo "Unable to lock memory bus of $MODEL ($DEVICE)." fi -echo "\n$DEVICE clocks have been locked - to reset, reboot the device\n"
\ No newline at end of file +echo "$DEVICE clocks have been locked - to reset, reboot the device" diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp index c83a3c88cbdd..a4d7b825520d 100644 --- a/libs/hwui/tests/unit/CacheManagerTests.cpp +++ b/libs/hwui/tests/unit/CacheManagerTests.cpp @@ -47,7 +47,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, trimMemory) { sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(grContext, SkBudgeted::kYes, info); surface->getCanvas()->drawColor(SK_AlphaTRANSPARENT); - grContext->flush(); + grContext->flushAndSubmit(); surfaces.push_back(surface); } diff --git a/libs/hwui/tests/unit/CanvasContextTests.cpp b/libs/hwui/tests/unit/CanvasContextTests.cpp index 28cff5b9b154..1771c3590e10 100644 --- a/libs/hwui/tests/unit/CanvasContextTests.cpp +++ b/libs/hwui/tests/unit/CanvasContextTests.cpp @@ -42,14 +42,3 @@ RENDERTHREAD_TEST(CanvasContext, create) { canvasContext->destroy(); } - -RENDERTHREAD_TEST(CanvasContext, invokeFunctor) { - TestUtils::MockFunctor functor; - CanvasContext::invokeFunctor(renderThread, &functor); - if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { - // we currently don't support OpenGL WebViews on the Vulkan backend - ASSERT_EQ(functor.getLastMode(), DrawGlInfo::kModeProcessNoContext); - } else { - ASSERT_EQ(functor.getLastMode(), DrawGlInfo::kModeProcess); - } -} diff --git a/libs/hwui/tests/unit/FatalTestCanvas.h b/libs/hwui/tests/unit/FatalTestCanvas.h index 1723c2eb4948..76ae0853b477 100644 --- a/libs/hwui/tests/unit/FatalTestCanvas.h +++ b/libs/hwui/tests/unit/FatalTestCanvas.h @@ -81,21 +81,6 @@ public: const SkPaint*) { ADD_FAILURE() << "onDrawImageLattice not expected in this test"; } - void onDrawBitmap(const SkBitmap&, SkScalar dx, SkScalar dy, const SkPaint*) { - ADD_FAILURE() << "onDrawBitmap not expected in this test"; - } - void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*, - SrcRectConstraint) { - ADD_FAILURE() << "onDrawBitmapRect not expected in this test"; - } - void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, - const SkPaint*) { - ADD_FAILURE() << "onDrawBitmapNine not expected in this test"; - } - void onDrawBitmapLattice(const SkBitmap&, const Lattice& lattice, const SkRect& dst, - const SkPaint*) { - ADD_FAILURE() << "onDrawBitmapLattice not expected in this test"; - } void onClipRRect(const SkRRect& rrect, SkClipOp, ClipEdgeStyle) { ADD_FAILURE() << "onClipRRect not expected in this test"; } diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp index 3632be06c45f..7aa6be8722cf 100644 --- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp @@ -108,27 +108,27 @@ protected: TEST(RenderNodeDrawable, zReorder) { auto parent = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - canvas.insertReorderBarrier(true); - canvas.insertReorderBarrier(false); + canvas.enableZ(true); + canvas.enableZ(false); drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder drawOrderedRect(&canvas, 1); - canvas.insertReorderBarrier(true); + canvas.enableZ(true); drawOrderedNode(&canvas, 6, 2.0f); drawOrderedRect(&canvas, 3); drawOrderedNode(&canvas, 4, 0.0f); drawOrderedRect(&canvas, 5); drawOrderedNode(&canvas, 2, -2.0f); drawOrderedNode(&canvas, 7, 2.0f); - canvas.insertReorderBarrier(false); + canvas.enableZ(false); drawOrderedRect(&canvas, 8); drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder - canvas.insertReorderBarrier(true); // reorder a node ahead of drawrect op + canvas.enableZ(true); // reorder a node ahead of drawrect op drawOrderedRect(&canvas, 11); drawOrderedNode(&canvas, 10, -1.0f); - canvas.insertReorderBarrier(false); - canvas.insertReorderBarrier(true); // test with two empty reorder sections - canvas.insertReorderBarrier(true); - canvas.insertReorderBarrier(false); + canvas.enableZ(false); + canvas.enableZ(true); // test with two empty reorder sections + canvas.enableZ(true); + canvas.enableZ(false); drawOrderedRect(&canvas, 12); }); @@ -1142,7 +1142,7 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) { 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { canvas.translate(TRANSLATE_X, TRANSLATE_Y); - canvas.insertReorderBarrier(true); + canvas.enableZ(true); auto node = TestUtils::createSkiaNode( CASTER_X, CASTER_Y, CASTER_X + CASTER_WIDTH, CASTER_Y + CASTER_HEIGHT, @@ -1152,7 +1152,7 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) { props.mutableOutline().setShouldClip(true); }); canvas.drawRenderNode(node.get()); - canvas.insertReorderBarrier(false); + canvas.enableZ(false); }); // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection @@ -1169,7 +1169,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) { class VectorDrawableTestCanvas : public TestCanvasBase { public: VectorDrawableTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {} - void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, + void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint) override { const int index = mDrawCounter++; switch (index) { diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp index 1cd9bd8ee9d9..c19e1ed6ce75 100644 --- a/libs/hwui/tests/unit/RenderNodeTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeTests.cpp @@ -231,39 +231,41 @@ TEST(RenderNode, multiTreeValidity) { } TEST(RenderNode, releasedCallback) { - class DecRefOnReleased : public GlFunctorLifecycleListener { - public: - explicit DecRefOnReleased(int* refcnt) : mRefCnt(refcnt) {} - void onGlFunctorReleased(Functor* functor) override { *mRefCnt -= 1; } - - private: - int* mRefCnt; - }; - - int refcnt = 0; - sp<DecRefOnReleased> listener(new DecRefOnReleased(&refcnt)); - Functor noopFunctor; + int functor = WebViewFunctor_create( + nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES); auto node = TestUtils::createNode(0, 0, 200, 400, [&](RenderProperties& props, Canvas& canvas) { - refcnt++; - canvas.callDrawGLFunction(&noopFunctor, listener.get()); + canvas.drawWebViewFunctor(functor); + }); + TestUtils::runOnRenderThreadUnmanaged([&] (RenderThread&) { + TestUtils::syncHierarchyPropertiesAndDisplayList(node); }); - TestUtils::syncHierarchyPropertiesAndDisplayList(node); - EXPECT_EQ(1, refcnt); + auto& counts = TestUtils::countsForFunctor(functor); + EXPECT_EQ(1, counts.sync); + EXPECT_EQ(0, counts.destroyed); TestUtils::recordNode(*node, [&](Canvas& canvas) { - refcnt++; - canvas.callDrawGLFunction(&noopFunctor, listener.get()); + canvas.drawWebViewFunctor(functor); }); - EXPECT_EQ(2, refcnt); + EXPECT_EQ(1, counts.sync); + EXPECT_EQ(0, counts.destroyed); - TestUtils::syncHierarchyPropertiesAndDisplayList(node); - EXPECT_EQ(1, refcnt); + TestUtils::runOnRenderThreadUnmanaged([&] (RenderThread&) { + TestUtils::syncHierarchyPropertiesAndDisplayList(node); + }); + EXPECT_EQ(2, counts.sync); + EXPECT_EQ(0, counts.destroyed); + + WebViewFunctor_release(functor); + EXPECT_EQ(2, counts.sync); + EXPECT_EQ(0, counts.destroyed); TestUtils::recordNode(*node, [](Canvas& canvas) {}); - EXPECT_EQ(1, refcnt); - TestUtils::syncHierarchyPropertiesAndDisplayList(node); - EXPECT_EQ(0, refcnt); + TestUtils::runOnRenderThreadUnmanaged([&] (RenderThread&) { + TestUtils::syncHierarchyPropertiesAndDisplayList(node); + }); + EXPECT_EQ(2, counts.sync); + EXPECT_EQ(1, counts.destroyed); } RENDERTHREAD_TEST(RenderNode, prepareTree_nullableDisplayList) { diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp index d08aea668b2a..74a565439f85 100644 --- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp +++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp @@ -48,7 +48,10 @@ TEST(SkiaDisplayList, reset) { SkCanvas dummyCanvas; RenderNodeDrawable drawable(nullptr, &dummyCanvas); skiaDL->mChildNodes.emplace_back(nullptr, &dummyCanvas); - GLFunctorDrawable functorDrawable(nullptr, nullptr, &dummyCanvas); + int functor1 = WebViewFunctor_create( + nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES); + GLFunctorDrawable functorDrawable{functor1, &dummyCanvas}; + WebViewFunctor_release(functor1); skiaDL->mChildFunctors.push_back(&functorDrawable); skiaDL->mMutableImages.push_back(nullptr); skiaDL->appendVD(nullptr); @@ -97,16 +100,13 @@ TEST(SkiaDisplayList, syncContexts) { SkiaDisplayList skiaDL; SkCanvas dummyCanvas; - TestUtils::MockFunctor functor; - GLFunctorDrawable functorDrawable(&functor, nullptr, &dummyCanvas); - skiaDL.mChildFunctors.push_back(&functorDrawable); - int functor2 = WebViewFunctor_create( + int functor1 = WebViewFunctor_create( nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES); - auto& counts = TestUtils::countsForFunctor(functor2); + auto& counts = TestUtils::countsForFunctor(functor1); skiaDL.mChildFunctors.push_back( - skiaDL.allocateDrawable<GLFunctorDrawable>(functor2, &dummyCanvas)); - WebViewFunctor_release(functor2); + skiaDL.allocateDrawable<GLFunctorDrawable>(functor1, &dummyCanvas)); + WebViewFunctor_release(functor1); SkRect bounds = SkRect::MakeWH(200, 200); VectorDrawableRoot vectorDrawable(new VectorDrawable::Group()); @@ -120,7 +120,6 @@ TEST(SkiaDisplayList, syncContexts) { }); }); - EXPECT_EQ(functor.getLastMode(), DrawGlInfo::kModeSync); EXPECT_EQ(counts.sync, 1); EXPECT_EQ(counts.destroyed, 0); EXPECT_EQ(vectorDrawable.mutateProperties()->getBounds(), bounds); diff --git a/libs/hwui/utils/Blur.h b/libs/hwui/utils/Blur.h index d6b41b83def8..6b822f01e25c 100644 --- a/libs/hwui/utils/Blur.h +++ b/libs/hwui/utils/Blur.h @@ -26,9 +26,9 @@ namespace uirenderer { class Blur { public: // If radius > 0, return the corresponding sigma, else return 0 - ANDROID_API static float convertRadiusToSigma(float radius); + static float convertRadiusToSigma(float radius); // If sigma > 0.5, return the corresponding radius, else return 0 - ANDROID_API static float convertSigmaToRadius(float sigma); + static float convertSigmaToRadius(float sigma); // If the original radius was on an integer boundary then after the sigma to // radius conversion a small rounding error may be introduced. This function // accounts for that error and snaps to the appropriate integer boundary. diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp index 71a27ced2e09..ca1bf690cfd0 100644 --- a/libs/hwui/utils/Color.cpp +++ b/libs/hwui/utils/Color.cpp @@ -16,8 +16,8 @@ #include "Color.h" -#include <utils/Log.h> #include <ui/ColorSpace.h> +#include <utils/Log.h> #ifdef __ANDROID__ // Layoutlib does not support hardware buffers or native windows #include <android/hardware_buffer.h> @@ -72,46 +72,34 @@ SkImageInfo BufferDescriptionToImageInfo(const AHardwareBuffer_Desc& bufferDesc, sk_sp<SkColorSpace> colorSpace) { return createImageInfo(bufferDesc.width, bufferDesc.height, bufferDesc.format, colorSpace); } -#endif -android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) { +uint32_t ColorTypeToBufferFormat(SkColorType colorType) { switch (colorType) { case kRGBA_8888_SkColorType: - return PIXEL_FORMAT_RGBA_8888; + return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; case kRGBA_F16_SkColorType: - return PIXEL_FORMAT_RGBA_FP16; + return AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT; case kRGB_565_SkColorType: - return PIXEL_FORMAT_RGB_565; + return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM; case kRGB_888x_SkColorType: - return PIXEL_FORMAT_RGBX_8888; + return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM; case kRGBA_1010102_SkColorType: - return PIXEL_FORMAT_RGBA_1010102; + return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM; case kARGB_4444_SkColorType: - return PIXEL_FORMAT_RGBA_4444; + // Hardcoding the value from android::PixelFormat + static constexpr uint64_t kRGBA4444 = 7; + return kRGBA4444; default: ALOGV("Unsupported colorType: %d, return RGBA_8888 by default", (int)colorType); - return PIXEL_FORMAT_RGBA_8888; - } -} - -SkColorType PixelFormatToColorType(android::PixelFormat format) { - switch (format) { - case PIXEL_FORMAT_RGBX_8888: return kRGB_888x_SkColorType; - case PIXEL_FORMAT_RGBA_8888: return kRGBA_8888_SkColorType; - case PIXEL_FORMAT_RGBA_FP16: return kRGBA_F16_SkColorType; - case PIXEL_FORMAT_RGB_565: return kRGB_565_SkColorType; - case PIXEL_FORMAT_RGBA_1010102: return kRGBA_1010102_SkColorType; - case PIXEL_FORMAT_RGBA_4444: return kARGB_4444_SkColorType; - default: - ALOGV("Unsupported PixelFormat: %d, return kUnknown_SkColorType by default", format); - return kUnknown_SkColorType; + return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; } } +#endif namespace { static constexpr skcms_TransferFunction k2Dot6 = {2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; -// Skia's SkNamedGamut::kDCIP3 is based on a white point of D65. This gamut +// Skia's SkNamedGamut::kDisplayP3 is based on a white point of D65. This gamut // matches the white point used by ColorSpace.Named.DCIP3. static constexpr skcms_Matrix3x3 kDCIP3 = {{ {0.486143, 0.323835, 0.154234}, @@ -180,7 +168,7 @@ android_dataspace ColorSpaceToADataSpace(SkColorSpace* colorSpace, SkColorType c } } - if (nearlyEqual(fn, SkNamedTransferFn::kSRGB) && nearlyEqual(gamut, SkNamedGamut::kDCIP3)) { + if (nearlyEqual(fn, SkNamedTransferFn::kSRGB) && nearlyEqual(gamut, SkNamedGamut::kDisplayP3)) { return HAL_DATASPACE_DISPLAY_P3; } @@ -221,7 +209,7 @@ sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) { gamut = SkNamedGamut::kRec2020; break; case HAL_DATASPACE_STANDARD_DCI_P3: - gamut = SkNamedGamut::kDCIP3; + gamut = SkNamedGamut::kDisplayP3; break; case HAL_DATASPACE_STANDARD_ADOBE_RGB: gamut = SkNamedGamut::kAdobeRGB; diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h index a76f7e499c37..71ed68371a9a 100644 --- a/libs/hwui/utils/Color.h +++ b/libs/hwui/utils/Color.h @@ -16,14 +16,12 @@ #ifndef COLOR_H #define COLOR_H -#include <math.h> -#include <cutils/compiler.h> -#include <system/graphics.h> -#include <ui/PixelFormat.h> - #include <SkColor.h> #include <SkColorSpace.h> #include <SkImageInfo.h> +#include <cutils/compiler.h> +#include <math.h> +#include <system/graphics.h> struct ANativeWindow_Buffer; struct AHardwareBuffer_Desc; @@ -93,15 +91,14 @@ static constexpr float EOCF_sRGB(float srgb) { } #ifdef __ANDROID__ // Layoutlib does not support hardware buffers or native windows -ANDROID_API SkImageInfo ANativeWindowToImageInfo(const ANativeWindow_Buffer& buffer, +SkImageInfo ANativeWindowToImageInfo(const ANativeWindow_Buffer& buffer, sk_sp<SkColorSpace> colorSpace); SkImageInfo BufferDescriptionToImageInfo(const AHardwareBuffer_Desc& bufferDesc, sk_sp<SkColorSpace> colorSpace); -#endif -android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType); -ANDROID_API SkColorType PixelFormatToColorType(android::PixelFormat format); +uint32_t ColorTypeToBufferFormat(SkColorType colorType); +#endif ANDROID_API sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace); diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h index cc8d83f10d43..62bf39ca8a7a 100644 --- a/libs/hwui/utils/MathUtils.h +++ b/libs/hwui/utils/MathUtils.h @@ -31,7 +31,9 @@ public: * Check for floats that are close enough to zero. */ inline static bool isZero(float value) { - return (value >= -NON_ZERO_EPSILON) && (value <= NON_ZERO_EPSILON); + // Using fabsf is more performant as ARM computes + // fabsf in a single instruction. + return fabsf(value) <= NON_ZERO_EPSILON; } inline static bool isOne(float value) { diff --git a/libs/hwui/GlFunctorLifecycleListener.h b/libs/hwui/utils/NdkUtils.cpp index 5adc46961c8b..de6274ee5bcc 100644 --- a/libs/hwui/GlFunctorLifecycleListener.h +++ b/libs/hwui/utils/NdkUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,19 +14,19 @@ * limitations under the License. */ -#pragma once - -#include <utils/Functor.h> -#include <utils/RefBase.h> +#include <utils/NdkUtils.h> namespace android { namespace uirenderer { -class GlFunctorLifecycleListener : public VirtualLightRefBase { -public: - virtual ~GlFunctorLifecycleListener() {} - virtual void onGlFunctorReleased(Functor* functor) = 0; -}; +UniqueAHardwareBuffer allocateAHardwareBuffer(const AHardwareBuffer_Desc& desc) { + AHardwareBuffer* buffer; + if (AHardwareBuffer_allocate(&desc, &buffer) != 0) { + return nullptr; + } else { + return UniqueAHardwareBuffer{buffer}; + } +} } // namespace uirenderer } // namespace android diff --git a/libs/hwui/utils/NdkUtils.h b/libs/hwui/utils/NdkUtils.h new file mode 100644 index 000000000000..f218eb2ff404 --- /dev/null +++ b/libs/hwui/utils/NdkUtils.h @@ -0,0 +1,38 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * 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. + */ + +#pragma once + +#include <android/hardware_buffer.h> + +#include <memory> + +namespace android { +namespace uirenderer { + +// Deleter for an AHardwareBuffer, to be passed to an std::unique_ptr. +struct AHardwareBuffer_deleter { + void operator()(AHardwareBuffer* ahb) const { AHardwareBuffer_release(ahb); } +}; + +using UniqueAHardwareBuffer = std::unique_ptr<AHardwareBuffer, AHardwareBuffer_deleter>; + +// Allocates a UniqueAHardwareBuffer with the provided buffer description. +// Returns nullptr if allocation did not succeed. +UniqueAHardwareBuffer allocateAHardwareBuffer(const AHardwareBuffer_Desc& desc); + +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/utils/VectorDrawableUtils.h b/libs/hwui/utils/VectorDrawableUtils.h index 4be48fb942fc..4f63959165db 100644 --- a/libs/hwui/utils/VectorDrawableUtils.h +++ b/libs/hwui/utils/VectorDrawableUtils.h @@ -28,10 +28,10 @@ namespace uirenderer { class VectorDrawableUtils { public: - ANDROID_API static bool canMorph(const PathData& morphFrom, const PathData& morphTo); - ANDROID_API static bool interpolatePathData(PathData* outData, const PathData& morphFrom, + static bool canMorph(const PathData& morphFrom, const PathData& morphTo); + static bool interpolatePathData(PathData* outData, const PathData& morphFrom, const PathData& morphTo, float fraction); - ANDROID_API static void verbsToPath(SkPath* outPath, const PathData& data); + static void verbsToPath(SkPath* outPath, const PathData& data); static void interpolatePaths(PathData* outPathData, const PathData& from, const PathData& to, float fraction); }; diff --git a/libs/usb/tests/AccessoryChat/AndroidManifest.xml b/libs/usb/tests/AccessoryChat/AndroidManifest.xml index 6667ebaa4d49..b93eeab11324 100644 --- a/libs/usb/tests/AccessoryChat/AndroidManifest.xml +++ b/libs/usb/tests/AccessoryChat/AndroidManifest.xml @@ -15,26 +15,28 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.accessorychat"> + package="com.android.accessorychat"> - <uses-feature android:name="android.hardware.usb.accessory" /> + <uses-feature android:name="android.hardware.usb.accessory"/> <application android:label="Accessory Chat"> - <activity android:name="AccessoryChat" android:label="Accessory Chat"> + <activity android:name="AccessoryChat" + android:label="Accessory Chat" + android:exported="true"> <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.DEFAULT" /> - <category android:name="android.intent.category.LAUNCHER" /> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.DEFAULT"/> + <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> <intent-filter> - <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /> + <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"/> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" - android:resource="@xml/accessory_filter" /> + android:resource="@xml/accessory_filter"/> </activity> </application> - <uses-sdk android:minSdkVersion="12" /> + <uses-sdk android:minSdkVersion="12"/> </manifest> |