chromium/android_webview/browser/gfx/aw_gl_functor.cc

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "android_webview/browser/gfx/aw_gl_functor.h"

#include "android_webview/public/browser/draw_gl.h"
#include "base/trace_event/trace_event.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"

// Must come after all headers that specialize FromJniType() / ToJniType().
#include "android_webview/browser_jni_headers/AwGLFunctor_jni.h"

using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
using content::BrowserThread;
using jni_zero::AttachCurrentThread;

extern "C" {
static AwDrawGLFunction DrawGLFunction;
static void DrawGLFunction(long view_context,
                           AwDrawGLInfo* draw_info,
                           void* spare) {
  // |view_context| is the value that was returned from the java
  // AwContents.onPrepareDrawGL; this cast must match the code there.
  reinterpret_cast<android_webview::AwGLFunctor*>(view_context)
      ->DrawGL(draw_info);
}
}

namespace android_webview {

namespace {
int g_instance_count = 0;
}

AwGLFunctor::AwGLFunctor(const JavaObjectWeakGlobalRef& java_ref)
    : java_ref_(java_ref),
      render_thread_manager_(content::GetUIThreadTaskRunner({})) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  ++g_instance_count;
}

AwGLFunctor::~AwGLFunctor() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  --g_instance_count;
}

bool AwGLFunctor::RequestInvokeGL(bool wait_for_completion) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  JNIEnv* env = AttachCurrentThread();
  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
  if (!obj)
    return false;
  return Java_AwGLFunctor_requestInvokeGL(env, obj, wait_for_completion);
}

void AwGLFunctor::DetachFunctorFromView() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  JNIEnv* env = AttachCurrentThread();
  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
  if (obj)
    Java_AwGLFunctor_detachFunctorFromView(env, obj);
}

void AwGLFunctor::Destroy(JNIEnv* env) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  java_ref_.reset();
  delete this;
}

void AwGLFunctor::DeleteHardwareRenderer(
    JNIEnv* env,
    const base::android::JavaParamRef<jobject>& obj) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  RenderThreadManager::InsideHardwareReleaseReset release_reset(
      &render_thread_manager_);
  DetachFunctorFromView();

  // Receiving at least one frame is a precondition for
  // initialization (such as looing up GL bindings and constructing
  // hardware_renderer_).
  bool draw_functor_succeeded = RequestInvokeGL(true);
  if (!draw_functor_succeeded) {
    LOG(ERROR) << "Unable to free GL resources. Has the Window leaked?";
    // Calling release on wrong thread intentionally.
    render_thread_manager_.DestroyHardwareRendererOnRT(
        true /* save_restore */, false /* abandon_context */);
  }
}

void AwGLFunctor::DrawGL(AwDrawGLInfo* draw_info) {
  TRACE_EVENT0("android_webview,toplevel", "DrawFunctor");
  bool save_restore = draw_info->version < 3;
  switch (draw_info->mode) {
    case AwDrawGLInfo::kModeSync:
      TRACE_EVENT_INSTANT0("android_webview", "kModeSync",
                           TRACE_EVENT_SCOPE_THREAD);
      render_thread_manager_.CommitFrameOnRT();
      break;
    case AwDrawGLInfo::kModeProcessNoContext:
      LOG(ERROR) << "Received unexpected kModeProcessNoContext";
      render_thread_manager_.DestroyHardwareRendererOnRT(
          save_restore, true /* abandon_context */);
      break;
    case AwDrawGLInfo::kModeProcess:
      render_thread_manager_.DestroyHardwareRendererOnRT(
          save_restore, false /* abandon_context */);
      break;
    case AwDrawGLInfo::kModeDraw: {
      HardwareRendererDrawParams params{
          draw_info->clip_left,   draw_info->clip_top, draw_info->clip_right,
          draw_info->clip_bottom, draw_info->width,    draw_info->height,
      };
      static_assert(std::size(decltype(draw_info->transform){}) ==
                        std::size(params.transform),
                    "transform size mismatch");
      for (unsigned int i = 0; i < std::size(params.transform); ++i) {
        params.transform[i] = draw_info->transform[i];
      }
      render_thread_manager_.DrawOnRT(save_restore, params, OverlaysParams(),
                                      ReportRenderingThreadsCallback());
      break;
    }
  }
}

void AwGLFunctor::RemoveFromCompositorFrameProducer(
    JNIEnv* env,
    const base::android::JavaParamRef<jobject>& obj) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  render_thread_manager_.RemoveFromCompositorFrameProducerOnUI();
}

jlong AwGLFunctor::GetCompositorFrameConsumer(
    JNIEnv* env,
    const base::android::JavaParamRef<jobject>& obj) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  return reinterpret_cast<intptr_t>(GetCompositorFrameConsumer());
}

static jint JNI_AwGLFunctor_GetNativeInstanceCount(JNIEnv* env) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  return g_instance_count;
}

static jlong JNI_AwGLFunctor_GetAwDrawGLFunction(JNIEnv* env) {
  return reinterpret_cast<intptr_t>(&DrawGLFunction);
}

static jlong JNI_AwGLFunctor_Create(
    JNIEnv* env,
    const base::android::JavaParamRef<jobject>& obj) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  return reinterpret_cast<intptr_t>(
      new AwGLFunctor(JavaObjectWeakGlobalRef(env, obj)));
}

}  // namespace android_webview