diff options
27 files changed, 374 insertions, 291 deletions
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 4c2a021836f0..e2e34205df7d 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -206,6 +206,7 @@ cc_defaults { "FrameInfoVisualizer.cpp", "GlLayer.cpp", "GpuMemoryTracker.cpp", + "HardwareBitmapUploader.cpp", "Interpolator.cpp", "JankTracker.cpp", "Layer.cpp", diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index c0944e03fdea..8cf115ebc540 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -44,9 +44,7 @@ Caches* Caches::sInstance = nullptr; // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// -Caches::Caches(RenderState& renderState) - : mRenderState(&renderState) - , mInitialized(false) { +Caches::Caches(RenderState& renderState) : mRenderState(&renderState), mInitialized(false) { INIT_LOGD("Creating OpenGL renderer caches"); init(); initConstraints(); @@ -153,8 +151,7 @@ void Caches::dumpMemoryUsage(String8& log) { // Memory management /////////////////////////////////////////////////////////////////////////////// -void Caches::clearGarbage() { -} +void Caches::clearGarbage() {} void Caches::flush(FlushMode mode) { clearGarbage(); diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp index 40cc73a82846..10fcee88a995 100644 --- a/libs/hwui/DeviceInfo.cpp +++ b/libs/hwui/DeviceInfo.cpp @@ -31,7 +31,7 @@ namespace android { namespace uirenderer { -static constexpr android::DisplayInfo sDummyDisplay { +static constexpr android::DisplayInfo sDummyDisplay{ 1080, // w 1920, // h 320.0, // xdpi diff --git a/libs/hwui/EglReadback.cpp b/libs/hwui/EglReadback.cpp index 2d5367b2508a..65becf88b930 100644 --- a/libs/hwui/EglReadback.cpp +++ b/libs/hwui/EglReadback.cpp @@ -25,8 +25,7 @@ namespace android { namespace uirenderer { -CopyResult EglReadback::copySurfaceInto(Surface& surface, const Rect& srcRect, - SkBitmap* bitmap) { +CopyResult EglReadback::copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) { ATRACE_CALL(); // Setup the source sp<GraphicBuffer> sourceBuffer; @@ -55,9 +54,8 @@ CopyResult EglReadback::copySurfaceInto(Surface& surface, const Rect& srcRect, return copyGraphicBufferInto(sourceBuffer.get(), texTransform, srcRect, bitmap); } -CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, - Matrix4& texTransform, const Rect& srcRect, - SkBitmap* bitmap) { +CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform, + const Rect& srcRect, SkBitmap* bitmap) { mRenderThread.requireGlContext(); // TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via // GL_OES_EGL_image, which doesn't work since we need samplerExternalOES diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp new file mode 100644 index 000000000000..6408ce6c04f4 --- /dev/null +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2018 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. + */ + +#include "HardwareBitmapUploader.h" + +#include "hwui/Bitmap.h" +#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 <SkCanvas.h> +#include <utils/GLUtils.h> +#include <utils/Trace.h> +#include <utils/TraceUtils.h> +#include <thread> + +namespace android::uirenderer { + +static std::mutex sLock{}; +static ThreadBase* sUploadThread = nullptr; +static renderthread::EglManager sEglManager; +static int sPendingUploads = 0; +static nsecs_t sLastUpload = 0; + +static bool shouldTimeOutLocked() { + nsecs_t durationSince = systemTime() - sLastUpload; + return durationSince > 2000_ms; +} + +static void checkIdleTimeout() { + std::lock_guard{sLock}; + if (sPendingUploads == 0 && shouldTimeOutLocked()) { + sEglManager.destroy(); + } else { + sUploadThread->queue().postDelayed(5000_ms, checkIdleTimeout); + } +} + +static void beginUpload() { + std::lock_guard{sLock}; + sPendingUploads++; + + if (!sUploadThread) { + sUploadThread = new ThreadBase{}; + } + + if (!sUploadThread->isRunning()) { + sUploadThread->start("GrallocUploadThread"); + } + + if (!sEglManager.hasEglContext()) { + sUploadThread->queue().runSync([]() { + sEglManager.initialize(); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + }); + sUploadThread->queue().postDelayed(5000_ms, checkIdleTimeout); + } +} + +static void endUpload() { + std::lock_guard{sLock}; + sPendingUploads--; + sLastUpload = systemTime(); +} + +static EGLDisplay getUploadEglDisplay() { + std::lock_guard{sLock}; + LOG_ALWAYS_FATAL_IF(!sEglManager.hasEglContext(), "Forgot to begin an upload?"); + return sEglManager.eglDisplay(); +} + +static bool hasFP16Support() { + static std::once_flag sOnce; + static bool hasFP16Support = false; + + // 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; + }); + + return hasFP16Support; +} + +#define FENCE_TIMEOUT 2000000000 + +class AutoEglImage { +public: + AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) { + EGLint imageAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; + image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, + imageAttrs); + } + + ~AutoEglImage() { + if (image != EGL_NO_IMAGE_KHR) { + eglDestroyImageKHR(mDisplay, image); + } + } + + EGLImageKHR image = EGL_NO_IMAGE_KHR; + +private: + EGLDisplay mDisplay = EGL_NO_DISPLAY; +}; + +class AutoSkiaGlTexture { +public: + AutoSkiaGlTexture() { + glGenTextures(1, &mTexture); + glBindTexture(GL_TEXTURE_2D, mTexture); + } + + ~AutoSkiaGlTexture() { glDeleteTextures(1, &mTexture); } + +private: + GLuint mTexture = 0; +}; + +struct FormatInfo { + PixelFormat pixelFormat; + GLint format, type; + bool isSupported = false; + bool valid = true; +}; + +static FormatInfo determineFormat(const SkBitmap& skBitmap) { + FormatInfo formatInfo; + // TODO: add support for linear blending (when ANDROID_ENABLE_LINEAR_BLENDING is defined) + switch (skBitmap.info().colorType()) { + case kRGBA_8888_SkColorType: + formatInfo.isSupported = true; + // ARGB_4444 is upconverted to RGBA_8888 + case kARGB_4444_SkColorType: + formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; + formatInfo.format = GL_RGBA; + formatInfo.type = GL_UNSIGNED_BYTE; + break; + case kRGBA_F16_SkColorType: + formatInfo.isSupported = hasFP16Support(); + if (formatInfo.isSupported) { + formatInfo.type = GL_HALF_FLOAT; + formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16; + } else { + formatInfo.type = GL_UNSIGNED_BYTE; + formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; + } + formatInfo.format = GL_RGBA; + break; + case kRGB_565_SkColorType: + formatInfo.isSupported = true; + formatInfo.pixelFormat = PIXEL_FORMAT_RGB_565; + formatInfo.format = GL_RGB; + formatInfo.type = GL_UNSIGNED_SHORT_5_6_5; + break; + case kGray_8_SkColorType: + formatInfo.isSupported = true; + formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; + formatInfo.format = GL_LUMINANCE; + formatInfo.type = GL_UNSIGNED_BYTE; + break; + default: + ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType()); + formatInfo.valid = false; + } + return formatInfo; +} + +static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& source) { + if (format.isSupported) { + return source; + } else { + SkBitmap bitmap; + const SkImageInfo& info = source.info(); + bitmap.allocPixels( + SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(), nullptr)); + bitmap.eraseColor(0); + if (info.colorType() == kRGBA_F16_SkColorType) { + // Drawing RGBA_F16 onto ARGB_8888 is not supported + source.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()), + bitmap.getPixels(), bitmap.rowBytes(), 0, 0); + } else { + SkCanvas canvas(bitmap); + canvas.drawBitmap(source, 0.0f, 0.0f, nullptr); + } + return bitmap; + } +} + +class ScopedUploadRequest { +public: + ScopedUploadRequest() { beginUpload(); } + ~ScopedUploadRequest() { endUpload(); } +}; + +sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sourceBitmap) { + ATRACE_CALL(); + + FormatInfo format = determineFormat(sourceBitmap); + if (!format.valid) { + return nullptr; + } + + ScopedUploadRequest _uploadRequest{}; + + 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::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) + + "]"); + + status_t error = buffer->initCheck(); + if (error < 0) { + ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()"); + return nullptr; + } + + 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 + // The EGL image is later bound to a 2D texture + EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer->getNativeBuffer(); + AutoEglImage autoImage(display, clientBuffer); + if (autoImage.image == EGL_NO_IMAGE_KHR) { + ALOGW("Could not create EGL image, err =%s", + uirenderer::renderthread::EglManager::eglErrorString()); + return nullptr; + } + + { + ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height()); + EGLSyncKHR fence = sUploadThread->queue().runSync([&]() -> EGLSyncKHR { + AutoSkiaGlTexture glTexture; + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image); + GL_CHECKPOINT(MODERATE); + + // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we + // provide. + // But asynchronous in sense that driver may upload texture onto hardware buffer when we + // first + // use it in drawing + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), format.format, + format.type, bitmap.getPixels()); + GL_CHECKPOINT(MODERATE); + + EGLSyncKHR uploadFence = + eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL); + LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR, "Could not create sync fence %#x", + eglGetError()); + glFlush(); + return uploadFence; + }); + + EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT); + LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR, + "Failed to wait for the fence %#x", eglGetError()); + + eglDestroySyncKHR(display, fence); + } + + return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info())); +} + +}; // namespace android::uirenderer diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h new file mode 100644 index 000000000000..c0113d81fefb --- /dev/null +++ b/libs/hwui/HardwareBitmapUploader.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 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 <hwui/Bitmap.h> + +namespace android::uirenderer { + +class HardwareBitmapUploader { +public: + static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& sourceBitmap); +}; + +}; // namespace android::uirenderer diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 89bcddcc96d0..31878ac23642 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -19,9 +19,9 @@ #include <GpuMemoryTracker.h> #include <utils/RefBase.h> +#include <SkBlendMode.h> #include <SkColorFilter.h> #include <SkColorSpace.h> -#include <SkBlendMode.h> #include <SkPaint.h> #include "Matrix.h" @@ -95,8 +95,7 @@ public: void postDecStrong(); protected: - Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter>, int alpha, - SkBlendMode mode); + Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter>, int alpha, SkBlendMode mode); RenderState& mRenderState; diff --git a/libs/hwui/NinePatchUtils.h b/libs/hwui/NinePatchUtils.h index db9509fff378..082e95fb1440 100644 --- a/libs/hwui/NinePatchUtils.h +++ b/libs/hwui/NinePatchUtils.h @@ -53,9 +53,8 @@ static inline int NumDistinctRects(const SkCanvas::Lattice& lattice) { return xRects * yRects; } -static inline void SetLatticeFlags(SkCanvas::Lattice* lattice, - SkCanvas::Lattice::RectType* flags, int numFlags, const Res_png_9patch& chunk, - SkColor* colors) { +static inline void SetLatticeFlags(SkCanvas::Lattice* lattice, SkCanvas::Lattice::RectType* flags, + int numFlags, const Res_png_9patch& chunk, SkColor* colors) { lattice->fRectTypes = flags; lattice->fColors = colors; sk_bzero(flags, numFlags * sizeof(SkCanvas::Lattice::RectType)); diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h index 4ddacc8a922d..f1c38031980e 100644 --- a/libs/hwui/Outline.h +++ b/libs/hwui/Outline.h @@ -42,9 +42,8 @@ public: mBounds.set(left, top, right, bottom); mRadius = radius; - // Reuse memory if previous outline was the same shape (rect or round rect). - if ( mPath.countVerbs() > 10) { + if (mPath.countVerbs() > 10) { mPath.reset(); } else { mPath.rewind(); diff --git a/libs/hwui/PathParser.cpp b/libs/hwui/PathParser.cpp index 47fcca92bcca..ad599e9ec316 100644 --- a/libs/hwui/PathParser.cpp +++ b/libs/hwui/PathParser.cpp @@ -210,9 +210,8 @@ void PathParser::validateVerbAndPoints(char verb, size_t points, PathParser::Par if (numberOfPointsExpected > 0) { result->failureMessage += "a multiple of "; } - result->failureMessage += std::to_string(numberOfPointsExpected) - + " floats. However, " + std::to_string(points) - + " float(s) are found. "; + result->failureMessage += std::to_string(numberOfPointsExpected) + " floats. However, " + + std::to_string(points) + " float(s) are found. "; } void PathParser::getPathDataFromAsciiString(PathData* data, ParseResult* result, @@ -242,8 +241,8 @@ void PathParser::getPathDataFromAsciiString(PathData* data, ParseResult* result, validateVerbAndPoints(pathStr[start], points.size(), result); if (result->failureOccurred) { // If either verb or points is not valid, return immediately. - result->failureMessage += "Failure occurred at position " + - std::to_string(start) + " of path: " + pathStr; + result->failureMessage += "Failure occurred at position " + std::to_string(start) + + " of path: " + pathStr; return; } data->verbs.push_back(pathStr[start]); @@ -257,8 +256,8 @@ void PathParser::getPathDataFromAsciiString(PathData* data, ParseResult* result, validateVerbAndPoints(pathStr[start], 0, result); if (result->failureOccurred) { // If either verb or points is not valid, return immediately. - result->failureMessage += "Failure occurred at position " + - std::to_string(start) + " of path: " + pathStr; + result->failureMessage += "Failure occurred at position " + std::to_string(start) + + " of path: " + pathStr; return; } data->verbs.push_back(pathStr[start]); diff --git a/libs/hwui/ProfileData.cpp b/libs/hwui/ProfileData.cpp index 16966619aace..70ca4e3e8074 100644 --- a/libs/hwui/ProfileData.cpp +++ b/libs/hwui/ProfileData.cpp @@ -104,8 +104,8 @@ void ProfileData::dump(int fd) const { dprintf(fd, "\nStats since: %" PRIu64 "ns", mStatStartTime); dprintf(fd, "\nTotal frames rendered: %u", mTotalFrameCount); dprintf(fd, "\nJanky frames: %u (%.2f%%)", mJankFrameCount, - mTotalFrameCount == 0 ? 0.0f : - (float)mJankFrameCount / (float)mTotalFrameCount * 100.0f); + mTotalFrameCount == 0 ? 0.0f + : (float)mJankFrameCount / (float)mTotalFrameCount * 100.0f); dprintf(fd, "\n50th percentile: %ums", findPercentile(50)); dprintf(fd, "\n90th percentile: %ums", findPercentile(90)); dprintf(fd, "\n95th percentile: %ums", findPercentile(95)); diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h index 6470d4c16130..c024373efb9e 100644 --- a/libs/hwui/RenderProperties.h +++ b/libs/hwui/RenderProperties.h @@ -328,9 +328,7 @@ public: bool isPivotExplicitlySet() const { return mPrimitiveFields.mPivotExplicitlySet; } - bool resetPivot() { - return RP_SET_AND_DIRTY(mPrimitiveFields.mPivotExplicitlySet, false); - } + bool resetPivot() { return RP_SET_AND_DIRTY(mPrimitiveFields.mPivotExplicitlySet, false); } bool setCameraDistance(float distance) { if (distance != getCameraDistance()) { @@ -510,17 +508,13 @@ public: getOutline().getAlpha() != 0.0f; } - SkColor getSpotShadowColor() const { - return mPrimitiveFields.mSpotShadowColor; - } + SkColor getSpotShadowColor() const { return mPrimitiveFields.mSpotShadowColor; } bool setSpotShadowColor(SkColor shadowColor) { return RP_SET(mPrimitiveFields.mSpotShadowColor, shadowColor); } - SkColor getAmbientShadowColor() const { - return mPrimitiveFields.mAmbientShadowColor; - } + SkColor getAmbientShadowColor() const { return mPrimitiveFields.mAmbientShadowColor; } bool setAmbientShadowColor(SkColor shadowColor) { return RP_SET(mPrimitiveFields.mAmbientShadowColor, shadowColor); diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 6bd12f4c7ff3..7b41f89605d2 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -736,8 +736,8 @@ void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& p SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); // Stroke with a hairline is drawn on HW with a fill style for compatibility with Android O and // older. - if (!mCanvasOwned && sApiLevel <= 27 && paintCopy.getStrokeWidth() <= 0 - && paintCopy.getStyle() == SkPaint::kStroke_Style) { + if (!mCanvasOwned && sApiLevel <= 27 && paintCopy.getStrokeWidth() <= 0 && + paintCopy.getStyle() == SkPaint::kStroke_Style) { paintCopy.setStyle(SkPaint::kFill_Style); } diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp index 18358e25fd5b..402fbadfec22 100644 --- a/libs/hwui/VectorDrawable.cpp +++ b/libs/hwui/VectorDrawable.cpp @@ -558,8 +558,8 @@ void Tree::draw(SkCanvas* canvas, const SkRect& bounds) { SkRect src; sk_sp<SkSurface> vdSurface = mCache.getSurface(&src); if (vdSurface) { - canvas->drawImageRect(vdSurface->makeImageSnapshot().get(), src, - bounds, getPaint(), SkCanvas::kFast_SrcRectConstraint); + canvas->drawImageRect(vdSurface->makeImageSnapshot().get(), src, bounds, getPaint(), + SkCanvas::kFast_SrcRectConstraint); } else { // Handle the case when VectorDrawableAtlas has been destroyed, because of memory pressure. // We render the VD into a temporary standalone buffer and mark the frame as dirty. Next @@ -570,8 +570,8 @@ void Tree::draw(SkCanvas* canvas, const SkRect& bounds) { int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth()); int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight()); - canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight), - bounds, getPaint(), SkCanvas::kFast_SrcRectConstraint); + canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight), bounds, + getPaint(), SkCanvas::kFast_SrcRectConstraint); mCache.clear(); markDirty(); } diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h index a92b62db14f0..bf98fd619042 100644 --- a/libs/hwui/hwui/AnimatedImageDrawable.h +++ b/libs/hwui/hwui/AnimatedImageDrawable.h @@ -102,9 +102,7 @@ public: Snapshot decodeNextFrame(); Snapshot reset(); - size_t byteSize() const { - return sizeof(this) + mBytesUsed; - } + size_t byteSize() const { return sizeof(this) + mBytesUsed; } protected: virtual void onDraw(SkCanvas* canvas) override; diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index e3b5b8c29cea..962fea9b5f4f 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -16,9 +16,8 @@ #include "Bitmap.h" #include "Caches.h" -#include "renderthread/EglManager.h" +#include "HardwareBitmapUploader.h" #include "renderthread/RenderProxy.h" -#include "renderthread/RenderThread.h" #include "utils/Color.h" #include <sys/mman.h> @@ -85,7 +84,7 @@ static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& info, si } sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(SkBitmap& bitmap) { - return uirenderer::renderthread::RenderProxy::allocateHardwareBitmap(bitmap); + return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap); } sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap) { @@ -206,7 +205,7 @@ Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info) buffer->incStrong(buffer); setImmutable(); // HW bitmaps are always immutable mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast<AHardwareBuffer*>(buffer), - mInfo.alphaType(), mInfo.refColorSpace()); + mInfo.alphaType(), mInfo.refColorSpace()); } Bitmap::~Bitmap() { @@ -286,9 +285,8 @@ void Bitmap::setAlphaType(SkAlphaType alphaType) { void Bitmap::getSkBitmap(SkBitmap* outBitmap) { outBitmap->setHasHardwareMipMap(mHasHardwareMipMap); if (isHardware()) { - outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(), - info().colorType(), info().alphaType(), - nullptr)); + outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(), + info().colorType(), info().alphaType(), nullptr)); uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap); if (mInfo.colorSpace()) { sk_sp<SkPixelRef> pixelRef = sk_ref_sp(outBitmap->pixelRef()); diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h index 4f06656e8e6d..dbd445682bde 100644 --- a/libs/hwui/hwui/Bitmap.h +++ b/libs/hwui/hwui/Bitmap.h @@ -65,9 +65,7 @@ public: Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes); Bitmap(GraphicBuffer* buffer, const SkImageInfo& info); - int rowBytesAsPixels() const { - return rowBytes() >> mInfo.shiftPerPixel(); - } + int rowBytesAsPixels() const { return rowBytes() >> mInfo.shiftPerPixel(); } void reconfigure(const SkImageInfo& info, size_t rowBytes); void reconfigure(const SkImageInfo& info); diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp index 4b8b83227e93..fb6bd6f0821a 100644 --- a/libs/hwui/hwui/Canvas.cpp +++ b/libs/hwui/hwui/Canvas.cpp @@ -158,9 +158,8 @@ void Canvas::drawText(const uint16_t* text, int textSize, int start, int count, // minikin may modify the original paint Paint paint(origPaint); - minikin::Layout layout = - MinikinUtils::doLayout(&paint, bidiFlags, typeface, text, textSize, start, count, - contextStart, contextCount, mt); + minikin::Layout layout = MinikinUtils::doLayout(&paint, bidiFlags, typeface, text, textSize, + start, count, contextStart, contextCount, mt); x += MinikinUtils::xOffsetForTextAlign(&paint, layout); @@ -207,11 +206,11 @@ void Canvas::drawTextOnPath(const uint16_t* text, int count, minikin::Bidi bidiF const SkPath& path, float hOffset, float vOffset, const Paint& paint, const Typeface* typeface) { Paint paintCopy(paint); - minikin::Layout layout = MinikinUtils::doLayout(&paintCopy, bidiFlags, typeface, - text, count, // text buffer - 0, count, // draw range - 0, count, // context range - nullptr); + minikin::Layout layout = + MinikinUtils::doLayout(&paintCopy, bidiFlags, typeface, text, count, // text buffer + 0, count, // draw range + 0, count, // context range + nullptr); hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path); // Set align to left for drawing, as we don't want individual diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp index 3ccb8f32a656..a52263c847d0 100644 --- a/libs/hwui/hwui/MinikinSkia.cpp +++ b/libs/hwui/hwui/MinikinSkia.cpp @@ -135,9 +135,8 @@ uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) { SkPaint::Hinting hinting = paint->getHinting(); // select only flags that might affect text layout flags &= (SkPaint::kAntiAlias_Flag | SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag | - SkPaint::kSubpixelText_Flag | - SkPaint::kEmbeddedBitmapText_Flag | SkPaint::kAutoHinting_Flag | - SkPaint::kVerticalText_Flag); + SkPaint::kSubpixelText_Flag | SkPaint::kEmbeddedBitmapText_Flag | + SkPaint::kAutoHinting_Flag | SkPaint::kVerticalText_Flag); flags |= (hinting << 16); return flags; } diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h index 60e0e7e86531..d27d54454ea0 100644 --- a/libs/hwui/hwui/MinikinUtils.h +++ b/libs/hwui/hwui/MinikinUtils.h @@ -25,11 +25,11 @@ #define _ANDROID_GRAPHICS_MINIKIN_UTILS_H_ #include <cutils/compiler.h> +#include <log/log.h> #include <minikin/Layout.h> #include "MinikinSkia.h" #include "Paint.h" #include "Typeface.h" -#include <log/log.h> namespace minikin { class MeasuredText; diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp index dca9ef5559a6..d9856336e8bd 100644 --- a/libs/hwui/hwui/Typeface.cpp +++ b/libs/hwui/hwui/Typeface.cpp @@ -132,8 +132,10 @@ Typeface* Typeface::createFromFamilies(std::vector<std::shared_ptr<minikin::Font bool italicFromFont; const minikin::FontStyle defaultStyle; - const minikin::MinikinFont* mf = families.empty() ? nullptr - : families[0]->getClosestMatch(defaultStyle).font->typeface().get(); + const minikin::MinikinFont* mf = + families.empty() + ? nullptr + : families[0]->getClosestMatch(defaultStyle).font->typeface().get(); if (mf != nullptr) { SkTypeface* skTypeface = reinterpret_cast<const MinikinFontSkia*>(mf)->GetSkTypeface(); const SkFontStyle& style = skTypeface->fontStyle(); diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index 766fab61f3db..78f5a71dee3b 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -251,210 +251,6 @@ void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* func } } -#define FENCE_TIMEOUT 2000000000 - -class AutoEglImage { -public: - AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) { - EGLint imageAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; - image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, - imageAttrs); - } - - ~AutoEglImage() { - if (image != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(mDisplay, image); - } - } - - EGLImageKHR image = EGL_NO_IMAGE_KHR; - -private: - EGLDisplay mDisplay = EGL_NO_DISPLAY; -}; - -class AutoSkiaGlTexture { -public: - AutoSkiaGlTexture() { - glGenTextures(1, &mTexture); - glBindTexture(GL_TEXTURE_2D, mTexture); - } - - ~AutoSkiaGlTexture() { glDeleteTextures(1, &mTexture); } - -private: - GLuint mTexture = 0; -}; - -struct FormatInfo { - PixelFormat pixelFormat; - GLint format, type; - bool isSupported = false; - bool valid = true; -}; - -static bool gpuSupportsHalfFloatTextures(renderthread::RenderThread& renderThread) { - static bool isSupported = renderThread.queue().runSync([&renderThread]() -> bool { - renderThread.requireGlContext(); - sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext()); - if (!grContext->colorTypeSupportedAsImage(kRGBA_F16_SkColorType)) { - return false; - } - 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(); - return error != OK; - }); - return isSupported; -} - -static FormatInfo determineFormat(renderthread::RenderThread& renderThread, - const SkBitmap& skBitmap) { - FormatInfo formatInfo; - // TODO: add support for linear blending (when ANDROID_ENABLE_LINEAR_BLENDING is defined) - switch (skBitmap.info().colorType()) { - case kRGBA_8888_SkColorType: - formatInfo.isSupported = true; - // ARGB_4444 is upconverted to RGBA_8888 - case kARGB_4444_SkColorType: - formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; - formatInfo.format = GL_RGBA; - formatInfo.type = GL_UNSIGNED_BYTE; - break; - case kRGBA_F16_SkColorType: - formatInfo.isSupported = gpuSupportsHalfFloatTextures(renderThread); - if (formatInfo.isSupported) { - formatInfo.type = GL_HALF_FLOAT; - formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16; - } else { - formatInfo.type = GL_UNSIGNED_BYTE; - formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; - } - formatInfo.format = GL_RGBA; - break; - case kRGB_565_SkColorType: - formatInfo.isSupported = true; - formatInfo.pixelFormat = PIXEL_FORMAT_RGB_565; - formatInfo.format = GL_RGB; - formatInfo.type = GL_UNSIGNED_SHORT_5_6_5; - break; - case kGray_8_SkColorType: - formatInfo.isSupported = true; - formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; - formatInfo.format = GL_LUMINANCE; - formatInfo.type = GL_UNSIGNED_BYTE; - break; - default: - ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType()); - formatInfo.valid = false; - } - return formatInfo; -} - -static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& source) { - if (format.isSupported) { - return source; - } else { - SkBitmap bitmap; - const SkImageInfo& info = source.info(); - bitmap.allocPixels( - SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(), nullptr)); - bitmap.eraseColor(0); - if (info.colorType() == kRGBA_F16_SkColorType) { - // Drawing RGBA_F16 onto ARGB_8888 is not supported - source.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()), - bitmap.getPixels(), bitmap.rowBytes(), 0, 0); - } else { - SkCanvas canvas(bitmap); - canvas.drawBitmap(source, 0.0f, 0.0f, nullptr); - } - return bitmap; - } -} - -sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThread& thread, - const SkBitmap& sourceBitmap) { - ATRACE_CALL(); - - LOG_ALWAYS_FATAL_IF(thread.isCurrent(), "Must not be called on RenderThread"); - - FormatInfo format = determineFormat(thread, sourceBitmap); - if (!format.valid) { - return nullptr; - } - - 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::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) + - "]"); - - status_t error = buffer->initCheck(); - if (error < 0) { - ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()"); - return nullptr; - } - - EGLDisplay display = thread.queue().runSync([&]() -> EGLDisplay { - thread.requireGlContext(); - return eglGetCurrentDisplay(); - }); - - 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 - // The EGL image is later bound to a 2D texture - EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer->getNativeBuffer(); - AutoEglImage autoImage(display, clientBuffer); - if (autoImage.image == EGL_NO_IMAGE_KHR) { - ALOGW("Could not create EGL image, err =%s", - uirenderer::renderthread::EglManager::eglErrorString()); - return nullptr; - } - - { - ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height()); - EGLSyncKHR fence = thread.queue().runSync([&]() -> EGLSyncKHR { - thread.requireGlContext(); - sk_sp<GrContext> grContext = sk_ref_sp(thread.getGrContext()); - AutoSkiaGlTexture glTexture; - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image); - GL_CHECKPOINT(MODERATE); - - // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we - // provide. - // But asynchronous in sense that driver may upload texture onto hardware buffer when we - // first - // use it in drawing - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), format.format, - format.type, bitmap.getPixels()); - GL_CHECKPOINT(MODERATE); - - EGLSyncKHR uploadFence = - eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL); - LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR, "Could not create sync fence %#x", - eglGetError()); - glFlush(); - grContext->resetContext(kTextureBinding_GrGLBackendState); - return uploadFence; - }); - - EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT); - LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR, - "Failed to wait for the fence %#x", eglGetError()); - - eglDestroySyncKHR(display, fence); - } - - return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info())); -} - } /* namespace skiapipeline */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index 04b68f5e3278..2e2e1522b717 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -50,10 +50,6 @@ public: static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor); - // May be called by any thread except RenderThread. - static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread, - const SkBitmap& skBitmap); - private: renderthread::EglManager& mEglManager; EGLSurface mEglSurface = EGL_NO_SURFACE; diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h index ca6d1b8b74c6..8e8bb8b68a1c 100644 --- a/libs/hwui/renderthread/EglManager.h +++ b/libs/hwui/renderthread/EglManager.h @@ -64,6 +64,8 @@ public: void fence(); + EGLDisplay eglDisplay() const { return mEglDisplay; } + private: void initExtensions(); diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 4d1e1e8fb04b..02d0b6d4a77f 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -319,17 +319,6 @@ void RenderProxy::prepareToDraw(Bitmap& bitmap) { } } -sk_sp<Bitmap> RenderProxy::allocateHardwareBitmap(SkBitmap& bitmap) { - auto& thread = RenderThread::getInstance(); - if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { - return skiapipeline::SkiaOpenGLPipeline::allocateHardwareBitmap(thread, bitmap); - } else { - return thread.queue().runSync([&]() -> auto { - return thread.allocateHardwareBitmap(bitmap); - }); - } -} - int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) { RenderThread& thread = RenderThread::getInstance(); if (gettid() == thread.getTid()) { diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 433adeb5eb37..9e46161454fe 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -123,8 +123,6 @@ public: int bottom, SkBitmap* bitmap); ANDROID_API static void prepareToDraw(Bitmap& bitmap); - static sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& bitmap); - static int copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap); static void onBitmapDestroyed(uint32_t pixelRefId); diff --git a/libs/hwui/thread/ThreadBase.h b/libs/hwui/thread/ThreadBase.h index 8068121f64cf..f9de8a5037e5 100644 --- a/libs/hwui/thread/ThreadBase.h +++ b/libs/hwui/thread/ThreadBase.h @@ -47,6 +47,8 @@ public: void join() { Thread::join(); } + bool isRunning() const { return Thread::isRunning(); } + protected: void waitForWork() { nsecs_t nextWakeup; |