Plumb new functor in native/webview

Add plumbing to native/webview for the new functor.
Add a void* data parameter to avoid having to use a thread safe
map for in both the plumbing and in webview.

Test: Compiles and webview runs
Bug: 120997728
Change-Id: I0f9f3acb05688a5afcf95974bc0b3b117f33a8e3
This commit is contained in:
Bo Liu
2018-12-14 19:37:41 -08:00
parent b34e8528ca
commit d6668e7c0c
12 changed files with 210 additions and 43 deletions

View File

@@ -7760,6 +7760,7 @@ package android.webkit {
method public void callDrawGlFunction(android.graphics.Canvas, long, java.lang.Runnable);
method public boolean canInvokeDrawGlFunctor(android.view.View);
method public void detachDrawGlFunctor(android.view.View, long);
method public void drawWebViewFunctor(android.graphics.Canvas, int);
method public android.app.Application getApplication();
method public java.lang.String getDataDirectorySuffix();
method public java.lang.String getErrorString(android.content.Context, int);

View File

@@ -137,6 +137,20 @@ public final class WebViewDelegate {
((RecordingCanvas) canvas).drawGLFunctor2(nativeDrawGLFunctor, releasedRunnable);
}
/**
* Call webview draw functor. See API in draw_fn.h.
* @param canvas a hardware accelerated canvas (see {@link Canvas#isHardwareAccelerated()}).
* @param functor created by AwDrawFn_CreateFunctor in draw_fn.h.
*/
public void drawWebViewFunctor(@NonNull Canvas canvas, int functor) {
if (!(canvas instanceof RecordingCanvas)) {
// Canvas#isHardwareAccelerated() is only true for subclasses of RecordingCanvas.
throw new IllegalArgumentException(canvas.getClass().getName()
+ " is not a RecordingCanvas canvas");
}
((RecordingCanvas) canvas).drawWebViewFunctor(functor);
}
/**
* Detaches the draw GL functor.
*

View File

@@ -37,7 +37,8 @@ RenderMode WebViewFunctor_queryPlatformRenderMode() {
}
}
int WebViewFunctor_create(const WebViewFunctorCallbacks& prototype, RenderMode functorMode) {
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;
@@ -47,7 +48,7 @@ int WebViewFunctor_create(const WebViewFunctorCallbacks& prototype, RenderMode f
ALOGW("Unable to map from GLES platform to a vulkan functor");
return -1;
}
return WebViewFunctorManager::instance().createFunctor(prototype, functorMode);
return WebViewFunctorManager::instance().createFunctor(data, prototype, functorMode);
}
void WebViewFunctor_release(int functor) {
@@ -56,7 +57,9 @@ void WebViewFunctor_release(int functor) {
static std::atomic_int sNextId{1};
WebViewFunctor::WebViewFunctor(const WebViewFunctorCallbacks& callbacks, RenderMode functorMode) {
WebViewFunctor::WebViewFunctor(void* data, const WebViewFunctorCallbacks& callbacks,
RenderMode functorMode)
: mData(data) {
mFunctor = sNextId++;
mCallbacks = callbacks;
mMode = functorMode;
@@ -66,12 +69,12 @@ WebViewFunctor::~WebViewFunctor() {
destroyContext();
ATRACE_NAME("WebViewFunctor::onDestroy");
mCallbacks.onDestroyed(mFunctor);
mCallbacks.onDestroyed(mFunctor, mData);
}
void WebViewFunctor::sync(const WebViewSyncData& syncData) const {
ATRACE_NAME("WebViewFunctor::sync");
mCallbacks.onSync(mFunctor, syncData);
mCallbacks.onSync(mFunctor, mData, syncData);
}
void WebViewFunctor::drawGl(const DrawGlInfo& drawInfo) {
@@ -79,14 +82,14 @@ void WebViewFunctor::drawGl(const DrawGlInfo& drawInfo) {
if (!mHasContext) {
mHasContext = true;
}
mCallbacks.gles.draw(mFunctor, drawInfo);
mCallbacks.gles.draw(mFunctor, mData, drawInfo);
}
void WebViewFunctor::destroyContext() {
if (mHasContext) {
mHasContext = false;
ATRACE_NAME("WebViewFunctor::onContextDestroyed");
mCallbacks.onContextDestroyed(mFunctor);
mCallbacks.onContextDestroyed(mFunctor, mData);
}
}
@@ -95,9 +98,9 @@ WebViewFunctorManager& WebViewFunctorManager::instance() {
return sInstance;
}
int WebViewFunctorManager::createFunctor(const WebViewFunctorCallbacks& callbacks,
int WebViewFunctorManager::createFunctor(void* data, const WebViewFunctorCallbacks& callbacks,
RenderMode functorMode) {
auto object = std::make_unique<WebViewFunctor>(callbacks, functorMode);
auto object = std::make_unique<WebViewFunctor>(data, callbacks, functorMode);
int id = object->id();
auto handle = object->createHandle();
{
@@ -164,4 +167,4 @@ sp<WebViewFunctor::Handle> WebViewFunctorManager::handleFor(int functor) {
return nullptr;
}
} // namespace android::uirenderer
} // namespace android::uirenderer

View File

@@ -29,7 +29,7 @@ class WebViewFunctorManager;
class WebViewFunctor {
public:
WebViewFunctor(const WebViewFunctorCallbacks& callbacks, RenderMode functorMode);
WebViewFunctor(void* data, const WebViewFunctorCallbacks& callbacks, RenderMode functorMode);
~WebViewFunctor();
class Handle : public LightRefBase<Handle> {
@@ -63,6 +63,7 @@ public:
private:
WebViewFunctorCallbacks mCallbacks;
void* const mData;
int mFunctor;
RenderMode mMode;
bool mHasContext = false;
@@ -73,7 +74,7 @@ class WebViewFunctorManager {
public:
static WebViewFunctorManager& instance();
int createFunctor(const WebViewFunctorCallbacks& callbacks, RenderMode functorMode);
int createFunctor(void* data, const WebViewFunctorCallbacks& callbacks, RenderMode functorMode);
void releaseFunctor(int functor);
void onContextDestroyed();
void destroyFunctor(int functor);

View File

@@ -17,6 +17,7 @@
#ifndef FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H
#define FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H
#include <cutils/compiler.h>
#include <private/hwui/DrawGlInfo.h>
namespace android::uirenderer {
@@ -27,7 +28,7 @@ enum class RenderMode {
};
// Static for the lifetime of the process
RenderMode WebViewFunctor_queryPlatformRenderMode();
ANDROID_API RenderMode WebViewFunctor_queryPlatformRenderMode();
struct WebViewSyncData {
bool applyForceDark;
@@ -35,21 +36,21 @@ struct WebViewSyncData {
struct WebViewFunctorCallbacks {
// kModeSync, called on RenderThread
void (*onSync)(int functor, const WebViewSyncData& syncData);
void (*onSync)(int functor, void* data, const WebViewSyncData& syncData);
// Called when either the context is destroyed _or_ when the functor's last reference goes
// away. Will always be called with an active context and always on renderthread.
void (*onContextDestroyed)(int functor);
void (*onContextDestroyed)(int functor, void* data);
// Called when the last reference to the handle goes away and the handle is considered
// irrevocably destroyed. Will always be proceeded by a call to onContextDestroyed if
// this functor had ever been drawn.
void (*onDestroyed)(int functor);
void (*onDestroyed)(int functor, void* data);
union {
struct {
// Called on RenderThread. initialize is guaranteed to happen before this call
void (*draw)(int functor, const DrawGlInfo& params);
void (*draw)(int functor, void* data, const DrawGlInfo& params);
} gles;
// TODO: VK support. The current DrawVkInfo is monolithic and needs to be split up for
// what params are valid on what callbacks
@@ -70,12 +71,12 @@ struct WebViewFunctorCallbacks {
// Creates a new WebViewFunctor from the given prototype. The prototype is copied after
// this function returns. Caller retains full ownership of it.
// Returns -1 if the creation fails (such as an unsupported functorMode + platform mode combination)
int WebViewFunctor_create(const WebViewFunctorCallbacks& prototype, RenderMode functorMode);
ANDROID_API int WebViewFunctor_create(void* data, const WebViewFunctorCallbacks& prototype, RenderMode functorMode);
// May be called on any thread to signal that the functor should be destroyed.
// The functor will receive an onDestroyed when the last usage of it is released,
// and it should be considered alive & active until that point.
void WebViewFunctor_release(int functor);
ANDROID_API void WebViewFunctor_release(int functor);
} // namespace android::uirenderer

View File

@@ -315,24 +315,24 @@ public:
static WebViewFunctorCallbacks createMockFunctor(RenderMode mode) {
auto callbacks = WebViewFunctorCallbacks{
.onSync =
[](int functor, const WebViewSyncData& data) {
[](int functor, void* client_data, const WebViewSyncData& data) {
expectOnRenderThread();
sMockFunctorCounts[functor].sync++;
},
.onContextDestroyed =
[](int functor) {
[](int functor, void* client_data) {
expectOnRenderThread();
sMockFunctorCounts[functor].contextDestroyed++;
},
.onDestroyed =
[](int functor) {
[](int functor, void* client_data) {
expectOnRenderThread();
sMockFunctorCounts[functor].destroyed++;
},
};
switch (mode) {
case RenderMode::OpenGL_ES:
callbacks.gles.draw = [](int functor, const DrawGlInfo& params) {
callbacks.gles.draw = [](int functor, void* client_data, const DrawGlInfo& params) {
expectOnRenderThread();
sMockFunctorCounts[functor].glesDraw++;
};

View File

@@ -100,8 +100,8 @@ TEST(SkiaDisplayList, syncContexts) {
GLFunctorDrawable functorDrawable(&functor, nullptr, &dummyCanvas);
skiaDL.mChildFunctors.push_back(&functorDrawable);
int functor2 = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES),
RenderMode::OpenGL_ES);
int functor2 = WebViewFunctor_create(
nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
auto& counts = TestUtils::countsForFunctor(functor2);
skiaDL.mChildFunctors.push_back(
skiaDL.allocateDrawable<GLFunctorDrawable>(functor2, &dummyCanvas));

View File

@@ -27,8 +27,8 @@ using namespace android;
using namespace android::uirenderer;
TEST(WebViewFunctor, createDestroyGLES) {
int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES),
RenderMode::OpenGL_ES);
int functor = WebViewFunctor_create(
nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
ASSERT_NE(-1, functor);
WebViewFunctor_release(functor);
TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) {
@@ -41,8 +41,8 @@ TEST(WebViewFunctor, createDestroyGLES) {
}
TEST(WebViewFunctor, createSyncHandleGLES) {
int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES),
RenderMode::OpenGL_ES);
int functor = WebViewFunctor_create(
nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
ASSERT_NE(-1, functor);
auto handle = WebViewFunctorManager::instance().handleFor(functor);
ASSERT_TRUE(handle);
@@ -82,8 +82,8 @@ TEST(WebViewFunctor, createSyncHandleGLES) {
}
TEST(WebViewFunctor, createSyncDrawGLES) {
int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES),
RenderMode::OpenGL_ES);
int functor = WebViewFunctor_create(
nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
ASSERT_NE(-1, functor);
auto handle = WebViewFunctorManager::instance().handleFor(functor);
ASSERT_TRUE(handle);
@@ -109,8 +109,8 @@ TEST(WebViewFunctor, createSyncDrawGLES) {
}
TEST(WebViewFunctor, contextDestroyed) {
int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES),
RenderMode::OpenGL_ES);
int functor = WebViewFunctor_create(
nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
ASSERT_NE(-1, functor);
auto handle = WebViewFunctorManager::instance().handleFor(functor);
ASSERT_TRUE(handle);
@@ -151,4 +151,4 @@ TEST(WebViewFunctor, contextDestroyed) {
EXPECT_EQ(2, counts.glesDraw);
EXPECT_EQ(2, counts.contextDestroyed);
EXPECT_EQ(1, counts.destroyed);
}
}

View File

@@ -22,6 +22,7 @@ cc_library_shared {
name: "libwebviewchromium_plat_support",
srcs: [
"draw_functor.cpp",
"draw_gl_functor.cpp",
"draw_vk_functor.cpp",
"functor_utils.cpp",

View File

@@ -129,31 +129,31 @@ struct AwDrawFn_PostDrawVkParams {
// Called on render thread while UI thread is blocked. Called for both GL and
// VK.
typedef void AwDrawFn_OnSync(int functor, AwDrawFn_OnSyncParams* params);
typedef void AwDrawFn_OnSync(int functor, void* data, AwDrawFn_OnSyncParams* params);
// Called on render thread when either the context is destroyed _or_ when the
// functor's last reference goes away. Will always be called with an active
// context. Called for both GL and VK.
typedef void AwDrawFn_OnContextDestroyed(int functor);
typedef void AwDrawFn_OnContextDestroyed(int functor, void* data);
// Called on render thread when the last reference to the handle goes away and
// the handle is considered irrevocably destroyed. Will always be proceeded by
// the handle is considered irrevocably destroyed. Will always be preceded by
// a call to OnContextDestroyed if this functor had ever been drawn. Called for
// both GL and VK.
typedef void AwDrawFn_OnDestroyed(int functor);
typedef void AwDrawFn_OnDestroyed(int functor, void* data);
// Only called for GL.
typedef void AwDrawFn_DrawGL(int functor, AwDrawFn_DrawGLParams* params);
typedef void AwDrawFn_DrawGL(int functor, void* data, AwDrawFn_DrawGLParams* params);
// Initialize vulkan state. Needs to be called again after any
// OnContextDestroyed. Only called for Vulkan.
typedef void AwDrawFn_InitVk(int functor, AwDrawFn_InitVkParams* params);
typedef void AwDrawFn_InitVk(int functor, void* data, AwDrawFn_InitVkParams* params);
// Only called for Vulkan.
typedef void AwDrawFn_DrawVk(int functor, AwDrawFn_DrawVkParams* params);
typedef void AwDrawFn_DrawVk(int functor, void* data, AwDrawFn_DrawVkParams* params);
// Only called for Vulkan.
typedef void AwDrawFn_PostDrawVk(int functor,
typedef void AwDrawFn_PostDrawVk(int functor, void* data,
AwDrawFn_PostDrawVkParams* params);
struct AwDrawFnFunctorCallbacks {
@@ -176,7 +176,7 @@ enum AwDrawFnRenderMode {
typedef AwDrawFnRenderMode AwDrawFn_QueryRenderMode(void);
// Create a functor. |functor_callbacks| should be valid until OnDestroyed.
typedef int AwDrawFn_CreateFunctor(AwDrawFnFunctorCallbacks* functor_callbacks);
typedef int AwDrawFn_CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks);
// May be called on any thread to signal that the functor should be destroyed.
// The functor will receive an onDestroyed when the last usage of it is

View File

@@ -0,0 +1,144 @@
/*
* 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 "draw_fn.h"
#include <jni.h>
#include <private/hwui/WebViewFunctor.h>
#include <utils/Log.h>
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
#define COMPILE_ASSERT(expr, err) \
__unused static const char (err)[(expr) ? 1 : -1] = "";
namespace android {
namespace {
struct SupportData {
void* const data;
AwDrawFnFunctorCallbacks callbacks;
};
void onSync(int functor, void* data,
const uirenderer::WebViewSyncData& syncData) {
AwDrawFn_OnSyncParams params = {
.version = kAwDrawFnVersion,
.apply_force_dark = syncData.applyForceDark,
};
SupportData* support = static_cast<SupportData*>(data);
support->callbacks.on_sync(functor, support->data, &params);
}
void onContextDestroyed(int functor, void* data) {
SupportData* support = static_cast<SupportData*>(data);
support->callbacks.on_context_destroyed(functor, support->data);
}
void onDestroyed(int functor, void* data) {
SupportData* support = static_cast<SupportData*>(data);
support->callbacks.on_destroyed(functor, support->data);
delete support;
}
void draw_gl(int functor, void* data,
const uirenderer::DrawGlInfo& draw_gl_params) {
AwDrawFn_DrawGLParams params = {
.version = kAwDrawFnVersion,
.clip_left = draw_gl_params.clipLeft,
.clip_top = draw_gl_params.clipTop,
.clip_right = draw_gl_params.clipRight,
.clip_bottom = draw_gl_params.clipBottom,
.width = draw_gl_params.width,
.height = draw_gl_params.height,
.is_layer = draw_gl_params.isLayer,
};
COMPILE_ASSERT(NELEM(params.transform) == NELEM(draw_gl_params.transform),
mismatched_transform_matrix_sizes);
for (int i = 0; i < NELEM(params.transform); ++i) {
params.transform[i] = draw_gl_params.transform[i];
}
SupportData* support = static_cast<SupportData*>(data);
support->callbacks.draw_gl(functor, support->data, &params);
}
int CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks) {
static bool callbacks_initialized = false;
static uirenderer::WebViewFunctorCallbacks webview_functor_callbacks = {
.onSync = &onSync,
.onContextDestroyed = &onContextDestroyed,
.onDestroyed = &onDestroyed,
};
if (!callbacks_initialized) {
switch (uirenderer::WebViewFunctor_queryPlatformRenderMode()) {
case uirenderer::RenderMode::OpenGL_ES:
webview_functor_callbacks.gles.draw = &draw_gl;
break;
case uirenderer::RenderMode::Vulkan:
break;
}
callbacks_initialized = true;
}
SupportData* support = new SupportData{
.data = data,
.callbacks = *functor_callbacks,
};
int functor = uirenderer::WebViewFunctor_create(
support, webview_functor_callbacks,
uirenderer::WebViewFunctor_queryPlatformRenderMode());
if (functor <= 0) delete support;
return functor;
}
void ReleaseFunctor(int functor) {
uirenderer::WebViewFunctor_release(functor);
}
AwDrawFnRenderMode QueryRenderMode(void) {
switch (uirenderer::WebViewFunctor_queryPlatformRenderMode()) {
case uirenderer::RenderMode::OpenGL_ES:
return AW_DRAW_FN_RENDER_MODE_OPENGL_ES;
case uirenderer::RenderMode::Vulkan:
return AW_DRAW_FN_RENDER_MODE_VULKAN;
}
}
jlong GetDrawFnFunctionTable() {
static AwDrawFnFunctionTable function_table = {
.version = kAwDrawFnVersion,
.query_render_mode = &QueryRenderMode,
.create_functor = &CreateFunctor,
.release_functor = &ReleaseFunctor,
};
return reinterpret_cast<intptr_t>(&function_table);
}
const char kClassName[] = "com/android/webview/chromium/DrawFunctor";
const JNINativeMethod kJniMethods[] = {
{"nativeGetFunctionTable", "()J",
reinterpret_cast<void*>(GetDrawFnFunctionTable)},
};
} // namespace
void RegisterDrawFunctor(JNIEnv* env) {
jclass clazz = env->FindClass(kClassName);
LOG_ALWAYS_FATAL_IF(!clazz, "Unable to find class '%s'", kClassName);
int res = env->RegisterNatives(clazz, kJniMethods, NELEM(kJniMethods));
LOG_ALWAYS_FATAL_IF(res < 0, "register native methods failed: res=%d", res);
}
} // namespace android

View File

@@ -21,6 +21,7 @@
namespace android {
void RegisterDrawFunctor(JNIEnv* env);
void RegisterDrawGLFunctor(JNIEnv* env);
void RegisterGraphicsUtils(JNIEnv* env);
@@ -30,6 +31,7 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
jint ret = vm->AttachCurrentThread(&env, NULL);
LOG_ALWAYS_FATAL_IF(ret != JNI_OK, "AttachCurrentThread failed");
android::RegisterDrawFunctor(env);
android::RegisterDrawGLFunctor(env);
android::RegisterGraphicsUtils(env);