diff options
-rw-r--r-- | libs/renderengine/Android.bp | 4 | ||||
-rw-r--r-- | libs/renderengine/skia/AutoBackendTexture.cpp | 163 | ||||
-rw-r--r-- | libs/renderengine/skia/AutoBackendTexture.h | 111 | ||||
-rw-r--r-- | libs/renderengine/skia/SkiaGLRenderEngine.cpp | 141 | ||||
-rw-r--r-- | libs/renderengine/skia/SkiaGLRenderEngine.h | 14 | ||||
-rw-r--r-- | libs/renderengine/skia/filters/LinearEffect.cpp | 5 | ||||
-rw-r--r-- | libs/renderengine/skia/filters/LinearEffect.h | 18 |
7 files changed, 369 insertions, 87 deletions
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index cd7f37b20d..b878150426 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -31,6 +31,9 @@ cc_defaults { "libui", "libutils", ], + include_dirs: [ + "external/skia/src/gpu", + ], whole_static_libs: ["libskia"], local_include_dirs: ["include"], export_include_dirs: ["include"], @@ -75,6 +78,7 @@ filegroup { filegroup { name: "librenderengine_skia_sources", srcs: [ + "skia/AutoBackendTexture.cpp", "skia/SkiaRenderEngine.cpp", "skia/SkiaGLRenderEngine.cpp", "skia/filters/BlurFilter.cpp", diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp new file mode 100644 index 0000000000..d126c27728 --- /dev/null +++ b/libs/renderengine/skia/AutoBackendTexture.cpp @@ -0,0 +1,163 @@ +/* + * Copyright 2020 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 "AutoBackendTexture.h" + +#undef LOG_TAG +#define LOG_TAG "RenderEngine" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include <utils/Trace.h> + +#include "log/log_main.h" +#include "utils/Trace.h" + +namespace android { +namespace renderengine { +namespace skia { + +// Converts an android dataspace to a supported SkColorSpace +// Supported dataspaces are +// 1. sRGB +// 2. Display P3 +// 3. BT2020 PQ +// 4. BT2020 HLG +// Unknown primaries are mapped to BT709, and unknown transfer functions +// are mapped to sRGB. +static sk_sp<SkColorSpace> toSkColorSpace(ui::Dataspace dataspace) { + skcms_Matrix3x3 gamut; + switch (dataspace & HAL_DATASPACE_STANDARD_MASK) { + case HAL_DATASPACE_STANDARD_BT709: + gamut = SkNamedGamut::kSRGB; + break; + case HAL_DATASPACE_STANDARD_BT2020: + gamut = SkNamedGamut::kRec2020; + break; + case HAL_DATASPACE_STANDARD_DCI_P3: + gamut = SkNamedGamut::kDisplayP3; + break; + default: + ALOGV("Unsupported Gamut: %d, defaulting to sRGB", dataspace); + gamut = SkNamedGamut::kSRGB; + break; + } + + switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_LINEAR: + return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut); + case HAL_DATASPACE_TRANSFER_SRGB: + return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut); + case HAL_DATASPACE_TRANSFER_ST2084: + return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut); + case HAL_DATASPACE_TRANSFER_HLG: + return SkColorSpace::MakeRGB(SkNamedTransferFn::kHLG, gamut); + default: + ALOGV("Unsupported Gamma: %d, defaulting to sRGB transfer", dataspace); + return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut); + } +} + +AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer, + bool isRender) { + AHardwareBuffer_Desc desc; + AHardwareBuffer_describe(buffer, &desc); + bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT); + GrBackendFormat backendFormat = + GrAHardwareBufferUtils::GetBackendFormat(context, buffer, desc.format, false); + mBackendTexture = + GrAHardwareBufferUtils::MakeBackendTexture(context, buffer, desc.width, desc.height, + &mDeleteProc, &mUpdateProc, &mImageCtx, + createProtectedImage, backendFormat, + isRender); + mColorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format); +} + +void AutoBackendTexture::unref(bool releaseLocalResources) { + if (releaseLocalResources) { + mSurface = nullptr; + mImage = nullptr; + } + + mUsageCount--; + if (mUsageCount <= 0) { + if (mBackendTexture.isValid()) { + mDeleteProc(mImageCtx); + mBackendTexture = {}; + } + delete this; + } +} + +// releaseSurfaceProc is invoked by SkSurface, when the texture is no longer in use. +// "releaseContext" contains an "AutoBackendTexture*". +void AutoBackendTexture::releaseSurfaceProc(SkSurface::ReleaseContext releaseContext) { + AutoBackendTexture* textureRelease = reinterpret_cast<AutoBackendTexture*>(releaseContext); + textureRelease->unref(false); +} + +// releaseImageProc is invoked by SkImage, when the texture is no longer in use. +// "releaseContext" contains an "AutoBackendTexture*". +void AutoBackendTexture::releaseImageProc(SkImage::ReleaseContext releaseContext) { + AutoBackendTexture* textureRelease = reinterpret_cast<AutoBackendTexture*>(releaseContext); + textureRelease->unref(false); +} + +sk_sp<SkImage> AutoBackendTexture::makeImage(ui::Dataspace dataspace, SkAlphaType alphaType, + GrDirectContext* context) { + ATRACE_CALL(); + + if (mBackendTexture.isValid()) { + mUpdateProc(mImageCtx, context); + } + + sk_sp<SkImage> image = + SkImage::MakeFromTexture(context, mBackendTexture, kTopLeft_GrSurfaceOrigin, mColorType, + alphaType, toSkColorSpace(dataspace), releaseImageProc, this); + if (image.get()) { + // The following ref will be counteracted by releaseProc, when SkImage is discarded. + ref(); + } + + mImage = image; + mDataspace = dataspace; + LOG_ALWAYS_FATAL_IF(mImage == nullptr, "Unable to generate SkImage from buffer"); + return mImage; +} + +sk_sp<SkSurface> AutoBackendTexture::getOrCreateSurface(ui::Dataspace dataspace, + GrDirectContext* context) { + ATRACE_CALL(); + if (!mSurface.get() || mDataspace != dataspace) { + sk_sp<SkSurface> surface = + SkSurface::MakeFromBackendTexture(context, mBackendTexture, + kTopLeft_GrSurfaceOrigin, 0, mColorType, + toSkColorSpace(dataspace), nullptr, + releaseSurfaceProc, this); + if (surface.get()) { + // The following ref will be counteracted by releaseProc, when SkSurface is discarded. + ref(); + } + mSurface = surface; + } + + mDataspace = dataspace; + LOG_ALWAYS_FATAL_IF(mSurface == nullptr, "Unable to generate SkSurface"); + return mSurface; +} + +} // namespace skia +} // namespace renderengine +} // namespace android
\ No newline at end of file diff --git a/libs/renderengine/skia/AutoBackendTexture.h b/libs/renderengine/skia/AutoBackendTexture.h new file mode 100644 index 0000000000..30f4b77573 --- /dev/null +++ b/libs/renderengine/skia/AutoBackendTexture.h @@ -0,0 +1,111 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <GrAHardwareBufferUtils.h> +#include <GrDirectContext.h> +#include <SkImage.h> +#include <SkSurface.h> +#include <sys/types.h> + +#include "android-base/macros.h" +#include "ui/GraphicTypes.h" + +namespace android { +namespace renderengine { +namespace skia { + +/** + * AutoBackendTexture manages GPU image lifetime. It is a ref-counted object + * that keeps GPU resources alive until the last SkImage or SkSurface object using them is + * destroyed. + */ +class AutoBackendTexture { +public: + // Local reference that supports RAII-style management of an AutoBackendTexture + // AutoBackendTexture by itself can't be managed in a similar fashion because + // of shared ownership with Skia objects, so we wrap it here instead. + class LocalRef { + public: + LocalRef() {} + + ~LocalRef() { + // Destroying the texture is the same as setting it to null + setTexture(nullptr); + } + + // Sets the texture to locally ref-track. + void setTexture(AutoBackendTexture* texture) { + if (mTexture != nullptr) { + mTexture->unref(true); + } + + mTexture = texture; + if (mTexture != nullptr) { + mTexture->ref(); + } + } + + AutoBackendTexture* getTexture() const { return mTexture; } + + DISALLOW_COPY_AND_ASSIGN(LocalRef); + + private: + AutoBackendTexture* mTexture = nullptr; + }; + + // Creates a GrBackendTexture whose contents come from the provided buffer. + AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer, bool isRender); + + void ref() { mUsageCount++; } + + // releaseLocalResources is true if the underlying SkImage and SkSurface + // should be deleted from local tracking. + void unref(bool releaseLocalResources); + + // Makes a new SkImage from the texture content. + // As SkImages are immutable but buffer content is not, we create + // a new SkImage every time. + sk_sp<SkImage> makeImage(ui::Dataspace dataspace, SkAlphaType alphaType, + GrDirectContext* context); + + // Makes a new SkSurface from the texture content, if needed. + sk_sp<SkSurface> getOrCreateSurface(ui::Dataspace dataspace, GrDirectContext* context); + +private: + // The only way to invoke dtor is with unref, when mUsageCount is 0. + ~AutoBackendTexture() {} + + GrBackendTexture mBackendTexture; + GrAHardwareBufferUtils::DeleteImageProc mDeleteProc; + GrAHardwareBufferUtils::UpdateImageProc mUpdateProc; + GrAHardwareBufferUtils::TexImageCtx mImageCtx; + + static void releaseSurfaceProc(SkSurface::ReleaseContext releaseContext); + static void releaseImageProc(SkImage::ReleaseContext releaseContext); + + int mUsageCount = 0; + + sk_sp<SkImage> mImage = nullptr; + sk_sp<SkSurface> mSurface = nullptr; + ui::Dataspace mDataspace = ui::Dataspace::UNKNOWN; + SkColorType mColorType = kUnknown_SkColorType; +}; + +} // namespace skia +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 579260bba5..74f342a1a8 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -16,8 +16,10 @@ //#define LOG_NDEBUG 0 #include <cstdint> +#include <memory> #include "SkImageInfo.h" +#include "log/log_main.h" #include "system/graphics-base-v1.0.h" #undef LOG_TAG #define LOG_TAG "RenderEngine" @@ -145,47 +147,6 @@ static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint render return err; } -// Converts an android dataspace to a supported SkColorSpace -// Supported dataspaces are -// 1. sRGB -// 2. Display P3 -// 3. BT2020 PQ -// 4. BT2020 HLG -// Unknown primaries are mapped to BT709, and unknown transfer functions -// are mapped to sRGB. -static sk_sp<SkColorSpace> toColorSpace(ui::Dataspace dataspace) { - skcms_Matrix3x3 gamut; - switch (dataspace & HAL_DATASPACE_STANDARD_MASK) { - case HAL_DATASPACE_STANDARD_BT709: - gamut = SkNamedGamut::kSRGB; - break; - case HAL_DATASPACE_STANDARD_BT2020: - gamut = SkNamedGamut::kRec2020; - break; - case HAL_DATASPACE_STANDARD_DCI_P3: - gamut = SkNamedGamut::kDisplayP3; - break; - default: - ALOGV("Unsupported Gamut: %d, defaulting to sRGB", dataspace); - gamut = SkNamedGamut::kSRGB; - break; - } - - switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) { - case HAL_DATASPACE_TRANSFER_LINEAR: - return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut); - case HAL_DATASPACE_TRANSFER_SRGB: - return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut); - case HAL_DATASPACE_TRANSFER_ST2084: - return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut); - case HAL_DATASPACE_TRANSFER_HLG: - return SkColorSpace::MakeRGB(SkNamedTransferFn::kHLG, gamut); - default: - ALOGV("Unsupported Gamma: %d, defaulting to sRGB transfer", dataspace); - return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut); - } -} - std::unique_ptr<SkiaGLRenderEngine> SkiaGLRenderEngine::create( const RenderEngineCreationArgs& args) { // initialize EGL for the default display @@ -457,7 +418,8 @@ static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destin void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) { std::lock_guard<std::mutex> lock(mRenderingMutex); - mImageCache.erase(bufferId); + mTextureCache.erase(bufferId); + mProtectedTextureCache.erase(bufferId); } status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, @@ -486,36 +448,36 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, } auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext; - auto& cache = mInProtectedContext ? mProtectedSurfaceCache : mSurfaceCache; + auto& cache = mInProtectedContext ? mProtectedTextureCache : mTextureCache; AHardwareBuffer_Desc bufferDesc; AHardwareBuffer_describe(buffer->toAHardwareBuffer(), &bufferDesc); LOG_ALWAYS_FATAL_IF(!hasUsage(bufferDesc, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE), "missing usage"); - sk_sp<SkSurface> surface; + std::shared_ptr<AutoBackendTexture::LocalRef> surfaceTextureRef = nullptr; if (useFramebufferCache) { auto iter = cache.find(buffer->getId()); if (iter != cache.end()) { ALOGV("Cache hit!"); - surface = iter->second; + surfaceTextureRef = iter->second; } } - if (!surface) { - surface = SkSurface::MakeFromAHardwareBuffer(grContext.get(), buffer->toAHardwareBuffer(), - GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin, - mUseColorManagement - ? toColorSpace(display.outputDataspace) - : SkColorSpace::MakeSRGB(), - nullptr); - if (useFramebufferCache && surface) { + + if (surfaceTextureRef == nullptr || surfaceTextureRef->getTexture() == nullptr) { + surfaceTextureRef = std::make_shared<AutoBackendTexture::LocalRef>(); + surfaceTextureRef->setTexture( + new AutoBackendTexture(mGrContext.get(), buffer->toAHardwareBuffer(), true)); + if (useFramebufferCache) { ALOGD("Adding to cache"); - cache.insert({buffer->getId(), surface}); + cache.insert({buffer->getId(), surfaceTextureRef}); } } - if (!surface) { - ALOGE("Failed to make surface"); - return BAD_VALUE; - } + + sk_sp<SkSurface> surface = + surfaceTextureRef->getTexture()->getOrCreateSurface(mUseColorManagement + ? display.outputDataspace + : ui::Dataspace::SRGB, + mGrContext.get()); auto canvas = surface->getCanvas(); // Clear the entire canvas with a transparent black to prevent ghost images. @@ -586,28 +548,35 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, const auto& item = layer->source.buffer; const auto bufferWidth = item.buffer->getBounds().width(); const auto bufferHeight = item.buffer->getBounds().height(); - sk_sp<SkImage> image; - auto iter = mImageCache.find(item.buffer->getId()); - if (iter != mImageCache.end()) { - image = iter->second; + std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr; + auto iter = mTextureCache.find(item.buffer->getId()); + if (iter != mTextureCache.end()) { + imageTextureRef = iter->second; } else { - image = SkImage::MakeFromAHardwareBuffer( - item.buffer->toAHardwareBuffer(), - item.isOpaque ? kOpaque_SkAlphaType - : (item.usePremultipliedAlpha ? kPremul_SkAlphaType - : kUnpremul_SkAlphaType), - mUseColorManagement - ? (needsToneMapping(layer->sourceDataspace, display.outputDataspace) - // If we need to map to linear space, then - // mark the source image with the same - // colorspace as the destination surface so - // that Skia's color management is a no-op. - ? toColorSpace(display.outputDataspace) - : toColorSpace(layer->sourceDataspace)) - : SkColorSpace::MakeSRGB()); - mImageCache.insert({item.buffer->getId(), image}); + imageTextureRef = std::make_shared<AutoBackendTexture::LocalRef>(); + imageTextureRef->setTexture(new AutoBackendTexture(mGrContext.get(), + item.buffer->toAHardwareBuffer(), + false)); + mTextureCache.insert({buffer->getId(), imageTextureRef}); } - + sk_sp<SkImage> image = + imageTextureRef->getTexture() + ->makeImage(mUseColorManagement + ? (needsToneMapping(layer->sourceDataspace, + display.outputDataspace) + // If we need to map to linear space, + // then mark the source image with the + // same colorspace as the destination + // surface so that Skia's color + // management is a no-op. + ? display.outputDataspace + : layer->sourceDataspace) + : ui::Dataspace::SRGB, + item.isOpaque ? kOpaque_SkAlphaType + : (item.usePremultipliedAlpha + ? kPremul_SkAlphaType + : kUnpremul_SkAlphaType), + mGrContext.get()); SkMatrix matrix; if (layer->geometry.roundedCornersRadius > 0) { const auto roundedRect = getRoundedRect(layer); @@ -669,7 +638,16 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, .outputDataspace = display.outputDataspace, .undoPremultipliedAlpha = !item.isOpaque && item.usePremultipliedAlpha}; - sk_sp<SkRuntimeEffect> runtimeEffect = buildRuntimeEffect(effect); + + auto effectIter = mRuntimeEffects.find(effect); + sk_sp<SkRuntimeEffect> runtimeEffect = nullptr; + if (effectIter == mRuntimeEffects.end()) { + runtimeEffect = buildRuntimeEffect(effect); + mRuntimeEffects.insert({effect, runtimeEffect}); + } else { + runtimeEffect = effectIter->second; + } + paint.setShader(createLinearEffectShader(shader, effect, runtimeEffect, display.maxLuminance, layer->source.buffer.maxMasteringLuminance, @@ -921,10 +899,7 @@ EGLSurface SkiaGLRenderEngine::createPlaceholderEglPbufferSurface(EGLDisplay dis return eglCreatePbufferSurface(display, placeholderConfig, attributes.data()); } -void SkiaGLRenderEngine::cleanFramebufferCache() { - mSurfaceCache.clear(); - mProtectedSurfaceCache.clear(); -} +void SkiaGLRenderEngine::cleanFramebufferCache() {} } // namespace skia } // namespace renderengine diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index 965cb41a15..f5eed1ebb2 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -29,9 +29,13 @@ #include <mutex> #include <unordered_map> +#include "AutoBackendTexture.h" #include "EGL/egl.h" +#include "SkImageInfo.h" #include "SkiaRenderEngine.h" +#include "android-base/macros.h" #include "filters/BlurFilter.h" +#include "skia/filters/LinearEffect.h" namespace android { namespace renderengine { @@ -92,8 +96,12 @@ private: const bool mUseColorManagement; - // Cache of GL images that we'll store per GraphicBuffer ID - std::unordered_map<uint64_t, sk_sp<SkImage>> mImageCache GUARDED_BY(mRenderingMutex); + // Cache of GL textures that we'll store per GraphicBuffer ID + std::unordered_map<uint64_t, std::shared_ptr<AutoBackendTexture::LocalRef>> mTextureCache + GUARDED_BY(mRenderingMutex); + std::unordered_map<uint64_t, std::shared_ptr<AutoBackendTexture::LocalRef>> + mProtectedTextureCache GUARDED_BY(mRenderingMutex); + std::unordered_map<LinearEffect, sk_sp<SkRuntimeEffect>, LinearEffectHasher> mRuntimeEffects; // Mutex guarding rendering operations, so that: // 1. GL operations aren't interleaved, and // 2. Internal state related to rendering that is potentially modified by @@ -107,8 +115,6 @@ private: // Same as above, but for protected content (eg. DRM) sk_sp<GrDirectContext> mProtectedGrContext; - std::unordered_map<uint64_t, sk_sp<SkSurface>> mSurfaceCache; - std::unordered_map<uint64_t, sk_sp<SkSurface>> mProtectedSurfaceCache; bool mInProtectedContext = false; }; diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp index b628b3ee1e..b3d5d63f25 100644 --- a/libs/renderengine/skia/filters/LinearEffect.cpp +++ b/libs/renderengine/skia/filters/LinearEffect.cpp @@ -16,7 +16,10 @@ #include "LinearEffect.h" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + #include <SkString.h> +#include <utils/Trace.h> #include <optional> @@ -427,6 +430,7 @@ static ColorSpace toColorSpace(ui::Dataspace dataspace) { } sk_sp<SkRuntimeEffect> buildRuntimeEffect(const LinearEffect& linearEffect) { + ATRACE_CALL(); SkString shaderString; generateEOTF(linearEffect.inputDataspace, shaderString); generateXYZTransforms(shaderString); @@ -445,6 +449,7 @@ sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> shader, const LinearEff sk_sp<SkRuntimeEffect> runtimeEffect, float maxDisplayLuminance, float maxMasteringLuminance, float maxContentLuminance) { + ATRACE_CALL(); SkRuntimeShaderBuilder effectBuilder(runtimeEffect); effectBuilder.child("input") = shader; diff --git a/libs/renderengine/skia/filters/LinearEffect.h b/libs/renderengine/skia/filters/LinearEffect.h index 2615669cac..dadba32228 100644 --- a/libs/renderengine/skia/filters/LinearEffect.h +++ b/libs/renderengine/skia/filters/LinearEffect.h @@ -63,6 +63,24 @@ struct LinearEffect { const bool undoPremultipliedAlpha = false; }; +static inline bool operator==(const LinearEffect& lhs, const LinearEffect& rhs) { + return lhs.inputDataspace == rhs.inputDataspace && lhs.outputDataspace == rhs.outputDataspace && + lhs.undoPremultipliedAlpha == rhs.undoPremultipliedAlpha; +} + +struct LinearEffectHasher { + // Inspired by art/runtime/class_linker.cc + // Also this is what boost:hash_combine does + static size_t HashCombine(size_t seed, size_t val) { + return seed ^ (val + 0x9e3779b9 + (seed << 6) + (seed >> 2)); + } + size_t operator()(const LinearEffect& le) const { + size_t result = std::hash<ui::Dataspace>{}(le.inputDataspace); + result = HashCombine(result, std::hash<ui::Dataspace>{}(le.outputDataspace)); + return HashCombine(result, std::hash<bool>{}(le.undoPremultipliedAlpha)); + } +}; + sk_sp<SkRuntimeEffect> buildRuntimeEffect(const LinearEffect& linearEffect); // Generates a shader resulting from applying the a linear effect created from |