提交 796259c0 编写于 作者: G Gary Qian 提交者: GitHub

Allow switching to the software rendering backend on Android. (#3719)

* Enable software rendering backend on android. Add "enable-software-rendering" flag.

* Fix variable naming and threading.
上级 9e0eaa15
......@@ -26,6 +26,7 @@ struct Settings {
bool enable_dart_profiling = false;
bool use_test_fonts = false;
bool dart_non_checked_mode = false;
bool enable_software_rendering = false;
std::string aot_snapshot_path;
std::string aot_vm_snapshot_data_filename;
std::string aot_vm_snapshot_instr_filename;
......
......@@ -136,8 +136,7 @@ void Shell::InitStandalone(ftl::CommandLine command_line,
}
}
settings.ipv6 =
command_line.HasOption(FlagForSwitch(Switch::IPv6));
settings.ipv6 = command_line.HasOption(FlagForSwitch(Switch::IPv6));
settings.start_paused =
command_line.HasOption(FlagForSwitch(Switch::StartPaused));
......@@ -145,6 +144,9 @@ void Shell::InitStandalone(ftl::CommandLine command_line,
settings.enable_dart_profiling =
command_line.HasOption(FlagForSwitch(Switch::EnableDartProfiling));
settings.enable_software_rendering =
command_line.HasOption(FlagForSwitch(Switch::EnableSoftwareRendering));
settings.endless_trace_buffer =
command_line.HasOption(FlagForSwitch(Switch::EndlessTraceBuffer));
......
......@@ -58,6 +58,11 @@ DEF_SWITCH(EndlessTraceBuffer,
"This is useful when very old events need to viewed. For example, "
"during application launch. Memory usage will continue to grow "
"indefinitely however.")
DEF_SWITCH(EnableSoftwareRendering,
"enable-software-rendering",
"Enable rendering using the Skia software backend. This is useful"
"when testing Flutter on emulators. By default, Flutter will"
"attempt to either use OpenGL or Vulkan.")
DEF_SWITCH(FLX, "flx", "Specify the the FLX path.")
DEF_SWITCH(Help, "help", "Display this help text.")
DEF_SWITCH(LogTag, "log-tag", "Tag associated with log messages.")
......
......@@ -23,6 +23,8 @@ shared_library("flutter_shell_native") {
"android_surface.h",
"android_surface_gl.cc",
"android_surface_gl.h",
"android_surface_software.h",
"android_surface_software.cc",
"flutter_main.cc",
"flutter_main.h",
"library_loader.cc",
......
......@@ -7,6 +7,8 @@
#include <memory>
#include "flutter/fml/platform/android/jni_util.h"
#include "flutter/fml/platform/android/jni_weak_ref.h"
#include "flutter/shell/common/platform_view.h"
#include "flutter/shell/common/surface.h"
#include "flutter/shell/platform/android/android_native_window.h"
......@@ -33,6 +35,9 @@ class AndroidSurface {
virtual bool SetNativeWindow(ftl::RefPtr<AndroidNativeWindow> window,
PlatformView::SurfaceConfig config = {}) = 0;
virtual void SetFlutterView(
const fml::jni::JavaObjectWeakGlobalRef& flutter_view) = 0;
};
} // namespace shell
......
......@@ -149,4 +149,7 @@ intptr_t AndroidSurfaceGL::GLContextFBO() const {
return 0;
}
void AndroidSurfaceGL::SetFlutterView(
const fml::jni::JavaObjectWeakGlobalRef& flutter_view) {}
} // namespace shell
......@@ -5,6 +5,7 @@
#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_GL_H_
#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_GL_H_
#include <jni.h>
#include <memory>
#include "flutter/shell/gpu/gpu_surface_gl.h"
......@@ -46,6 +47,9 @@ class AndroidSurfaceGL : public GPUSurfaceGLDelegate, public AndroidSurface {
intptr_t GLContextFBO() const override;
void SetFlutterView(
const fml::jni::JavaObjectWeakGlobalRef& flutter_view) override;
private:
ftl::RefPtr<AndroidContextGL> onscreen_context_;
ftl::RefPtr<AndroidContextGL> offscreen_context_;
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/platform/android/android_surface_software.h"
#include "flutter/common/threads.h"
#include "flutter/fml/platform/android/jni_weak_ref.h"
#include "flutter/fml/platform/android/scoped_java_ref.h"
#include "flutter/shell/platform/android/platform_view_android_jni.h"
#include <memory>
#include <vector>
#include "flutter/fml/trace_event.h"
#include "lib/ftl/logging.h"
namespace shell {
AndroidSurfaceSoftware::AndroidSurfaceSoftware() : AndroidSurface() {}
AndroidSurfaceSoftware::~AndroidSurfaceSoftware() = default;
bool AndroidSurfaceSoftware::IsValid() const {
return true;
}
bool AndroidSurfaceSoftware::ResourceContextMakeCurrent() {
// Resource Context always not available on software backend.
return false;
}
std::unique_ptr<Surface> AndroidSurfaceSoftware::CreateGPUSurface() {
if (!IsValid()) {
return nullptr;
}
auto surface = std::make_unique<GPUSurfaceSoftware>(this);
if (!surface->IsValid()) {
return nullptr;
}
return surface;
}
sk_sp<SkSurface> AndroidSurfaceSoftware::AcquireBackingStore(
const SkISize& size) {
TRACE_EVENT0("flutter", "AndroidSurfaceSoftware::AcquireBackingStore");
if (!IsValid()) {
return nullptr;
}
if (sk_surface_ != nullptr &&
SkISize::Make(sk_surface_->width(), sk_surface_->height()) == size) {
// The old and new surface sizes are the same. Nothing to do here.
return sk_surface_;
}
sk_surface_ = SkSurface::MakeRasterN32Premul(
size.fWidth, size.fHeight, nullptr /* SkSurfaceProps as out */);
return sk_surface_;
}
bool AndroidSurfaceSoftware::PresentBackingStore(
sk_sp<SkSurface> backing_store) {
TRACE_EVENT0("flutter", "AndroidSurfaceSoftware::PresentBackingStore");
if (!IsValid() || backing_store == nullptr) {
return false;
}
SkPixmap pixmap;
if (!backing_store->peekPixels(&pixmap)) {
return false;
}
// Some basic sanity checking.
uint64_t expected_pixmap_data_size = pixmap.width() * pixmap.height() * 4;
if (expected_pixmap_data_size != pixmap.getSize64()) {
return false;
}
// Pass the sk_surface buffer to the android FlutterView.
JNIEnv* env = fml::jni::AttachCurrentThread();
// Buffer will be copied into a Bitmap Java-side.
fml::jni::ScopedJavaLocalRef<jobject> direct_buffer(
env,
env->NewDirectByteBuffer(pixmap.writable_addr(), pixmap.getSize64()));
FlutterViewUpdateSoftwareBuffer(env, flutter_view_.get(env).obj(),
direct_buffer.obj(), pixmap.width(),
pixmap.height());
return true;
}
void AndroidSurfaceSoftware::TeardownOnScreenContext() {}
SkISize AndroidSurfaceSoftware::OnScreenSurfaceSize() const {
return SkISize();
}
bool AndroidSurfaceSoftware::OnScreenSurfaceResize(const SkISize& size) const {
return true;
}
bool AndroidSurfaceSoftware::SetNativeWindow(
ftl::RefPtr<AndroidNativeWindow> window,
PlatformView::SurfaceConfig config) {
return true;
}
void AndroidSurfaceSoftware::SetFlutterView(
const fml::jni::JavaObjectWeakGlobalRef& flutter_view) {
flutter_view_ = flutter_view;
}
} // namespace shell
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_SOFTWARE_H_
#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_SOFTWARE_H_
#include "flutter/fml/platform/android/jni_weak_ref.h"
#include "flutter/fml/platform/android/scoped_java_ref.h"
#include "flutter/shell/gpu/gpu_surface_software.h"
#include "flutter/shell/platform/android/android_surface.h"
#include "lib/ftl/macros.h"
namespace shell {
class AndroidSurfaceSoftware : public AndroidSurface,
public GPUSurfaceSoftwareDelegate {
public:
AndroidSurfaceSoftware();
~AndroidSurfaceSoftware() override;
bool IsValid() const override;
bool ResourceContextMakeCurrent() override;
std::unique_ptr<Surface> CreateGPUSurface() override;
sk_sp<SkSurface> AcquireBackingStore(const SkISize& size) override;
bool PresentBackingStore(sk_sp<SkSurface> backing_store) override;
void TeardownOnScreenContext() override;
SkISize OnScreenSurfaceSize() const override;
bool OnScreenSurfaceResize(const SkISize& size) const override;
bool SetNativeWindow(ftl::RefPtr<AndroidNativeWindow> window,
PlatformView::SurfaceConfig config) override;
void SetFlutterView(
const fml::jni::JavaObjectWeakGlobalRef& flutter_view) override;
private:
sk_sp<SkSurface> sk_surface_;
fml::jni::JavaObjectWeakGlobalRef flutter_view_;
FTL_DISALLOW_COPY_AND_ASSIGN(AndroidSurfaceSoftware);
};
} // namespace shell
#endif // FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_SOFTWARE_H_
......@@ -68,6 +68,9 @@ bool AndroidSurfaceVulkan::ResourceContextMakeCurrent() {
return false;
}
void AndroidSurfaceVulkan::SetFlutterView(
const fml::jni::JavaObjectWeakGlobalRef& flutter_view) {}
bool AndroidSurfaceVulkan::SetNativeWindow(
ftl::RefPtr<AndroidNativeWindow> window,
PlatformView::SurfaceConfig config) {
......
......@@ -5,6 +5,7 @@
#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_VULKAN_H_
#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_VULKAN_H_
#include <jni.h>
#include <memory>
#include "flutter/shell/platform/android/android_native_window.h"
#include "flutter/shell/platform/android/android_surface.h"
......@@ -34,6 +35,9 @@ class AndroidSurfaceVulkan : public AndroidSurface {
bool SetNativeWindow(ftl::RefPtr<AndroidNativeWindow> window,
PlatformView::SurfaceConfig config) override;
void SetFlutterView(
const fml::jni::JavaObjectWeakGlobalRef& flutter_view) override;
private:
ftl::RefPtr<vulkan::VulkanProcTable> proc_table_;
ftl::RefPtr<AndroidNativeWindow> native_window_;
......
......@@ -13,6 +13,9 @@ import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Matrix;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
......@@ -81,6 +84,9 @@ public class FlutterView extends SurfaceView
private final BroadcastReceiver mDiscoveryReceiver;
private final List<ActivityLifecycleListener> mActivityLifecycleListeners;
private long mNativePlatformView;
private boolean mIsSoftwareRenderingEnabled = false; // using the software renderer or not
private volatile Bitmap mSoftwareRenderingBitmap;
public FlutterView(Context context) {
this(context, null);
......@@ -89,6 +95,8 @@ public class FlutterView extends SurfaceView
public FlutterView(Context context, AttributeSet attrs) {
super(context, attrs);
mIsSoftwareRenderingEnabled = nativeGetIsSoftwareRenderingEnabled();
mMetrics = new ViewportMetrics();
mMetrics.devicePixelRatio = context.getResources().getDisplayMetrics().density;
setFocusable(true);
......@@ -198,6 +206,21 @@ public class FlutterView extends SurfaceView
return super.onKeyDown(keyCode, event);
}
@Override
protected void onDraw(Canvas canvas) {
if (mSoftwareRenderingBitmap != null) {
canvas.drawBitmap(mSoftwareRenderingBitmap, new Matrix(), new Paint());
}
}
// This method will be called on the GPU Thread.
public void updateSoftwareBuffer(ByteBuffer buffer, int width, int height) {
Bitmap newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
newBitmap.copyPixelsFromBuffer(buffer);
mSoftwareRenderingBitmap = newBitmap;
postInvalidate();
}
public void addActivityLifecycleListener(ActivityLifecycleListener listener) {
mActivityLifecycleListeners.add(listener);
}
......@@ -593,6 +616,8 @@ public class FlutterView extends SurfaceView
private static native void nativeInvokePlatformMessageEmptyResponseCallback(
long nativePlatformViewAndroid, int responseId);
private static native boolean nativeGetIsSoftwareRenderingEnabled();
private void updateViewportMetrics() {
nativeSetViewportMetrics(mNativePlatformView,
mMetrics.devicePixelRatio,
......@@ -697,7 +722,11 @@ public class FlutterView extends SurfaceView
}
private void resetWillNotDraw() {
if (!mIsSoftwareRenderingEnabled) {
setWillNotDraw(!(mAccessibilityEnabled || mTouchExplorationEnabled));
} else {
setWillNotDraw(false);
}
}
@Override
......
......@@ -11,12 +11,14 @@
#include <utility>
#include "flutter/common/settings.h"
#include "flutter/common/threads.h"
#include "flutter/fml/platform/android/jni_util.h"
#include "flutter/fml/platform/android/scoped_java_ref.h"
#include "flutter/runtime/dart_service_isolate.h"
#include "flutter/shell/gpu/gpu_rasterizer.h"
#include "flutter/shell/platform/android/android_surface_gl.h"
#include "flutter/shell/platform/android/android_surface_software.h"
#include "flutter/shell/platform/android/platform_view_android_jni.h"
#include "flutter/shell/platform/android/vsync_waiter_android.h"
#include "lib/ftl/functional/make_copyable.h"
......@@ -45,8 +47,7 @@ class PlatformMessageResponseAndroid : public blink::PlatformMessageResponse {
void CompleteEmpty() override {
ftl::RefPtr<PlatformMessageResponseAndroid> self(this);
blink::Threads::Platform()->PostTask(
ftl::MakeCopyable([ self ]() mutable {
blink::Threads::Platform()->PostTask(ftl::MakeCopyable([self]() mutable {
if (!self->view_)
return;
static_cast<PlatformViewAndroid*>(self->view_.get())
......@@ -85,7 +86,19 @@ static std::unique_ptr<AndroidSurface> InitializePlatformSurfaceVulkan() {
#endif // SHELL_ENABLE_VULKAN
}
static std::unique_ptr<AndroidSurface> InitializePlatformSurfaceSoftware() {
auto surface = std::make_unique<AndroidSurfaceSoftware>();
return surface->IsValid() ? std::move(surface) : nullptr;
}
static std::unique_ptr<AndroidSurface> InitializePlatformSurface() {
if (blink::Settings::Get().enable_software_rendering) {
if (auto surface = InitializePlatformSurfaceSoftware()) {
FTL_DLOG(INFO) << "Software surface initialized.";
return surface;
}
}
if (auto surface = InitializePlatformSurfaceVulkan()) {
FTL_DLOG(INFO) << "Vulkan surface initialized.";
return surface;
......@@ -252,8 +265,8 @@ void PlatformViewAndroid::DispatchEmptyPlatformMessage(JNIEnv* env,
}
PlatformView::DispatchPlatformMessage(
ftl::MakeRefCounted<blink::PlatformMessage>(
std::move(name), std::move(response)));
ftl::MakeRefCounted<blink::PlatformMessage>(std::move(name),
std::move(response)));
}
void PlatformViewAndroid::DispatchPointerDataPacket(JNIEnv* env,
......@@ -282,8 +295,8 @@ void PlatformViewAndroid::InvokePlatformMessageResponseCallback(
return;
uint8_t* response_data =
static_cast<uint8_t*>(env->GetDirectBufferAddress(java_response_data));
std::vector<uint8_t> response = std::vector<uint8_t>(response_data,
response_data + java_response_position);
std::vector<uint8_t> response = std::vector<uint8_t>(
response_data, response_data + java_response_position);
auto message_response = std::move(it->second);
pending_responses_.erase(it);
message_response->Complete(std::move(response));
......@@ -316,22 +329,22 @@ void PlatformViewAndroid::HandlePlatformMessage(
}
auto java_channel = fml::jni::StringToJavaString(env, message->channel());
if (message->hasData()) {
fml::jni::ScopedJavaLocalRef<jbyteArray> message_array(env,
env->NewByteArray(message->data().size()));
fml::jni::ScopedJavaLocalRef<jbyteArray> message_array(
env, env->NewByteArray(message->data().size()));
env->SetByteArrayRegion(
message_array.obj(), 0, message->data().size(),
reinterpret_cast<const jbyte*>(message->data().data()));
message = nullptr;
// This call can re-enter in InvokePlatformMessageXxxResponseCallback.
FlutterViewHandlePlatformMessage(
env, view.obj(), java_channel.obj(), message_array.obj(), response_id);
FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(),
message_array.obj(), response_id);
} else {
message = nullptr;
// This call can re-enter in InvokePlatformMessageXxxResponseCallback.
FlutterViewHandlePlatformMessage(
env, view.obj(), java_channel.obj(), nullptr, response_id);
FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(),
nullptr, response_id);
}
}
......@@ -344,8 +357,8 @@ void PlatformViewAndroid::HandlePlatformMessageResponse(
if (view.is_null())
return;
fml::jni::ScopedJavaLocalRef<jbyteArray> data_array(env,
env->NewByteArray(data.size()));
fml::jni::ScopedJavaLocalRef<jbyteArray> data_array(
env, env->NewByteArray(data.size()));
env->SetByteArrayRegion(data_array.obj(), 0, data.size(),
reinterpret_cast<const jbyte*>(data.data()));
......@@ -353,8 +366,7 @@ void PlatformViewAndroid::HandlePlatformMessageResponse(
data_array.obj());
}
void PlatformViewAndroid::HandlePlatformMessageEmptyResponse(
int response_id) {
void PlatformViewAndroid::HandlePlatformMessageEmptyResponse(int response_id) {
JNIEnv* env = fml::jni::AttachCurrentThread();
fml::jni::ScopedJavaLocalRef<jobject> view = flutter_view_.get(env);
......@@ -433,8 +445,8 @@ void PlatformViewAndroid::UpdateSemantics(
buffer_int32[position++] = child;
}
fml::jni::ScopedJavaLocalRef<jobject> direct_buffer(env,
env->NewDirectByteBuffer(buffer.data(), buffer.size()));
fml::jni::ScopedJavaLocalRef<jobject> direct_buffer(
env, env->NewDirectByteBuffer(buffer.data(), buffer.size()));
FlutterViewUpdateSemantics(
env, view.obj(), direct_buffer.obj(),
......
......@@ -97,8 +97,10 @@ class PlatformViewAndroid : public PlatformView {
void set_flutter_view(const fml::jni::JavaObjectWeakGlobalRef& flutter_view) {
flutter_view_ = flutter_view;
android_surface_->SetFlutterView(flutter_view);
}
private:
const std::unique_ptr<AndroidSurface> android_surface_;
fml::jni::JavaObjectWeakGlobalRef flutter_view_;
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "flutter/shell/platform/android/platform_view_android_jni.h"
#include "flutter/common/settings.h"
#include "flutter/fml/platform/android/jni_util.h"
#include "flutter/fml/platform/android/jni_weak_ref.h"
#include "flutter/fml/platform/android/scoped_java_ref.h"
......@@ -48,6 +49,17 @@ void FlutterViewUpdateSemantics(JNIEnv* env,
FTL_CHECK(env->ExceptionCheck() == JNI_FALSE);
}
static jmethodID g_handle_platform_update_software_buffer = nullptr;
void FlutterViewUpdateSoftwareBuffer(JNIEnv* env,
jobject obj,
jobject buffer,
jint width,
jint height) {
env->CallVoidMethod(obj, g_handle_platform_update_software_buffer, buffer,
width, height);
FTL_CHECK(env->ExceptionCheck() == JNI_FALSE);
}
// Called By Java
static jlong Attach(JNIEnv* env, jclass clazz, jobject flutterView) {
......@@ -179,6 +191,10 @@ static void SetSemanticsEnabled(JNIEnv* env,
return PLATFORM_VIEW->SetSemanticsEnabled(enabled);
}
static jboolean GetIsSoftwareRendering(JNIEnv* env, jobject jcaller) {
return blink::Settings::Get().enable_software_rendering;
}
static void InvokePlatformMessageResponseCallback(JNIEnv* env,
jobject jcaller,
jlong platform_view,
......@@ -193,8 +209,8 @@ static void InvokePlatformMessageEmptyResponseCallback(JNIEnv* env,
jobject jcaller,
jlong platform_view,
jint responseId) {
return PLATFORM_VIEW->InvokePlatformMessageEmptyResponseCallback(
env, responseId);
return PLATFORM_VIEW->InvokePlatformMessageEmptyResponseCallback(env,
responseId);
}
bool PlatformViewAndroid::Register(JNIEnv* env) {
......@@ -269,7 +285,8 @@ bool PlatformViewAndroid::Register(JNIEnv* env) {
{
.name = "nativeDispatchEmptyPlatformMessage",
.signature = "(JLjava/lang/String;I)V",
.fnPtr = reinterpret_cast<void*>(&shell::DispatchEmptyPlatformMessage),
.fnPtr =
reinterpret_cast<void*>(&shell::DispatchEmptyPlatformMessage),
},
{
.name = "nativeDispatchPointerDataPacket",
......@@ -298,6 +315,11 @@ bool PlatformViewAndroid::Register(JNIEnv* env) {
.fnPtr = reinterpret_cast<void*>(
&shell::InvokePlatformMessageEmptyResponseCallback),
},
{
.name = "nativeGetIsSoftwareRenderingEnabled",
.signature = "()Z",
.fnPtr = reinterpret_cast<void*>(&shell::GetIsSoftwareRendering),
},
};
if (env->RegisterNatives(g_flutter_view_class->obj(), methods,
......@@ -328,6 +350,13 @@ bool PlatformViewAndroid::Register(JNIEnv* env) {
return false;
}
g_handle_platform_update_software_buffer =
env->GetMethodID(g_flutter_view_class->obj(), "updateSoftwareBuffer",
"(Ljava/nio/ByteBuffer;II)V");
if (g_handle_platform_update_software_buffer == nullptr) {
return false;
}
return true;
}
......
......@@ -27,6 +27,12 @@ void FlutterViewUpdateSemantics(JNIEnv* env,
jobject buffer,
jobjectArray strings);
void FlutterViewUpdateSoftwareBuffer(JNIEnv* env,
jobject obj,
jobject buffer,
jint width,
jint height);
} // namespace shell
#endif // FLUTTER_SHELL_PLATFORM_ANDROID_PLATFORM_VIEW_ANDROID_JNI_H_
......@@ -1420,6 +1420,8 @@ FILE: ../../../flutter/lib/ui/painting/vertices.cc
FILE: ../../../flutter/lib/ui/painting/vertices.h
FILE: ../../../flutter/shell/gpu/gpu_surface_software.cc
FILE: ../../../flutter/shell/gpu/gpu_surface_software.h
FILE: ../../../flutter/shell/platform/android/android_surface_software.cc
FILE: ../../../flutter/shell/platform/android/android_surface_software.h
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/BasicMessageChannel.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/BinaryCodec.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/EventChannel.java
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册