Merge QP1A.180823.001
Change-Id: Ia2d6fa811b3c57185c1975db603d59e6eaef73fc
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index fc625bb..843c146 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -74,6 +74,7 @@
const char* AssetManager::IDMAP_BIN = "/system/bin/idmap";
const char* AssetManager::OVERLAY_DIR = "/vendor/overlay";
const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay";
+const char* AssetManager::PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay";
const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme";
const char* AssetManager::TARGET_PACKAGE_NAME = "android";
const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk";
diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h
index 08da731..cdb87bc 100644
--- a/libs/androidfw/include/androidfw/AssetManager.h
+++ b/libs/androidfw/include/androidfw/AssetManager.h
@@ -61,6 +61,7 @@
static const char* IDMAP_BIN;
static const char* OVERLAY_DIR;
static const char* PRODUCT_OVERLAY_DIR;
+ static const char* PRODUCT_SERVICES_OVERLAY_DIR;
/*
* If OVERLAY_THEME_DIR_PROPERTY is set, search for runtime resource overlay
* APKs in OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 59760ab..83e90b6 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -72,7 +72,6 @@
"libft2",
"libminikin",
"libandroidfw",
- "libRScpp",
],
static_libs: [
"libEGL_blobCache",
@@ -230,7 +229,6 @@
"RenderProperties.cpp",
"ResourceCache.cpp",
"SkiaCanvas.cpp",
- "SkiaCanvasProxy.cpp",
"Snapshot.cpp",
"Texture.cpp",
"VectorDrawable.cpp",
@@ -243,7 +241,6 @@
},
export_include_dirs: ["."],
- export_shared_lib_headers: ["libRScpp"],
}
cc_library {
diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp
index bac7a4d..1b15dbd 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 <ui/ColorSpace.h>
#include <SkColorFilter.h>
#include <SkPaint.h>
-#include <log/log.h>
+
+#include <algorithm>
+#include <cmath>
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 6408ce6..ab80d3d 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -286,7 +286,7 @@
eglDestroySyncKHR(display, fence);
}
- return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info()));
+ return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info(), Bitmap::computePalette(bitmap)));
}
}; // namespace android::uirenderer
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
deleted file mode 100644
index fc009d8..0000000
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ /dev/null
@@ -1,486 +0,0 @@
-/*
- * Copyright (C) 2015 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 "SkiaCanvasProxy.h"
-
-#include <memory>
-
-#include <log/log.h>
-
-#include <SkLatticeIter.h>
-#include <SkPaint.h>
-#include <SkPatchUtils.h>
-#include <SkPath.h>
-#include <SkPixelRef.h>
-#include <SkRRect.h>
-#include <SkRSXform.h>
-#include <SkRect.h>
-#include <SkSurface.h>
-#include <SkTextBlobRunIterator.h>
-#include <SkVertices.h>
-#include "hwui/Bitmap.h"
-
-namespace android {
-namespace uirenderer {
-
-SkiaCanvasProxy::SkiaCanvasProxy(Canvas* canvas, bool filterHwuiCalls)
- : INHERITED(canvas->width(), canvas->height())
- , mCanvas(canvas)
- , mFilterHwuiCalls(filterHwuiCalls) {}
-
-void SkiaCanvasProxy::onDrawPaint(const SkPaint& paint) {
- mCanvas->drawPaint(paint);
-}
-
-void SkiaCanvasProxy::onDrawPoints(PointMode pointMode, size_t count, const SkPoint pts[],
- const SkPaint& paint) {
- if (!pts || count == 0) {
- return;
- }
-
- // convert the SkPoints into floats
- static_assert(sizeof(SkPoint) == sizeof(float) * 2, "SkPoint is no longer two floats");
- const size_t floatCount = count << 1;
- const float* floatArray = &pts[0].fX;
-
- switch (pointMode) {
- case kPoints_PointMode: {
- mCanvas->drawPoints(floatArray, floatCount, paint);
- break;
- }
- case kLines_PointMode: {
- mCanvas->drawLines(floatArray, floatCount, paint);
- break;
- }
- case kPolygon_PointMode: {
- SkPaint strokedPaint(paint);
- strokedPaint.setStyle(SkPaint::kStroke_Style);
-
- SkPath path;
- for (size_t i = 0; i < count - 1; i++) {
- path.moveTo(pts[i]);
- path.lineTo(pts[i + 1]);
- this->drawPath(path, strokedPaint);
- path.rewind();
- }
- break;
- }
- default:
- LOG_ALWAYS_FATAL("Unknown point type");
- }
-}
-
-void SkiaCanvasProxy::onDrawOval(const SkRect& rect, const SkPaint& paint) {
- mCanvas->drawOval(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint);
-}
-
-void SkiaCanvasProxy::onDrawRect(const SkRect& rect, const SkPaint& paint) {
- mCanvas->drawRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint);
-}
-
-void SkiaCanvasProxy::onDrawRRect(const SkRRect& roundRect, const SkPaint& paint) {
- if (!roundRect.isComplex()) {
- const SkRect& rect = roundRect.rect();
- SkVector radii = roundRect.getSimpleRadii();
- mCanvas->drawRoundRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, radii.fX, radii.fY,
- paint);
- } else {
- SkPath path;
- path.addRRect(roundRect);
- mCanvas->drawPath(path, paint);
- }
-}
-
-void SkiaCanvasProxy::onDrawArc(const SkRect& rect, SkScalar startAngle, SkScalar sweepAngle,
- bool useCenter, const SkPaint& paint) {
- mCanvas->drawArc(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, startAngle, sweepAngle,
- useCenter, paint);
-}
-
-void SkiaCanvasProxy::onDrawPath(const SkPath& path, const SkPaint& paint) {
- mCanvas->drawPath(path, paint);
-}
-
-void SkiaCanvasProxy::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
- const SkPaint* paint) {
- sk_sp<Bitmap> hwuiBitmap = Bitmap::createFrom(bitmap.info(), *bitmap.pixelRef());
- // HWUI doesn't support extractSubset(), so convert any subsetted bitmap into
- // a drawBitmapRect(); pass through an un-subsetted bitmap.
- if (hwuiBitmap && bitmap.dimensions() != hwuiBitmap->info().dimensions()) {
- SkIPoint origin = bitmap.pixelRefOrigin();
- mCanvas->drawBitmap(
- *hwuiBitmap, origin.fX, origin.fY, origin.fX + bitmap.dimensions().width(),
- origin.fY + bitmap.dimensions().height(), left, top,
- left + bitmap.dimensions().width(), top + bitmap.dimensions().height(), paint);
- } else {
- mCanvas->drawBitmap(*hwuiBitmap, left, top, paint);
- }
-}
-
-void SkiaCanvasProxy::onDrawBitmapRect(const SkBitmap& skBitmap, const SkRect* srcPtr,
- const SkRect& dst, const SkPaint* paint, SrcRectConstraint) {
- SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(skBitmap.width(), skBitmap.height());
- // TODO: if bitmap is a subset, do we need to add pixelRefOrigin to src?
- Bitmap* bitmap = reinterpret_cast<Bitmap*>(skBitmap.pixelRef());
- mCanvas->drawBitmap(*bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom, dst.fLeft, dst.fTop,
- dst.fRight, dst.fBottom, paint);
-}
-
-void SkiaCanvasProxy::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
- const SkRect& dst, const SkPaint*) {
- // TODO make nine-patch drawing a method on Canvas.h
- SkDEBUGFAIL("SkiaCanvasProxy::onDrawBitmapNine is not yet supported");
-}
-
-void SkiaCanvasProxy::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,
- const SkPaint* paint) {
- SkBitmap skiaBitmap;
- SkPixmap pixmap;
- if (image->peekPixels(&pixmap) && skiaBitmap.installPixels(pixmap)) {
- onDrawBitmap(skiaBitmap, left, top, paint);
- }
-}
-
-void SkiaCanvasProxy::onDrawImageRect(const SkImage* image, const SkRect* srcPtr, const SkRect& dst,
- const SkPaint* paint, SrcRectConstraint constraint) {
- SkBitmap skiaBitmap;
- SkPixmap pixmap;
- if (image->peekPixels(&pixmap) && skiaBitmap.installPixels(pixmap)) {
- sk_sp<Bitmap> bitmap = Bitmap::createFrom(skiaBitmap.info(), *skiaBitmap.pixelRef());
- SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(image->width(), image->height());
- mCanvas->drawBitmap(*bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom, dst.fLeft,
- dst.fTop, dst.fRight, dst.fBottom, paint);
- }
-}
-
-void SkiaCanvasProxy::onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
- const SkPaint*) {
- SkDEBUGFAIL("SkiaCanvasProxy::onDrawImageNine is not yet supported");
-}
-
-void SkiaCanvasProxy::onDrawImageLattice(const SkImage* image, const Lattice& lattice,
- const SkRect& dst, const SkPaint* paint) {
- SkLatticeIter iter(lattice, dst);
- SkRect srcR, dstR;
- while (iter.next(&srcR, &dstR)) {
- onDrawImageRect(image, &srcR, dstR, paint, SkCanvas::kFast_SrcRectConstraint);
- }
-}
-
-void SkiaCanvasProxy::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
- const SkPaint& paint) {
- if (mFilterHwuiCalls) {
- return;
- }
- mCanvas->drawVertices(vertices, bmode, paint);
-}
-
-sk_sp<SkSurface> SkiaCanvasProxy::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) {
- SkDEBUGFAIL("SkiaCanvasProxy::onNewSurface is not supported");
- return NULL;
-}
-
-void SkiaCanvasProxy::willSave() {
- mCanvas->save(android::SaveFlags::MatrixClip);
-}
-
-static inline SaveFlags::Flags saveFlags(SkCanvas::SaveLayerFlags layerFlags) {
- SaveFlags::Flags saveFlags = 0;
-
- if (!(layerFlags & SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag)) {
- saveFlags |= SaveFlags::ClipToLayer;
- }
-
- return saveFlags;
-}
-
-SkCanvas::SaveLayerStrategy SkiaCanvasProxy::getSaveLayerStrategy(
- const SaveLayerRec& saveLayerRec) {
- SkRect rect;
- if (saveLayerRec.fBounds) {
- rect = *saveLayerRec.fBounds;
- } else if (!mCanvas->getClipBounds(&rect)) {
- rect = SkRect::MakeEmpty();
- }
- mCanvas->saveLayer(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, saveLayerRec.fPaint,
- saveFlags(saveLayerRec.fSaveLayerFlags));
- return SkCanvas::kNoLayer_SaveLayerStrategy;
-}
-
-void SkiaCanvasProxy::willRestore() {
- mCanvas->restore();
-}
-
-void SkiaCanvasProxy::didConcat(const SkMatrix& matrix) {
- mCanvas->concat(matrix);
-}
-
-void SkiaCanvasProxy::didSetMatrix(const SkMatrix& matrix) {
- mCanvas->setMatrix(matrix);
-}
-
-void SkiaCanvasProxy::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
- const SkPaint& paint) {
- SkPath path;
- path.addRRect(outer);
- path.addRRect(inner);
- path.setFillType(SkPath::kEvenOdd_FillType);
- this->drawPath(path, paint);
-}
-
-/**
- * Utility class that converts the incoming text & paint from the given encoding
- * into glyphIDs.
- */
-class GlyphIDConverter {
-public:
- GlyphIDConverter(const void* text, size_t byteLength, const SkPaint& origPaint) {
- paint = origPaint;
- if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
- glyphIDs = (uint16_t*)text;
- count = byteLength >> 1;
- } else {
- // ensure space for one glyph per ID given UTF8 encoding.
- storage.reset(new uint16_t[byteLength]);
- glyphIDs = storage.get();
- count = paint.textToGlyphs(text, byteLength, storage.get());
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- }
- }
-
- SkPaint paint;
- uint16_t* glyphIDs;
- int count;
-
-private:
- std::unique_ptr<uint16_t[]> storage;
-};
-
-void SkiaCanvasProxy::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
- const SkPaint& origPaint) {
- // convert to glyphIDs if necessary
- GlyphIDConverter glyphs(text, byteLength, origPaint);
-
- // compute the glyph positions
- std::unique_ptr<SkScalar[]> glyphWidths(new SkScalar[glyphs.count]);
- glyphs.paint.getTextWidths(glyphs.glyphIDs, glyphs.count << 1, glyphWidths.get());
-
- // compute conservative bounds
- // NOTE: We could call the faster paint.getFontBounds for a less accurate,
- // but even more conservative bounds if this is too slow.
- SkRect bounds;
- glyphs.paint.measureText(glyphs.glyphIDs, glyphs.count << 1, &bounds);
-
- // adjust for non-left alignment
- if (glyphs.paint.getTextAlign() != SkPaint::kLeft_Align) {
- SkScalar stop = 0;
- for (int i = 0; i < glyphs.count; i++) {
- stop += glyphWidths[i];
- }
- if (glyphs.paint.getTextAlign() == SkPaint::kCenter_Align) {
- stop = SkScalarHalf(stop);
- }
- if (glyphs.paint.isVerticalText()) {
- y -= stop;
- } else {
- x -= stop;
- }
- }
-
- // setup the first glyph position and adjust bounds if needed
- int xBaseline = 0;
- int yBaseline = 0;
- if (mCanvas->drawTextAbsolutePos()) {
- bounds.offset(x, y);
- xBaseline = x;
- yBaseline = y;
- }
-
- static_assert(sizeof(SkPoint) == sizeof(float) * 2, "SkPoint is no longer two floats");
- auto glyphFunc = [&](uint16_t* text, float* positions) {
- memcpy(text, glyphs.glyphIDs, glyphs.count * sizeof(uint16_t));
- size_t posIndex = 0;
- // setup the first glyph position
- positions[posIndex++] = xBaseline;
- positions[posIndex++] = yBaseline;
- // setup the remaining glyph positions
- if (glyphs.paint.isVerticalText()) {
- float yPosition = yBaseline;
- for (int i = 1; i < glyphs.count; i++) {
- positions[posIndex++] = xBaseline;
- yPosition += glyphWidths[i - 1];
- positions[posIndex++] = yPosition;
- }
- } else {
- float xPosition = xBaseline;
- for (int i = 1; i < glyphs.count; i++) {
- xPosition += glyphWidths[i - 1];
- positions[posIndex++] = xPosition;
- positions[posIndex++] = yBaseline;
- }
- }
- };
- mCanvas->drawGlyphs(glyphFunc, glyphs.count, glyphs.paint, x, y, bounds.fLeft, bounds.fTop,
- bounds.fRight, bounds.fBottom, 0);
-}
-
-void SkiaCanvasProxy::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
- const SkPaint& origPaint) {
- // convert to glyphIDs if necessary
- GlyphIDConverter glyphs(text, byteLength, origPaint);
-
- // convert to relative positions if necessary
- int x, y;
- if (mCanvas->drawTextAbsolutePos()) {
- x = 0;
- y = 0;
- } else {
- x = pos[0].fX;
- y = pos[0].fY;
- }
-
- // Compute conservative bounds. If the content has already been processed
- // by Minikin then it had already computed these bounds. Unfortunately,
- // there is no way to capture those bounds as part of the Skia drawPosText
- // API so we need to do that computation again here.
- SkRect bounds = SkRect::MakeEmpty();
- for (int i = 0; i < glyphs.count; i++) {
- SkRect glyphBounds = SkRect::MakeEmpty();
- glyphs.paint.measureText(&glyphs.glyphIDs[i], sizeof(uint16_t), &glyphBounds);
- glyphBounds.offset(pos[i].fX, pos[i].fY);
- bounds.join(glyphBounds);
- }
-
- static_assert(sizeof(SkPoint) == sizeof(float) * 2, "SkPoint is no longer two floats");
- auto glyphFunc = [&](uint16_t* text, float* positions) {
- memcpy(text, glyphs.glyphIDs, glyphs.count * sizeof(uint16_t));
- if (mCanvas->drawTextAbsolutePos()) {
- memcpy(positions, pos, 2 * glyphs.count * sizeof(float));
- } else {
- for (int i = 0, posIndex = 0; i < glyphs.count; i++) {
- positions[posIndex++] = pos[i].fX - x;
- positions[posIndex++] = pos[i].fY - y;
- }
- }
- };
- mCanvas->drawGlyphs(glyphFunc, glyphs.count, glyphs.paint, x, y, bounds.fLeft, bounds.fTop,
- bounds.fRight, bounds.fBottom, 0);
-}
-
-void SkiaCanvasProxy::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
- SkScalar constY, const SkPaint& paint) {
- const size_t pointCount = byteLength >> 1;
- std::unique_ptr<SkPoint[]> pts(new SkPoint[pointCount]);
- for (size_t i = 0; i < pointCount; i++) {
- pts[i].set(xpos[i], constY);
- }
- this->onDrawPosText(text, byteLength, pts.get(), paint);
-}
-
-void SkiaCanvasProxy::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
- const SkMatrix* matrix, const SkPaint& origPaint) {
- SkDEBUGFAIL("SkiaCanvasProxy::onDrawTextOnPath is not supported");
-}
-
-void SkiaCanvasProxy::onDrawTextRSXform(const void* text, size_t byteLength,
- const SkRSXform xform[], const SkRect* cullRect,
- const SkPaint& paint) {
- GlyphIDConverter glyphs(text, byteLength, paint); // Just get count
- SkMatrix localM, currM, origM;
- mCanvas->getMatrix(&currM);
- origM = currM;
- for (int i = 0; i < glyphs.count; i++) {
- localM.setRSXform(*xform++);
- currM.setConcat(origM, localM);
- mCanvas->setMatrix(currM);
- this->onDrawText((char*)text + (byteLength / glyphs.count * i), byteLength / glyphs.count,
- 0, 0, paint);
- }
- mCanvas->setMatrix(origM);
-}
-
-void SkiaCanvasProxy::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
- const SkPaint& paint) {
- SkPaint runPaint = paint;
-
- SkTextBlobRunIterator it(blob);
- for (; !it.done(); it.next()) {
- size_t textLen = it.glyphCount() * sizeof(uint16_t);
- const SkPoint& offset = it.offset();
- // applyFontToPaint() always overwrites the exact same attributes,
- // so it is safe to not re-seed the paint for this reason.
- it.applyFontToPaint(&runPaint);
-
- switch (it.positioning()) {
- case SkTextBlob::kDefault_Positioning:
- this->drawText(it.glyphs(), textLen, x + offset.x(), y + offset.y(), runPaint);
- break;
- case SkTextBlob::kHorizontal_Positioning: {
- std::unique_ptr<SkPoint[]> pts(new SkPoint[it.glyphCount()]);
- for (size_t i = 0; i < it.glyphCount(); i++) {
- pts[i].set(x + offset.x() + it.pos()[i], y + offset.y());
- }
- this->drawPosText(it.glyphs(), textLen, pts.get(), runPaint);
- break;
- }
- case SkTextBlob::kFull_Positioning: {
- std::unique_ptr<SkPoint[]> pts(new SkPoint[it.glyphCount()]);
- for (size_t i = 0; i < it.glyphCount(); i++) {
- const size_t xIndex = i * 2;
- const size_t yIndex = xIndex + 1;
- pts[i].set(x + offset.x() + it.pos()[xIndex],
- y + offset.y() + it.pos()[yIndex]);
- }
- this->drawPosText(it.glyphs(), textLen, pts.get(), runPaint);
- break;
- }
- default:
- SK_ABORT("unhandled positioning mode");
- }
- }
-}
-
-void SkiaCanvasProxy::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
- const SkPoint texCoords[4], SkBlendMode bmode,
- const SkPaint& paint) {
- if (mFilterHwuiCalls) {
- return;
- }
- SkMatrix matrix;
- mCanvas->getMatrix(&matrix);
- SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, &matrix);
-
- mCanvas->drawVertices(
- SkPatchUtils::MakeVertices(cubics, colors, texCoords, lod.width(), lod.height()).get(),
- bmode, paint);
-}
-
-void SkiaCanvasProxy::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle) {
- mCanvas->clipRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, op);
-}
-
-void SkiaCanvasProxy::onClipRRect(const SkRRect& roundRect, SkClipOp op, ClipEdgeStyle) {
- SkPath path;
- path.addRRect(roundRect);
- mCanvas->clipPath(&path, op);
-}
-
-void SkiaCanvasProxy::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle) {
- mCanvas->clipPath(&path, op);
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
deleted file mode 100644
index 360d5a0..0000000
--- a/libs/hwui/SkiaCanvasProxy.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#ifndef SkiaCanvasProxy_DEFINED
-#define SkiaCanvasProxy_DEFINED
-
-#include <SkCanvas.h>
-#include <cutils/compiler.h>
-
-#include "hwui/Canvas.h"
-
-namespace android {
-namespace uirenderer {
-
-/**
- * This class serves as a proxy between Skia's SkCanvas and Android Framework's
- * Canvas. The class does not maintain any draw-related state and will pass
- * through most requests directly to the Canvas provided in the constructor.
- *
- * Upon construction it is expected that the provided Canvas has already been
- * prepared for recording and will continue to be in the recording state while
- * this proxy class is being used.
- *
- * If filterHwuiCalls is true, the proxy silently ignores away draw calls that
- * aren't supported by HWUI.
- */
-class ANDROID_API SkiaCanvasProxy : public SkCanvas {
-public:
- explicit SkiaCanvasProxy(Canvas* canvas, bool filterHwuiCalls = false);
- virtual ~SkiaCanvasProxy() {}
-
-protected:
- virtual sk_sp<SkSurface> onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override;
-
- virtual void willSave() override;
- virtual SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
- virtual void willRestore() override;
-
- virtual void didConcat(const SkMatrix&) override;
- virtual void didSetMatrix(const SkMatrix&) override;
-
- virtual void onDrawPaint(const SkPaint& paint) override;
- virtual void onDrawPoints(PointMode, size_t count, const SkPoint pts[],
- const SkPaint&) override;
- virtual void onDrawOval(const SkRect&, const SkPaint&) override;
- virtual void onDrawRect(const SkRect&, const SkPaint&) override;
- virtual void onDrawRRect(const SkRRect&, const SkPaint&) override;
- virtual void onDrawPath(const SkPath& path, const SkPaint&) override;
- virtual void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
- const SkPaint&) override;
- virtual void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
- const SkPaint*) override;
- virtual void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst,
- const SkPaint* paint, SrcRectConstraint) override;
- virtual void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
- const SkPaint*) override;
- virtual void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*);
- virtual void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*,
- SrcRectConstraint);
- virtual void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
- const SkPaint*);
- virtual void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
- const SkPaint*);
- virtual void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
-
- virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
-
- virtual void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
- const SkPaint&) override;
- virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
- const SkPaint&) override;
- virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
- SkScalar constY, const SkPaint&) override;
- virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
- const SkMatrix* matrix, const SkPaint&) override;
- virtual void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform[],
- const SkRect* cullRect, const SkPaint& paint);
- virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
- const SkPaint& paint) override;
-
- virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
- const SkPoint texCoords[4], SkBlendMode,
- const SkPaint& paint) override;
-
- virtual void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
- virtual void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
- virtual void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override;
-
-private:
- Canvas* mCanvas;
- bool mFilterHwuiCalls;
-
- typedef SkCanvas INHERITED;
-};
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // SkiaCanvasProxy_DEFINED
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 402fbad..9f82d0f 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -474,14 +474,13 @@
// Update the given paint with alpha and color filter. Return nullptr if no color filter is
// specified and root alpha is 1. Otherwise, return updated paint.
SkPaint* Tree::updatePaint(SkPaint* outPaint, TreeProperties* prop) {
- if (prop->getRootAlpha() == 1.0f && prop->getColorFilter() == nullptr) {
- return nullptr;
- } else {
+ // HWUI always draws VD with bilinear filtering.
+ outPaint->setFilterQuality(kLow_SkFilterQuality);
+ if (prop->getRootAlpha() < 1.0f || prop->getColorFilter() != nullptr) {
outPaint->setColorFilter(sk_ref_sp(prop->getColorFilter()));
- outPaint->setFilterQuality(kLow_SkFilterQuality);
outPaint->setAlpha(prop->getRootAlpha() * 255);
- return outPaint;
}
+ return outPaint;
}
Bitmap& Tree::getBitmapUpdateIfDirty() {
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp
index 007961a..8d4e7e0 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.cpp
+++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp
@@ -21,7 +21,8 @@
#include <SkPicture.h>
#include <SkRefCnt.h>
-#include <SkTLazy.h>
+
+#include <optional>
namespace android {
@@ -126,13 +127,13 @@
// Only called on the RenderThread.
void AnimatedImageDrawable::onDraw(SkCanvas* canvas) {
- SkTLazy<SkPaint> lazyPaint;
+ std::optional<SkPaint> lazyPaint;
SkAutoCanvasRestore acr(canvas, false);
if (mProperties.mAlpha != SK_AlphaOPAQUE || mProperties.mColorFilter.get()) {
- lazyPaint.init();
- lazyPaint.get()->setAlpha(mProperties.mAlpha);
- lazyPaint.get()->setColorFilter(mProperties.mColorFilter);
- lazyPaint.get()->setFilterQuality(kLow_SkFilterQuality);
+ lazyPaint.emplace();
+ lazyPaint->setAlpha(mProperties.mAlpha);
+ lazyPaint->setColorFilter(mProperties.mColorFilter);
+ lazyPaint->setFilterQuality(kLow_SkFilterQuality);
}
if (mProperties.mMirrored) {
canvas->save();
@@ -147,8 +148,8 @@
if (drawDirectly) {
// The image is not animating, and never was. Draw directly from
// mSkAnimatedImage.
- if (lazyPaint.isValid()) {
- canvas->saveLayer(mSkAnimatedImage->getBounds(), lazyPaint.get());
+ if (lazyPaint) {
+ canvas->saveLayer(mSkAnimatedImage->getBounds(), &*lazyPaint);
}
std::unique_lock lock{mImageLock};
@@ -193,7 +194,7 @@
if (!drawDirectly) {
// No other thread will modify mCurrentSnap so this should be safe to
// use without locking.
- canvas->drawPicture(mSnapshot.mPic, nullptr, lazyPaint.getMaybeNull());
+ canvas->drawPicture(mSnapshot.mPic, nullptr, lazyPaint ? &*lazyPaint : nullptr);
}
if (finalFrame) {
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index a401b3f..7a8d026 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 <SkToSRGBColorFilter.h>
#include <limits>
+#include <SkHighContrastFilter.h>
namespace android {
@@ -195,11 +197,13 @@
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 @@
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 dbd4456..d268042 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -34,6 +34,12 @@
Hardware,
};
+enum class BitmapPalette {
+ Unknown,
+ Light,
+ Dark,
+};
+
namespace uirenderer {
namespace renderthread {
class RenderThread;
@@ -63,7 +69,7 @@
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 @@
*/
sk_sp<SkImage> makeImage(sk_sp<SkColorFilter>* 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 @@
const PixelStorageType mPixelStorageType;
+ BitmapPalette mPalette = BitmapPalette::Unknown;
+ uint32_t mPaletteGenerationId = -1;
+
bool mHasHardwareMipMap = false;
union {
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 5d380a6..b9af7de2 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -74,7 +74,6 @@
} // namespace SaveFlags
namespace uirenderer {
-class SkiaCanvasProxy;
namespace VectorDrawable {
class Tree;
};
@@ -305,7 +304,6 @@
friend class DrawTextFunctor;
friend class DrawTextOnPathFunctor;
- friend class uirenderer::SkiaCanvasProxy;
};
}; // namespace android
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 85fdc103..ea14d11 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -21,6 +21,8 @@
#include "SkiaPipeline.h"
#include "utils/TraceUtils.h"
+#include <optional>
+
namespace android {
namespace uirenderer {
namespace skiapipeline {
@@ -171,9 +173,9 @@
protected:
bool onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type t) const override {
- SkTLazy<SkPaint> defaultPaint;
+ std::optional<SkPaint> defaultPaint;
if (!*paint) {
- paint->init(*defaultPaint.init());
+ paint->init(defaultPaint.emplace());
}
paint->writable()->setAlpha((uint8_t)(*paint)->getAlpha() * mAlpha);
return true;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 46e39aa..b9748af 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -257,9 +257,8 @@
SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
PaintCoW filteredPaint(paint);
- // Besides kNone, the other three SkFilterQualities are treated the same. And Android's
- // Java API only supports kLow and kNone anyway.
- if (!filteredPaint || filteredPaint->getFilterQuality() == kNone_SkFilterQuality) {
+ // HWUI always draws 9-patches with bilinear filtering, regardless of what is set in the Paint.
+ if (!filteredPaint || filteredPaint->getFilterQuality() != kLow_SkFilterQuality) {
filteredPaint.writeable().setFilterQuality(kLow_SkFilterQuality);
}
sk_sp<SkColorFilter> colorFilter;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 6eca8d2..e3807e6 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -85,6 +85,11 @@
[ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); });
}
+void RenderProxy::allocateBuffers(const sp<Surface>& surface) {
+ mRenderThread.queue().post(
+ [ surf = surface ]() mutable { surf->allocateBuffers(); });
+}
+
void RenderProxy::updateSurface(const sp<Surface>& surface) {
mRenderThread.queue().post(
[ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); });
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 5668484..c2964a4 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -70,6 +70,7 @@
ANDROID_API void setName(const char* name);
ANDROID_API void initialize(const sp<Surface>& surface);
+ ANDROID_API void allocateBuffers(const sp<Surface>& surface);
ANDROID_API void updateSurface(const sp<Surface>& surface);
ANDROID_API bool pauseSurface(const sp<Surface>& surface);
ANDROID_API void setStopped(bool stopped);
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 3eaf43b..c1284ec 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -189,6 +189,7 @@
LOG_ALWAYS_FATAL_IF(!glInterface.get());
GrContextOptions options;
+ options.fPreferExternalImagesOverES3 = true;
options.fDisableDistanceFieldPaths = true;
cacheManager().configureContext(&options);
sk_sp<GrContext> grContext(GrContext::MakeGL(std::move(glInterface), options));
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index a19edae..1517f57 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -25,6 +25,8 @@
#include <GrBackendSurface.h>
#include <GrContext.h>
#include <GrTypes.h>
+#include <GrTypes.h>
+#include <vk/GrVkExtensions.h>
#include <vk/GrVkTypes.h>
namespace android {
@@ -62,7 +64,7 @@
mInstance = VK_NULL_HANDLE;
}
-bool VulkanManager::setupDevice(VkPhysicalDeviceFeatures& deviceFeatures) {
+bool VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFeatures2& features) {
VkResult err;
constexpr VkApplicationInfo app_info = {
@@ -128,7 +130,7 @@
GET_INST_PROC(DestroyInstance);
GET_INST_PROC(EnumeratePhysicalDevices);
GET_INST_PROC(GetPhysicalDeviceQueueFamilyProperties);
- GET_INST_PROC(GetPhysicalDeviceFeatures);
+ GET_INST_PROC(GetPhysicalDeviceFeatures2);
GET_INST_PROC(CreateDevice);
GET_INST_PROC(EnumerateDeviceExtensionProperties);
GET_INST_PROC(CreateAndroidSurfaceKHR);
@@ -217,11 +219,38 @@
}
}
- // query to get the physical device properties
- mGetPhysicalDeviceFeatures(mPhysicalDevice, &deviceFeatures);
+ auto getProc = [] (const char* proc_name, VkInstance instance, VkDevice device) {
+ if (device != VK_NULL_HANDLE) {
+ return vkGetDeviceProcAddr(device, proc_name);
+ }
+ return vkGetInstanceProcAddr(instance, proc_name);
+ };
+ grExtensions.init(getProc, mInstance, mPhysicalDevice, instanceExtensions.size(),
+ instanceExtensions.data(), deviceExtensions.size(), deviceExtensions.data());
+
+ memset(&features, 0, sizeof(VkPhysicalDeviceFeatures2));
+ features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ features.pNext = nullptr;
+
+ // Setup all extension feature structs we may want to use.
+ void** tailPNext = &features.pNext;
+
+ if (grExtensions.hasExtension(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, 2)) {
+ VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT* blend;
+ blend = (VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT*) malloc(
+ sizeof(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT));
+ LOG_ALWAYS_FATAL_IF(!blend);
+ blend->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT;
+ blend->pNext = nullptr;
+ *tailPNext = blend;
+ tailPNext = &blend->pNext;
+ }
+
+ // query to get the physical device features
+ mGetPhysicalDeviceFeatures2(mPhysicalDevice, &features);
// this looks like it would slow things down,
// and we can't depend on it on all platforms
- deviceFeatures.robustBufferAccess = VK_FALSE;
+ features.features.robustBufferAccess = VK_FALSE;
float queuePriorities[1] = { 0.0 };
@@ -247,7 +276,7 @@
const VkDeviceCreateInfo deviceInfo = {
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
- nullptr, // pNext
+ &features, // pNext
0, // VkDeviceCreateFlags
queueInfoCount, // queueCreateInfoCount
queueInfo, // pQueueCreateInfos
@@ -255,7 +284,7 @@
nullptr, // ppEnabledLayerNames
(uint32_t) deviceExtensions.size(), // extensionCount
deviceExtensions.data(), // ppEnabledExtensionNames
- &deviceFeatures // ppEnabledFeatures
+ nullptr, // ppEnabledFeatures
};
err = mCreateDevice(mPhysicalDevice, &deviceInfo, nullptr, &mDevice);
@@ -294,33 +323,39 @@
return true;
}
+static void free_features_extensions_structs(const VkPhysicalDeviceFeatures2& features) {
+ // All Vulkan structs that could be part of the features chain will start with the
+ // structure type followed by the pNext pointer. We cast to the CommonVulkanHeader
+ // so we can get access to the pNext for the next struct.
+ struct CommonVulkanHeader {
+ VkStructureType sType;
+ void* pNext;
+ };
+
+ void* pNext = features.pNext;
+ while (pNext) {
+ void* current = pNext;
+ pNext = static_cast<CommonVulkanHeader*>(current)->pNext;
+ free(current);
+ }
+}
+
void VulkanManager::initialize() {
if (mDevice != VK_NULL_HANDLE) {
return;
}
- std::vector<const char*> instanceExtensions;
- std::vector<const char*> deviceExtensions;
- VkPhysicalDeviceFeatures deviceFeatures;
- LOG_ALWAYS_FATAL_IF(!this->setupDevice(deviceFeatures));
+ GET_PROC(EnumerateInstanceVersion);
+ uint32_t instanceVersion = 0;
+ LOG_ALWAYS_FATAL_IF(mEnumerateInstanceVersion(&instanceVersion));
+ LOG_ALWAYS_FATAL_IF(instanceVersion < VK_MAKE_VERSION(1, 1, 0));
+
+ GrVkExtensions extensions;
+ VkPhysicalDeviceFeatures2 features;
+ LOG_ALWAYS_FATAL_IF(!this->setupDevice(extensions, features));
mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
- uint32_t extensionFlags = kKHR_surface_GrVkExtensionFlag |
- kKHR_android_surface_GrVkExtensionFlag |
- kKHR_swapchain_GrVkExtensionFlag;
-
- uint32_t featureFlags = 0;
- if (deviceFeatures.geometryShader) {
- featureFlags |= kGeometryShader_GrVkFeatureFlag;
- }
- if (deviceFeatures.dualSrcBlend) {
- featureFlags |= kDualSrcBlend_GrVkFeatureFlag;
- }
- if (deviceFeatures.sampleRateShading) {
- featureFlags |= kSampleRateShading_GrVkFeatureFlag;
- }
-
auto getProc = [] (const char* proc_name, VkInstance instance, VkDevice device) {
if (device != VK_NULL_HANDLE) {
return vkGetDeviceProcAddr(device, proc_name);
@@ -334,11 +369,10 @@
backendContext.fDevice = mDevice;
backendContext.fQueue = mGraphicsQueue;
backendContext.fGraphicsQueueIndex = mGraphicsQueueIndex;
- backendContext.fMinAPIVersion = VK_MAKE_VERSION(1, 0, 0);
- backendContext.fExtensions = extensionFlags;
- backendContext.fFeatures = featureFlags;
+ backendContext.fInstanceVersion = instanceVersion;
+ backendContext.fVkExtensions = &extensions;
+ backendContext.fDeviceFeatures2 = &features;
backendContext.fGetProc = std::move(getProc);
- backendContext.fOwnsInstanceAndDevice = false;
// create the command pool for the command buffers
if (VK_NULL_HANDLE == mCommandPool) {
@@ -361,6 +395,9 @@
sk_sp<GrContext> grContext(GrContext::MakeVulkan(backendContext, options));
LOG_ALWAYS_FATAL_IF(!grContext.get());
mRenderThread.setGrContext(grContext);
+
+ free_features_extensions_structs(features);
+
DeviceInfo::initialize(mRenderThread.getGrContext()->maxRenderTargetSize());
if (Properties::enablePartialUpdates && Properties::useBufferAge) {
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 9a72706..5524c39 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -17,10 +17,15 @@
#ifndef VULKANMANAGER_H
#define VULKANMANAGER_H
+#if !defined(VK_USE_PLATFORM_ANDROID_KHR)
+# define VK_USE_PLATFORM_ANDROID_KHR
+#endif
+#include <vulkan/vulkan.h>
+
#include <SkSurface.h>
#include <vk/GrVkBackendContext.h>
-#include <vulkan/vulkan.h>
+class GrVkExtensions;
namespace android {
namespace uirenderer {
@@ -113,7 +118,7 @@
// Sets up the VkInstance and VkDevice objects. Also fills out the passed in
// VkPhysicalDeviceFeatures struct.
- bool setupDevice(VkPhysicalDeviceFeatures& deviceFeatures);
+ bool setupDevice(GrVkExtensions&, VkPhysicalDeviceFeatures2&);
void destroyBuffers(VulkanSurface* surface);
@@ -153,13 +158,14 @@
VkPtr<PFN_vkCreateSharedSwapchainsKHR> mCreateSharedSwapchainsKHR;
// Instance Functions
+ VkPtr<PFN_vkEnumerateInstanceVersion> mEnumerateInstanceVersion;
VkPtr<PFN_vkEnumerateInstanceExtensionProperties> mEnumerateInstanceExtensionProperties;
VkPtr<PFN_vkCreateInstance> mCreateInstance;
VkPtr<PFN_vkDestroyInstance> mDestroyInstance;
VkPtr<PFN_vkEnumeratePhysicalDevices> mEnumeratePhysicalDevices;
VkPtr<PFN_vkGetPhysicalDeviceQueueFamilyProperties> mGetPhysicalDeviceQueueFamilyProperties;
- VkPtr<PFN_vkGetPhysicalDeviceFeatures> mGetPhysicalDeviceFeatures;
+ VkPtr<PFN_vkGetPhysicalDeviceFeatures2> mGetPhysicalDeviceFeatures2;
VkPtr<PFN_vkCreateDevice> mCreateDevice;
VkPtr<PFN_vkEnumerateDeviceExtensionProperties> mEnumerateDeviceExtensionProperties;
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index 75740e8..a3e7859 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -16,8 +16,10 @@
#include "Color.h"
-
#include <utils/Log.h>
+#include <ui/ColorSpace.h>
+
+#include <algorithm>
#include <cmath>
namespace android {
@@ -107,5 +109,97 @@
}
}
+template<typename T>
+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<uint8_t>(rgb.r * 255),
+ static_cast<uint8_t>(rgb.g * 255),
+ static_cast<uint8_t>(rgb.b * 255));
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 2bec1f5..3c13a54 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -114,6 +114,16 @@
bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
sk_sp<SkColorSpace> 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 */