From e170fb6686c3e88cee6e32f4e3eb12fcf9bfe931 Mon Sep 17 00:00:00 2001 From: John Reck Date: Mon, 7 May 2018 08:12:07 -0700 Subject: A better HW Bitmap uploader Move all HW bitmap upload operations off of RenderThread. Ensure EGL context outlives all upload requests Bug: 79250950 Test: builds, boots, systrace is good, CTS bitmap tests pass Change-Id: I5ace6c516d33b1afdf1a407cd8b183f6b60c22c1 --- libs/hwui/HardwareBitmapUploader.cpp | 292 +++++++++++++++++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 libs/hwui/HardwareBitmapUploader.cpp (limited to 'libs/hwui/HardwareBitmapUploader.cpp') 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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sourceBitmap) { + ATRACE_CALL(); + + FormatInfo format = determineFormat(sourceBitmap); + if (!format.valid) { + return nullptr; + } + + ScopedUploadRequest _uploadRequest{}; + + SkBitmap bitmap = makeHwCompatible(format, sourceBitmap); + sp buffer = new GraphicBuffer( + static_cast(bitmap.width()), static_cast(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(new Bitmap(buffer.get(), bitmap.info())); +} + +}; // namespace android::uirenderer -- cgit v1.2.3-59-g8ed1b From 339cf9b3272f8581aa4cae34be368d1ff78e85c8 Mon Sep 17 00:00:00 2001 From: John Reck Date: Wed, 18 Jul 2018 16:32:27 -0700 Subject: More auto-dark stuff Initial attempt at selective bitmap inverting Use CIE_LAB colorspace for inverting instead of HSV Test: Manually poking around Change-Id: I014ff31eeae471ee7f6a40a6daa4e7099c2a7ff8 --- libs/hwui/CanvasTransform.cpp | 36 +++++++----- libs/hwui/HardwareBitmapUploader.cpp | 2 +- libs/hwui/hwui/Bitmap.cpp | 107 ++++++++++++++++++++++++++++++++++- libs/hwui/hwui/Bitmap.h | 25 +++++++- libs/hwui/utils/Color.cpp | 96 ++++++++++++++++++++++++++++++- libs/hwui/utils/Color.h | 10 ++++ 6 files changed, 256 insertions(+), 20 deletions(-) (limited to 'libs/hwui/HardwareBitmapUploader.cpp') diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp index bac7a4d17a49..1b15dbd526cc 100644 --- a/libs/hwui/CanvasTransform.cpp +++ b/libs/hwui/CanvasTransform.cpp @@ -15,32 +15,38 @@ */ #include "CanvasTransform.h" +#include "utils/Color.h" #include "Properties.h" +#include #include #include -#include + +#include +#include namespace android::uirenderer { static SkColor makeLight(SkColor color) { - SkScalar hsv[3]; - SkColorToHSV(color, hsv); - if (hsv[1] > .2f) return color; - // hsv[1] *= .85f; - // hsv[2] = std::min(1.0f, std::max(hsv[2], 1 - hsv[2]) * 1.3f); - hsv[2] = std::max(hsv[2], 1.1f - hsv[2]); - return SkHSVToColor(SkColorGetA(color), hsv); + Lab lab = sRGBToLab(color); + float invertedL = std::min(110 - lab.L, 100.0f); + if (invertedL > lab.L) { + lab.L = invertedL; + return LabToSRGB(lab, SkColorGetA(color)); + } else { + return color; + } } static SkColor makeDark(SkColor color) { - SkScalar hsv[3]; - SkColorToHSV(color, hsv); - if (hsv[1] > .2f) return color; - // hsv[1] *= .85f; - // hsv[2] = std::max(0.0f, std::min(hsv[2], 1 - hsv[2]) * .7f); - hsv[2] = std::min(hsv[2], 1.1f - hsv[2]); - return SkHSVToColor(SkColorGetA(color), hsv); + Lab lab = sRGBToLab(color); + float invertedL = std::min(110 - lab.L, 100.0f); + if (invertedL < lab.L) { + lab.L = invertedL; + return LabToSRGB(lab, SkColorGetA(color)); + } else { + return color; + } } static SkColor transformColor(ColorTransform transform, SkColor color) { diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp index 6408ce6c04f4..ab80d3d98448 100644 --- a/libs/hwui/HardwareBitmapUploader.cpp +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -286,7 +286,7 @@ sk_sp HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sou eglDestroySyncKHR(display, fence); } - return sk_sp(new Bitmap(buffer.get(), bitmap.info())); + return sk_sp(new Bitmap(buffer.get(), bitmap.info(), Bitmap::computePalette(bitmap))); } }; // namespace android::uirenderer diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index a401b3f96ef2..7a8d026df3b4 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -17,6 +17,7 @@ #include "Caches.h" #include "HardwareBitmapUploader.h" +#include "Properties.h" #include "renderthread/RenderProxy.h" #include "utils/Color.h" @@ -34,6 +35,7 @@ #include #include +#include namespace android { @@ -195,11 +197,13 @@ Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info mPixelStorage.ashmem.size = mappedSize; } -Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info) +Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info, BitmapPalette palette) : SkPixelRef(info.width(), info.height(), nullptr, bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride()) , mInfo(validateAlpha(info)) - , mPixelStorageType(PixelStorageType::Hardware) { + , mPixelStorageType(PixelStorageType::Hardware) + , mPalette(palette) + , mPaletteGenerationId(getGenerationID()) { mPixelStorage.hardware.buffer = buffer; buffer->incStrong(buffer); setImmutable(); // HW bitmaps are always immutable @@ -326,7 +330,106 @@ sk_sp Bitmap::makeImage(sk_sp* outputColorFilter) { if (image->colorSpace() != nullptr && !image->colorSpace()->isSRGB()) { *outputColorFilter = SkToSRGBColorFilter::Make(image->refColorSpace()); } + + // TODO: Move this to the canvas (or other?) layer where we have the target lightness + // mode and can selectively do the right thing. + if (palette() != BitmapPalette::Unknown && uirenderer::Properties::forceDarkMode) { + SkHighContrastConfig config; + config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness; + *outputColorFilter = SkHighContrastFilter::Make(config)->makeComposed(*outputColorFilter); + } return image; } +class MinMaxAverage { +public: + + void add(float sample) { + if (mCount == 0) { + mMin = sample; + mMax = sample; + } else { + mMin = std::min(mMin, sample); + mMax = std::max(mMax, sample); + } + mTotal += sample; + mCount++; + } + + float average() { + return mTotal / mCount; + } + + float min() { + return mMin; + } + + float max() { + return mMax; + } + + float delta() { + return mMax - mMin; + } + +private: + float mMin = 0.0f; + float mMax = 0.0f; + float mTotal = 0.0f; + int mCount = 0; +}; + +BitmapPalette Bitmap::computePalette(const SkImageInfo& info, const void* addr, size_t rowBytes) { + ATRACE_CALL(); + + SkPixmap pixmap{info, addr, rowBytes}; + + // TODO: This calculation of converting to HSV & tracking min/max is probably overkill + // Experiment with something simpler since we just want to figure out if it's "color-ful" + // and then the average perceptual lightness. + + MinMaxAverage hue, saturation, value; + int sampledCount = 0; + + // Sample a grid of 100 pixels to get an overall estimation of the colors in play + const int x_step = std::max(1, pixmap.width() / 10); + const int y_step = std::max(1, pixmap.height() / 10); + for (int x = 0; x < pixmap.width(); x += x_step) { + for (int y = 0; y < pixmap.height(); y += y_step) { + SkColor color = pixmap.getColor(x, y); + if (!info.isOpaque() && SkColorGetA(color) < 75) { + continue; + } + + sampledCount++; + float hsv[3]; + SkColorToHSV(color, hsv); + hue.add(hsv[0]); + saturation.add(hsv[1]); + value.add(hsv[2]); + } + } + + // TODO: Tune the coverage threshold + if (sampledCount < 5) { + ALOGV("Not enough samples, only found %d for image sized %dx%d, format = %d, alpha = %d", + sampledCount, info.width(), info.height(), (int) info.colorType(), (int) info.alphaType()); + return BitmapPalette::Unknown; + } + + ALOGV("samples = %d, hue [min = %f, max = %f, avg = %f]; saturation [min = %f, max = %f, avg = %f]", + sampledCount, + hue.min(), hue.max(), hue.average(), + saturation.min(), saturation.max(), saturation.average()); + + if (hue.delta() <= 20 && saturation.delta() <= .1f) { + if (value.average() >= .5f) { + return BitmapPalette::Light; + } else { + return BitmapPalette::Dark; + } + } + return BitmapPalette::Unknown; +} + } // namespace android diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h index dbd445682bde..d2680429a1e9 100644 --- a/libs/hwui/hwui/Bitmap.h +++ b/libs/hwui/hwui/Bitmap.h @@ -34,6 +34,12 @@ enum class PixelStorageType { Hardware, }; +enum class BitmapPalette { + Unknown, + Light, + Dark, +}; + namespace uirenderer { namespace renderthread { class RenderThread; @@ -63,7 +69,7 @@ public: Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info, size_t rowBytes); Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes); - Bitmap(GraphicBuffer* buffer, const SkImageInfo& info); + Bitmap(GraphicBuffer* buffer, const SkImageInfo& info, BitmapPalette palette = BitmapPalette::Unknown); int rowBytesAsPixels() const { return rowBytes() >> mInfo.shiftPerPixel(); } @@ -103,6 +109,20 @@ public: */ sk_sp makeImage(sk_sp* outputColorFilter); + static BitmapPalette computePalette(const SkImageInfo& info, const void* addr, size_t rowBytes); + + static BitmapPalette computePalette(const SkBitmap& bitmap) { + return computePalette(bitmap.info(), bitmap.getPixels(), bitmap.rowBytes()); + } + + BitmapPalette palette() { + if (!isHardware() && mPaletteGenerationId != getGenerationID()) { + mPalette = computePalette(info(), pixels(), rowBytes()); + mPaletteGenerationId = getGenerationID(); + } + return mPalette; + } + private: virtual ~Bitmap(); void* getStorage() const; @@ -111,6 +131,9 @@ private: const PixelStorageType mPixelStorageType; + BitmapPalette mPalette = BitmapPalette::Unknown; + uint32_t mPaletteGenerationId = -1; + bool mHasHardwareMipMap = false; union { diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp index 75740e8b5baf..a3e785957526 100644 --- a/libs/hwui/utils/Color.cpp +++ b/libs/hwui/utils/Color.cpp @@ -16,8 +16,10 @@ #include "Color.h" - #include +#include + +#include #include namespace android { @@ -107,5 +109,97 @@ sk_sp DataSpaceToColorSpace(android_dataspace dataspace) { } } +template +static constexpr T clamp(T x, T min, T max) { + return x < min ? min : x > max ? max : x; +} + +//static const float2 ILLUMINANT_D50_XY = {0.34567f, 0.35850f}; +static const float3 ILLUMINANT_D50_XYZ = {0.964212f, 1.0f, 0.825188f}; +static const mat3 BRADFORD = mat3{ + float3{ 0.8951f, -0.7502f, 0.0389f}, + float3{ 0.2664f, 1.7135f, -0.0685f}, + float3{-0.1614f, 0.0367f, 1.0296f} +}; + +static mat3 adaptation(const mat3& matrix, const float3& srcWhitePoint, const float3& dstWhitePoint) { + float3 srcLMS = matrix * srcWhitePoint; + float3 dstLMS = matrix * dstWhitePoint; + return inverse(matrix) * mat3{dstLMS / srcLMS} * matrix; +} + +namespace LabColorSpace { + +static constexpr float A = 216.0f / 24389.0f; +static constexpr float B = 841.0f / 108.0f; +static constexpr float C = 4.0f / 29.0f; +static constexpr float D = 6.0f / 29.0f; + +float3 toXyz(const Lab& lab) { + float3 v { lab.L, lab.a, lab.b }; + v[0] = clamp(v[0], 0.0f, 100.0f); + v[1] = clamp(v[1], -128.0f, 128.0f); + v[2] = clamp(v[2], -128.0f, 128.0f); + + float fy = (v[0] + 16.0f) / 116.0f; + float fx = fy + (v[1] * 0.002f); + float fz = fy - (v[2] * 0.005f); + float X = fx > D ? fx * fx * fx : (1.0f / B) * (fx - C); + float Y = fy > D ? fy * fy * fy : (1.0f / B) * (fy - C); + float Z = fz > D ? fz * fz * fz : (1.0f / B) * (fz - C); + + v[0] = X * ILLUMINANT_D50_XYZ[0]; + v[1] = Y * ILLUMINANT_D50_XYZ[1]; + v[2] = Z * ILLUMINANT_D50_XYZ[2]; + + return v; +} + +Lab fromXyz(const float3& v) { + float X = v[0] / ILLUMINANT_D50_XYZ[0]; + float Y = v[1] / ILLUMINANT_D50_XYZ[1]; + float Z = v[2] / ILLUMINANT_D50_XYZ[2]; + + float fx = X > A ? pow(X, 1.0f / 3.0f) : B * X + C; + float fy = Y > A ? pow(Y, 1.0f / 3.0f) : B * Y + C; + float fz = Z > A ? pow(Z, 1.0f / 3.0f) : B * Z + C; + + float L = 116.0f * fy - 16.0f; + float a = 500.0f * (fx - fy); + float b = 200.0f * (fy - fz); + + return Lab { + clamp(L, 0.0f, 100.0f), + clamp(a, -128.0f, 128.0f), + clamp(b, -128.0f, 128.0f) + }; +} + +}; + +Lab sRGBToLab(SkColor color) { + auto colorSpace = ColorSpace::sRGB(); + float3 rgb; + rgb.r = SkColorGetR(color) / 255.0f; + rgb.g = SkColorGetG(color) / 255.0f; + rgb.b = SkColorGetB(color) / 255.0f; + float3 xyz = colorSpace.rgbToXYZ(rgb); + float3 srcXYZ = ColorSpace::XYZ(float3{colorSpace.getWhitePoint(), 1}); + xyz = adaptation(BRADFORD, srcXYZ, ILLUMINANT_D50_XYZ) * xyz; + return LabColorSpace::fromXyz(xyz); +} + +SkColor LabToSRGB(const Lab& lab, SkAlpha alpha) { + auto colorSpace = ColorSpace::sRGB(); + float3 xyz = LabColorSpace::toXyz(lab); + float3 dstXYZ = ColorSpace::XYZ(float3{colorSpace.getWhitePoint(), 1}); + xyz = adaptation(BRADFORD, ILLUMINANT_D50_XYZ, dstXYZ) * xyz; + float3 rgb = colorSpace.xyzToRGB(xyz); + return SkColorSetARGB(alpha, + static_cast(rgb.r * 255), + static_cast(rgb.g * 255), + static_cast(rgb.b * 255)); +} + }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h index 2bec1f5f7852..3c13a548fe76 100644 --- a/libs/hwui/utils/Color.h +++ b/libs/hwui/utils/Color.h @@ -114,6 +114,16 @@ static constexpr float EOCF(float srgb) { bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace); sk_sp DataSpaceToColorSpace(android_dataspace dataspace); + +struct Lab { + float L; + float a; + float b; +}; + +Lab sRGBToLab(SkColor color); +SkColor LabToSRGB(const Lab& lab, SkAlpha alpha); + } /* namespace uirenderer */ } /* namespace android */ -- cgit v1.2.3-59-g8ed1b From d1a491fdfa40ee63372c531c7c7fe2d8c0dfe989 Mon Sep 17 00:00:00 2001 From: John Reck Date: Mon, 17 Sep 2018 15:01:58 -0700 Subject: Fix silly mistake Need to actually store to a local or the scope is lost -_- Test: builds Bug: 114220418 Change-Id: I372e9df11c3e3671af124b9f1c490f32abf8342c --- libs/hwui/HardwareBitmapUploader.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'libs/hwui/HardwareBitmapUploader.cpp') diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp index ab80d3d98448..8ae8525f1441 100644 --- a/libs/hwui/HardwareBitmapUploader.cpp +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -45,7 +45,7 @@ static bool shouldTimeOutLocked() { } static void checkIdleTimeout() { - std::lock_guard{sLock}; + std::lock_guard _lock{sLock}; if (sPendingUploads == 0 && shouldTimeOutLocked()) { sEglManager.destroy(); } else { @@ -54,7 +54,7 @@ static void checkIdleTimeout() { } static void beginUpload() { - std::lock_guard{sLock}; + std::lock_guard _lock{sLock}; sPendingUploads++; if (!sUploadThread) { @@ -75,13 +75,13 @@ static void beginUpload() { } static void endUpload() { - std::lock_guard{sLock}; + std::lock_guard _lock{sLock}; sPendingUploads--; sLastUpload = systemTime(); } static EGLDisplay getUploadEglDisplay() { - std::lock_guard{sLock}; + std::lock_guard _lock{sLock}; LOG_ALWAYS_FATAL_IF(!sEglManager.hasEglContext(), "Forgot to begin an upload?"); return sEglManager.eglDisplay(); } -- cgit v1.2.3-59-g8ed1b From 11606ffa364a5f99b892c550c750e482133a9f45 Mon Sep 17 00:00:00 2001 From: Stan Iliev Date: Mon, 17 Sep 2018 14:01:16 -0400 Subject: Implement WebView support for Vulkan using temporary buffer Draw WebView in an offscreen GL buffer, then import and draw the buffer with Vulkan. Bug: 115610873 Test: Passed WebView CTS tests that are part of UiRendering. Change-Id: Ida137fe9b8652d2a936ec2798b909be7e77b3462 --- libs/hwui/Android.bp | 1 + libs/hwui/HardwareBitmapUploader.cpp | 33 ---- libs/hwui/pipeline/skia/DumpOpsCanvas.h | 8 +- libs/hwui/pipeline/skia/FunctorDrawable.h | 53 ++++++ libs/hwui/pipeline/skia/GLFunctorDrawable.cpp | 6 - libs/hwui/pipeline/skia/GLFunctorDrawable.h | 18 +- libs/hwui/pipeline/skia/SkiaDisplayList.cpp | 2 +- libs/hwui/pipeline/skia/SkiaDisplayList.h | 6 +- libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp | 15 +- libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp | 5 +- libs/hwui/pipeline/skia/VkFunctorDrawable.cpp | 223 ++++++++++++++++++++++++ libs/hwui/pipeline/skia/VkFunctorDrawable.h | 55 ++++++ libs/hwui/tests/unit/SkiaDisplayListTests.cpp | 7 +- libs/hwui/utils/Color.cpp | 20 +++ libs/hwui/utils/Color.h | 3 + libs/hwui/utils/GLUtils.cpp | 17 ++ libs/hwui/utils/GLUtils.h | 51 ++++++ 17 files changed, 454 insertions(+), 69 deletions(-) create mode 100644 libs/hwui/pipeline/skia/FunctorDrawable.h create mode 100644 libs/hwui/pipeline/skia/VkFunctorDrawable.cpp create mode 100644 libs/hwui/pipeline/skia/VkFunctorDrawable.h (limited to 'libs/hwui/HardwareBitmapUploader.cpp') diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index b01136361101..11dad2e0d731 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -175,6 +175,7 @@ cc_defaults { "pipeline/skia/SkiaRecordingCanvas.cpp", "pipeline/skia/SkiaVulkanPipeline.cpp", "pipeline/skia/VectorDrawableAtlas.cpp", + "pipeline/skia/VkFunctorDrawable.cpp", "renderstate/RenderState.cpp", "renderthread/CacheManager.cpp", "renderthread/CanvasContext.cpp", diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp index ab80d3d98448..7dbef65f10cb 100644 --- a/libs/hwui/HardwareBitmapUploader.cpp +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -107,39 +107,6 @@ static bool 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; diff --git a/libs/hwui/pipeline/skia/DumpOpsCanvas.h b/libs/hwui/pipeline/skia/DumpOpsCanvas.h index dcfe6b371171..e4ba13da709c 100644 --- a/libs/hwui/pipeline/skia/DumpOpsCanvas.h +++ b/libs/hwui/pipeline/skia/DumpOpsCanvas.h @@ -138,7 +138,7 @@ protected: renderNodeDrawable->getRenderNode()->output(mOutput, mLevel + 1); return; } - auto glFunctorDrawable = getGLFunctorDrawable(drawable); + auto glFunctorDrawable = getFunctorDrawable(drawable); if (nullptr != glFunctorDrawable) { mOutput << std::string(mLevel * 2, ' ') << "drawGLFunctorDrawable" << std::endl; return; @@ -157,10 +157,10 @@ private: return nullptr; } - GLFunctorDrawable* getGLFunctorDrawable(SkDrawable* drawable) { + FunctorDrawable* getFunctorDrawable(SkDrawable* drawable) { for (auto& child : mDisplayList.mChildFunctors) { - if (drawable == &child) { - return &child; + if (drawable == child) { + return child; } } return nullptr; diff --git a/libs/hwui/pipeline/skia/FunctorDrawable.h b/libs/hwui/pipeline/skia/FunctorDrawable.h new file mode 100644 index 000000000000..162d13762e1a --- /dev/null +++ b/libs/hwui/pipeline/skia/FunctorDrawable.h @@ -0,0 +1,53 @@ +/* + * 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 "GlFunctorLifecycleListener.h" + +#include +#include + +#include + +namespace android { +namespace uirenderer { + +namespace skiapipeline { + +/** + * This drawable wraps a functor enabling it to be recorded into a list + * of Skia drawing commands. + */ +class FunctorDrawable : public SkDrawable { +public: + FunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas) + : mFunctor(functor), mListener(listener), mBounds(canvas->getLocalClipBounds()) {} + virtual ~FunctorDrawable() {} + + virtual void syncFunctor() const = 0; + +protected: + virtual SkRect onGetBounds() override { return mBounds; } + + Functor* mFunctor; + sp mListener; + const SkRect mBounds; +}; + +}; // namespace skiapipeline +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp index b0fec7a70699..90d5e715f8cd 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp @@ -18,7 +18,6 @@ #include #include #include "GlFunctorLifecycleListener.h" -#include "Properties.h" #include "RenderNode.h" #include "SkAndroidFrameworkUtils.h" #include "SkClipStack.h" @@ -80,11 +79,6 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { return; } - if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { - canvas->clear(SK_ColorRED); - return; - } - GLuint fboID = 0; SkISize fboSize; if (!GetFboDetails(canvas, &fboID, &fboSize)) { diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.h b/libs/hwui/pipeline/skia/GLFunctorDrawable.h index d9e65c95444e..dd6ef25f30c5 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.h +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.h @@ -16,12 +16,8 @@ #pragma once -#include "GlFunctorLifecycleListener.h" +#include "FunctorDrawable.h" -#include -#include - -#include #include namespace android { @@ -33,22 +29,16 @@ namespace skiapipeline { * This drawable wraps a OpenGL functor enabling it to be recorded into a list * of Skia drawing commands. */ -class GLFunctorDrawable : public SkDrawable { +class GLFunctorDrawable : public FunctorDrawable { public: GLFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas) - : mFunctor(functor), mListener(listener), mBounds(canvas->getLocalClipBounds()) {} + : FunctorDrawable(functor, listener, canvas) {} virtual ~GLFunctorDrawable(); - void syncFunctor() const; + void syncFunctor() const override; protected: - virtual SkRect onGetBounds() override { return mBounds; } virtual void onDraw(SkCanvas* canvas) override; - -private: - Functor* mFunctor; - sp mListener; - const SkRect mBounds; }; }; // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index 82179a37f5be..78b64b2f01eb 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -29,7 +29,7 @@ namespace skiapipeline { void SkiaDisplayList::syncContents() { for (auto& functor : mChildFunctors) { - functor.syncFunctor(); + functor->syncFunctor(); } for (auto& animatedImage : mAnimatedImages) { animatedImage->syncProperties(); diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index 4f30f98e147d..4c7853931029 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -17,7 +17,7 @@ #pragma once #include "hwui/AnimatedImageDrawable.h" -#include "GLFunctorDrawable.h" +#include "FunctorDrawable.h" #include "RecordingCanvas.h" #include "RenderNodeDrawable.h" #include "TreeInfo.h" @@ -77,7 +77,7 @@ public: * that creates them. Allocator dtor invokes all SkDrawable dtors. */ template - SkDrawable* allocateDrawable(Params&&... params) { + T* allocateDrawable(Params&&... params) { return allocator.create(std::forward(params)...); } @@ -155,7 +155,7 @@ public: * cannot relocate. */ std::deque mChildNodes; - std::deque mChildFunctors; + std::deque mChildFunctors; std::vector mMutableImages; std::vector mVectorDrawables; std::vector mAnimatedImages; diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index 83d7e6a361bc..3c281e78ddd5 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -23,6 +23,8 @@ #include "NinePatchUtils.h" #include "RenderNode.h" #include "pipeline/skia/AnimatedDrawables.h" +#include "pipeline/skia/GLFunctorDrawable.h" +#include "pipeline/skia/VkFunctorDrawable.h" namespace android { namespace uirenderer { @@ -118,9 +120,16 @@ void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) { void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor, uirenderer::GlFunctorLifecycleListener* listener) { - // Drawable dtor will be invoked when mChildFunctors deque is cleared. - mDisplayList->mChildFunctors.emplace_back(functor, listener, asSkCanvas()); - drawDrawable(&mDisplayList->mChildFunctors.back()); + FunctorDrawable* functorDrawable; + if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { + functorDrawable = mDisplayList->allocateDrawable(functor, listener, + asSkCanvas()); + } else { + functorDrawable = mDisplayList->allocateDrawable(functor, listener, + asSkCanvas()); + } + mDisplayList->mChildFunctors.push_back(functorDrawable); + drawDrawable(functorDrawable); } class VectorDrawable : public SkDrawable { diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index 5cbe33debbce..e34f160467af 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -22,6 +22,7 @@ #include "SkiaProfileRenderer.h" #include "renderstate/RenderState.h" #include "renderthread/Frame.h" +#include "VkFunctorDrawable.h" #include #include @@ -146,9 +147,7 @@ sk_sp SkiaVulkanPipeline::getSurfaceColorSpace() { } void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) { - // TODO: we currently don't support OpenGL WebView's - DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext; - (*functor)(mode, nullptr); + VkFunctorDrawable::vkInvokeFunctor(functor); } sk_sp SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread, diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp new file mode 100644 index 000000000000..6486ddb05aac --- /dev/null +++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp @@ -0,0 +1,223 @@ +/* + * 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 "VkFunctorDrawable.h" +#include + +#include "renderthread/EglManager.h" +#include "thread/ThreadBase.h" +#include "utils/TimeUtils.h" +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace android { +namespace uirenderer { +namespace skiapipeline { + +static std::mutex sLock{}; +static ThreadBase* sGLDrawThread = nullptr; +static renderthread::EglManager sEglManager; + +// ScopedDrawRequest makes sure a GL thread is started and EGL context is initialized on it. +class ScopedDrawRequest { +public: + ScopedDrawRequest() { beginDraw(); } +private: + void beginDraw() { + std::lock_guard{sLock}; + + if (!sGLDrawThread) { + sGLDrawThread = new ThreadBase{}; + } + + if (!sGLDrawThread->isRunning()) { + sGLDrawThread->start("GLFunctorThread"); + } + + if (!sEglManager.hasEglContext()) { + sGLDrawThread->queue().runSync([]() { + sEglManager.initialize(); + }); + } + } +}; + +void VkFunctorDrawable::vkInvokeFunctor(Functor* functor) { + ScopedDrawRequest _drawRequest{}; + sGLDrawThread->queue().runSync([&]() { + EGLDisplay display = sEglManager.eglDisplay(); + DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext; + if (display != EGL_NO_DISPLAY) { + mode = DrawGlInfo::kModeProcess; + } + (*functor)(mode, nullptr); + }); +} + +#define FENCE_TIMEOUT 2000000000 + +void VkFunctorDrawable::onDraw(SkCanvas* canvas) { + ATRACE_CALL(); + + if (canvas->getGrContext() == nullptr) { + SkDEBUGF(("Attempting to draw VkFunctor into an unsupported surface")); + return; + } + + ScopedDrawRequest _drawRequest{}; + + SkImageInfo surfaceInfo = canvas->imageInfo(); + + if (!mFrameBuffer.get() || 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(surfaceInfo.width()), + static_cast(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("VkFunctorDrawable::onDraw pid [") + std::to_string(getpid()) + "]"); + status_t error = mFrameBuffer->initCheck(); + if (error < 0) { + ALOGW("VkFunctorDrawable::onDraw() failed in GraphicBuffer.create()"); + return; + } + + mFBInfo = surfaceInfo; + } + + //TODO: Synchronization is needed on mFrameBuffer to guarantee that the previous Vulkan + //TODO: draw command has completed. + //TODO: A simple but inefficient way is to flush and issue a QueueWaitIdle call. See + //TODO: GrVkGpu::destroyResources() for example. + bool success = sGLDrawThread->queue().runSync([&]() -> bool { + ATRACE_FORMAT("WebViewDraw_%dx%d", mFBInfo.width(), mFBInfo.height()); + EGLDisplay display = sEglManager.eglDisplay(); + 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)mFrameBuffer->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 false; + } + + AutoSkiaGlTexture glTexture; + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image); + GL_CHECKPOINT(MODERATE); + + glBindTexture(GL_TEXTURE_2D, 0); + + DrawGlInfo info; + SkMatrix44 mat4(canvas->getTotalMatrix()); + SkIRect clipBounds = canvas->getDeviceClipBounds(); + + info.clipLeft = clipBounds.fLeft; + info.clipTop = clipBounds.fTop; + info.clipRight = clipBounds.fRight; + info.clipBottom = clipBounds.fBottom; + info.isLayer = true; + info.width = mFBInfo.width(); + info.height = mFBInfo.height(); + mat4.asColMajorf(&info.transform[0]); + + glViewport(0, 0, info.width, info.height); + + AutoGLFramebuffer glFb; + // Bind texture to the frame buffer. + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + glTexture.mTexture, 0); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + ALOGE("Failed framebuffer check for created target buffer: %s", + GLUtils::getGLFramebufferError()); + return false; + } + + glDisable(GL_STENCIL_TEST); + glDisable(GL_SCISSOR_TEST); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); + + (*mFunctor)(DrawGlInfo::kModeDraw, &info); + + EGLSyncKHR glDrawFinishedFence = + eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL); + LOG_ALWAYS_FATAL_IF(glDrawFinishedFence == EGL_NO_SYNC_KHR, + "Could not create sync fence %#x", eglGetError()); + glFlush(); + // TODO: export EGLSyncKHR in file descr + // TODO: import file desc in Vulkan Semaphore + // TODO: instead block the GPU: probably by using external Vulkan semaphore. + // Block the CPU until the glFlush finish. + EGLint waitStatus = eglClientWaitSyncKHR(display, glDrawFinishedFence, 0, + FENCE_TIMEOUT); + LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR, + "Failed to wait for the fence %#x", eglGetError()); + eglDestroySyncKHR(display, glDrawFinishedFence); + return true; + }); + + if (!success) { + return; + } + + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrcOver); + canvas->save(); + // The size of the image matches the size of the canvas. We've used the matrix already, while + // drawing into the offscreen surface, so we need to reset it here. + canvas->resetMatrix(); + + auto functorImage = SkImage::MakeFromAHardwareBuffer( + reinterpret_cast(mFrameBuffer.get()), kPremul_SkAlphaType, + nullptr, kBottomLeft_GrSurfaceOrigin); + canvas->drawImage(functorImage, 0, 0, &paint); + canvas->restore(); +} + +VkFunctorDrawable::~VkFunctorDrawable() { + if (mListener.get() != nullptr) { + ScopedDrawRequest _drawRequest{}; + sGLDrawThread->queue().runSync([&]() { + mListener->onGlFunctorReleased(mFunctor); + }); + } +} + +void VkFunctorDrawable::syncFunctor() const { + ScopedDrawRequest _drawRequest{}; + sGLDrawThread->queue().runSync([&]() { + (*mFunctor)(DrawGlInfo::kModeSync, nullptr); + }); +} + +}; // namespace skiapipeline +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkFunctorDrawable.h new file mode 100644 index 000000000000..e37f6fb85090 --- /dev/null +++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.h @@ -0,0 +1,55 @@ +/* + * 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 "FunctorDrawable.h" + +#include +#include + +namespace android { +namespace uirenderer { + +namespace skiapipeline { + +/** + * This drawable wraps a Vulkan functor enabling it to be recorded into a list + * of Skia drawing commands. + */ +class VkFunctorDrawable : public FunctorDrawable { +public: + VkFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas) + : FunctorDrawable(functor, listener, canvas) {} + virtual ~VkFunctorDrawable(); + + void syncFunctor() const override; + + static void vkInvokeFunctor(Functor* functor); + +protected: + virtual void onDraw(SkCanvas* canvas) override; + +private: + + // Variables below describe/store temporary offscreen buffer used for Vulkan pipeline. + sp mFrameBuffer; + SkImageInfo mFBInfo; +}; + +}; // namespace skiapipeline +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp index 6c398eea895f..415f9e8517ff 100644 --- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp +++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp @@ -20,6 +20,7 @@ #include "AnimationContext.h" #include "DamageAccumulator.h" #include "IContextFactory.h" +#include "pipeline/skia/GLFunctorDrawable.h" #include "pipeline/skia/SkiaDisplayList.h" #include "renderthread/CanvasContext.h" #include "tests/common/TestUtils.h" @@ -46,7 +47,8 @@ TEST(SkiaDisplayList, reset) { SkCanvas dummyCanvas; RenderNodeDrawable drawable(nullptr, &dummyCanvas); skiaDL->mChildNodes.emplace_back(nullptr, &dummyCanvas); - skiaDL->mChildFunctors.emplace_back(nullptr, nullptr, &dummyCanvas); + GLFunctorDrawable functorDrawable(nullptr, nullptr, &dummyCanvas); + skiaDL->mChildFunctors.push_back(&functorDrawable); skiaDL->mMutableImages.push_back(nullptr); skiaDL->mVectorDrawables.push_back(nullptr); skiaDL->mProjectionReceiver = &drawable; @@ -95,7 +97,8 @@ TEST(SkiaDisplayList, syncContexts) { SkCanvas dummyCanvas; TestUtils::MockFunctor functor; - skiaDL.mChildFunctors.emplace_back(&functor, nullptr, &dummyCanvas); + GLFunctorDrawable functorDrawable(&functor, nullptr, &dummyCanvas); + skiaDL.mChildFunctors.push_back(&functorDrawable); SkRect bounds = SkRect::MakeWH(200, 200); VectorDrawableRoot vectorDrawable(new VectorDrawable::Group()); diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp index d35fe4f01aa0..9f71e91629fb 100644 --- a/libs/hwui/utils/Color.cpp +++ b/libs/hwui/utils/Color.cpp @@ -72,6 +72,26 @@ SkColorType PixelFormatToColorType(android_pixel_format pixelFormat) { } } +android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) { + switch (colorType) { + case kRGBA_8888_SkColorType: + return PIXEL_FORMAT_RGBA_8888; + case kRGBA_F16_SkColorType: + return PIXEL_FORMAT_RGBA_FP16; + case kRGB_565_SkColorType: + return PIXEL_FORMAT_RGB_565; + case kRGB_888x_SkColorType: + return PIXEL_FORMAT_RGBX_8888; + case kRGBA_1010102_SkColorType: + return PIXEL_FORMAT_RGBA_1010102; + case kARGB_4444_SkColorType: + return PIXEL_FORMAT_RGBA_4444; + default: + ALOGW("Unsupported colorType: %d, return RGBA_8888 by default", (int)colorType); + return PIXEL_FORMAT_RGBA_8888; + } +} + SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace) { switch (dataSpace & HAL_DATASPACE_STANDARD_MASK) { case HAL_DATASPACE_STANDARD_BT709: diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h index ff0e755934f2..e935a0d5ec8b 100644 --- a/libs/hwui/utils/Color.h +++ b/libs/hwui/utils/Color.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -116,6 +117,8 @@ bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace); SkColorType PixelFormatToColorType(android_pixel_format pixelFormat); +android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType); + SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace); sk_sp DataSpaceToColorSpace(android_dataspace dataspace); diff --git a/libs/hwui/utils/GLUtils.cpp b/libs/hwui/utils/GLUtils.cpp index bf27300029c6..fcd036c451e9 100644 --- a/libs/hwui/utils/GLUtils.cpp +++ b/libs/hwui/utils/GLUtils.cpp @@ -59,5 +59,22 @@ bool GLUtils::dumpGLErrors() { #endif } +const char* GLUtils::getGLFramebufferError() { + switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) { + case GL_FRAMEBUFFER_COMPLETE: + return "GL_FRAMEBUFFER_COMPLETE"; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; + case GL_FRAMEBUFFER_UNSUPPORTED: + return "GL_FRAMEBUFFER_UNSUPPORTED"; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS"; + default: + return "Unknown error"; + } +} + }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/utils/GLUtils.h b/libs/hwui/utils/GLUtils.h index debfb5d06944..ca8810bde070 100644 --- a/libs/hwui/utils/GLUtils.h +++ b/libs/hwui/utils/GLUtils.h @@ -20,6 +20,12 @@ #include +#include +#include +#include +#include +#include + namespace android { namespace uirenderer { @@ -43,8 +49,53 @@ public: */ static bool dumpGLErrors(); + static const char* getGLFramebufferError(); }; // class GLUtils +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); } + + GLuint mTexture = 0; +}; + +class AutoGLFramebuffer { +public: + AutoGLFramebuffer() { + glGenFramebuffers(1, &mFb); + glBindFramebuffer(GL_FRAMEBUFFER, mFb); + } + + ~AutoGLFramebuffer() { glDeleteFramebuffers(1, &mFb); } + + GLuint mFb; +}; + } /* namespace uirenderer */ } /* namespace android */ -- cgit v1.2.3-59-g8ed1b From 7b8a808b7db019b383c3a281e24c270ba2e0fc0b Mon Sep 17 00:00:00 2001 From: Chris Blume Date: Fri, 30 Nov 2018 15:51:58 -0800 Subject: Remove ; from closing namespaces in libs/hwui When closing a namespace a } is sufficient. It doesn't need to be }; like closing a class or enum. Within frameworks/base/libs/hwui there is a mix between } and }; when closing a namespace. There are even mixes between a .h and the corresponding .cpp files. In a separate CL I was asked to not close with };. That was a good comment. I adopted the style from nearby code. This CL cleans up the nearby code. Test: I made sure the code still built as expected. Change-Id: Ieb314a4f48d6e33752463f3be4361fdc9be97482 --- libs/hwui/CanvasTransform.cpp | 2 +- libs/hwui/DisplayList.h | 4 ++-- libs/hwui/FrameMetricsObserver.h | 4 ++-- libs/hwui/FrameMetricsReporter.h | 4 ++-- libs/hwui/GlFunctorLifecycleListener.h | 4 ++-- libs/hwui/HardwareBitmapUploader.cpp | 2 +- libs/hwui/HardwareBitmapUploader.h | 2 +- libs/hwui/Layer.cpp | 4 ++-- libs/hwui/Layer.h | 4 ++-- libs/hwui/LayerUpdateQueue.h | 4 ++-- libs/hwui/Lighting.h | 4 ++-- libs/hwui/Matrix.cpp | 4 ++-- libs/hwui/Matrix.h | 4 ++-- libs/hwui/NinePatchUtils.h | 4 ++-- libs/hwui/PathParser.cpp | 4 ++-- libs/hwui/PathParser.h | 4 ++-- libs/hwui/Properties.cpp | 4 ++-- libs/hwui/Properties.h | 4 ++-- libs/hwui/RecordingCanvas.cpp | 4 ++-- libs/hwui/RecordingCanvas.h | 4 ++-- libs/hwui/Rect.h | 4 ++-- libs/hwui/UvMapper.h | 4 ++-- libs/hwui/Vector.h | 4 ++-- libs/hwui/VectorDrawable.cpp | 6 +++--- libs/hwui/Vertex.h | 4 ++-- libs/hwui/VertexBuffer.h | 4 ++-- libs/hwui/hwui/Canvas.h | 6 +++--- libs/hwui/pipeline/skia/AnimatedDrawables.h | 6 +++--- libs/hwui/pipeline/skia/DumpOpsCanvas.h | 6 +++--- libs/hwui/pipeline/skia/FunctorDrawable.h | 6 +++--- libs/hwui/pipeline/skia/GLFunctorDrawable.cpp | 6 +++--- libs/hwui/pipeline/skia/GLFunctorDrawable.h | 6 +++--- libs/hwui/pipeline/skia/LayerDrawable.cpp | 6 +++--- libs/hwui/pipeline/skia/LayerDrawable.h | 6 +++--- libs/hwui/pipeline/skia/RenderNodeDrawable.cpp | 6 +++--- libs/hwui/pipeline/skia/RenderNodeDrawable.h | 6 +++--- libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp | 6 +++--- libs/hwui/pipeline/skia/ReorderBarrierDrawables.h | 6 +++--- libs/hwui/pipeline/skia/SkiaDisplayList.cpp | 6 +++--- libs/hwui/pipeline/skia/SkiaDisplayList.h | 8 ++++---- libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp | 6 +++--- libs/hwui/pipeline/skia/SkiaRecordingCanvas.h | 6 +++--- libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp | 6 +++--- libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h | 6 +++--- libs/hwui/private/hwui/DrawGlInfo.h | 4 ++-- libs/hwui/renderthread/RenderProxy.h | 2 +- libs/hwui/surfacetexture/EGLConsumer.cpp | 2 +- libs/hwui/surfacetexture/EGLConsumer.h | 2 +- libs/hwui/surfacetexture/ImageConsumer.h | 2 +- libs/hwui/surfacetexture/SurfaceTexture.cpp | 2 +- libs/hwui/surfacetexture/SurfaceTexture.h | 2 +- libs/hwui/tests/unit/LayerUpdateQueueTests.cpp | 4 ++-- libs/hwui/tests/unit/VectorDrawableTests.cpp | 4 ++-- libs/hwui/thread/Barrier.h | 4 ++-- libs/hwui/thread/Future.h | 4 ++-- libs/hwui/thread/Signal.h | 4 ++-- libs/hwui/thread/Task.h | 4 ++-- libs/hwui/thread/TaskManager.cpp | 4 ++-- libs/hwui/thread/TaskManager.h | 4 ++-- libs/hwui/utils/Blur.cpp | 4 ++-- libs/hwui/utils/Blur.h | 4 ++-- libs/hwui/utils/Color.cpp | 4 ++-- libs/hwui/utils/FatVector.h | 4 ++-- libs/hwui/utils/GLUtils.cpp | 4 ++-- libs/hwui/utils/LinearAllocator.cpp | 4 ++-- libs/hwui/utils/LinearAllocator.h | 4 ++-- libs/hwui/utils/Pair.h | 4 ++-- libs/hwui/utils/Result.h | 2 +- libs/hwui/utils/RingBuffer.h | 4 ++-- libs/hwui/utils/StringUtils.cpp | 4 ++-- libs/hwui/utils/TypeLogic.h | 2 +- 71 files changed, 151 insertions(+), 151 deletions(-) (limited to 'libs/hwui/HardwareBitmapUploader.cpp') diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp index 06e937ab66f4..0cfaa8c61279 100644 --- a/libs/hwui/CanvasTransform.cpp +++ b/libs/hwui/CanvasTransform.cpp @@ -146,4 +146,4 @@ bool transformPaint(ColorTransform transform, SkPaint* paint, BitmapPalette pale return shouldInvert; } -}; // namespace android::uirenderer \ No newline at end of file +} // namespace android::uirenderer diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index a952cc23e1ef..dc63e5db4a70 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -31,5 +31,5 @@ typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; */ using DisplayList = skiapipeline::SkiaDisplayList; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/FrameMetricsObserver.h b/libs/hwui/FrameMetricsObserver.h index ba72e937095f..237fc622dd2e 100644 --- a/libs/hwui/FrameMetricsObserver.h +++ b/libs/hwui/FrameMetricsObserver.h @@ -26,5 +26,5 @@ public: virtual void notify(const int64_t* buffer); }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/FrameMetricsReporter.h b/libs/hwui/FrameMetricsReporter.h index d920a99f5ee3..75b8038c5040 100644 --- a/libs/hwui/FrameMetricsReporter.h +++ b/libs/hwui/FrameMetricsReporter.h @@ -56,5 +56,5 @@ private: std::vector > mObservers; }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/GlFunctorLifecycleListener.h b/libs/hwui/GlFunctorLifecycleListener.h index 5d07b46919d4..5adc46961c8b 100644 --- a/libs/hwui/GlFunctorLifecycleListener.h +++ b/libs/hwui/GlFunctorLifecycleListener.h @@ -28,5 +28,5 @@ public: virtual void onGlFunctorReleased(Functor* functor) = 0; }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp index 165fc4860fb2..a97c12cad9fd 100644 --- a/libs/hwui/HardwareBitmapUploader.cpp +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -256,4 +256,4 @@ sk_sp HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sou return sk_sp(new Bitmap(buffer.get(), bitmap.info(), Bitmap::computePalette(bitmap))); } -}; // namespace android::uirenderer +} // namespace android::uirenderer diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h index c0113d81fefb..6298013bd263 100644 --- a/libs/hwui/HardwareBitmapUploader.h +++ b/libs/hwui/HardwareBitmapUploader.h @@ -25,4 +25,4 @@ public: static sk_sp allocateHardwareBitmap(const SkBitmap& sourceBitmap); }; -}; // namespace android::uirenderer +} // namespace android::uirenderer diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index d0df200d2fa6..a15ff2235db2 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -54,5 +54,5 @@ SkBlendMode Layer::getMode() const { } } -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 98600dbf1eea..ea3bfc9e80cb 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -144,5 +144,5 @@ private: }; // struct Layer -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/LayerUpdateQueue.h b/libs/hwui/LayerUpdateQueue.h index 6857999500f0..2c63af6aaab4 100644 --- a/libs/hwui/LayerUpdateQueue.h +++ b/libs/hwui/LayerUpdateQueue.h @@ -50,7 +50,7 @@ private: std::vector mEntries; }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif // ANDROID_HWUI_LAYER_UPDATE_QUEUE_H diff --git a/libs/hwui/Lighting.h b/libs/hwui/Lighting.h index d972c2181aea..ccfbb93b00ef 100644 --- a/libs/hwui/Lighting.h +++ b/libs/hwui/Lighting.h @@ -34,5 +34,5 @@ struct LightInfo { uint8_t spotShadowAlpha; }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp index d84ed321a4cb..d0dbff031e99 100644 --- a/libs/hwui/Matrix.cpp +++ b/libs/hwui/Matrix.cpp @@ -526,5 +526,5 @@ void Matrix4::dump(const char* label) const { ALOGD("]"); } -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index 1b5cb60ca4bd..b33cfe2ec511 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -245,5 +245,5 @@ private: typedef Matrix4 mat4; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/NinePatchUtils.h b/libs/hwui/NinePatchUtils.h index 082e95fb1440..86d3cb9a5b11 100644 --- a/libs/hwui/NinePatchUtils.h +++ b/libs/hwui/NinePatchUtils.h @@ -103,5 +103,5 @@ static inline void SetLatticeFlags(SkCanvas::Lattice* lattice, SkCanvas::Lattice } } -}; // namespace NinePatchUtils -}; // namespace android +} // namespace NinePatchUtils +} // namespace android diff --git a/libs/hwui/PathParser.cpp b/libs/hwui/PathParser.cpp index ad599e9ec316..808921d344da 100644 --- a/libs/hwui/PathParser.cpp +++ b/libs/hwui/PathParser.cpp @@ -304,5 +304,5 @@ void PathParser::parseAsciiStringForSkPath(SkPath* skPath, ParseResult* result, return; } -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/PathParser.h b/libs/hwui/PathParser.h index 474eb97b53c6..f5bebce605fb 100644 --- a/libs/hwui/PathParser.h +++ b/libs/hwui/PathParser.h @@ -46,6 +46,6 @@ public: static void validateVerbAndPoints(char verb, size_t points, ParseResult* result); }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif // ANDROID_HWUI_PATHPARSER_H diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 3f2c616eb8ff..4a3e10c54cef 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -223,5 +223,5 @@ void Properties::overrideRenderPipelineType(RenderPipelineType type) { sRenderPipelineType = type; } -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 542bc71f7c72..da53f6657ff7 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -289,7 +289,7 @@ private: static RenderPipelineType sRenderPipelineType; }; // class Caches -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif // ANDROID_HWUI_PROPERTIES_H diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index f928de9b92a6..c63e449319dd 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -1028,5 +1028,5 @@ void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) { fDL->drawVectorDrawable(tree); } -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h index 099e0be433ea..08cfc6266f56 100644 --- a/libs/hwui/RecordingCanvas.h +++ b/libs/hwui/RecordingCanvas.h @@ -216,5 +216,5 @@ private: DisplayListData* fDL; }; -}; // namespace uirenderer -}; // namespace android \ No newline at end of file +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h index 0715187e19ea..d6362ef10aad 100644 --- a/libs/hwui/Rect.h +++ b/libs/hwui/Rect.h @@ -262,5 +262,5 @@ public: } }; // class Rect -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/UvMapper.h b/libs/hwui/UvMapper.h index b495e3394bc9..833ca4a79ce5 100644 --- a/libs/hwui/UvMapper.h +++ b/libs/hwui/UvMapper.h @@ -124,7 +124,7 @@ private: float mMaxV; }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif // ANDROID_HWUI_UV_MAPPER_H diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h index d2c15ad872a5..e6eea1c5c0ca 100644 --- a/libs/hwui/Vector.h +++ b/libs/hwui/Vector.h @@ -113,7 +113,7 @@ public: } }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif // ANDROID_HWUI_VECTOR_H diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp index 6cf04bf5f811..dd62bbbdc84f 100644 --- a/libs/hwui/VectorDrawable.cpp +++ b/libs/hwui/VectorDrawable.cpp @@ -691,7 +691,7 @@ BitmapPalette Tree::computePalette() { return BitmapPalette::Unknown; } -}; // namespace VectorDrawable +} // namespace VectorDrawable -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h index f0912777e3d8..28cabb9be0f1 100644 --- a/libs/hwui/Vertex.h +++ b/libs/hwui/Vertex.h @@ -73,7 +73,7 @@ struct TextureVertex { REQUIRE_COMPATIBLE_LAYOUT(TextureVertex); -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif // ANDROID_HWUI_VERTEX_H diff --git a/libs/hwui/VertexBuffer.h b/libs/hwui/VertexBuffer.h index 613cf4af64b2..6543a2251f7a 100644 --- a/libs/hwui/VertexBuffer.h +++ b/libs/hwui/VertexBuffer.h @@ -174,7 +174,7 @@ private: void (*mCleanupIndexMethod)(void*); }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif // ANDROID_HWUI_VERTEX_BUFFER_H diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index e99742bc2eba..a5f21d8e6d73 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -76,8 +76,8 @@ typedef uint32_t Flags; namespace uirenderer { namespace VectorDrawable { class Tree; -}; -}; +} +} typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; typedef std::function ReadGlyphFunc; @@ -318,4 +318,4 @@ protected: friend class DrawTextOnPathFunctor; }; -}; // namespace android +} // namespace android diff --git a/libs/hwui/pipeline/skia/AnimatedDrawables.h b/libs/hwui/pipeline/skia/AnimatedDrawables.h index efef6de2a9e1..bf19655825b3 100644 --- a/libs/hwui/pipeline/skia/AnimatedDrawables.h +++ b/libs/hwui/pipeline/skia/AnimatedDrawables.h @@ -79,6 +79,6 @@ private: sp mPaint; }; -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/pipeline/skia/DumpOpsCanvas.h b/libs/hwui/pipeline/skia/DumpOpsCanvas.h index e4ba13da709c..206219426bb0 100644 --- a/libs/hwui/pipeline/skia/DumpOpsCanvas.h +++ b/libs/hwui/pipeline/skia/DumpOpsCanvas.h @@ -172,6 +172,6 @@ private: std::string mIdent; }; -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/pipeline/skia/FunctorDrawable.h b/libs/hwui/pipeline/skia/FunctorDrawable.h index 162d13762e1a..af3a056864a7 100644 --- a/libs/hwui/pipeline/skia/FunctorDrawable.h +++ b/libs/hwui/pipeline/skia/FunctorDrawable.h @@ -48,6 +48,6 @@ protected: const SkRect mBounds; }; -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp index 90d5e715f8cd..4a87e7502c6f 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp @@ -216,6 +216,6 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { } } -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.h b/libs/hwui/pipeline/skia/GLFunctorDrawable.h index b06f7f029f23..215979cba2e3 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.h +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.h @@ -41,6 +41,6 @@ protected: void onDraw(SkCanvas* canvas) override; }; -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index 9b408fbc95ca..f08ac17e4082 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -145,6 +145,6 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer return layerImage != nullptr; } -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h index 5c125908ffb2..95dc6d0cf096 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.h +++ b/libs/hwui/pipeline/skia/LayerDrawable.h @@ -45,6 +45,6 @@ private: sp mLayerUpdater; }; -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp index d80cb6d1ab70..4494cb05df10 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp @@ -332,6 +332,6 @@ void RenderNodeDrawable::setViewProperties(const RenderProperties& properties, S } } -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.h b/libs/hwui/pipeline/skia/RenderNodeDrawable.h index d746978b0a61..6ba8e599818c 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.h +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.h @@ -150,6 +150,6 @@ private: SkiaDisplayList* mProjectedDisplayList = nullptr; }; -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp index dba97fe5ef9f..0a3c8f4347eb 100644 --- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp +++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp @@ -211,6 +211,6 @@ void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0); } -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h index 26cfa908228c..cfc0f9b258da 100644 --- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h +++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h @@ -74,6 +74,6 @@ private: StartReorderBarrierDrawable* mStartBarrier; }; -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index 38905138e332..ac6f6a3f776d 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -141,6 +141,6 @@ void SkiaDisplayList::output(std::ostream& output, uint32_t level) { mDisplayList.draw(&canvas); } -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index ac7bb7b0950c..d7879e722a29 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -36,7 +36,7 @@ class Outline; namespace VectorDrawable { class Tree; -}; +} typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; namespace skiapipeline { @@ -179,6 +179,6 @@ public: SkMatrix mParentMatrix; }; -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index f5de1c8adfaf..b682ab0256dd 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -259,6 +259,6 @@ double SkiaRecordingCanvas::drawAnimatedImage(AnimatedImageDrawable* animatedIma return 0; } -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h index 988728dfe23e..d6107a9d9969 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h @@ -92,6 +92,6 @@ private: PaintCoW&& filterBitmap(PaintCoW&& paint, sk_sp colorSpaceFilter); }; -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp index a594206a2dd9..004a558dd9d0 100644 --- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp @@ -219,6 +219,6 @@ void VkInteropFunctorDrawable::syncFunctor() const { }); } -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h index 3269cfbb8fe3..8fe52c5ef700 100644 --- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h +++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h @@ -51,6 +51,6 @@ private: SkImageInfo mFBInfo; }; -}; // namespace skiapipeline -}; // namespace uirenderer -}; // namespace android +} // namespace skiapipeline +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/private/hwui/DrawGlInfo.h b/libs/hwui/private/hwui/DrawGlInfo.h index efa9da27199d..9e1bb8e8e548 100644 --- a/libs/hwui/private/hwui/DrawGlInfo.h +++ b/libs/hwui/private/hwui/DrawGlInfo.h @@ -83,7 +83,7 @@ struct DrawGlInfo { }; }; // struct DrawGlInfo -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif // ANDROID_HWUI_DRAW_GL_INFO_H diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 6668c5840c3e..d9b789f28f8d 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -49,7 +49,7 @@ enum { Reset = 1 << 1, JankStats = 1 << 2, }; -}; +} /* * RenderProxy is strictly single threaded. All methods must be invoked on the owning diff --git a/libs/hwui/surfacetexture/EGLConsumer.cpp b/libs/hwui/surfacetexture/EGLConsumer.cpp index c8220c6cb0d4..85b3917809fa 100644 --- a/libs/hwui/surfacetexture/EGLConsumer.cpp +++ b/libs/hwui/surfacetexture/EGLConsumer.cpp @@ -672,4 +672,4 @@ EGLImageKHR EGLConsumer::EglImage::createImage(EGLDisplay dpy, return image; } -}; // namespace android +} // namespace android diff --git a/libs/hwui/surfacetexture/EGLConsumer.h b/libs/hwui/surfacetexture/EGLConsumer.h index eccb08298f6f..7dac3ef0f44a 100644 --- a/libs/hwui/surfacetexture/EGLConsumer.h +++ b/libs/hwui/surfacetexture/EGLConsumer.h @@ -308,4 +308,4 @@ protected: sp mReleasedTexImage; }; -}; // namespace android +} // namespace android diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h index 5bab0ef58a9a..f0e55bbf19f8 100644 --- a/libs/hwui/surfacetexture/ImageConsumer.h +++ b/libs/hwui/surfacetexture/ImageConsumer.h @@ -97,4 +97,4 @@ private: ImageSlot mImageSlots[BufferQueueDefs::NUM_BUFFER_SLOTS]; }; -}; /* namespace android */ +} /* namespace android */ diff --git a/libs/hwui/surfacetexture/SurfaceTexture.cpp b/libs/hwui/surfacetexture/SurfaceTexture.cpp index 90f891265572..da094442684d 100644 --- a/libs/hwui/surfacetexture/SurfaceTexture.cpp +++ b/libs/hwui/surfacetexture/SurfaceTexture.cpp @@ -491,4 +491,4 @@ sk_sp SurfaceTexture::dequeueImage(SkMatrix& transformMatrix, bool* que return image; } -}; // namespace android +} // namespace android diff --git a/libs/hwui/surfacetexture/SurfaceTexture.h b/libs/hwui/surfacetexture/SurfaceTexture.h index 96afd82b0d40..b5d136ff3058 100644 --- a/libs/hwui/surfacetexture/SurfaceTexture.h +++ b/libs/hwui/surfacetexture/SurfaceTexture.h @@ -449,4 +449,4 @@ protected: }; // ---------------------------------------------------------------------------- -}; // namespace android +} // namespace android diff --git a/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp b/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp index 217d63f9c2e1..41714ebd84b1 100644 --- a/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp +++ b/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp @@ -81,5 +81,5 @@ TEST(LayerUpdateQueue, clear) { EXPECT_TRUE(queue.entries().empty()); } -}; -}; +} +} diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp index 02f740cee096..ee6beba847a0 100644 --- a/libs/hwui/tests/unit/VectorDrawableTests.cpp +++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp @@ -406,5 +406,5 @@ TEST(VectorDrawable, drawPathWithoutIncrementingShaderRefCount) { EXPECT_TRUE(shader->unique()); } -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/thread/Barrier.h b/libs/hwui/thread/Barrier.h index 8faeee6b391a..bb750ca0fa88 100644 --- a/libs/hwui/thread/Barrier.h +++ b/libs/hwui/thread/Barrier.h @@ -48,7 +48,7 @@ private: mutable Condition mCondition; }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif // ANDROID_HWUI_BARRIER_H diff --git a/libs/hwui/thread/Future.h b/libs/hwui/thread/Future.h index 45f3102492e3..df53348e58fb 100644 --- a/libs/hwui/thread/Future.h +++ b/libs/hwui/thread/Future.h @@ -53,7 +53,7 @@ private: T mResult; }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif // ANDROID_HWUI_FUTURE_H diff --git a/libs/hwui/thread/Signal.h b/libs/hwui/thread/Signal.h index ffcd4b675a85..6d33ac473ac4 100644 --- a/libs/hwui/thread/Signal.h +++ b/libs/hwui/thread/Signal.h @@ -53,7 +53,7 @@ private: mutable Condition mCondition; }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif // ANDROID_HWUI_SIGNAL_H diff --git a/libs/hwui/thread/Task.h b/libs/hwui/thread/Task.h index 276a22f941fe..228ce19a2fd5 100644 --- a/libs/hwui/thread/Task.h +++ b/libs/hwui/thread/Task.h @@ -48,7 +48,7 @@ private: sp > mFuture; }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif // ANDROID_HWUI_TASK_H diff --git a/libs/hwui/thread/TaskManager.cpp b/libs/hwui/thread/TaskManager.cpp index 54b55e472095..26ff6ebad3b4 100644 --- a/libs/hwui/thread/TaskManager.cpp +++ b/libs/hwui/thread/TaskManager.cpp @@ -129,5 +129,5 @@ void TaskManager::WorkerThread::exit() { mSignal.signal(); } -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/thread/TaskManager.h b/libs/hwui/thread/TaskManager.h index 29b4fcdbfde9..c4c1291e755c 100644 --- a/libs/hwui/thread/TaskManager.h +++ b/libs/hwui/thread/TaskManager.h @@ -101,7 +101,7 @@ private: std::vector > mThreads; }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif // ANDROID_HWUI_TASK_MANAGER_H diff --git a/libs/hwui/utils/Blur.cpp b/libs/hwui/utils/Blur.cpp index 1bc5646993c9..763d1aa177b7 100644 --- a/libs/hwui/utils/Blur.cpp +++ b/libs/hwui/utils/Blur.cpp @@ -178,5 +178,5 @@ void Blur::vertical(float* weights, int32_t radius, const uint8_t* source, uint8 } } -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/utils/Blur.h b/libs/hwui/utils/Blur.h index bec3837106e8..d6b41b83def8 100644 --- a/libs/hwui/utils/Blur.h +++ b/libs/hwui/utils/Blur.h @@ -41,7 +41,7 @@ public: int32_t width, int32_t height); }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif // ANDROID_HWUI_BLUR_H diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp index 3fb6a31a7d97..dc347f615d98 100644 --- a/libs/hwui/utils/Color.cpp +++ b/libs/hwui/utils/Color.cpp @@ -221,5 +221,5 @@ SkColor LabToSRGB(const Lab& lab, SkAlpha alpha) { static_cast(rgb.b * 255)); } -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/utils/FatVector.h b/libs/hwui/utils/FatVector.h index eafe2f13c16d..8cc4d1010ab6 100644 --- a/libs/hwui/utils/FatVector.h +++ b/libs/hwui/utils/FatVector.h @@ -99,7 +99,7 @@ private: typename InlineStdAllocator::Allocation mAllocation; }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif // ANDROID_FAT_VECTOR_H diff --git a/libs/hwui/utils/GLUtils.cpp b/libs/hwui/utils/GLUtils.cpp index fcd036c451e9..c694e93f7e21 100644 --- a/libs/hwui/utils/GLUtils.cpp +++ b/libs/hwui/utils/GLUtils.cpp @@ -76,5 +76,5 @@ const char* GLUtils::getGLFramebufferError() { } } -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/utils/LinearAllocator.cpp b/libs/hwui/utils/LinearAllocator.cpp index 3e5021cd45d4..8baa4b770f85 100644 --- a/libs/hwui/utils/LinearAllocator.cpp +++ b/libs/hwui/utils/LinearAllocator.cpp @@ -249,5 +249,5 @@ void LinearAllocator::dumpMemoryStats(const char* prefix) { ALOGD("%sPages %zu (dedicated %zu)", prefix, mPageCount, mDedicatedPageCount); } -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h index 03f685e8aca8..b401fcf58f76 100644 --- a/libs/hwui/utils/LinearAllocator.h +++ b/libs/hwui/utils/LinearAllocator.h @@ -201,7 +201,7 @@ public: : std::vector>(allocator) {} }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif // ANDROID_LINEARALLOCATOR_H diff --git a/libs/hwui/utils/Pair.h b/libs/hwui/utils/Pair.h index 4bcd57629e0c..76f93cbfeb92 100644 --- a/libs/hwui/utils/Pair.h +++ b/libs/hwui/utils/Pair.h @@ -36,7 +36,7 @@ struct Pair { inline const S& getSecond() const { return second; } }; -}; // namespace uirenderer +} // namespace uirenderer template struct trait_trivial_ctor > { @@ -55,6 +55,6 @@ struct trait_trivial_move > { enum { value = aggregate_traits::has_trivial_move }; }; -}; // namespace android +} // namespace android #endif // ANDROID_HWUI_PAIR_H diff --git a/libs/hwui/utils/Result.h b/libs/hwui/utils/Result.h index 7f33f2e3424d..bd20ba66d8a7 100644 --- a/libs/hwui/utils/Result.h +++ b/libs/hwui/utils/Result.h @@ -51,4 +51,4 @@ private: std::variant> result; }; -}; // namespace android::uirenderer +} // namespace android::uirenderer diff --git a/libs/hwui/utils/RingBuffer.h b/libs/hwui/utils/RingBuffer.h index b3e893139cf8..081386a7f671 100644 --- a/libs/hwui/utils/RingBuffer.h +++ b/libs/hwui/utils/RingBuffer.h @@ -61,7 +61,7 @@ private: size_t mCount = 0; }; -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android #endif /* RINGBUFFER_H_ */ diff --git a/libs/hwui/utils/StringUtils.cpp b/libs/hwui/utils/StringUtils.cpp index 5304b762f3dc..304982e8e493 100644 --- a/libs/hwui/utils/StringUtils.cpp +++ b/libs/hwui/utils/StringUtils.cpp @@ -34,5 +34,5 @@ unordered_string_set StringUtils::split(const char* spacedList) { return set; } -}; // namespace uirenderer -}; // namespace android +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/utils/TypeLogic.h b/libs/hwui/utils/TypeLogic.h index dbdad33d8335..1689ccecd6b1 100644 --- a/libs/hwui/utils/TypeLogic.h +++ b/libs/hwui/utils/TypeLogic.h @@ -37,4 +37,4 @@ template struct copy_cv { template using same_cv = copy_cv, S>; template using same_cv_t = typename same_cv::type; -}; // namespace android::uirenderer \ No newline at end of file +} // namespace android::uirenderer -- cgit v1.2.3-59-g8ed1b From e216948d63958e75a2321096bda5598bd1608711 Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Tue, 20 Nov 2018 10:57:20 -0500 Subject: Cleanup of Bitmap.h entry points. All Bitmap constructors have been made private and the only way to create one is through the allocate or createFrom factories. SkColorSpace is now explicitly passed in to all the factories and is no longer assumed to be sRGB. Test: atest CtsGraphicsTestCases Change-Id: I92c1c5c59df6de7fdd90e9504a2c2717cb854588 --- core/jni/android/graphics/Bitmap.cpp | 18 ++--- core/jni/android/graphics/Graphics.cpp | 30 -------- core/jni/android/graphics/GraphicsJNI.h | 3 - core/jni/android_view_ThreadedRenderer.cpp | 10 +-- libs/hwui/HardwareBitmapUploader.cpp | 3 +- libs/hwui/hwui/Bitmap.cpp | 85 ++++++++++++++-------- libs/hwui/hwui/Bitmap.h | 44 +++++++---- libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp | 2 +- .../common/scenes/HwBitmapInCompositeShader.cpp | 2 +- libs/hwui/utils/Color.h | 3 +- 10 files changed, 100 insertions(+), 100 deletions(-) (limited to 'libs/hwui/HardwareBitmapUploader.cpp') diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index c32de0a5737e..12ca78a7ce92 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -725,9 +725,10 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { return NULL; } - // Map the pixels in place and take ownership of the ashmem region. - nativeBitmap = sk_sp(GraphicsJNI::mapAshmemBitmap(env, bitmap.get(), - dupFd, const_cast(blob.data()), size, !isMutable)); + // 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(blob.data()), size, !isMutable); if (!nativeBitmap) { close(dupFd); blob.release(); @@ -1097,21 +1098,20 @@ static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bit SkBitmap src; hwuiBitmap.getSkBitmap(&src); - SkBitmap result; - HeapAllocator allocator; - if (!bitmapCopyTo(&result, hwuiBitmap.info().colorType(), src, &allocator)) { + if (src.pixelRef() == nullptr) { doThrowRE(env, "Could not copy a hardware bitmap."); return NULL; } - return createBitmap(env, allocator.getStorageObjAndReset(), getPremulBitmapCreateFlags(false)); + + sk_sp bitmap = Bitmap::createFrom(src.info(), *src.pixelRef()); + return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false)); } static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) { sp buffer(graphicBufferForJavaObject(env, graphicBuffer)); - // Bitmap::createFrom currently assumes SRGB color space for RGBA images. // To support any color space, we need to pass an additional ColorSpace argument to // java Bitmap.createHardwareBitmap. - sk_sp bitmap = Bitmap::createFrom(buffer); + sk_sp bitmap = Bitmap::createFrom(buffer, SkColorSpace::MakeSRGB()); if (!bitmap.get()) { ALOGW("failed to create hardware bitmap from graphic buffer"); return NULL; diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index 26af15e79e2d..67d0c8aced61 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -424,36 +424,6 @@ jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region) /////////////////////////////////////////////////////////////////////////////// -android::Bitmap* GraphicsJNI::mapAshmemBitmap(JNIEnv* env, SkBitmap* bitmap, - int fd, void* addr, size_t size, bool readOnly) { - const SkImageInfo& info = bitmap->info(); - if (info.colorType() == kUnknown_SkColorType) { - doThrowIAE(env, "unknown bitmap configuration"); - return nullptr; - } - - if (!addr) { - // Map existing ashmem region if not already mapped. - int flags = readOnly ? (PROT_READ) : (PROT_READ | PROT_WRITE); - size = ashmem_get_size_region(fd); - addr = mmap(NULL, size, flags, MAP_SHARED, fd, 0); - if (addr == MAP_FAILED) { - return nullptr; - } - } - - // we must respect the rowBytes value already set on the bitmap instead of - // attempting to compute our own. - const size_t rowBytes = bitmap->rowBytes(); - - auto wrapper = new android::Bitmap(addr, fd, size, info, rowBytes); - wrapper->getSkBitmap(bitmap); - if (readOnly) { - bitmap->pixelRef()->setImmutable(); - } - return wrapper; -} - SkColorSpaceTransferFn GraphicsJNI::getNativeTransferParameters(JNIEnv* env, jobject transferParams) { SkColorSpaceTransferFn p; p.fA = (float) env->GetDoubleField(transferParams, gTransferParams_aFieldID); diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index cee3c46dd67f..b0bd68336e08 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -85,9 +85,6 @@ public: static jobject createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap); - static android::Bitmap* mapAshmemBitmap(JNIEnv* env, SkBitmap* bitmap, - int fd, void* addr, size_t size, bool readOnly); - /** * Given a bitmap we natively allocate a memory block to store the contents * of that bitmap. The memory is then attached to the bitmap via an diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 702741eb813c..5a8ab3c1bdc4 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -31,8 +31,6 @@ #include #include -#include -#include #include #include @@ -58,6 +56,7 @@ #include #include #include +#include namespace android { @@ -1011,10 +1010,9 @@ static jobject android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode( buffer->getWidth(), buffer->getHeight(), width, height); // Continue I guess? } - sk_sp bitmap = Bitmap::createFrom(buffer); - // Bitmap::createFrom currently can only attach to a GraphicBuffer with PIXEL_FORMAT_RGBA_8888 - // format and SRGB color space. - // To support any color space, we could extract it from BufferItem and pass it to Bitmap. + + sk_sp cs = uirenderer::DataSpaceToColorSpace(bufferItem.mDataSpace); + sk_sp bitmap = Bitmap::createFrom(buffer, cs); return bitmap::createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_Premultiplied); } diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp index a97c12cad9fd..b9860ada18fc 100644 --- a/libs/hwui/HardwareBitmapUploader.cpp +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -253,7 +253,8 @@ sk_sp HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sou eglDestroySyncKHR(display, fence); } - return sk_sp(new Bitmap(buffer.get(), bitmap.info(), Bitmap::computePalette(bitmap))); + return Bitmap::createFrom(buffer.get(), bitmap.refColorSpace(), bitmap.alphaType(), + Bitmap::computePalette(bitmap)); } } // namespace android::uirenderer diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 6c77f9ee1845..6e0258c9ecb2 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -75,20 +75,33 @@ sk_sp Bitmap::allocateAshmemBitmap(SkBitmap* bitmap) { return allocateBitmap(bitmap, &Bitmap::allocateAshmemBitmap); } -static sk_sp allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) { - void* addr = calloc(size, 1); - if (!addr) { +sk_sp Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) { + // Create new ashmem region with read/write priv + int fd = ashmem_create_region("bitmap", size); + if (fd < 0) { return nullptr; } - return sk_sp(new Bitmap(addr, size, info, rowBytes)); + + void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (addr == MAP_FAILED) { + close(fd); + return nullptr; + } + + if (ashmem_set_prot_region(fd, PROT_READ) < 0) { + munmap(addr, size); + close(fd); + return nullptr; + } + return sk_sp(new Bitmap(addr, fd, size, info, rowBytes)); } -sk_sp Bitmap::allocateHardwareBitmap(SkBitmap& bitmap) { +sk_sp Bitmap::allocateHardwareBitmap(const SkBitmap& bitmap) { return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap); } sk_sp Bitmap::allocateHeapBitmap(SkBitmap* bitmap) { - return allocateBitmap(bitmap, &android::allocateHeapBitmap); + return allocateBitmap(bitmap, &Bitmap::allocateHeapBitmap); } sk_sp Bitmap::allocateHeapBitmap(const SkImageInfo& info) { @@ -97,28 +110,15 @@ sk_sp Bitmap::allocateHeapBitmap(const SkImageInfo& info) { LOG_ALWAYS_FATAL("trying to allocate too large bitmap"); return nullptr; } - return android::allocateHeapBitmap(size, info, info.minRowBytes()); + return allocateHeapBitmap(size, info, info.minRowBytes()); } -sk_sp Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) { - // Create new ashmem region with read/write priv - int fd = ashmem_create_region("bitmap", size); - if (fd < 0) { - return nullptr; - } - - void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (addr == MAP_FAILED) { - close(fd); - return nullptr; - } - - if (ashmem_set_prot_region(fd, PROT_READ) < 0) { - munmap(addr, size); - close(fd); +sk_sp Bitmap::allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) { + void* addr = calloc(size, 1); + if (!addr) { return nullptr; } - return sk_sp(new Bitmap(addr, fd, size, info, rowBytes)); + return sk_sp(new Bitmap(addr, size, info, rowBytes)); } void FreePixelRef(void* addr, void* context) { @@ -132,17 +132,38 @@ sk_sp Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) pixelRef.rowBytes())); } -sk_sp Bitmap::createFrom(sp graphicBuffer) { - return createFrom(graphicBuffer, SkColorSpace::MakeSRGB()); -} -sk_sp Bitmap::createFrom(sp graphicBuffer, sk_sp colorSpace) { +sk_sp Bitmap::createFrom(sp graphicBuffer, sk_sp colorSpace, + SkAlphaType alphaType, BitmapPalette palette) { // As we will be effectively texture-sampling the buffer (using either EGL or Vulkan), we can - // view the colorspace as RGBA8888. + // view the format as RGBA8888. SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(), - kRGBA_8888_SkColorType, kPremul_SkAlphaType, - colorSpace); - return sk_sp(new Bitmap(graphicBuffer.get(), info)); + kRGBA_8888_SkColorType, alphaType, colorSpace); + return sk_sp(new Bitmap(graphicBuffer.get(), info, palette)); +} + +sk_sp Bitmap::createFrom(const SkImageInfo& info, size_t rowBytes, int fd, void* addr, + size_t size, bool readOnly) { + if (info.colorType() == kUnknown_SkColorType) { + LOG_ALWAYS_FATAL("unknown bitmap configuration"); + return nullptr; + } + + if (!addr) { + // Map existing ashmem region if not already mapped. + int flags = readOnly ? (PROT_READ) : (PROT_READ | PROT_WRITE); + size = ashmem_get_size_region(fd); + addr = mmap(NULL, size, flags, MAP_SHARED, fd, 0); + if (addr == MAP_FAILED) { + return nullptr; + } + } + + sk_sp bitmap(new Bitmap(addr, fd, size, info, rowBytes)); + if (readOnly) { + bitmap->setImmutable(); + } + return bitmap; } void Bitmap::setColorSpace(sk_sp colorSpace) { diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h index d446377ec1d9..2138040d9690 100644 --- a/libs/hwui/hwui/Bitmap.h +++ b/libs/hwui/hwui/Bitmap.h @@ -54,28 +54,31 @@ typedef void (*FreeFunc)(void* addr, void* context); class ANDROID_API 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. + * + * The factories that accept SkBitmap* as a param will modify those params by + * installing the returned bitmap as their SkPixelRef. + * + * The factories that accept const SkBitmap& as a param will copy the contents of the + * provided bitmap into the newly allocated buffer. + */ + static sk_sp allocateAshmemBitmap(SkBitmap* bitmap); + static sk_sp allocateHardwareBitmap(const SkBitmap& bitmap); static sk_sp allocateHeapBitmap(SkBitmap* bitmap); static sk_sp allocateHeapBitmap(const SkImageInfo& info); - static sk_sp allocateHardwareBitmap(SkBitmap& bitmap); - - static sk_sp allocateAshmemBitmap(SkBitmap* bitmap); - static sk_sp allocateAshmemBitmap(size_t allocSize, const SkImageInfo& info, - size_t rowBytes); - - static sk_sp createFrom(sp graphicBuffer); + /* The createFrom factories construct a new Bitmap object by wrapping the already allocated + * memory that is provided as an input param. + */ static sk_sp createFrom(sp graphicBuffer, - sk_sp colorSpace); - + sk_sp colorSpace, + SkAlphaType alphaType = kPremul_SkAlphaType, + BitmapPalette palette = BitmapPalette::Unknown); + static sk_sp createFrom(const SkImageInfo& info, size_t rowBytes, int fd, void* addr, + size_t size, bool readOnly); static sk_sp createFrom(const SkImageInfo&, SkPixelRef&); - 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(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes); - Bitmap(GraphicBuffer* buffer, const SkImageInfo& info, - BitmapPalette palette = BitmapPalette::Unknown); - int rowBytesAsPixels() const { return rowBytes() >> mInfo.shiftPerPixel(); } void reconfigure(const SkImageInfo& info, size_t rowBytes); @@ -123,6 +126,15 @@ public: } private: + static sk_sp allocateAshmemBitmap(size_t size, const SkImageInfo& i, size_t rowBytes); + static sk_sp 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(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes); + Bitmap(GraphicBuffer* buffer, const SkImageInfo& info, BitmapPalette palette); + virtual ~Bitmap(); void* getStorage() const; diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index c67134cddb8a..1d3a24463057 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -158,7 +158,7 @@ sk_sp SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThr ALOGW("SkiaVulkanPipeline::allocateHardwareBitmap() failed in GraphicBuffer.create()"); return nullptr; } - return sk_sp(new Bitmap(buffer.get(), skBitmap.info())); + return Bitmap::createFrom(buffer, skBitmap.refColorSpace()); } } /* namespace skiapipeline */ diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp index 448408d19eb1..ec81f629ee45 100644 --- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp +++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp @@ -50,7 +50,7 @@ public: pixels[4000 + 4 * i + 3] = 255; } buffer->unlock(); - sk_sp hardwareBitmap(Bitmap::createFrom(buffer)); + sk_sp hardwareBitmap(Bitmap::createFrom(buffer, SkColorSpace::MakeSRGB())); sk_sp hardwareShader(createBitmapShader(*hardwareBitmap)); SkPoint center; diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h index 4daccda78e23..4473ce632b1b 100644 --- a/libs/hwui/utils/Color.h +++ b/libs/hwui/utils/Color.h @@ -17,6 +17,7 @@ #define COLOR_H #include +#include #include #include @@ -117,7 +118,7 @@ bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace); android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType); -sk_sp DataSpaceToColorSpace(android_dataspace dataspace); +ANDROID_API sk_sp DataSpaceToColorSpace(android_dataspace dataspace); struct Lab { float L; -- cgit v1.2.3-59-g8ed1b From 6104cea3fb0bddd766f390f9f4e2db9fc00b410e Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 10 Jan 2019 14:37:17 -0800 Subject: Fix leak/crash in exit Bug: 120440607 Test: hwuimacro32 doesn't crash Change-Id: I35b7a924e338efb314f07b923ba22ffcf98f75ee --- libs/hwui/HardwareBitmapUploader.cpp | 13 ++++++++++++- libs/hwui/HardwareBitmapUploader.h | 1 + libs/hwui/renderthread/EglManager.cpp | 4 +++- libs/hwui/tests/macrobench/main.cpp | 5 +++++ libs/hwui/thread/ThreadBase.h | 2 +- 5 files changed, 22 insertions(+), 3 deletions(-) (limited to 'libs/hwui/HardwareBitmapUploader.cpp') diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp index b9860ada18fc..635d0ec66673 100644 --- a/libs/hwui/HardwareBitmapUploader.cpp +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -34,7 +34,7 @@ namespace android::uirenderer { static std::mutex sLock{}; -static ThreadBase* sUploadThread = nullptr; +static sp sUploadThread = nullptr; static renderthread::EglManager sEglManager; static int sPendingUploads = 0; static nsecs_t sLastUpload = 0; @@ -257,4 +257,15 @@ sk_sp HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sou Bitmap::computePalette(bitmap)); } +void HardwareBitmapUploader::terminate() { + std::lock_guard _lock{sLock}; + LOG_ALWAYS_FATAL_IF(sPendingUploads, "terminate called while uploads in progress"); + if (sUploadThread) { + sUploadThread->requestExit(); + sUploadThread->join(); + sUploadThread = nullptr; + } + sEglManager.destroy(); +} + } // namespace android::uirenderer diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h index 6298013bd263..40f2b0c7873c 100644 --- a/libs/hwui/HardwareBitmapUploader.h +++ b/libs/hwui/HardwareBitmapUploader.h @@ -23,6 +23,7 @@ namespace android::uirenderer { class HardwareBitmapUploader { public: static sk_sp allocateHardwareBitmap(const SkBitmap& sourceBitmap); + static void terminate(); }; } // namespace android::uirenderer diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 56eedff4a6e6..8cd97ed20215 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -93,7 +93,9 @@ EglManager::EglManager() , mHasWideColorGamutSupport(false) {} EglManager::~EglManager() { - destroy(); + if (hasEglContext()) { + ALOGW("~EglManager() leaked an EGL context"); + } } void EglManager::initialize() { diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp index 524dfb0fe4ef..174a14080eff 100644 --- a/libs/hwui/tests/macrobench/main.cpp +++ b/libs/hwui/tests/macrobench/main.cpp @@ -19,6 +19,8 @@ #include "Properties.h" #include "hwui/Typeface.h" +#include "HardwareBitmapUploader.h" +#include "renderthread/RenderProxy.h" #include #include @@ -353,6 +355,9 @@ int main(int argc, char* argv[]) { gBenchmarkReporter->Finalize(); } + renderthread::RenderProxy::trimMemory(100); + HardwareBitmapUploader::terminate(); + LeakChecker::checkForLeaks(); return 0; } diff --git a/libs/hwui/thread/ThreadBase.h b/libs/hwui/thread/ThreadBase.h index f9de8a5037e5..8cdcc46b97fb 100644 --- a/libs/hwui/thread/ThreadBase.h +++ b/libs/hwui/thread/ThreadBase.h @@ -27,7 +27,7 @@ namespace android::uirenderer { -class ThreadBase : protected Thread { +class ThreadBase : public Thread { PREVENT_COPY_AND_ASSIGN(ThreadBase); public: -- cgit v1.2.3-59-g8ed1b From 6e35e63740e9becb0976f3dc54ea0cd5ffc26564 Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Tue, 22 Jan 2019 13:56:25 -0500 Subject: Don't assume all FP16 bitmaps are linearly encoded. The bitmap.create() function that does not take a colorspace does not enforce that the bitmap is linearly encoded and as such it is possible for us to end up with FP16 bitmaps that are sRGB encoded. Given that we want to remove that restriction (see b/120870651) we update getColorSpace to report the actual colorSpace of the underlying bitmap. This pulls a thread that causes a chain of updates to various classes to ensure proper handling of the native colorspace. Bug: 120904891 Test: CtsUiRenderingTestCases Change-Id: I27780aa603138b0e48f9320c2837bc53e22cdf95 --- core/jni/android/graphics/Bitmap.cpp | 16 ++++++++++++-- core/jni/android_view_ThreadedRenderer.cpp | 3 ++- graphics/java/android/graphics/Bitmap.java | 25 ++++++++++++---------- libs/hwui/HardwareBitmapUploader.cpp | 18 ++++++---------- libs/hwui/hwui/Bitmap.cpp | 9 ++++---- libs/hwui/hwui/Bitmap.h | 1 + libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp | 16 ++------------ .../common/scenes/HwBitmapInCompositeShader.cpp | 3 ++- libs/hwui/utils/Color.cpp | 14 ++++++++++++ libs/hwui/utils/Color.h | 1 + 10 files changed, 61 insertions(+), 45 deletions(-) (limited to 'libs/hwui/HardwareBitmapUploader.cpp') diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index ad51c4701d84..5de088397690 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -602,6 +603,14 @@ static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) { return static_cast(bitmap->getGenerationID()); } +static jboolean Bitmap_isConfigF16(JNIEnv* env, jobject, jlong bitmapHandle) { + LocalScopedBitmap bitmap(bitmapHandle); + if (bitmap->info().colorType() == kRGBA_F16_SkColorType) { + return JNI_TRUE; + } + return JNI_FALSE; +} + static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) { LocalScopedBitmap bitmap(bitmapHandle); if (bitmap->info().alphaType() == kPremul_SkAlphaType) { @@ -1120,7 +1129,8 @@ static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphic sp buffer(graphicBufferForJavaObject(env, graphicBuffer)); // To support any color space, we need to pass an additional ColorSpace argument to // java Bitmap.createHardwareBitmap. - sk_sp bitmap = Bitmap::createFrom(buffer, SkColorSpace::MakeSRGB()); + SkColorType ct = uirenderer::PixelFormatToColorType(buffer->getPixelFormat()); + sk_sp bitmap = Bitmap::createFrom(buffer, ct, SkColorSpace::MakeSRGB()); if (!bitmap.get()) { ALOGW("failed to create hardware bitmap from graphic buffer"); return NULL; @@ -1133,7 +1143,8 @@ static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject har AHardwareBuffer* hwBuf = android_hardware_HardwareBuffer_getNativeHardwareBuffer(env, hardwareBuffer); sp buffer(AHardwareBuffer_to_GraphicBuffer(hwBuf)); - sk_sp bitmap = Bitmap::createFrom(buffer, + SkColorType ct = uirenderer::PixelFormatToColorType(buffer->getPixelFormat()); + sk_sp bitmap = Bitmap::createFrom(buffer, ct, GraphicsJNI::getNativeColorSpace(colorSpacePtr)); if (!bitmap.get()) { ALOGW("failed to create hardware bitmap from hardware buffer"); @@ -1193,6 +1204,7 @@ static const JNINativeMethod gBitmapMethods[] = { { "nativeErase", "(JJJ)V", (void*)Bitmap_eraseLong }, { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes }, { "nativeConfig", "(J)I", (void*)Bitmap_config }, + { "nativeIsConfigF16", "(J)Z", (void*)Bitmap_isConfigF16 }, { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha }, { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied}, { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha}, diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 5a8ab3c1bdc4..32e6ac0b717e 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -1011,8 +1011,9 @@ static jobject android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode( // Continue I guess? } + SkColorType ct = uirenderer::PixelFormatToColorType(buffer->getPixelFormat()); sk_sp cs = uirenderer::DataSpaceToColorSpace(bufferItem.mDataSpace); - sk_sp bitmap = Bitmap::createFrom(buffer, cs); + sk_sp bitmap = Bitmap::createFrom(buffer, ct, cs); return bitmap::createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_Premultiplied); } diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index bfbdbc585e08..8636949943b7 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -1711,20 +1711,22 @@ public final class Bitmap implements Parcelable { */ @Nullable public final ColorSpace getColorSpace() { - // A reconfigure can change the configuration and rgba16f is - // always linear scRGB at this time - if (getConfig() == Config.RGBA_F16) { - // Reset the color space for potential future reconfigurations - mColorSpace = null; - return ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB); - } - + checkRecycled("getColorSpace called on a recycled bitmap"); // Cache the color space retrieval since it can be fairly expensive if (mColorSpace == null) { - if (nativeIsSRGB(mNativePtr)) { + if (nativeIsConfigF16(mNativePtr)) { + // an F16 bitmaps is intended to always be linear extended, but due to + // inconsistencies in Bitmap.create() functions it is possible to have + // rendered into a bitmap in non-linear sRGB. + if (nativeIsSRGB(mNativePtr)) { + mColorSpace = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB); + } else { + mColorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB); + } + } else if (nativeIsSRGB(mNativePtr)) { mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB); - } else if (getConfig() == Config.HARDWARE && nativeIsSRGBLinear(mNativePtr)) { - mColorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB); + } else if (nativeIsSRGBLinear(mNativePtr)) { + mColorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_SRGB); } else { float[] xyz = new float[9]; float[] params = new float[7]; @@ -2127,6 +2129,7 @@ public final class Bitmap implements Parcelable { private static native void nativeErase(long nativeBitmap, long colorSpacePtr, long color); private static native int nativeRowBytes(long nativeBitmap); private static native int nativeConfig(long nativeBitmap); + private static native boolean nativeIsConfigF16(long nativeBitmap); private static native int nativeGetPixel(long nativeBitmap, int x, int y); private static native void nativeGetPixels(long nativeBitmap, int[] pixels, diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp index 635d0ec66673..39bfcdd944a4 100644 --- a/libs/hwui/HardwareBitmapUploader.cpp +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -164,15 +164,11 @@ static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& sourc 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); - } + + SkCanvas canvas(bitmap); + canvas.drawColor(0); + canvas.drawBitmap(source, 0.0f, 0.0f, nullptr); + return bitmap; } } @@ -253,8 +249,8 @@ sk_sp HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sou eglDestroySyncKHR(display, fence); } - return Bitmap::createFrom(buffer.get(), bitmap.refColorSpace(), bitmap.alphaType(), - Bitmap::computePalette(bitmap)); + return Bitmap::createFrom(buffer.get(), bitmap.colorType(), bitmap.refColorSpace(), + bitmap.alphaType(), Bitmap::computePalette(bitmap)); } void HardwareBitmapUploader::terminate() { diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 6e0258c9ecb2..3bbee18c6dd1 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -133,12 +133,11 @@ sk_sp Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) } -sk_sp Bitmap::createFrom(sp graphicBuffer, sk_sp colorSpace, - SkAlphaType alphaType, BitmapPalette palette) { - // As we will be effectively texture-sampling the buffer (using either EGL or Vulkan), we can - // view the format as RGBA8888. +sk_sp Bitmap::createFrom(sp graphicBuffer, SkColorType colorType, + sk_sp colorSpace, SkAlphaType alphaType, + BitmapPalette palette) { SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(), - kRGBA_8888_SkColorType, alphaType, colorSpace); + colorType, alphaType, colorSpace); return sk_sp(new Bitmap(graphicBuffer.get(), info, palette)); } diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h index 2138040d9690..01e45166e0a3 100644 --- a/libs/hwui/hwui/Bitmap.h +++ b/libs/hwui/hwui/Bitmap.h @@ -72,6 +72,7 @@ public: * memory that is provided as an input param. */ static sk_sp createFrom(sp graphicBuffer, + SkColorType colorType, sk_sp colorSpace, SkAlphaType alphaType = kPremul_SkAlphaType, BitmapPalette palette = BitmapPalette::Unknown); diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index 53495a7d62c0..20fbab3e8587 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -149,20 +149,8 @@ void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* func sk_sp SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread, SkBitmap& skBitmap) { - // TODO: implement this function for Vulkan pipeline - // code below is a hack to avoid crashing because of missing HW Bitmap support - sp buffer = new GraphicBuffer( - skBitmap.info().width(), skBitmap.info().height(), PIXEL_FORMAT_RGBA_8888, - GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER | - GraphicBuffer::USAGE_SW_READ_NEVER, - std::string("SkiaVulkanPipeline::allocateHardwareBitmap pid [") + - std::to_string(getpid()) + "]"); - status_t error = buffer->initCheck(); - if (error < 0) { - ALOGW("SkiaVulkanPipeline::allocateHardwareBitmap() failed in GraphicBuffer.create()"); - return nullptr; - } - return Bitmap::createFrom(buffer, skBitmap.refColorSpace()); + LOG_ALWAYS_FATAL("Unimplemented"); + return nullptr; } } /* namespace skiapipeline */ diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp index ec81f629ee45..2af955fbb711 100644 --- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp +++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp @@ -50,7 +50,8 @@ public: pixels[4000 + 4 * i + 3] = 255; } buffer->unlock(); - sk_sp hardwareBitmap(Bitmap::createFrom(buffer, SkColorSpace::MakeSRGB())); + sk_sp hardwareBitmap(Bitmap::createFrom(buffer, kRGBA_8888_SkColorType, + SkColorSpace::MakeSRGB())); sk_sp hardwareShader(createBitmapShader(*hardwareBitmap)); SkPoint center; diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp index 4415a593f6ee..d14116f7b555 100644 --- a/libs/hwui/utils/Color.cpp +++ b/libs/hwui/utils/Color.cpp @@ -45,6 +45,20 @@ android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) { } } +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: + ALOGW("Unsupported PixelFormat: %d, return kUnknown_SkColorType by default", format); + return kUnknown_SkColorType; + } +} + sk_sp DataSpaceToColorSpace(android_dataspace dataspace) { skcms_Matrix3x3 gamut; diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h index 388025207ed6..b67d10d4249c 100644 --- a/libs/hwui/utils/Color.h +++ b/libs/hwui/utils/Color.h @@ -112,6 +112,7 @@ static constexpr float EOCF(float srgb) { } android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType); +ANDROID_API SkColorType PixelFormatToColorType(android::PixelFormat format); ANDROID_API sk_sp DataSpaceToColorSpace(android_dataspace dataspace); -- cgit v1.2.3-59-g8ed1b From ee3bfe7681d44da520ec646c3e500ccecaaab228 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Thu, 31 Jan 2019 08:42:23 -0500 Subject: Only decode to F16 if HARDWARE supports it Bug: 123301974 Test: Infeasible If a Bitmap is going to be decoded to F16 and then converted to HARDWARE, only decode to F16 if HARDWARE supports it. Previously, if we discovered after the decode that HARDWARE did not support F16, we had to copy back to 8888 before the upload. Change-Id: I3ceb9d053ba134bb96cfb9d638e54ac652e5db29 --- core/jni/android/graphics/BitmapFactory.cpp | 6 ++++++ core/jni/android/graphics/BitmapRegionDecoder.cpp | 5 +++++ core/jni/android/graphics/ImageDecoder.cpp | 17 +++++++++++++---- libs/hwui/HardwareBitmapUploader.cpp | 4 ++-- libs/hwui/HardwareBitmapUploader.h | 4 +++- 5 files changed, 29 insertions(+), 7 deletions(-) (limited to 'libs/hwui/HardwareBitmapUploader.cpp') diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 3f9ec452749f..7ef30f7ee786 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -15,6 +15,7 @@ #include "Utils.h" #include "core_jni_helpers.h" +#include #include #include #include @@ -278,6 +279,11 @@ static jobject doDecode(JNIEnv* env, std::unique_ptr stream, // Set the decode colorType SkColorType decodeColorType = codec->computeOutputColorType(prefColorType); + if (decodeColorType == kRGBA_F16_SkColorType && isHardware && + !uirenderer::HardwareBitmapUploader::hasFP16Support()) { + decodeColorType = kN32_SkColorType; + } + sk_sp decodeColorSpace = codec->computeOutputColorSpace( decodeColorType, prefColorSpace); diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp index b4ba749b75bf..d65f324d1065 100644 --- a/core/jni/android/graphics/BitmapRegionDecoder.cpp +++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp @@ -33,6 +33,7 @@ #include "android_util_Binder.h" #include "core_jni_helpers.h" +#include #include #include #include @@ -166,6 +167,10 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in SkBitmapRegionDecoder* brd = reinterpret_cast(brdHandle); SkColorType decodeColorType = brd->computeOutputColorType(colorType); + if (decodeColorType == kRGBA_F16_SkColorType && isHardware && + !uirenderer::HardwareBitmapUploader::hasFP16Support()) { + decodeColorType = kN32_SkColorType; + } // Set up the pixel allocator SkBRDAllocator* allocator = nullptr; diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp index 72e14e79f4f5..2d83ac320733 100644 --- a/core/jni/android/graphics/ImageDecoder.cpp +++ b/core/jni/android/graphics/ImageDecoder.cpp @@ -24,6 +24,7 @@ #include "core_jni_helpers.h" #include +#include #include #include @@ -256,6 +257,17 @@ static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong // This is currently the only way to know that we should decode to F16. colorType = codec->computeOutputColorType(colorType); } + + const bool isHardware = !requireMutable + && (allocator == ImageDecoder::kDefault_Allocator || + allocator == ImageDecoder::kHardware_Allocator) + && colorType != kGray_8_SkColorType; + + if (colorType == kRGBA_F16_SkColorType && isHardware && + !uirenderer::HardwareBitmapUploader::hasFP16Support()) { + colorType = kN32_SkColorType; + } + sk_sp colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle); colorSpace = codec->computeOutputColorSpace(colorType, colorSpace); decodeInfo = decodeInfo.makeColorType(colorType).makeColorSpace(colorSpace); @@ -449,10 +461,7 @@ static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong if (requireMutable) { bitmapCreateFlags |= bitmap::kBitmapCreateFlag_Mutable; } else { - if ((allocator == ImageDecoder::kDefault_Allocator || - allocator == ImageDecoder::kHardware_Allocator) - && bm.colorType() != kAlpha_8_SkColorType) - { + if (isHardware) { sk_sp hwBitmap = Bitmap::allocateHardwareBitmap(bm); if (hwBitmap) { hwBitmap->setImmutable(); diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp index 39bfcdd944a4..6b7ec97de4c8 100644 --- a/libs/hwui/HardwareBitmapUploader.cpp +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -86,7 +86,7 @@ static EGLDisplay getUploadEglDisplay() { return sEglManager.eglDisplay(); } -static bool hasFP16Support() { +bool HardwareBitmapUploader::hasFP16Support() { static std::once_flag sOnce; static bool hasFP16Support = false; @@ -127,7 +127,7 @@ static FormatInfo determineFormat(const SkBitmap& skBitmap) { formatInfo.type = GL_UNSIGNED_BYTE; break; case kRGBA_F16_SkColorType: - formatInfo.isSupported = hasFP16Support(); + formatInfo.isSupported = HardwareBitmapUploader::hasFP16Support(); if (formatInfo.isSupported) { formatInfo.type = GL_HALF_FLOAT; formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16; diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h index 40f2b0c7873c..6f41e6db4e32 100644 --- a/libs/hwui/HardwareBitmapUploader.h +++ b/libs/hwui/HardwareBitmapUploader.h @@ -20,10 +20,12 @@ namespace android::uirenderer { -class HardwareBitmapUploader { +class ANDROID_API HardwareBitmapUploader { public: static sk_sp allocateHardwareBitmap(const SkBitmap& sourceBitmap); static void terminate(); + + static bool hasFP16Support(); }; } // namespace android::uirenderer -- cgit v1.2.3-59-g8ed1b From 124975791084a660c32645260c151e4c3c537e76 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Thu, 31 Jan 2019 10:06:12 -0500 Subject: Remove references to ANDROID_ENABLE_LINEAR_BLENDING Test: make There is no longer any intent to turn on linear blending. Change-Id: Ia1016f31833212da6ad4b4c6ebe03d16a509746d --- core/jni/Android.bp | 4 ---- libs/hwui/Android.bp | 4 ---- libs/hwui/HardwareBitmapUploader.cpp | 1 - libs/hwui/VectorDrawable.cpp | 7 +------ libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp | 7 +------ libs/hwui/utils/Color.h | 22 ---------------------- 6 files changed, 2 insertions(+), 43 deletions(-) (limited to 'libs/hwui/HardwareBitmapUploader.cpp') diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 51a3b48e58ec..e7a1c49e7a99 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -27,10 +27,6 @@ cc_library_shared { "-Wno-error=deprecated-declarations", "-Wunused", "-Wunreachable-code", - - // TODO: Linear blending should be enabled by default, but we are - // TODO: making it an opt-in while it's a work in progress - //"-DANDROID_ENABLE_LINEAR_BLENDING", ], cppflags: ["-Wno-conversion-null"], diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 96798f978465..0335a7c6bd7d 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -28,10 +28,6 @@ cc_defaults { // clang's warning is broken, see: https://llvm.org/bugs/show_bug.cgi?id=21629 "-Wno-missing-braces", - - // TODO: Linear blending should be enabled by default, but we are - // TODO: making it an opt-in while it's a work in progress - //"-DANDROID_ENABLE_LINEAR_BLENDING", ], include_dirs: [ diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp index 6b7ec97de4c8..aeeb32c4620a 100644 --- a/libs/hwui/HardwareBitmapUploader.cpp +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -116,7 +116,6 @@ struct FormatInfo { 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; diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp index 72656922b03e..da905cf9e63a 100644 --- a/libs/hwui/VectorDrawable.cpp +++ b/libs/hwui/VectorDrawable.cpp @@ -606,12 +606,7 @@ void Tree::updateBitmapCache(Bitmap& bitmap, bool useStagingData) { bool Tree::allocateBitmapIfNeeded(Cache& cache, int width, int height) { if (!canReuseBitmap(cache.bitmap.get(), width, height)) { -#ifndef ANDROID_ENABLE_LINEAR_BLENDING - sk_sp colorSpace = nullptr; -#else - sk_sp colorSpace = SkColorSpace::MakeSRGB(); -#endif - SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType, colorSpace); + SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType); cache.bitmap = Bitmap::allocateHeapBitmap(info); return true; } diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp index 8fb621d24866..e783f389feb8 100644 --- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp +++ b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp @@ -262,12 +262,7 @@ void VectorDrawableAtlas::delayedReleaseEntries() { } sk_sp VectorDrawableAtlas::createSurface(int width, int height, GrContext* context) { -#ifndef ANDROID_ENABLE_LINEAR_BLENDING - sk_sp colorSpace = nullptr; -#else - sk_sp colorSpace = SkColorSpace::MakeSRGB(); -#endif - SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType, colorSpace); + SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType); // This must have a top-left origin so that calls to surface->canvas->writePixels // performs a basic texture upload instead of a more complex drawing operation return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0, kTopLeft_GrSurfaceOrigin, diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h index b67d10d4249c..79400de08ee0 100644 --- a/libs/hwui/utils/Color.h +++ b/libs/hwui/utils/Color.h @@ -82,17 +82,6 @@ static constexpr float OECF_sRGB(float linear) { return linear <= 0.0031308f ? linear * 12.92f : (powf(linear, 1.0f / 2.4f) * 1.055f) - 0.055f; } -// Opto-electronic conversion function for the sRGB color space -// Takes a linear sRGB value and converts it to a gamma-encoded sRGB value -// This function returns the input unmodified if linear blending is not enabled -static constexpr float OECF(float linear) { -#ifdef ANDROID_ENABLE_LINEAR_BLENDING - return OECF_sRGB(linear); -#else - return linear; -#endif -} - // Electro-optical conversion function for the sRGB color space // Takes a gamma-encoded sRGB value and converts it to a linear sRGB value static constexpr float EOCF_sRGB(float srgb) { @@ -100,17 +89,6 @@ static constexpr float EOCF_sRGB(float srgb) { return srgb <= 0.04045f ? srgb / 12.92f : powf((srgb + 0.055f) / 1.055f, 2.4f); } -// Electro-optical conversion function for the sRGB color space -// Takes a gamma-encoded sRGB value and converts it to a linear sRGB value -// This function returns the input unmodified if linear blending is not enabled -static constexpr float EOCF(float srgb) { -#ifdef ANDROID_ENABLE_LINEAR_BLENDING - return EOCF_sRGB(srgb); -#else - return srgb; -#endif -} - android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType); ANDROID_API SkColorType PixelFormatToColorType(android::PixelFormat format); -- cgit v1.2.3-59-g8ed1b From c073252f764529ac7859746d81d9a4a6818037d3 Mon Sep 17 00:00:00 2001 From: Greg Daniel Date: Wed, 20 Feb 2019 08:31:03 -0500 Subject: Add support for uploading to AHBs using Vulkan. Test: manual build and testing on blueline. Change-Id: I240a5f1e3ba34677b03131eba36ffd8783d99041 --- libs/hwui/HardwareBitmapUploader.cpp | 378 ++++++++++++++++++++++---------- libs/hwui/HardwareBitmapUploader.h | 4 +- libs/hwui/renderthread/RenderThread.cpp | 2 + 3 files changed, 272 insertions(+), 112 deletions(-) (limited to 'libs/hwui/HardwareBitmapUploader.cpp') diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp index aeeb32c4620a..8f7e8142e735 100644 --- a/libs/hwui/HardwareBitmapUploader.cpp +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -18,6 +18,7 @@ #include "hwui/Bitmap.h" #include "renderthread/EglManager.h" +#include "renderthread/VulkanManager.h" #include "thread/ThreadBase.h" #include "utils/TimeUtils.h" @@ -25,7 +26,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -33,58 +36,247 @@ namespace android::uirenderer { -static std::mutex sLock{}; -static sp sUploadThread = nullptr; -static renderthread::EglManager sEglManager; -static int sPendingUploads = 0; -static nsecs_t sLastUpload = 0; +class AHBUploader; +// This helper uploader classes allows us to upload using either EGL or Vulkan using the same +// interface. +static sp sUploader = nullptr; -static bool shouldTimeOutLocked() { - nsecs_t durationSince = systemTime() - sLastUpload; - return durationSince > 2000_ms; -} +struct FormatInfo { + PixelFormat pixelFormat; + GLint format, type; + VkFormat vkFormat; + bool isSupported = false; + bool valid = true; +}; -static void checkIdleTimeout() { - std::lock_guard _lock{sLock}; - if (sPendingUploads == 0 && shouldTimeOutLocked()) { - sEglManager.destroy(); - } else { - sUploadThread->queue().postDelayed(5000_ms, checkIdleTimeout); +class AHBUploader : public RefBase { +public: + virtual ~AHBUploader() {} + + // Called to start creation of the Vulkan and EGL contexts on another thread before we actually + // need to do an upload. + void initialize() { + onInitialize(); } -} -static void beginUpload() { - std::lock_guard _lock{sLock}; - sPendingUploads++; + void destroy() { + std::lock_guard _lock{mLock}; + LOG_ALWAYS_FATAL_IF(mPendingUploads, "terminate called while uploads in progress"); + if (mUploadThread) { + mUploadThread->requestExit(); + mUploadThread->join(); + mUploadThread = nullptr; + } + onDestroy(); + } + + bool uploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format, + sp graphicBuffer) { + ATRACE_CALL(); + beginUpload(); + bool result = onUploadHardwareBitmap(bitmap, format, graphicBuffer); + endUpload(); + return result; + } + + void postIdleTimeoutCheck() { + mUploadThread->queue().postDelayed(5000_ms, [this](){ this->idleTimeoutCheck(); }); + } - if (!sUploadThread) { - sUploadThread = new ThreadBase{}; +protected: + std::mutex mLock; + sp mUploadThread = nullptr; + +private: + virtual void onInitialize() = 0; + virtual void onIdle() = 0; + virtual void onDestroy() = 0; + + virtual bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format, + sp graphicBuffer) = 0; + virtual void onBeginUpload() = 0; + + bool shouldTimeOutLocked() { + nsecs_t durationSince = systemTime() - mLastUpload; + return durationSince > 2000_ms; } - if (!sUploadThread->isRunning()) { - sUploadThread->start("GrallocUploadThread"); + void idleTimeoutCheck() { + std::lock_guard _lock{mLock}; + if (mPendingUploads == 0 && shouldTimeOutLocked()) { + onIdle(); + } else { + this->postIdleTimeoutCheck(); + } } - if (!sEglManager.hasEglContext()) { - sUploadThread->queue().runSync([]() { - sEglManager.initialize(); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + void beginUpload() { + std::lock_guard _lock{mLock}; + mPendingUploads++; + + if (!mUploadThread) { + mUploadThread = new ThreadBase{}; + } + if (!mUploadThread->isRunning()) { + mUploadThread->start("GrallocUploadThread"); + } + + onBeginUpload(); + } + + void endUpload() { + std::lock_guard _lock{mLock}; + mPendingUploads--; + mLastUpload = systemTime(); + } + + int mPendingUploads = 0; + nsecs_t mLastUpload = 0; +}; + +#define FENCE_TIMEOUT 2000000000 + +class EGLUploader : public AHBUploader { +private: + void onInitialize() override {} + void onDestroy() override { + mEglManager.destroy(); + } + void onIdle() override { + mEglManager.destroy(); + } + + void onBeginUpload() override { + if (!mEglManager.hasEglContext()) { + mUploadThread->queue().runSync([this]() { + this->mEglManager.initialize(); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + }); + + this->postIdleTimeoutCheck(); + } + } + + + EGLDisplay getUploadEglDisplay() { + std::lock_guard _lock{mLock}; + LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(), "Forgot to begin an upload?"); + return mEglManager.eglDisplay(); + } + + bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format, + sp graphicBuffer) 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 + // The EGL image is later bound to a 2D texture + EGLClientBuffer clientBuffer = (EGLClientBuffer)graphicBuffer->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 false; + } + + { + ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height()); + EGLSyncKHR fence = mUploadThread->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 true; + } + + renderthread::EglManager mEglManager; +}; + +class VkUploader : public AHBUploader { +private: + void onInitialize() override { + std::lock_guard _lock{mLock}; + if (!mUploadThread) { + mUploadThread = new ThreadBase{}; + } + if (!mUploadThread->isRunning()) { + mUploadThread->start("GrallocUploadThread"); + } + + mUploadThread->queue().post([this]() { + std::lock_guard _lock{mVkLock}; + if (!mVulkanManager.hasVkContext()) { + mVulkanManager.initialize(); + } }); - sUploadThread->queue().postDelayed(5000_ms, checkIdleTimeout); } -} + void onDestroy() override { + mGrContext.reset(); + mVulkanManager.destroy(); + } + void onIdle() override { + mGrContext.reset(); + } -static void endUpload() { - std::lock_guard _lock{sLock}; - sPendingUploads--; - sLastUpload = systemTime(); -} + void onBeginUpload() override { + { + std::lock_guard _lock{mVkLock}; + if (!mVulkanManager.hasVkContext()) { + LOG_ALWAYS_FATAL_IF(mGrContext, + "GrContext exists with no VulkanManager for vulkan uploads"); + mUploadThread->queue().runSync([this]() { + mVulkanManager.initialize(); + }); + } + } + if (!mGrContext) { + GrContextOptions options; + mGrContext = mVulkanManager.createContext(options); + LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads"); + this->postIdleTimeoutCheck(); + } + } -static EGLDisplay getUploadEglDisplay() { - std::lock_guard _lock{sLock}; - LOG_ALWAYS_FATAL_IF(!sEglManager.hasEglContext(), "Forgot to begin an upload?"); - return sEglManager.eglDisplay(); -} + bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format, + sp graphicBuffer) override { + ATRACE_CALL(); + + std::lock_guard _lock{mLock}; + + sk_sp image = SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(), + bitmap.pixmap(), reinterpret_cast(graphicBuffer.get())); + return (image.get() != nullptr); + } + + sk_sp mGrContext; + renderthread::VulkanManager mVulkanManager; + std::mutex mVkLock; +}; bool HardwareBitmapUploader::hasFP16Support() { static std::once_flag sOnce; @@ -105,16 +297,7 @@ bool HardwareBitmapUploader::hasFP16Support() { return hasFP16Support; } -#define FENCE_TIMEOUT 2000000000 - -struct FormatInfo { - PixelFormat pixelFormat; - GLint format, type; - bool isSupported = false; - bool valid = true; -}; - -static FormatInfo determineFormat(const SkBitmap& skBitmap) { +static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) { FormatInfo formatInfo; switch (skBitmap.info().colorType()) { case kRGBA_8888_SkColorType: @@ -124,15 +307,18 @@ static FormatInfo determineFormat(const SkBitmap& skBitmap) { formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; formatInfo.format = GL_RGBA; formatInfo.type = GL_UNSIGNED_BYTE; + formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM; break; case kRGBA_F16_SkColorType: formatInfo.isSupported = HardwareBitmapUploader::hasFP16Support(); if (formatInfo.isSupported) { formatInfo.type = GL_HALF_FLOAT; formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16; + formatInfo.vkFormat = VK_FORMAT_R16G16B16A16_SFLOAT; } else { formatInfo.type = GL_UNSIGNED_BYTE; formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; + formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM; } formatInfo.format = GL_RGBA; break; @@ -141,12 +327,14 @@ static FormatInfo determineFormat(const SkBitmap& skBitmap) { formatInfo.pixelFormat = PIXEL_FORMAT_RGB_565; 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 = true; + formatInfo.isSupported = usingGL; formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; formatInfo.format = GL_LUMINANCE; formatInfo.type = GL_UNSIGNED_BYTE; + formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM; break; default: ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType()); @@ -172,29 +360,37 @@ static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& sourc } } -class ScopedUploadRequest { -public: - ScopedUploadRequest() { beginUpload(); } - ~ScopedUploadRequest() { endUpload(); } -}; + +static void createUploader(bool usingGL) { + static std::mutex lock; + std::lock_guard _lock{lock}; + if (!sUploader.get()) { + if (usingGL) { + sUploader = new EGLUploader(); + } else { + sUploader = new VkUploader(); + } + } +} sk_sp HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sourceBitmap) { ATRACE_CALL(); - FormatInfo format = determineFormat(sourceBitmap); + bool usingGL = uirenderer::Properties::getRenderPipelineType() == + uirenderer::RenderPipelineType::SkiaGL; + + FormatInfo format = determineFormat(sourceBitmap, usingGL); if (!format.valid) { return nullptr; } - ScopedUploadRequest _uploadRequest{}; - SkBitmap bitmap = makeHwCompatible(format, sourceBitmap); sp buffer = new GraphicBuffer( static_cast(bitmap.width()), static_cast(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()) + + std::string("Bitmap::allocateHardwareBitmap pid [") + std::to_string(getpid()) + "]"); status_t error = buffer->initCheck(); @@ -203,64 +399,24 @@ sk_sp HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sou 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()); + createUploader(usingGL); - eglDestroySyncKHR(display, fence); + if (!sUploader->uploadHardwareBitmap(bitmap, format, buffer)) { + return nullptr; } - - return Bitmap::createFrom(buffer.get(), bitmap.colorType(), bitmap.refColorSpace(), + return Bitmap::createFrom(buffer, bitmap.colorType(), bitmap.refColorSpace(), bitmap.alphaType(), Bitmap::computePalette(bitmap)); } +void HardwareBitmapUploader::initialize() { + bool usingGL = uirenderer::Properties::getRenderPipelineType() == + uirenderer::RenderPipelineType::SkiaGL; + createUploader(usingGL); + sUploader->initialize(); +} + void HardwareBitmapUploader::terminate() { - std::lock_guard _lock{sLock}; - LOG_ALWAYS_FATAL_IF(sPendingUploads, "terminate called while uploads in progress"); - if (sUploadThread) { - sUploadThread->requestExit(); - sUploadThread->join(); - sUploadThread = nullptr; - } - sEglManager.destroy(); + sUploader->destroy(); } } // namespace android::uirenderer diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h index 6f41e6db4e32..c300593d47a1 100644 --- a/libs/hwui/HardwareBitmapUploader.h +++ b/libs/hwui/HardwareBitmapUploader.h @@ -22,9 +22,11 @@ namespace android::uirenderer { class ANDROID_API HardwareBitmapUploader { public: - static sk_sp allocateHardwareBitmap(const SkBitmap& sourceBitmap); + static void initialize(); static void terminate(); + static sk_sp allocateHardwareBitmap(const SkBitmap& sourceBitmap); + static bool hasFP16Support(); }; diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index def805adeeea..6cce31943d03 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -29,6 +29,7 @@ #include "utils/FatVector.h" #include "utils/TimeUtils.h" #include "utils/TraceUtils.h" +#include "../HardwareBitmapUploader.h" #ifdef HWUI_GLES_WRAP_ENABLED #include "debug/GlesDriver.h" @@ -415,6 +416,7 @@ void RenderThread::preload() { if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { requireVkContext(); } + HardwareBitmapUploader::initialize(); } } /* namespace renderthread */ -- cgit v1.2.3-59-g8ed1b From 78b7ddc12e512771177eeca43dc0b0e247f7abbc Mon Sep 17 00:00:00 2001 From: Greg Daniel Date: Wed, 27 Mar 2019 12:52:43 -0400 Subject: Couple fixes to HardwareBitmapUploader. When we had to make a copy SkBitmap for an unsupported format, we were dropping the color space information. Added a null check in terminate. Test: manual build and running on blueline Change-Id: I3cf386231e76b7505a691d006585918d343f6c96 --- libs/hwui/HardwareBitmapUploader.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'libs/hwui/HardwareBitmapUploader.cpp') diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp index 8f7e8142e735..9bb6031b76ac 100644 --- a/libs/hwui/HardwareBitmapUploader.cpp +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -349,8 +349,7 @@ static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& sourc } else { SkBitmap bitmap; const SkImageInfo& info = source.info(); - bitmap.allocPixels( - SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(), nullptr)); + bitmap.allocPixels(info.makeColorType(kN32_SkColorType)); SkCanvas canvas(bitmap); canvas.drawColor(0); @@ -416,7 +415,9 @@ void HardwareBitmapUploader::initialize() { } void HardwareBitmapUploader::terminate() { - sUploader->destroy(); + if (sUploader) { + sUploader->destroy(); + } } } // namespace android::uirenderer -- cgit v1.2.3-59-g8ed1b