Loading libs/renderengine/Android.bp +4 −0 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,9 @@ cc_defaults { "libui", "libui", "libutils", "libutils", ], ], include_dirs: [ "external/skia/src/gpu", ], whole_static_libs: ["libskia"], whole_static_libs: ["libskia"], local_include_dirs: ["include"], local_include_dirs: ["include"], export_include_dirs: ["include"], export_include_dirs: ["include"], Loading Loading @@ -75,6 +78,7 @@ filegroup { filegroup { filegroup { name: "librenderengine_skia_sources", name: "librenderengine_skia_sources", srcs: [ srcs: [ "skia/AutoBackendTexture.cpp", "skia/SkiaRenderEngine.cpp", "skia/SkiaRenderEngine.cpp", "skia/SkiaGLRenderEngine.cpp", "skia/SkiaGLRenderEngine.cpp", "skia/filters/BlurFilter.cpp", "skia/filters/BlurFilter.cpp", Loading libs/renderengine/skia/AutoBackendTexture.cpp 0 → 100644 +163 −0 Original line number Original line Diff line number Diff line /* * 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 libs/renderengine/skia/AutoBackendTexture.h 0 → 100644 +111 −0 Original line number Original line Diff line number Diff line /* * 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 libs/renderengine/skia/SkiaGLRenderEngine.cpp +58 −83 Original line number Original line Diff line number Diff line Loading @@ -16,8 +16,10 @@ //#define LOG_NDEBUG 0 //#define LOG_NDEBUG 0 #include <cstdint> #include <cstdint> #include <memory> #include "SkImageInfo.h" #include "SkImageInfo.h" #include "log/log_main.h" #include "system/graphics-base-v1.0.h" #include "system/graphics-base-v1.0.h" #undef LOG_TAG #undef LOG_TAG #define LOG_TAG "RenderEngine" #define LOG_TAG "RenderEngine" Loading Loading @@ -145,47 +147,6 @@ static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint render return err; 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( std::unique_ptr<SkiaGLRenderEngine> SkiaGLRenderEngine::create( const RenderEngineCreationArgs& args) { const RenderEngineCreationArgs& args) { // initialize EGL for the default display // initialize EGL for the default display Loading Loading @@ -457,7 +418,8 @@ static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destin void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) { void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) { std::lock_guard<std::mutex> lock(mRenderingMutex); std::lock_guard<std::mutex> lock(mRenderingMutex); mImageCache.erase(bufferId); mTextureCache.erase(bufferId); mProtectedTextureCache.erase(bufferId); } } status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, Loading Loading @@ -486,36 +448,36 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, } } auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext; auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext; auto& cache = mInProtectedContext ? mProtectedSurfaceCache : mSurfaceCache; auto& cache = mInProtectedContext ? mProtectedTextureCache : mTextureCache; AHardwareBuffer_Desc bufferDesc; AHardwareBuffer_Desc bufferDesc; AHardwareBuffer_describe(buffer->toAHardwareBuffer(), &bufferDesc); AHardwareBuffer_describe(buffer->toAHardwareBuffer(), &bufferDesc); LOG_ALWAYS_FATAL_IF(!hasUsage(bufferDesc, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE), LOG_ALWAYS_FATAL_IF(!hasUsage(bufferDesc, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE), "missing usage"); "missing usage"); sk_sp<SkSurface> surface; std::shared_ptr<AutoBackendTexture::LocalRef> surfaceTextureRef = nullptr; if (useFramebufferCache) { if (useFramebufferCache) { auto iter = cache.find(buffer->getId()); auto iter = cache.find(buffer->getId()); if (iter != cache.end()) { if (iter != cache.end()) { ALOGV("Cache hit!"); ALOGV("Cache hit!"); surface = iter->second; surfaceTextureRef = iter->second; } } } } if (!surface) { surface = SkSurface::MakeFromAHardwareBuffer(grContext.get(), buffer->toAHardwareBuffer(), if (surfaceTextureRef == nullptr || surfaceTextureRef->getTexture() == nullptr) { GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin, surfaceTextureRef = std::make_shared<AutoBackendTexture::LocalRef>(); mUseColorManagement surfaceTextureRef->setTexture( ? toColorSpace(display.outputDataspace) new AutoBackendTexture(mGrContext.get(), buffer->toAHardwareBuffer(), true)); : SkColorSpace::MakeSRGB(), if (useFramebufferCache) { nullptr); if (useFramebufferCache && surface) { ALOGD("Adding to cache"); ALOGD("Adding to cache"); cache.insert({buffer->getId(), surface}); cache.insert({buffer->getId(), surfaceTextureRef}); } } } } if (!surface) { ALOGE("Failed to make surface"); sk_sp<SkSurface> surface = return BAD_VALUE; surfaceTextureRef->getTexture()->getOrCreateSurface(mUseColorManagement } ? display.outputDataspace : ui::Dataspace::SRGB, mGrContext.get()); auto canvas = surface->getCanvas(); auto canvas = surface->getCanvas(); // Clear the entire canvas with a transparent black to prevent ghost images. // Clear the entire canvas with a transparent black to prevent ghost images. Loading Loading @@ -586,28 +548,35 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, const auto& item = layer->source.buffer; const auto& item = layer->source.buffer; const auto bufferWidth = item.buffer->getBounds().width(); const auto bufferWidth = item.buffer->getBounds().width(); const auto bufferHeight = item.buffer->getBounds().height(); const auto bufferHeight = item.buffer->getBounds().height(); sk_sp<SkImage> image; std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr; auto iter = mImageCache.find(item.buffer->getId()); auto iter = mTextureCache.find(item.buffer->getId()); if (iter != mImageCache.end()) { if (iter != mTextureCache.end()) { image = iter->second; imageTextureRef = iter->second; } else { } else { image = SkImage::MakeFromAHardwareBuffer( imageTextureRef = std::make_shared<AutoBackendTexture::LocalRef>(); imageTextureRef->setTexture(new AutoBackendTexture(mGrContext.get(), item.buffer->toAHardwareBuffer(), 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.isOpaque ? kOpaque_SkAlphaType : (item.usePremultipliedAlpha ? kPremul_SkAlphaType : (item.usePremultipliedAlpha ? kPremul_SkAlphaType : kUnpremul_SkAlphaType), : kUnpremul_SkAlphaType), mUseColorManagement mGrContext.get()); ? (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}); } SkMatrix matrix; SkMatrix matrix; if (layer->geometry.roundedCornersRadius > 0) { if (layer->geometry.roundedCornersRadius > 0) { const auto roundedRect = getRoundedRect(layer); const auto roundedRect = getRoundedRect(layer); Loading Loading @@ -669,7 +638,16 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, .outputDataspace = display.outputDataspace, .outputDataspace = display.outputDataspace, .undoPremultipliedAlpha = !item.isOpaque && .undoPremultipliedAlpha = !item.isOpaque && item.usePremultipliedAlpha}; 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, paint.setShader(createLinearEffectShader(shader, effect, runtimeEffect, display.maxLuminance, display.maxLuminance, layer->source.buffer.maxMasteringLuminance, layer->source.buffer.maxMasteringLuminance, Loading Loading @@ -921,10 +899,7 @@ EGLSurface SkiaGLRenderEngine::createPlaceholderEglPbufferSurface(EGLDisplay dis return eglCreatePbufferSurface(display, placeholderConfig, attributes.data()); return eglCreatePbufferSurface(display, placeholderConfig, attributes.data()); } } void SkiaGLRenderEngine::cleanFramebufferCache() { void SkiaGLRenderEngine::cleanFramebufferCache() {} mSurfaceCache.clear(); mProtectedSurfaceCache.clear(); } } // namespace skia } // namespace skia } // namespace renderengine } // namespace renderengine Loading libs/renderengine/skia/SkiaGLRenderEngine.h +10 −4 Original line number Original line Diff line number Diff line Loading @@ -29,9 +29,13 @@ #include <mutex> #include <mutex> #include <unordered_map> #include <unordered_map> #include "AutoBackendTexture.h" #include "EGL/egl.h" #include "EGL/egl.h" #include "SkImageInfo.h" #include "SkiaRenderEngine.h" #include "SkiaRenderEngine.h" #include "android-base/macros.h" #include "filters/BlurFilter.h" #include "filters/BlurFilter.h" #include "skia/filters/LinearEffect.h" namespace android { namespace android { namespace renderengine { namespace renderengine { Loading Loading @@ -92,8 +96,12 @@ private: const bool mUseColorManagement; const bool mUseColorManagement; // Cache of GL images that we'll store per GraphicBuffer ID // Cache of GL textures that we'll store per GraphicBuffer ID std::unordered_map<uint64_t, sk_sp<SkImage>> mImageCache GUARDED_BY(mRenderingMutex); 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: // Mutex guarding rendering operations, so that: // 1. GL operations aren't interleaved, and // 1. GL operations aren't interleaved, and // 2. Internal state related to rendering that is potentially modified by // 2. Internal state related to rendering that is potentially modified by Loading @@ -107,8 +115,6 @@ private: // Same as above, but for protected content (eg. DRM) // Same as above, but for protected content (eg. DRM) sk_sp<GrDirectContext> mProtectedGrContext; 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; bool mInProtectedContext = false; }; }; Loading Loading
libs/renderengine/Android.bp +4 −0 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,9 @@ cc_defaults { "libui", "libui", "libutils", "libutils", ], ], include_dirs: [ "external/skia/src/gpu", ], whole_static_libs: ["libskia"], whole_static_libs: ["libskia"], local_include_dirs: ["include"], local_include_dirs: ["include"], export_include_dirs: ["include"], export_include_dirs: ["include"], Loading Loading @@ -75,6 +78,7 @@ filegroup { filegroup { filegroup { name: "librenderengine_skia_sources", name: "librenderengine_skia_sources", srcs: [ srcs: [ "skia/AutoBackendTexture.cpp", "skia/SkiaRenderEngine.cpp", "skia/SkiaRenderEngine.cpp", "skia/SkiaGLRenderEngine.cpp", "skia/SkiaGLRenderEngine.cpp", "skia/filters/BlurFilter.cpp", "skia/filters/BlurFilter.cpp", Loading
libs/renderengine/skia/AutoBackendTexture.cpp 0 → 100644 +163 −0 Original line number Original line Diff line number Diff line /* * 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
libs/renderengine/skia/AutoBackendTexture.h 0 → 100644 +111 −0 Original line number Original line Diff line number Diff line /* * 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
libs/renderengine/skia/SkiaGLRenderEngine.cpp +58 −83 Original line number Original line Diff line number Diff line Loading @@ -16,8 +16,10 @@ //#define LOG_NDEBUG 0 //#define LOG_NDEBUG 0 #include <cstdint> #include <cstdint> #include <memory> #include "SkImageInfo.h" #include "SkImageInfo.h" #include "log/log_main.h" #include "system/graphics-base-v1.0.h" #include "system/graphics-base-v1.0.h" #undef LOG_TAG #undef LOG_TAG #define LOG_TAG "RenderEngine" #define LOG_TAG "RenderEngine" Loading Loading @@ -145,47 +147,6 @@ static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint render return err; 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( std::unique_ptr<SkiaGLRenderEngine> SkiaGLRenderEngine::create( const RenderEngineCreationArgs& args) { const RenderEngineCreationArgs& args) { // initialize EGL for the default display // initialize EGL for the default display Loading Loading @@ -457,7 +418,8 @@ static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destin void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) { void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) { std::lock_guard<std::mutex> lock(mRenderingMutex); std::lock_guard<std::mutex> lock(mRenderingMutex); mImageCache.erase(bufferId); mTextureCache.erase(bufferId); mProtectedTextureCache.erase(bufferId); } } status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, Loading Loading @@ -486,36 +448,36 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, } } auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext; auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext; auto& cache = mInProtectedContext ? mProtectedSurfaceCache : mSurfaceCache; auto& cache = mInProtectedContext ? mProtectedTextureCache : mTextureCache; AHardwareBuffer_Desc bufferDesc; AHardwareBuffer_Desc bufferDesc; AHardwareBuffer_describe(buffer->toAHardwareBuffer(), &bufferDesc); AHardwareBuffer_describe(buffer->toAHardwareBuffer(), &bufferDesc); LOG_ALWAYS_FATAL_IF(!hasUsage(bufferDesc, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE), LOG_ALWAYS_FATAL_IF(!hasUsage(bufferDesc, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE), "missing usage"); "missing usage"); sk_sp<SkSurface> surface; std::shared_ptr<AutoBackendTexture::LocalRef> surfaceTextureRef = nullptr; if (useFramebufferCache) { if (useFramebufferCache) { auto iter = cache.find(buffer->getId()); auto iter = cache.find(buffer->getId()); if (iter != cache.end()) { if (iter != cache.end()) { ALOGV("Cache hit!"); ALOGV("Cache hit!"); surface = iter->second; surfaceTextureRef = iter->second; } } } } if (!surface) { surface = SkSurface::MakeFromAHardwareBuffer(grContext.get(), buffer->toAHardwareBuffer(), if (surfaceTextureRef == nullptr || surfaceTextureRef->getTexture() == nullptr) { GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin, surfaceTextureRef = std::make_shared<AutoBackendTexture::LocalRef>(); mUseColorManagement surfaceTextureRef->setTexture( ? toColorSpace(display.outputDataspace) new AutoBackendTexture(mGrContext.get(), buffer->toAHardwareBuffer(), true)); : SkColorSpace::MakeSRGB(), if (useFramebufferCache) { nullptr); if (useFramebufferCache && surface) { ALOGD("Adding to cache"); ALOGD("Adding to cache"); cache.insert({buffer->getId(), surface}); cache.insert({buffer->getId(), surfaceTextureRef}); } } } } if (!surface) { ALOGE("Failed to make surface"); sk_sp<SkSurface> surface = return BAD_VALUE; surfaceTextureRef->getTexture()->getOrCreateSurface(mUseColorManagement } ? display.outputDataspace : ui::Dataspace::SRGB, mGrContext.get()); auto canvas = surface->getCanvas(); auto canvas = surface->getCanvas(); // Clear the entire canvas with a transparent black to prevent ghost images. // Clear the entire canvas with a transparent black to prevent ghost images. Loading Loading @@ -586,28 +548,35 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, const auto& item = layer->source.buffer; const auto& item = layer->source.buffer; const auto bufferWidth = item.buffer->getBounds().width(); const auto bufferWidth = item.buffer->getBounds().width(); const auto bufferHeight = item.buffer->getBounds().height(); const auto bufferHeight = item.buffer->getBounds().height(); sk_sp<SkImage> image; std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr; auto iter = mImageCache.find(item.buffer->getId()); auto iter = mTextureCache.find(item.buffer->getId()); if (iter != mImageCache.end()) { if (iter != mTextureCache.end()) { image = iter->second; imageTextureRef = iter->second; } else { } else { image = SkImage::MakeFromAHardwareBuffer( imageTextureRef = std::make_shared<AutoBackendTexture::LocalRef>(); imageTextureRef->setTexture(new AutoBackendTexture(mGrContext.get(), item.buffer->toAHardwareBuffer(), 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.isOpaque ? kOpaque_SkAlphaType : (item.usePremultipliedAlpha ? kPremul_SkAlphaType : (item.usePremultipliedAlpha ? kPremul_SkAlphaType : kUnpremul_SkAlphaType), : kUnpremul_SkAlphaType), mUseColorManagement mGrContext.get()); ? (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}); } SkMatrix matrix; SkMatrix matrix; if (layer->geometry.roundedCornersRadius > 0) { if (layer->geometry.roundedCornersRadius > 0) { const auto roundedRect = getRoundedRect(layer); const auto roundedRect = getRoundedRect(layer); Loading Loading @@ -669,7 +638,16 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, .outputDataspace = display.outputDataspace, .outputDataspace = display.outputDataspace, .undoPremultipliedAlpha = !item.isOpaque && .undoPremultipliedAlpha = !item.isOpaque && item.usePremultipliedAlpha}; 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, paint.setShader(createLinearEffectShader(shader, effect, runtimeEffect, display.maxLuminance, display.maxLuminance, layer->source.buffer.maxMasteringLuminance, layer->source.buffer.maxMasteringLuminance, Loading Loading @@ -921,10 +899,7 @@ EGLSurface SkiaGLRenderEngine::createPlaceholderEglPbufferSurface(EGLDisplay dis return eglCreatePbufferSurface(display, placeholderConfig, attributes.data()); return eglCreatePbufferSurface(display, placeholderConfig, attributes.data()); } } void SkiaGLRenderEngine::cleanFramebufferCache() { void SkiaGLRenderEngine::cleanFramebufferCache() {} mSurfaceCache.clear(); mProtectedSurfaceCache.clear(); } } // namespace skia } // namespace skia } // namespace renderengine } // namespace renderengine Loading
libs/renderengine/skia/SkiaGLRenderEngine.h +10 −4 Original line number Original line Diff line number Diff line Loading @@ -29,9 +29,13 @@ #include <mutex> #include <mutex> #include <unordered_map> #include <unordered_map> #include "AutoBackendTexture.h" #include "EGL/egl.h" #include "EGL/egl.h" #include "SkImageInfo.h" #include "SkiaRenderEngine.h" #include "SkiaRenderEngine.h" #include "android-base/macros.h" #include "filters/BlurFilter.h" #include "filters/BlurFilter.h" #include "skia/filters/LinearEffect.h" namespace android { namespace android { namespace renderengine { namespace renderengine { Loading Loading @@ -92,8 +96,12 @@ private: const bool mUseColorManagement; const bool mUseColorManagement; // Cache of GL images that we'll store per GraphicBuffer ID // Cache of GL textures that we'll store per GraphicBuffer ID std::unordered_map<uint64_t, sk_sp<SkImage>> mImageCache GUARDED_BY(mRenderingMutex); 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: // Mutex guarding rendering operations, so that: // 1. GL operations aren't interleaved, and // 1. GL operations aren't interleaved, and // 2. Internal state related to rendering that is potentially modified by // 2. Internal state related to rendering that is potentially modified by Loading @@ -107,8 +115,6 @@ private: // Same as above, but for protected content (eg. DRM) // Same as above, but for protected content (eg. DRM) sk_sp<GrDirectContext> mProtectedGrContext; 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; bool mInProtectedContext = false; }; }; Loading