diff options
author | 2018-10-19 15:55:33 -0400 | |
---|---|---|
committer | 2018-11-07 20:56:28 +0000 | |
commit | d01b5916d8b512ee4df8d749022c10419b58b4b2 (patch) | |
tree | 734292de80f5033a1cc32cede1d916d5806b8482 /libs/hwui | |
parent | fe878c454ad92f98db770eb51a55ac14ca7fcd08 (diff) |
Set the color space to sRGB on the Surface and remove colorFilter.
Also for a canvas wrapping a bitmap the colorspace of the bitmap
will be used to correctly blend content.
Test: CtsUiRenderingTestCases
Bug: 111436479
Change-Id: I63ad7a30605a7f725cc0ef4716d42ea978fb03e3
Diffstat (limited to 'libs/hwui')
24 files changed, 91 insertions, 299 deletions
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index b772e5b87f2a..3bee3018d36e 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -85,19 +85,18 @@ void DeferredLayerUpdater::apply() { mUpdateTexImage = false; sk_sp<SkImage> layerImage; SkMatrix textureTransform; - android_dataspace dataSpace; bool queueEmpty = true; // If the SurfaceTexture queue is in synchronous mode, need to discard all // but latest frame. Since we can't tell which mode it is in, // do this unconditionally. do { - layerImage = mSurfaceTexture->dequeueImage(textureTransform, dataSpace, &queueEmpty, + layerImage = mSurfaceTexture->dequeueImage(textureTransform, &queueEmpty, mRenderState); } while (layerImage.get() && (!queueEmpty)); if (layerImage.get()) { // force filtration if buffer size != layer size bool forceFilter = mWidth != layerImage->width() || mHeight != layerImage->height(); - updateLayer(forceFilter, textureTransform, dataSpace, layerImage); + updateLayer(forceFilter, textureTransform, layerImage); } } @@ -109,12 +108,11 @@ void DeferredLayerUpdater::apply() { } void DeferredLayerUpdater::updateLayer(bool forceFilter, const SkMatrix& textureTransform, - android_dataspace dataspace, const sk_sp<SkImage>& layerImage) { + const sk_sp<SkImage>& layerImage) { mLayer->setBlend(mBlend); mLayer->setForceFilter(forceFilter); mLayer->setSize(mWidth, mHeight); mLayer->getTexTransform() = textureTransform; - mLayer->setDataSpace(dataspace); mLayer->setImage(layerImage); } diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index b2c5131dd613..a91c111933c4 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -95,7 +95,7 @@ public: void detachSurfaceTexture(); void updateLayer(bool forceFilter, const SkMatrix& textureTransform, - android_dataspace dataspace, const sk_sp<SkImage>& layerImage); + const sk_sp<SkImage>& layerImage); void destroyLayer(); diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 32aaa54e696c..d0df200d2fa6 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -33,7 +33,6 @@ Layer::Layer(RenderState& renderState, sk_sp<SkColorFilter> colorFilter, int alp // TODO: This is a violation of Android's typical ref counting, but it // preserves the old inc/dec ref locations. This should be changed... incStrong(nullptr); - buildColorSpaceWithFilter(); renderState.registerLayer(this); texTransform.setIdentity(); transform.setIdentity(); @@ -43,36 +42,6 @@ Layer::~Layer() { mRenderState.unregisterLayer(this); } -void Layer::setColorFilter(sk_sp<SkColorFilter> filter) { - if (filter != mColorFilter) { - mColorFilter = filter; - buildColorSpaceWithFilter(); - } -} - -void Layer::setDataSpace(android_dataspace dataspace) { - if (dataspace != mCurrentDataspace) { - mCurrentDataspace = dataspace; - buildColorSpaceWithFilter(); - } -} - -void Layer::buildColorSpaceWithFilter() { - sk_sp<SkColorFilter> colorSpaceFilter; - sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(mCurrentDataspace); - if (colorSpace && !colorSpace->isSRGB()) { - colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace); - } - - if (mColorFilter && colorSpaceFilter) { - mColorSpaceWithFilter = mColorFilter->makeComposed(colorSpaceFilter); - } else if (colorSpaceFilter) { - mColorSpaceWithFilter = colorSpaceFilter; - } else { - mColorSpaceWithFilter = mColorFilter; - } -} - void Layer::postDecStrong() { mRenderState.postDecStrong(this); } diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index e4f96e914c36..98600dbf1eea 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -69,15 +69,9 @@ public: SkBlendMode getMode() const; - inline SkColorFilter* getColorFilter() const { return mColorFilter.get(); } + inline sk_sp<SkColorFilter> getColorFilter() const { return mColorFilter; } - void setColorFilter(sk_sp<SkColorFilter> filter); - - void setDataSpace(android_dataspace dataspace); - - void setColorSpace(sk_sp<SkColorSpace> colorSpace); - - inline sk_sp<SkColorFilter> getColorSpaceWithFilter() const { return mColorSpaceWithFilter; } + void setColorFilter(sk_sp<SkColorFilter> filter) { mColorFilter = filter; }; inline SkMatrix& getTexTransform() { return texTransform; } @@ -98,24 +92,12 @@ protected: RenderState& mRenderState; private: - void buildColorSpaceWithFilter(); - /** * Color filter used to draw this layer. Optional. */ sk_sp<SkColorFilter> mColorFilter; /** - * Colorspace of the contents of the layer. Optional. - */ - android_dataspace mCurrentDataspace = HAL_DATASPACE_UNKNOWN; - - /** - * A color filter that is the combination of the mColorFilter and mColorSpace. Optional. - */ - sk_sp<SkColorFilter> mColorSpaceWithFilter; - - /** * Indicates raster data backing the layer is scaled, requiring filtration. */ bool forceFilter = false; diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp index 80f2b5714659..2a488378e3a8 100644 --- a/libs/hwui/Readback.cpp +++ b/libs/hwui/Readback.cpp @@ -66,13 +66,10 @@ CopyResult Readback::copySurfaceInto(Surface& surface, const Rect& srcRect, SkBi sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(static_cast<android_dataspace>(surface.getBuffersDataSpace())); - sk_sp<SkColorFilter> colorSpaceFilter; - if (colorSpace && !colorSpace->isSRGB()) { - colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace); - } sk_sp<SkImage> image = SkImage::MakeFromAHardwareBuffer( - reinterpret_cast<AHardwareBuffer*>(sourceBuffer.get()), kPremul_SkAlphaType); - return copyImageInto(image, colorSpaceFilter, texTransform, srcRect, bitmap); + reinterpret_cast<AHardwareBuffer*>(sourceBuffer.get()), + kPremul_SkAlphaType, colorSpace); + return copyImageInto(image, texTransform, srcRect, bitmap); } CopyResult Readback::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) { @@ -83,20 +80,7 @@ CopyResult Readback::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) { transform.loadScale(1, -1, 1); transform.translate(0, -1); - // TODO: Try to take and reuse the image inside HW bitmap with "hwBitmap->makeImage". - // TODO: When this was attempted, it resulted in instability. - sk_sp<SkColorFilter> colorSpaceFilter; - sk_sp<SkColorSpace> colorSpace = hwBitmap->info().refColorSpace(); - if (colorSpace && !colorSpace->isSRGB()) { - colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace); - } - sk_sp<SkImage> image = SkImage::MakeFromAHardwareBuffer( - reinterpret_cast<AHardwareBuffer*>(hwBitmap->graphicBuffer()), kPremul_SkAlphaType); - - // HW Bitmap currently can only attach to a GraphicBuffer with PIXEL_FORMAT_RGBA_8888 format - // and SRGB color space. ImageDecoder can create a new HW Bitmap with non-SRGB color space: for - // example see android.graphics.cts.BitmapColorSpaceTest#testEncodeP3hardware test. - return copyImageInto(image, colorSpaceFilter, transform, srcRect, bitmap); + return copyImageInto(hwBitmap->makeImage(), transform, srcRect, bitmap); } CopyResult Readback::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) { @@ -118,8 +102,7 @@ CopyResult Readback::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap return copyResult; } -CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, - sk_sp<SkColorFilter>& colorSpaceFilter, Matrix4& texTransform, +CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap) { if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { mRenderThread.requireGlContext(); @@ -157,11 +140,7 @@ CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, return copyResult; } - // See Readback::copyLayerInto for an overview of color space conversion. - // HW Bitmap are allowed to be in a non-SRGB color space (for example coming from ImageDecoder). - // For Surface and HW Bitmap readback flows we pass colorSpaceFilter, which does the conversion. - // TextureView readback is using Layer::setDataSpace, which creates a SkColorFilter internally. - Layer layer(mRenderThread.renderState(), colorSpaceFilter, 255, SkBlendMode::kSrc); + Layer layer(mRenderThread.renderState(), nullptr, 255, SkBlendMode::kSrc); bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width()) && MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height()); layer.setForceFilter(!disableFilter); @@ -177,38 +156,6 @@ CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, bool Readback::copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* dstRect, SkBitmap* bitmap) { - /* - * In the past only TextureView readback was setting the temporary surface color space to null. - * Now all 3 readback flows are drawing into a SkSurface with null color space. - * At readback there are 3 options to convert the source image color space to the destination - * color space requested in "bitmap->info().colorSpace()": - * 1. Set color space for temporary surface render target to null (disables color management), - * colorspace tag from source SkImage is ignored by Skia, - * convert SkImage to SRGB at draw time with SkColorFilter/SkToSRGBColorFilter, - * do a readback from temporary SkSurface to a temporary SRGB SkBitmap "bitmap2", - * read back from SRGB "bitmap2" into non-SRGB "bitmap" which will do a CPU color conversion. - * - * 2. Set color space for temporary surface render target to SRGB (not nullptr), - * colorspace tag on the source SkImage is used by Skia to enable conversion, - * convert SkImage to SRGB at draw time with drawImage (no filters), - * do a readback from temporary SkSurface, which will do a color conversion from SRGB to - * bitmap->info().colorSpace() on the CPU. - * - * 3. Set color space for temporary surface render target to bitmap->info().colorSpace(), - * colorspace tag on the source SkImage is used by Skia to enable conversion, - * convert SkImage to bitmap->info().colorSpace() at draw time with drawImage (no filters), - * do a readback from SkSurface, which will not do any color conversion, because - * surface was created with the same color space as the "bitmap". - * - * Option 1 is used for all readback flows. - * Options 2 and 3 are new, because skia added support for non-SRGB render targets without - * linear blending. - * TODO: evaluate if options 2 or 3 for color space conversion are better. - */ - - // drop the colorSpace from the temporary surface. - SkImageInfo surfaceInfo = bitmap->info().makeColorSpace(nullptr); - /* This intermediate surface is present to work around a bug in SwiftShader that * prevents us from reading the contents of the layer's texture directly. The * workaround involves first rendering that texture into an intermediate buffer and @@ -217,70 +164,44 @@ bool Readback::copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* * with reading incorrect data from EGLImage backed SkImage (likely a driver bug). */ sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), - SkBudgeted::kYes, surfaceInfo); + SkBudgeted::kYes, bitmap->info()); + // if we can't generate a GPU surface that matches the destination bitmap (e.g. 565) then we + // attempt to do the intermediate rendering step in 8888 if (!tmpSurface.get()) { - surfaceInfo = surfaceInfo.makeColorType(SkColorType::kN32_SkColorType); + SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType); tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes, - surfaceInfo); + tmpInfo); if (!tmpSurface.get()) { - ALOGW("Unable to readback GPU contents into the provided bitmap"); + ALOGW("Unable to generate GPU buffer in a format compatible with the provided bitmap"); return false; } } - if (skiapipeline::LayerDrawable::DrawLayer(mRenderThread.getGrContext(), - tmpSurface->getCanvas(), layer, srcRect, dstRect, - false)) { - // If bitmap->info().colorSpace() is non-SRGB, convert the data from SRGB to non-SRGB on - // CPU. We can't just pass bitmap->info() to SkSurface::readPixels, because "tmpSurface" has - // disabled color conversion. - SkColorSpace* destColorSpace = bitmap->info().colorSpace(); - SkBitmap tempSRGBBitmap; - SkBitmap tmpN32Bitmap; - SkBitmap* bitmapInSRGB; - if (destColorSpace && !destColorSpace->isSRGB()) { - tempSRGBBitmap.allocPixels(bitmap->info().makeColorSpace(SkColorSpace::MakeSRGB())); - bitmapInSRGB = &tempSRGBBitmap; // Need to convert latter from SRGB to non-SRGB. - } else { - bitmapInSRGB = bitmap; // No need for color conversion - write directly into output. - } - bool success = false; - - // TODO: does any of the readbacks below clamp F16 exSRGB? - // Readback into a SRGB SkBitmap. - if (tmpSurface->readPixels(bitmapInSRGB->info(), bitmapInSRGB->getPixels(), - bitmapInSRGB->rowBytes(), 0, 0)) { - success = true; - } else { - // if we fail to readback from the GPU directly (e.g. 565) then we attempt to read into - // 8888 and then convert that into the destination format before giving up. - SkImageInfo bitmapInfo = - SkImageInfo::MakeN32(bitmap->width(), bitmap->height(), bitmap->alphaType(), - SkColorSpace::MakeSRGB()); - if (tmpN32Bitmap.tryAllocPixels(bitmapInfo) && - tmpSurface->readPixels(bitmapInfo, tmpN32Bitmap.getPixels(), - tmpN32Bitmap.rowBytes(), 0, 0)) { - success = true; - bitmapInSRGB = &tmpN32Bitmap; - } - } - - if (success) { - if (bitmapInSRGB != bitmap) { - // Convert from SRGB to non-SRGB color space if needed. Convert from N32 to - // destination bitmap color format if needed. - if (!bitmapInSRGB->readPixels(bitmap->info(), bitmap->getPixels(), - bitmap->rowBytes(), 0, 0)) { - return false; - } - } - bitmap->notifyPixelsChanged(); - return true; + if (!skiapipeline::LayerDrawable::DrawLayer(mRenderThread.getGrContext(), + tmpSurface->getCanvas(), layer, srcRect, dstRect, + false)) { + ALOGW("Unable to draw content from GPU into the provided bitmap"); + return false; + } + + if (!tmpSurface->readPixels(*bitmap, 0, 0)) { + // if we fail to readback from the GPU directly (e.g. 565) then we attempt to read into + // 8888 and then convert that into the destination format before giving up. + SkBitmap tmpBitmap; + SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType); + if (bitmap->info().colorType() == SkColorType::kN32_SkColorType || + !tmpBitmap.tryAllocPixels(tmpInfo) || + !tmpSurface->readPixels(tmpBitmap, 0, 0) || + !tmpBitmap.readPixels(bitmap->info(), bitmap->getPixels(), + bitmap->rowBytes(), 0, 0)) { + ALOGW("Unable to convert content into the provided bitmap"); + return false; } } - return false; + bitmap->notifyPixelsChanged(); + return true; } } /* namespace uirenderer */ diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h index d9e10cedc0e8..e86a8136cfa3 100644 --- a/libs/hwui/Readback.h +++ b/libs/hwui/Readback.h @@ -54,8 +54,8 @@ public: CopyResult copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap); private: - CopyResult copyImageInto(const sk_sp<SkImage>& image, sk_sp<SkColorFilter>& colorSpaceFilter, - Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap); + CopyResult copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTransform, + const Rect& srcRect, SkBitmap* bitmap); bool copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* dstRect, SkBitmap* bitmap); diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 9c707bab95f1..154338604663 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -27,7 +27,6 @@ #include <SkAnimatedImage.h> #include <SkCanvasStateUtils.h> #include <SkColorFilter.h> -#include <SkColorSpaceXformCanvas.h> #include <SkDeque.h> #include <SkDrawable.h> #include <SkGraphics.h> @@ -60,19 +59,8 @@ SkiaCanvas::SkiaCanvas() {} SkiaCanvas::SkiaCanvas(SkCanvas* canvas) : mCanvas(canvas) {} SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) { - sk_sp<SkColorSpace> cs = bitmap.refColorSpace(); - mCanvasOwned = - std::unique_ptr<SkCanvas>(new SkCanvas(bitmap, SkCanvas::ColorBehavior::kLegacy)); - if (cs.get() == nullptr || cs->isSRGB()) { - mCanvas = mCanvasOwned.get(); - } else { - /** The wrapper is needed if we are drawing into a non-sRGB destination, since - * we need to transform all colors (not just bitmaps via filters) into the - * destination's colorspace. - */ - mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), std::move(cs)); - mCanvas = mCanvasWrapper.get(); - } + mCanvasOwned = std::unique_ptr<SkCanvas>(new SkCanvas(bitmap)); + mCanvas = mCanvasOwned.get(); } SkiaCanvas::~SkiaCanvas() {} @@ -81,7 +69,6 @@ void SkiaCanvas::reset(SkCanvas* skiaCanvas) { if (mCanvas != skiaCanvas) { mCanvas = skiaCanvas; mCanvasOwned.reset(); - mCanvasWrapper.reset(); } mSaveStack.reset(nullptr); } @@ -91,18 +78,9 @@ void SkiaCanvas::reset(SkCanvas* skiaCanvas) { // ---------------------------------------------------------------------------- void SkiaCanvas::setBitmap(const SkBitmap& bitmap) { - sk_sp<SkColorSpace> cs = bitmap.refColorSpace(); - std::unique_ptr<SkCanvas> newCanvas = - std::unique_ptr<SkCanvas>(new SkCanvas(bitmap, SkCanvas::ColorBehavior::kLegacy)); - std::unique_ptr<SkCanvas> newCanvasWrapper; - if (cs.get() != nullptr && !cs->isSRGB()) { - newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), std::move(cs)); - } - // deletes the previously owned canvas (if any) - mCanvasOwned = std::move(newCanvas); - mCanvasWrapper = std::move(newCanvasWrapper); - mCanvas = mCanvasWrapper ? mCanvasWrapper.get() : mCanvasOwned.get(); + mCanvasOwned.reset(new SkCanvas(bitmap)); + mCanvas = mCanvasOwned.get(); // clean up the old save stack mSaveStack.reset(nullptr); @@ -547,40 +525,14 @@ void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, cons // Canvas draw operations: Bitmaps // ---------------------------------------------------------------------------- -SkiaCanvas::PaintCoW&& SkiaCanvas::filterBitmap(PaintCoW&& paint, - sk_sp<SkColorFilter> colorSpaceFilter) const { - /* We don't apply the colorSpace filter if this canvas is already wrapped with - * a SkColorSpaceXformCanvas since it already takes care of converting the - * contents of the bitmap into the appropriate colorspace. The mCanvasWrapper - * should only be used if this canvas is backed by a surface/bitmap that is known - * to have a non-sRGB colorspace. - */ - if (!mCanvasWrapper && colorSpaceFilter) { - SkPaint& tmpPaint = paint.writeable(); - if (tmpPaint.getColorFilter()) { - tmpPaint.setColorFilter(SkColorFilter::MakeComposeFilter(tmpPaint.refColorFilter(), - std::move(colorSpaceFilter))); - LOG_ALWAYS_FATAL_IF(!tmpPaint.getColorFilter()); - } else { - tmpPaint.setColorFilter(std::move(colorSpaceFilter)); - } - } - return filterPaint(std::move(paint)); -} - void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mCanvas->drawImage(image, left, top, filterBitmap(paint, std::move(colorFilter))); + mCanvas->drawImage(bitmap.makeImage(), left, top, filterPaint(paint)); } void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { SkAutoCanvasRestore acr(mCanvas, true); mCanvas->concat(matrix); - - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mCanvas->drawImage(image, 0, 0, filterBitmap(paint, std::move(colorFilter))); + mCanvas->drawImage(bitmap.makeImage(), 0, 0, filterPaint(paint)); } void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight, @@ -589,9 +541,7 @@ void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float s SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mCanvas->drawImageRect(image, srcRect, dstRect, filterBitmap(paint, std::move(colorFilter)), + mCanvas->drawImageRect(bitmap.makeImage(), srcRect, dstRect, filterPaint(paint), SkCanvas::kFast_SrcRectConstraint); } @@ -673,13 +623,9 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight, PaintCoW paintCoW(paint); SkPaint& tmpPaint = paintCoW.writeable(); - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + sk_sp<SkImage> image = bitmap.makeImage(); sk_sp<SkShader> shader = image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); - if (colorFilter) { - shader = shader->makeWithColorFilter(std::move(colorFilter)); - } tmpPaint.setShader(std::move(shader)); mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate, @@ -710,10 +656,7 @@ void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, floa lattice.fBounds = nullptr; SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mCanvas->drawImageLattice(image.get(), lattice, dst, - filterBitmap(paint, std::move(colorFilter))); + mCanvas->drawImageLattice(bitmap.makeImage().get(), lattice, dst, filterPaint(paint)); } double SkiaCanvas::drawAnimatedImage(AnimatedImageDrawable* imgDrawable) { diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h index 3a877cf84010..24d9c08ec1c6 100644 --- a/libs/hwui/SkiaCanvas.h +++ b/libs/hwui/SkiaCanvas.h @@ -232,7 +232,6 @@ private: class Clip; - std::unique_ptr<SkCanvas> mCanvasWrapper; // might own a wrapper on the canvas std::unique_ptr<SkCanvas> mCanvasOwned; // might own a canvas we allocated SkCanvas* mCanvas; // we do NOT own this canvas, it must survive us // unless it is the same as mCanvasOwned.get() diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 75a6e722dd8a..6c77f9ee1845 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -32,7 +32,6 @@ #include <SkCanvas.h> #include <SkImagePriv.h> -#include <SkToSRGBColorFilter.h> #include <SkHighContrastFilter.h> #include <limits> @@ -287,14 +286,8 @@ void Bitmap::setAlphaType(SkAlphaType alphaType) { void Bitmap::getSkBitmap(SkBitmap* outBitmap) { if (isHardware()) { - outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(), - info().colorType(), info().alphaType(), nullptr)); + outBitmap->allocPixels(mInfo); uirenderer::renderthread::RenderProxy::copyHWBitmapInto(this, outBitmap); - if (mInfo.colorSpace()) { - sk_sp<SkPixelRef> pixelRef = sk_ref_sp(outBitmap->pixelRef()); - outBitmap->setInfo(mInfo); - outBitmap->setPixelRef(std::move(pixelRef), 0, 0); - } return; } outBitmap->setInfo(mInfo, rowBytes()); @@ -313,7 +306,7 @@ GraphicBuffer* Bitmap::graphicBuffer() { return nullptr; } -sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) { +sk_sp<SkImage> Bitmap::makeImage() { sk_sp<SkImage> image = mImage; if (!image) { SkASSERT(!isHardware()); @@ -325,9 +318,6 @@ sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) { // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here. image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode); } - if (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 238c764cdea6..d446377ec1d9 100644 --- a/libs/hwui/hwui/Bitmap.h +++ b/libs/hwui/hwui/Bitmap.h @@ -105,14 +105,8 @@ public: * 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); + sk_sp<SkImage> makeImage(); static BitmapPalette computePalette(const SkImageInfo& info, const void* addr, size_t rowBytes); diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index 13d2dae8e281..41788b6ba55d 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -70,7 +70,7 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer SkPaint paint; paint.setAlpha(layer->getAlpha()); paint.setBlendMode(layer->getMode()); - paint.setColorFilter(layer->getColorSpaceWithFilter()); + paint.setColorFilter(layer->getColorFilter()); const bool nonIdentityMatrix = !matrix.isIdentity(); if (nonIdentityMatrix) { canvas->save(); diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index d401b385075e..d6adaf8087c4 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -97,7 +97,7 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, con SkASSERT(mRenderThread.getGrContext() != nullptr); sk_sp<SkSurface> surface(SkSurface::MakeFromBackendRenderTarget( mRenderThread.getGrContext(), backendRT, kBottomLeft_GrSurfaceOrigin, colorType, - nullptr, &props)); + mSurfaceColorSpace, &props)); SkiaPipeline::updateLighting(lightGeometry, lightInfo); renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); @@ -172,6 +172,7 @@ bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, } else if (colorMode == ColorMode::WideColorGamut) { mSurfaceColorType = SkColorType::kRGBA_F16_SkColorType; } + mSurfaceColorSpace = SkColorSpace::MakeSRGB(); if (mEglSurface != EGL_NO_SURFACE) { const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer); diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 2dfe7c71ca1b..7a255c15bf5f 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -169,7 +169,7 @@ bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator if (!layer || layer->width() != surfaceWidth || layer->height() != surfaceHeight) { SkImageInfo info; info = SkImageInfo::Make(surfaceWidth, surfaceHeight, getSurfaceColorType(), - kPremul_SkAlphaType); + kPremul_SkAlphaType, getSurfaceColorSpace()); SkSurfaceProps props(0, kUnknown_SkPixelGeometry); SkASSERT(mRenderThread.getGrContext() != nullptr); node->setLayerSurface(SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), @@ -204,8 +204,7 @@ void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { GrContext* context = thread.getGrContext(); if (context) { ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height()); - sk_sp<SkColorFilter> colorFilter; - auto image = bitmap->makeImage(&colorFilter); + auto image = bitmap->makeImage(); 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 596b8aff6d4a..b66a843223f0 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -179,9 +179,8 @@ SkiaCanvas::PaintCoW&& SkiaRecordingCanvas::filterBitmap(PaintCoW&& paint, } void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mRecorder.drawImage(image, left, top, filterBitmap(paint, std::move(colorFilter)), bitmap.palette()); + sk_sp<SkImage> image = bitmap.makeImage(); + mRecorder.drawImage(image, left, top, filterPaint(paint), bitmap.palette()); // 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. @@ -194,9 +193,8 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, con SkAutoCanvasRestore acr(&mRecorder, true); concat(matrix); - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mRecorder.drawImage(image, 0, 0, filterBitmap(paint, std::move(colorFilter)), bitmap.palette()); + sk_sp<SkImage> image = bitmap.makeImage(); + mRecorder.drawImage(image, 0, 0, filterPaint(paint), bitmap.palette()); if (!bitmap.isImmutable() && image.get() && !image->unique()) { mDisplayList->mMutableImages.push_back(image.get()); } @@ -208,9 +206,8 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mRecorder.drawImageRect(image, srcRect, dstRect, filterBitmap(paint, std::move(colorFilter)), + sk_sp<SkImage> image = bitmap.makeImage(); + mRecorder.drawImageRect(image, srcRect, dstRect, filterPaint(paint), SkCanvas::kFast_SrcRectConstraint, bitmap.palette()); if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() && !dstRect.isEmpty()) { @@ -247,10 +244,9 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& ch if (!filteredPaint || filteredPaint->getFilterQuality() != kLow_SkFilterQuality) { filteredPaint.writeable().setFilterQuality(kLow_SkFilterQuality); } - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + sk_sp<SkImage> image = bitmap.makeImage(); mRecorder.drawImageLattice(image, lattice, dst, - filterBitmap(std::move(filteredPaint), std::move(colorFilter)), + filterPaint(std::move(filteredPaint)), bitmap.palette()); if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) { mDisplayList->mMutableImages.push_back(image.get()); diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp index 9ffccfb4d340..15aec9f291a4 100644 --- a/libs/hwui/surfacetexture/ImageConsumer.cpp +++ b/libs/hwui/surfacetexture/ImageConsumer.cpp @@ -22,6 +22,7 @@ #include "renderthread/EglManager.h" #include "renderthread/RenderThread.h" #include "renderthread/VulkanManager.h" +#include "utils/Color.h" // Macro for including the SurfaceTexture name in log messages #define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__) @@ -44,13 +45,16 @@ void ImageConsumer::onReleaseBufferLocked(int buf) { mImageSlots[buf].mEglFence = EGL_NO_SYNC_KHR; } -void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer) { - if (!mImage.get()) { +void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer, + android_dataspace dataspace) { + if (!mImage.get() || dataspace != mDataspace) { mImage = graphicBuffer.get() ? SkImage::MakeFromAHardwareBuffer( reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()), - kPremul_SkAlphaType) + kPremul_SkAlphaType, + uirenderer::DataSpaceToColorSpace(dataspace)) : nullptr; + mDataspace = dataspace; } } @@ -66,7 +70,7 @@ sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st, int slot = st.mCurrentTexture; if (slot != BufferItem::INVALID_BUFFER_SLOT) { *queueEmpty = true; - mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer); + mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer, item.mDataSpace); return mImageSlots[slot].mImage; } } @@ -145,7 +149,7 @@ sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st, st.computeCurrentTransformMatrixLocked(); *queueEmpty = false; - mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer); + mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer, item.mDataSpace); return mImageSlots[slot].mImage; } diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h index 31ee8db52874..5bab0ef58a9a 100644 --- a/libs/hwui/surfacetexture/ImageConsumer.h +++ b/libs/hwui/surfacetexture/ImageConsumer.h @@ -68,18 +68,21 @@ private: * ImageConsumer maintains about a BufferQueue buffer slot. */ struct ImageSlot { - ImageSlot() : mEglFence(EGL_NO_SYNC_KHR) {} + ImageSlot() : mDataspace(HAL_DATASPACE_UNKNOWN), mEglFence(EGL_NO_SYNC_KHR) {} // mImage is the SkImage created from mGraphicBuffer. sk_sp<SkImage> mImage; + // the dataspace associated with the current image + android_dataspace mDataspace; + /** * mEglFence is the EGL sync object that must signal before the buffer * associated with this buffer slot may be dequeued. */ EGLSyncKHR mEglFence; - void createIfNeeded(sp<GraphicBuffer> graphicBuffer); + void createIfNeeded(sp<GraphicBuffer> graphicBuffer, android_dataspace dataspace); }; /** diff --git a/libs/hwui/surfacetexture/SurfaceTexture.cpp b/libs/hwui/surfacetexture/SurfaceTexture.cpp index 4bff715822e8..90f891265572 100644 --- a/libs/hwui/surfacetexture/SurfaceTexture.cpp +++ b/libs/hwui/surfacetexture/SurfaceTexture.cpp @@ -470,8 +470,7 @@ void SurfaceTexture::dumpLocked(String8& result, const char* prefix) const { ConsumerBase::dumpLocked(result, prefix); } -sk_sp<SkImage> SurfaceTexture::dequeueImage(SkMatrix& transformMatrix, android_dataspace& dataSpace, - bool* queueEmpty, +sk_sp<SkImage> SurfaceTexture::dequeueImage(SkMatrix& transformMatrix, bool* queueEmpty, uirenderer::RenderState& renderState) { Mutex::Autolock _l(mMutex); @@ -488,7 +487,6 @@ sk_sp<SkImage> SurfaceTexture::dequeueImage(SkMatrix& transformMatrix, android_d auto image = mImageConsumer.dequeueImage(queueEmpty, *this, renderState); if (image.get()) { uirenderer::mat4(mCurrentTransformMatrix).copyTo(transformMatrix); - dataSpace = mCurrentDataSpace; } return image; } diff --git a/libs/hwui/surfacetexture/SurfaceTexture.h b/libs/hwui/surfacetexture/SurfaceTexture.h index db392a9f8476..96afd82b0d40 100644 --- a/libs/hwui/surfacetexture/SurfaceTexture.h +++ b/libs/hwui/surfacetexture/SurfaceTexture.h @@ -258,8 +258,8 @@ public: */ status_t attachToContext(uint32_t tex); - sk_sp<SkImage> dequeueImage(SkMatrix& transformMatrix, android_dataspace& dataSpace, - bool* queueEmpty, uirenderer::RenderState& renderState); + sk_sp<SkImage> dequeueImage(SkMatrix& transformMatrix, bool* queueEmpty, + uirenderer::RenderState& renderState); /** * attachToView attaches a SurfaceTexture that is currently in the diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp index 66b9b85bdbe7..8a1bc4d2f7f2 100644 --- a/libs/hwui/tests/common/TestUtils.cpp +++ b/libs/hwui/tests/common/TestUtils.cpp @@ -72,9 +72,7 @@ sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater( layerUpdater->setTransform(&transform); // updateLayer so it's ready to draw - SkMatrix identity; - identity.setIdentity(); - layerUpdater->updateLayer(true, identity, HAL_DATASPACE_UNKNOWN, nullptr); + layerUpdater->updateLayer(true, SkMatrix::I(), nullptr); return layerUpdater; } diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp index 15039b5fa976..ad11a1d32310 100644 --- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp +++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp @@ -44,8 +44,7 @@ public: }); SkPaint paint; - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = hwuiBitmap->makeImage(&colorFilter); + sk_sp<SkImage> image = hwuiBitmap->makeImage(); sk_sp<SkShader> repeatShader = image->makeShader(SkShader::TileMode::kRepeat_TileMode, SkShader::TileMode::kRepeat_TileMode, nullptr); diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp index f137562e7c73..448408d19eb1 100644 --- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp +++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp @@ -72,8 +72,7 @@ public: void doFrame(int frameNr) override {} sk_sp<SkShader> createBitmapShader(Bitmap& bitmap) { - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + sk_sp<SkImage> image = bitmap.makeImage(); return image->makeShader(SkShader::TileMode::kClamp_TileMode, SkShader::TileMode::kClamp_TileMode); } diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp index c235715073f5..210fced574e9 100644 --- a/libs/hwui/tests/unit/CacheManagerTests.cpp +++ b/libs/hwui/tests/unit/CacheManagerTests.cpp @@ -54,8 +54,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, trimMemory) { // create an image and pin it so that we have something with a unique key in the cache sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(SkImageInfo::MakeA8(displayInfo.w, displayInfo.h)); - sk_sp<SkColorFilter> filter; - sk_sp<SkImage> image = bitmap->makeImage(&filter); + sk_sp<SkImage> image = bitmap->makeImage(); ASSERT_TRUE(SkImage_pinAsTexture(image.get(), grContext)); // attempt to trim all memory while we still hold strong refs diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp index 6c8775b1bdbb..a6869791a915 100644 --- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp +++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp @@ -43,7 +43,7 @@ RENDERTHREAD_TEST(DeferredLayerUpdater, updateLayer) { SkBitmap bitmap; bitmap.allocN32Pixels(16, 16); sk_sp<SkImage> layerImage = SkImage::MakeFromBitmap(bitmap); - layerUpdater->updateLayer(true, scaledMatrix, HAL_DATASPACE_UNKNOWN, layerImage); + layerUpdater->updateLayer(true, scaledMatrix, layerImage); // the backing layer should now have all the properties applied. EXPECT_EQ(100u, layerUpdater->backingLayer()->getWidth()); diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp index 634ceffe0741..f3a764874e2b 100644 --- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp +++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp @@ -53,12 +53,12 @@ TEST(SkiaCanvas, colorSpaceXform) { adobeBitmap->getSkBitmap(&adobeSkBitmap); *adobeSkBitmap.getAddr32(0, 0) = 0xFF0000F0; // Opaque, almost fully-red - SkImageInfo info = adobeInfo.makeColorSpace(nullptr); + SkImageInfo info = adobeInfo.makeColorSpace(SkColorSpace::MakeSRGB()); sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(info); SkBitmap skBitmap; bitmap->getSkBitmap(&skBitmap); - // Create a software canvas. + // Create a software sRGB canvas. SkiaCanvas canvas(skBitmap); canvas.drawBitmap(*adobeBitmap, 0, 0, nullptr); // The result should be fully red, since we convert to sRGB at draw time. @@ -77,7 +77,7 @@ TEST(SkiaCanvas, colorSpaceXform) { picCanvas.drawBitmap(*adobeBitmap, 0, 0, nullptr); sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture(); - // Playback to an software canvas. The result should be fully red. + // Playback to a software sRGB canvas. The result should be fully red. canvas.asSkCanvas()->drawPicture(picture); ASSERT_EQ(0xFF0000FF, *skBitmap.getAddr32(0, 0)); } |