Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 1 | #include <jni.h> |
Alex Vakulenko | 4fe6058 | 2017-02-02 11:35:59 -0800 | [diff] [blame^] | 2 | #include <log/log.h> |
| 3 | #include <future> |
Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 4 | |
| 5 | #include "render_thread.h" |
| 6 | #include "shell_view.h" |
| 7 | |
| 8 | namespace android { |
| 9 | namespace dvr { |
| 10 | |
| 11 | RenderThread::RenderThread(JNIEnv* env, jobject class_loader, |
| 12 | jobject android_context) |
| 13 | : jvm_(nullptr), |
| 14 | class_loader_global_ref_(0), |
| 15 | android_context_global_ref_(0), |
| 16 | quit_(false) { |
| 17 | env->GetJavaVM(&jvm_); |
| 18 | |
| 19 | // Create global references so we can access these objects on the render |
| 20 | // thread |
| 21 | class_loader_global_ref_ = env->NewGlobalRef(class_loader); |
| 22 | android_context_global_ref_ = env->NewGlobalRef(android_context); |
| 23 | |
| 24 | std::promise<int> render_thread_init_result_promise; |
| 25 | thread_ = std::thread([this, &render_thread_init_result_promise] { |
| 26 | JNIEnv* render_thread_jni_env = nullptr; |
| 27 | jvm_->AttachCurrentThread(&render_thread_jni_env, nullptr); |
| 28 | RunRenderLoop(&render_thread_init_result_promise); |
| 29 | jvm_->DetachCurrentThread(); |
| 30 | }); |
| 31 | |
| 32 | // Wait to see if the render thread started successfully. If not bail. |
| 33 | int render_thread_init_result = |
| 34 | render_thread_init_result_promise.get_future().get(); |
| 35 | LOG_ALWAYS_FATAL_IF(render_thread_init_result != 0, |
| 36 | "Failed initializing render thread. result=%d", |
| 37 | render_thread_init_result); |
| 38 | } |
| 39 | |
| 40 | RenderThread::~RenderThread() { Quit(); } |
| 41 | |
| 42 | void RenderThread::Quit() { |
| 43 | if (thread_.joinable()) { |
| 44 | quit_ = true; |
| 45 | thread_.join(); |
| 46 | } |
| 47 | |
| 48 | JNIEnv* env = GetJniEnv(); |
| 49 | if (class_loader_global_ref_ != 0) { |
| 50 | env->DeleteGlobalRef(class_loader_global_ref_); |
| 51 | class_loader_global_ref_ = 0; |
| 52 | } |
| 53 | if (android_context_global_ref_ != 0) { |
| 54 | env->DeleteGlobalRef(android_context_global_ref_); |
| 55 | android_context_global_ref_ = 0; |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | void RenderThread::EnableDebug(bool debug) { shell_view_.EnableDebug(debug); } |
| 60 | |
| 61 | void RenderThread::VrMode(bool mode) { shell_view_.VrMode(mode); } |
| 62 | |
| 63 | JNIEnv* RenderThread::GetJniEnv() { |
| 64 | JNIEnv* env; |
| 65 | jvm_->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6); |
| 66 | return env; |
| 67 | } |
| 68 | |
| 69 | void RenderThread::RunRenderLoop( |
| 70 | std::promise<int>* init_result_promise) { |
| 71 | // TODO(steventhomas): Create local refs to work around b/33251144. Remove |
| 72 | // once that bug is fixed. |
| 73 | JNIEnv* env = GetJniEnv(); |
| 74 | jobject class_loader = env->NewLocalRef(class_loader_global_ref_); |
| 75 | jobject android_context = env->NewLocalRef(android_context_global_ref_); |
| 76 | |
| 77 | int init_result = shell_view_.Initialize(env, android_context, class_loader); |
| 78 | init_result += shell_view_.AllocateResources(); |
| 79 | init_result_promise->set_value(init_result); |
| 80 | if (init_result == 0) { |
| 81 | while (!quit_) |
| 82 | shell_view_.DrawFrame(); |
| 83 | } else { |
| 84 | ALOGE("Failed to initialize ShellView"); |
| 85 | } |
| 86 | |
| 87 | env->DeleteLocalRef(class_loader); |
| 88 | env->DeleteLocalRef(android_context); |
| 89 | } |
| 90 | |
| 91 | } // namespace dvr |
| 92 | } // namespace android |