Enable colorspace conversion while perserving legacy blending.
When requesting an SkImage from a android::Bitmap we will also
return a colorFilter that will perform the sRGB conversion at draw
time.
Bug: 62347704
Test: CtsUiRenderingTestCases, CtsGraphicsTestCases, CtsViewTestCases
Change-Id: Icc4694e2c42605e29fcc834c252bc21263bac658
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index c19c1a1..8727a1d 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -296,6 +296,7 @@
colorVector[2] = EOCF(srcColorMatrix[14] / 255.0f);
colorVector[3] = srcColorMatrix[19] / 255.0f; // alpha is linear
} else {
+ ALOGE("unsupported ColorFilter type: %s", colorFilter->getTypeName());
LOG_ALWAYS_FATAL("unsupported ColorFilter");
}
} else {
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 0a642b6..9683d06 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -24,6 +24,8 @@
#include "pipeline/skia/AnimatedDrawables.h"
#include <SkCanvasStateUtils.h>
+#include <SkColorFilter.h>
+// TODO remove me!
#include <SkColorSpaceXformCanvas.h>
#include <SkDrawable.h>
#include <SkDeque.h>
@@ -529,25 +531,49 @@
// Canvas draw operations: Bitmaps
// ----------------------------------------------------------------------------
-void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
- mCanvas->drawImage(bitmap.makeImage(), left, top, paint);
+inline static const SkPaint* addFilter(const SkPaint* origPaint, SkPaint* tmpPaint,
+ sk_sp<SkColorFilter> colorFilter) {
+ if (colorFilter) {
+ if (origPaint) {
+ *tmpPaint = *origPaint;
+ }
+ tmpPaint->setColorFilter(colorFilter);
+ return tmpPaint;
+ } else {
+ return origPaint;
+ }
}
-void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix, const SkPaint* paint) {
+void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
+ SkPaint tmpPaint;
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ mCanvas->drawImage(image, left, top, addFilter(paint, &tmpPaint, colorFilter));
+}
+
+void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
SkAutoCanvasRestore acr(mCanvas, true);
mCanvas->concat(matrix);
- mCanvas->drawImage(hwuiBitmap.makeImage(), 0, 0, paint);
+
+ SkPaint tmpPaint;
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ mCanvas->drawImage(image, 0, 0, addFilter(paint, &tmpPaint, colorFilter));
}
-void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop,
+void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop,
float dstRight, float dstBottom, const SkPaint* paint) {
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- mCanvas->drawImageRect(hwuiBitmap.makeImage(), srcRect, dstRect, paint);
+
+ SkPaint tmpPaint;
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ mCanvas->drawImageRect(image, srcRect, dstRect, addFilter(paint, &tmpPaint, colorFilter));
}
-void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeight,
+void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) {
const int ptCount = (meshWidth + 1) * (meshHeight + 1);
const int indexCount = meshWidth * meshHeight * 6;
@@ -565,8 +591,8 @@
// cons up texture coordinates and indices
{
- const SkScalar w = SkIntToScalar(hwuiBitmap.width());
- const SkScalar h = SkIntToScalar(hwuiBitmap.height());
+ const SkScalar w = SkIntToScalar(bitmap.width());
+ const SkScalar h = SkIntToScalar(bitmap.height());
const SkScalar dx = w / meshWidth;
const SkScalar dy = h / meshHeight;
@@ -627,17 +653,22 @@
tmpPaint = *paint;
}
- sk_sp<SkImage> image = hwuiBitmap.makeImage();
- tmpPaint.setShader(image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode));
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ sk_sp<SkShader> shader = image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ if(colorFilter) {
+ shader = shader->makeWithColorFilter(colorFilter);
+ }
+ tmpPaint.setShader(shader);
mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate, tmpPaint);
}
-void SkiaCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,
+void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk,
float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
SkCanvas::Lattice lattice;
- NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height());
+ NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
lattice.fFlags = nullptr;
int numFlags = 0;
@@ -654,7 +685,11 @@
lattice.fBounds = nullptr;
SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- mCanvas->drawImageLattice(hwuiBitmap.makeImage().get(), lattice, dst, paint);
+
+ SkPaint tmpPaint;
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ mCanvas->drawImageLattice(image.get(), lattice, dst, addFilter(paint, &tmpPaint, colorFilter));
}
void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 75b6d23..0aeb762 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -31,6 +31,7 @@
#include <ui/PixelFormat.h>
#include <SkCanvas.h>
+#include <SkToSRGBColorFilter.h>
#include <SkImagePriv.h>
namespace android {
@@ -208,11 +209,8 @@
buffer->incStrong(buffer);
setImmutable(); // HW bitmaps are always immutable
if (uirenderer::Properties::isSkiaEnabled()) {
- // GraphicBuffer should be in the display color space (Bitmap::createFrom is always
- // passing SRGB). The code that uploads into a GraphicBuffer should do color conversion if
- // needed.
mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast<AHardwareBuffer*>(buffer),
- mInfo.alphaType(), nullptr);
+ mInfo.alphaType(), mInfo.refColorSpace());
}
}
@@ -319,7 +317,7 @@
return nullptr;
}
-sk_sp<SkImage> Bitmap::makeImage() {
+sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) {
sk_sp<SkImage> image = mImage;
if (!image) {
SkASSERT(!(isHardware() && uirenderer::Properties::isSkiaEnabled()));
@@ -330,12 +328,11 @@
// Note we don't cache in this case, because the raster image holds a pointer to this Bitmap
// internally and ~Bitmap won't be invoked.
// TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
- if (uirenderer::Properties::isSkiaEnabled()) {
- image = SkMakeImageInColorSpace(skiaBitmap, SkColorSpace::MakeSRGB(),
- skiaBitmap.getGenerationID(), kNever_SkCopyPixelsMode);
- } else {
- image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
- }
+ image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
+ }
+ if(uirenderer::Properties::isSkiaEnabled() && image->colorSpace() != nullptr
+ && !image->colorSpace()->isSRGB()) {
+ *outputColorFilter = SkToSRGBColorFilter::Make(image->refColorSpace());
}
return image;
}
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 634e764..fc27af9f 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -16,6 +16,7 @@
#pragma once
#include <SkBitmap.h>
+#include <SkColorFilter.h>
#include <SkColorSpace.h>
#include <SkImage.h>
#include <SkImageInfo.h>
@@ -96,9 +97,18 @@
GraphicBuffer* graphicBuffer();
- // makeImage creates or returns a cached SkImage. Can be invoked from UI or render thread.
- // Caching is supported only for HW Bitmaps with skia pipeline.
- sk_sp<SkImage> makeImage();
+ /**
+ * Creates or returns a cached SkImage and is safe to be invoked from either
+ * the UI or RenderThread.
+ *
+ * @param outputColorFilter is a required param that will be populated by
+ * this function if the bitmap's colorspace is not sRGB. If populated the
+ * filter will convert colors from the bitmaps colorspace into sRGB. It
+ * is the callers responsibility to use this colorFilter when drawing
+ * this image into any destination that is presumed to be sRGB (i.e. a
+ * buffer that has no colorspace defined).
+ */
+ sk_sp<SkImage> makeImage(sk_sp<SkColorFilter>* outputColorFilter);
private:
virtual ~Bitmap();
void* getStorage() const;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index bf77446..5f8ee18 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -305,12 +305,6 @@
return nullptr;
}
- auto colorSpace = info.colorSpace();
- bool convertToSRGB = false;
- if (colorSpace && (!colorSpace->isSRGB())) {
- isSupported = false;
- convertToSRGB = true;
- }
SkBitmap bitmap;
if (isSupported) {
@@ -319,7 +313,7 @@
bitmap.allocPixels(SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(),
nullptr));
bitmap.eraseColor(0);
- if (info.colorType() == kRGBA_F16_SkColorType || convertToSRGB) {
+ if (info.colorType() == kRGBA_F16_SkColorType) {
// Drawing RGBA_F16 onto ARGB_8888 is not supported
skBitmap.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index d08a62c..a8463ec 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -167,7 +167,8 @@
GrContext* context = thread.getGrContext();
if (context) {
ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height());
- auto image = bitmap->makeImage();
+ sk_sp<SkColorFilter> colorFilter;
+ auto image = bitmap->makeImage(&colorFilter);
if (image.get() && !bitmap->isHardware()) {
SkImage_pinAsTexture(image.get(), context);
SkImage_unpinAsTexture(image.get(), context);
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index a0cce98..6c88e93 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -145,10 +145,14 @@
// Recording Canvas draw operations: Bitmaps
// ----------------------------------------------------------------------------
-inline static const SkPaint* nonAAPaint(const SkPaint* origPaint, SkPaint* tmpPaint) {
- if (origPaint && origPaint->isAntiAlias()) {
- *tmpPaint = *origPaint;
+inline static const SkPaint* bitmapPaint(const SkPaint* origPaint, SkPaint* tmpPaint,
+ sk_sp<SkColorFilter> colorFilter) {
+ if ((origPaint && origPaint->isAntiAlias()) || colorFilter) {
+ if (origPaint) {
+ *tmpPaint = *origPaint;
+ }
tmpPaint->setAntiAlias(false);
+ tmpPaint->setColorFilter(colorFilter);
return tmpPaint;
} else {
return origPaint;
@@ -156,9 +160,10 @@
}
void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
- sk_sp<SkImage> image = bitmap.makeImage();
SkPaint tmpPaint;
- mRecorder.drawImage(image, left, top, nonAAPaint(paint, &tmpPaint));
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ mRecorder.drawImage(image, left, top, bitmapPaint(paint, &tmpPaint, colorFilter));
// if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means
// it is not safe to store a raw SkImage pointer, because the image object will be destroyed
// when this function ends.
@@ -167,36 +172,40 @@
}
}
-void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix,
+void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix,
const SkPaint* paint) {
SkAutoCanvasRestore acr(&mRecorder, true);
concat(matrix);
- sk_sp<SkImage> image = hwuiBitmap.makeImage();
+
SkPaint tmpPaint;
- mRecorder.drawImage(image, 0, 0, nonAAPaint(paint, &tmpPaint));
- if (!hwuiBitmap.isImmutable() && image.get() && !image->unique()) {
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ mRecorder.drawImage(image, 0, 0, bitmapPaint(paint, &tmpPaint, colorFilter));
+ if (!bitmap.isImmutable() && image.get() && !image->unique()) {
mDisplayList->mMutableImages.push_back(image.get());
}
}
-void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop,
+void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight,
float dstBottom, const SkPaint* paint) {
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- sk_sp<SkImage> image = hwuiBitmap.makeImage();
+
SkPaint tmpPaint;
- mRecorder.drawImageRect(image, srcRect, dstRect, nonAAPaint(paint, &tmpPaint));
- if (!hwuiBitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty()
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ mRecorder.drawImageRect(image, srcRect, dstRect, bitmapPaint(paint, &tmpPaint, colorFilter));
+ if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty()
&& !dstRect.isEmpty()) {
mDisplayList->mMutableImages.push_back(image.get());
}
}
-void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,
+void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk,
float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
SkCanvas::Lattice lattice;
- NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height());
+ NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
lattice.fFlags = nullptr;
int numFlags = 0;
@@ -213,11 +222,13 @@
lattice.fBounds = nullptr;
SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- sk_sp<SkImage> image = hwuiBitmap.makeImage();
SkPaint tmpPaint;
- mRecorder.drawImageLattice(image.get(), lattice, dst, nonAAPaint(paint, &tmpPaint));
- if (!hwuiBitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ mRecorder.drawImageLattice(image.get(), lattice, dst,
+ bitmapPaint(paint, &tmpPaint, colorFilter));
+ if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
mDisplayList->mMutableImages.push_back(image.get());
}
}
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index 4797dec..0f2dc03 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -46,7 +46,8 @@
});
SkPaint paint;
- sk_sp<SkImage> image = hwuiBitmap->makeImage();
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = hwuiBitmap->makeImage(&colorFilter);
sk_sp<SkShader> repeatShader = image->makeShader(
SkShader::TileMode::kRepeat_TileMode,
SkShader::TileMode::kRepeat_TileMode,
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
index c246eba..960b053 100644
--- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -75,7 +75,8 @@
void doFrame(int frameNr) override { }
sk_sp<SkShader> createBitmapShader(Bitmap& bitmap) {
- sk_sp<SkImage> image = bitmap.makeImage();
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
return image->makeShader(SkShader::TileMode::kClamp_TileMode,
SkShader::TileMode::kClamp_TileMode);
}