Index: remoting/client/jni/jni_gl_display_handler.cc |
diff --git a/remoting/client/jni/jni_gl_display_handler.cc b/remoting/client/jni/jni_gl_display_handler.cc |
index 4e86735f96e647f0103743eb6fc41a1ee3061bb0..039a47ee168599409b748ef963194628fbeee8d3 100644 |
--- a/remoting/client/jni/jni_gl_display_handler.cc |
+++ b/remoting/client/jni/jni_gl_display_handler.cc |
@@ -4,17 +4,32 @@ |
#include "remoting/client/jni/jni_gl_display_handler.h" |
+#include <android/native_window_jni.h> |
+#include <array> |
+ |
+#include "base/android/jni_android.h" |
+#include "base/bind.h" |
#include "base/logging.h" |
+#include "base/memory/ptr_util.h" |
#include "jni/GlDisplay_jni.h" |
+#include "remoting/client/cursor_shape_stub_proxy.h" |
+#include "remoting/client/dual_buffer_frame_consumer.h" |
#include "remoting/client/jni/chromoting_jni_runtime.h" |
-#include "remoting/protocol/video_renderer.h" |
+#include "remoting/client/jni/egl_thread_context.h" |
+#include "remoting/client/software_video_renderer.h" |
+#include "remoting/protocol/frame_consumer.h" |
+#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
+ |
namespace remoting { |
JniGlDisplayHandler::JniGlDisplayHandler(ChromotingJniRuntime* runtime) : |
- runtime_(runtime) { |
+ runtime_(runtime), |
+ weak_factory_(this) { |
+ weak_ptr_ = weak_factory_.GetWeakPtr(); |
java_display_.Reset(Java_GlDisplay_createJavaDisplayObject( |
base::android::AttachCurrentThread(), reinterpret_cast<intptr_t>(this))); |
+ renderer_.SetDelegate(weak_ptr_); |
} |
JniGlDisplayHandler::~JniGlDisplayHandler() { |
@@ -30,16 +45,29 @@ void JniGlDisplayHandler::InitializeClient( |
java_client.obj()); |
} |
+void JniGlDisplayHandler::SetCursorShape( |
+ const protocol::CursorShapeInfo& cursor_shape) { |
+ DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); |
+ renderer_.OnCursorShapeChanged(cursor_shape); |
+} |
+ |
std::unique_ptr<protocol::CursorShapeStub> |
JniGlDisplayHandler::CreateCursorShapeStub() { |
- NOTIMPLEMENTED(); |
- return std::unique_ptr<protocol::CursorShapeStub>(); |
+ return base::WrapUnique(new CursorShapeStubProxy( |
+ weak_ptr_, runtime_->display_task_runner())); |
} |
std::unique_ptr<protocol::VideoRenderer> |
JniGlDisplayHandler::CreateVideoRenderer() { |
- NOTIMPLEMENTED(); |
- return std::unique_ptr<protocol::VideoRenderer>(); |
+ DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); |
+ DCHECK(!frame_consumer_); |
+ std::unique_ptr<DualBufferFrameConsumer> consumer = base::WrapUnique( |
+ new DualBufferFrameConsumer( |
+ base::Bind(&GlRenderer::OnFrameReceived, renderer_.GetWeakPtr()), |
+ runtime_->display_task_runner(), |
+ protocol::FrameConsumer::PixelFormat::FORMAT_RGBA)); |
+ frame_consumer_ = consumer->GetWeakPtr(); |
+ return base::WrapUnique(new SoftwareVideoRenderer(std::move(consumer))); |
} |
// static |
@@ -52,7 +80,36 @@ void JniGlDisplayHandler::OnSurfaceCreated( |
const base::android::JavaParamRef<jobject>& caller, |
const base::android::JavaParamRef<jobject>& surface) { |
DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); |
- NOTIMPLEMENTED(); |
+ |
+ // Notifies the Java surface of the canvas size if the surface is recreated. |
+ runtime_->display_task_runner()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&JniGlDisplayHandler::SurfaceCreatedOnDisplayThread, weak_ptr_, |
+ base::android::ScopedJavaGlobalRef<jobject>(env, surface))); |
+} |
+ |
+bool JniGlDisplayHandler::CanRenderFrame() { |
+ DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); |
+ return !rendering_blocked_ && egl_context_ && egl_context_->IsWindowBound(); |
+} |
+ |
+void JniGlDisplayHandler::OnFrameRendered() { |
+ DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); |
+ egl_context_->SwapBuffers(); |
+ if (render_event_enabled_) { |
+ runtime_->ui_task_runner()->PostTask( |
+ FROM_HERE, base::Bind(&JniGlDisplayHandler::NotifyRenderDoneOnUiThread, |
+ java_display_)); |
+ } |
+} |
+ |
+void JniGlDisplayHandler::OnSizeChanged(int width, int height) { |
+ DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); |
+ runtime_->ui_task_runner()->PostTask( |
+ FROM_HERE, base::Bind(&JniGlDisplayHandler::ChangeCanvasSizeOnUiThread, |
+ java_display_, |
+ width, |
+ height)); |
} |
void JniGlDisplayHandler::OnSurfaceChanged( |
@@ -61,14 +118,19 @@ void JniGlDisplayHandler::OnSurfaceChanged( |
int width, |
int height) { |
DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); |
- NOTIMPLEMENTED(); |
+ runtime_->display_task_runner()->PostTask( |
+ FROM_HERE, base::Bind(&GlRenderer::OnSurfaceChanged, |
+ renderer_.GetWeakPtr(), width, height)); |
} |
void JniGlDisplayHandler::OnSurfaceDestroyed( |
JNIEnv* env, |
const base::android::JavaParamRef<jobject>& caller) { |
DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); |
- NOTIMPLEMENTED(); |
+ runtime_->display_task_runner()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&JniGlDisplayHandler::SurfaceDestroyedOnDisplayThread, |
+ weak_ptr_)); |
} |
void JniGlDisplayHandler::OnPixelTransformationChanged( |
@@ -76,16 +138,23 @@ void JniGlDisplayHandler::OnPixelTransformationChanged( |
const base::android::JavaParamRef<jobject>& caller, |
const base::android::JavaParamRef<jfloatArray>& jmatrix) { |
DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); |
- NOTIMPLEMENTED(); |
+ DCHECK(env->GetArrayLength(jmatrix.obj()) == 9); |
+ runtime_->display_task_runner()->PostTask(FROM_HERE, base::Bind( |
+ &JniGlDisplayHandler::ChangePixelTransformationOnDisplayThread, |
+ weak_ptr_, base::android::ScopedJavaGlobalRef<jfloatArray>(jmatrix))); |
} |
void JniGlDisplayHandler::OnCursorPixelPositionChanged( |
JNIEnv* env, |
const base::android::JavaParamRef<jobject>& caller, |
int x, |
- int y) { |
+ int y, |
+ bool followed_by_viewport_move) { |
DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); |
- NOTIMPLEMENTED(); |
+ runtime_->display_task_runner()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&JniGlDisplayHandler::ChangeCursorPositionOnDisplayThread, |
+ weak_ptr_, x, y, followed_by_viewport_move)); |
} |
void JniGlDisplayHandler::OnCursorVisibilityChanged( |
@@ -93,7 +162,10 @@ void JniGlDisplayHandler::OnCursorVisibilityChanged( |
const base::android::JavaParamRef<jobject>& caller, |
bool visible) { |
DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); |
- NOTIMPLEMENTED(); |
+ runtime_->display_task_runner()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&GlRenderer::OnCursorVisibilityChanged, |
+ renderer_.GetWeakPtr(), visible)); |
} |
void JniGlDisplayHandler::OnCursorInputFeedback( |
@@ -103,7 +175,10 @@ void JniGlDisplayHandler::OnCursorInputFeedback( |
int y, |
float diameter) { |
DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); |
- NOTIMPLEMENTED(); |
+ runtime_->display_task_runner()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&GlRenderer::OnCursorInputFeedback, |
+ renderer_.GetWeakPtr(), x, y, diameter)); |
} |
void JniGlDisplayHandler::SetRenderEventEnabled( |
@@ -111,23 +186,74 @@ void JniGlDisplayHandler::SetRenderEventEnabled( |
const base::android::JavaParamRef<jobject>& caller, |
jboolean enabled) { |
DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); |
- NOTIMPLEMENTED(); |
+ runtime_->display_task_runner()->PostTask(FROM_HERE, base::Bind( |
+ &JniGlDisplayHandler::SetRenderEventEnabledOnDisplayThread, weak_ptr_, |
+ enabled)); |
+} |
+ |
+void JniGlDisplayHandler::SetRenderEventEnabledOnDisplayThread(bool enabled) { |
+ DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); |
+ render_event_enabled_ = enabled; |
} |
// static |
-void JniGlDisplayHandler::NotifyRenderEventOnUiThread( |
- base::android::ScopedJavaGlobalRef<jobject> java_client) { |
+void JniGlDisplayHandler::NotifyRenderDoneOnUiThread( |
+ base::android::ScopedJavaGlobalRef<jobject> java_display) { |
Java_GlDisplay_canvasRendered(base::android::AttachCurrentThread(), |
- java_client.obj()); |
+ java_display.obj()); |
+} |
+ |
+void JniGlDisplayHandler::SurfaceCreatedOnDisplayThread( |
+ base::android::ScopedJavaGlobalRef<jobject> surface) { |
+ DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); |
+ renderer_.RequestCanvasSize(); |
+ ANativeWindow* window = ANativeWindow_fromSurface( |
+ base::android::AttachCurrentThread(), surface.obj()); |
+ egl_context_.reset(new EglThreadContext()); |
+ egl_context_->BindToWindow(window); |
+ ANativeWindow_release(window); |
+ renderer_.OnSurfaceCreated(static_cast<int>(egl_context_->client_version())); |
+ runtime_->network_task_runner()->PostTask( |
+ FROM_HERE, base::Bind(&DualBufferFrameConsumer::RequestFullDesktopFrame, |
+ frame_consumer_)); |
+} |
+ |
+void JniGlDisplayHandler::SurfaceDestroyedOnDisplayThread() { |
+ DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); |
+ renderer_.OnSurfaceDestroyed(); |
+ egl_context_.reset(); |
+} |
+ |
+void JniGlDisplayHandler::ChangePixelTransformationOnDisplayThread( |
+ base::android::ScopedJavaGlobalRef<jfloatArray> jmatrix) { |
+ DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); |
+ rendering_blocked_ = false; |
+ JNIEnv* env = base::android::AttachCurrentThread(); |
+ |
+ std::array<float, 9> matrix; |
+ |
+ env->GetFloatArrayRegion(jmatrix.obj(), 0, 9, matrix.data()); |
+ renderer_.OnPixelTransformationChanged(matrix); |
+} |
+ |
+void JniGlDisplayHandler::ChangeCursorPositionOnDisplayThread( |
+ int x, |
+ int y, |
+ bool followed_by_viewport_move) { |
+ DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); |
+ if (followed_by_viewport_move) { |
+ rendering_blocked_ = true; |
+ } |
+ renderer_.OnCursorMoved(x, y); |
} |
// static |
void JniGlDisplayHandler::ChangeCanvasSizeOnUiThread( |
- base::android::ScopedJavaGlobalRef<jobject> java_client, |
+ base::android::ScopedJavaGlobalRef<jobject> java_display, |
int width, |
int height) { |
JNIEnv* env = base::android::AttachCurrentThread(); |
- Java_GlDisplay_changeCanvasSize(env, java_client.obj(), width, height); |
+ Java_GlDisplay_changeCanvasSize(env, java_display.obj(), width, height); |
} |
} // namespace remoting |