Merge changes I61e8a679,Ic53a4225
* changes:
Support caching of {LinearEffect, SkRuntimeEffect} pairs
Introduce AutoBackendTexture into Skia-RenderEngine
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index cd7f37b..b878150 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -31,6 +31,9 @@
"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 {
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 0000000..d126c27
--- /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 0000000..30f4b77
--- /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 579260b..74f342a 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 @@
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 @@
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 @@
}
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 @@
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 @@
.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 @@
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 965cb41..f5eed1e 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 @@
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 @@
// 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 b628b3e..b3d5d63 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 @@
}
sk_sp<SkRuntimeEffect> buildRuntimeEffect(const LinearEffect& linearEffect) {
+ ATRACE_CALL();
SkString shaderString;
generateEOTF(linearEffect.inputDataspace, shaderString);
generateXYZTransforms(shaderString);
@@ -445,6 +449,7 @@
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 2615669..dadba32 100644
--- a/libs/renderengine/skia/filters/LinearEffect.h
+++ b/libs/renderengine/skia/filters/LinearEffect.h
@@ -63,6 +63,24 @@
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