/* * Copyright (C) 2018 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 "WebViewFunctorManager.h" #include #include "Properties.h" #include "renderthread/RenderThread.h" #include #include #include namespace android::uirenderer { RenderMode WebViewFunctor_queryPlatformRenderMode() { auto pipelineType = Properties::getRenderPipelineType(); switch (pipelineType) { case RenderPipelineType::SkiaGL: return RenderMode::OpenGL_ES; case RenderPipelineType::SkiaVulkan: return RenderMode::Vulkan; default: LOG_ALWAYS_FATAL("Unknown render pipeline type: %d", (int)pipelineType); } } int WebViewFunctor_create(void* data, const WebViewFunctorCallbacks& prototype, RenderMode functorMode) { if (functorMode != RenderMode::OpenGL_ES && functorMode != RenderMode::Vulkan) { ALOGW("Unknown rendermode %d", (int)functorMode); return -1; } if (functorMode == RenderMode::Vulkan && WebViewFunctor_queryPlatformRenderMode() != RenderMode::Vulkan) { ALOGW("Unable to map from GLES platform to a vulkan functor"); return -1; } return WebViewFunctorManager::instance().createFunctor(data, prototype, functorMode); } void WebViewFunctor_release(int functor) { WebViewFunctorManager::instance().releaseFunctor(functor); } static std::atomic_int sNextId{1}; WebViewFunctor::WebViewFunctor(void* data, const WebViewFunctorCallbacks& callbacks, RenderMode functorMode) : mData(data) { mFunctor = sNextId++; mCallbacks = callbacks; mMode = functorMode; } WebViewFunctor::~WebViewFunctor() { destroyContext(); ATRACE_NAME("WebViewFunctor::onDestroy"); mCallbacks.onDestroyed(mFunctor, mData); } void WebViewFunctor::sync(const WebViewSyncData& syncData) const { ATRACE_NAME("WebViewFunctor::sync"); mCallbacks.onSync(mFunctor, mData, syncData); } void WebViewFunctor::drawGl(const DrawGlInfo& drawInfo) { ATRACE_NAME("WebViewFunctor::drawGl"); if (!mHasContext) { mHasContext = true; } mCallbacks.gles.draw(mFunctor, mData, drawInfo); } void WebViewFunctor::initVk(const VkFunctorInitParams& params) { ATRACE_NAME("WebViewFunctor::initVk"); if (!mHasContext) { mHasContext = true; } else { return; } mCallbacks.vk.initialize(mFunctor, mData, params); } void WebViewFunctor::drawVk(const VkFunctorDrawParams& params) { ATRACE_NAME("WebViewFunctor::drawVk"); mCallbacks.vk.draw(mFunctor, mData, params); } void WebViewFunctor::postDrawVk() { ATRACE_NAME("WebViewFunctor::postDrawVk"); mCallbacks.vk.postDraw(mFunctor, mData); } void WebViewFunctor::destroyContext() { if (mHasContext) { mHasContext = false; ATRACE_NAME("WebViewFunctor::onContextDestroyed"); mCallbacks.onContextDestroyed(mFunctor, mData); // grContext may be null in unit tests. auto* grContext = renderthread::RenderThread::getInstance().getGrContext(); if (grContext) grContext->resetContext(); } } WebViewFunctorManager& WebViewFunctorManager::instance() { static WebViewFunctorManager sInstance; return sInstance; } int WebViewFunctorManager::createFunctor(void* data, const WebViewFunctorCallbacks& callbacks, RenderMode functorMode) { auto object = std::make_unique(data, callbacks, functorMode); int id = object->id(); auto handle = object->createHandle(); { std::lock_guard _lock{mLock}; mActiveFunctors.push_back(std::move(handle)); mFunctors.push_back(std::move(object)); } return id; } void WebViewFunctorManager::releaseFunctor(int functor) { sp toRelease; { std::lock_guard _lock{mLock}; for (auto iter = mActiveFunctors.begin(); iter != mActiveFunctors.end(); iter++) { if ((*iter)->id() == functor) { toRelease = std::move(*iter); mActiveFunctors.erase(iter); break; } } } } void WebViewFunctorManager::onContextDestroyed() { // WARNING: SKETCHY // Because we know that we always remove from mFunctors on RenderThread, the same // thread that always invokes onContextDestroyed, we know that the functor pointers // will remain valid without the lock held. // However, we won't block new functors from being added in the meantime. mLock.lock(); const size_t size = mFunctors.size(); WebViewFunctor* toDestroyContext[size]; for (size_t i = 0; i < size; i++) { toDestroyContext[i] = mFunctors[i].get(); } mLock.unlock(); for (size_t i = 0; i < size; i++) { toDestroyContext[i]->destroyContext(); } } void WebViewFunctorManager::destroyFunctor(int functor) { std::unique_ptr toRelease; { std::lock_guard _lock{mLock}; for (auto iter = mFunctors.begin(); iter != mFunctors.end(); iter++) { if ((*iter)->id() == functor) { toRelease = std::move(*iter); mFunctors.erase(iter); break; } } } } sp WebViewFunctorManager::handleFor(int functor) { std::lock_guard _lock{mLock}; for (auto& iter : mActiveFunctors) { if (iter->id() == functor) { return iter; } } return nullptr; } } // namespace android::uirenderer