| /* |
| * 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, ¶ms); |
| } |
| |
| 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) { |
| float gabcdef[7]; |
| draw_gl_params.color_space_ptr->transferFn(gabcdef); |
| 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, |
| .transfer_function_g = gabcdef[0], |
| .transfer_function_a = gabcdef[1], |
| .transfer_function_b = gabcdef[2], |
| .transfer_function_c = gabcdef[3], |
| .transfer_function_d = gabcdef[4], |
| .transfer_function_e = gabcdef[5], |
| .transfer_function_f = gabcdef[6], |
| }; |
| 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]; |
| } |
| COMPILE_ASSERT(sizeof(params.color_space_toXYZD50) == sizeof(skcms_Matrix3x3), |
| gamut_transform_size_mismatch); |
| draw_gl_params.color_space_ptr->toXYZD50( |
| reinterpret_cast<skcms_Matrix3x3*>(¶ms.color_space_toXYZD50)); |
| |
| SupportData* support = static_cast<SupportData*>(data); |
| support->callbacks.draw_gl(functor, support->data, ¶ms); |
| } |
| |
| void initializeVk(int functor, void* data, |
| const uirenderer::VkFunctorInitParams& init_vk_params) { |
| SupportData* support = static_cast<SupportData*>(data); |
| VkPhysicalDeviceFeatures2 device_features_2; |
| if (init_vk_params.device_features_2) |
| device_features_2 = *init_vk_params.device_features_2; |
| |
| AwDrawFn_InitVkParams params{ |
| .version = kAwDrawFnVersion, |
| .instance = init_vk_params.instance, |
| .physical_device = init_vk_params.physical_device, |
| .device = init_vk_params.device, |
| .queue = init_vk_params.queue, |
| .graphics_queue_index = init_vk_params.graphics_queue_index, |
| .instance_version = init_vk_params.instance_version, |
| .enabled_instance_extension_names = |
| init_vk_params.enabled_instance_extension_names, |
| .enabled_instance_extension_names_length = |
| init_vk_params.enabled_instance_extension_names_length, |
| .enabled_device_extension_names = |
| init_vk_params.enabled_device_extension_names, |
| .enabled_device_extension_names_length = |
| init_vk_params.enabled_device_extension_names_length, |
| .device_features = nullptr, |
| .device_features_2 = |
| init_vk_params.device_features_2 ? &device_features_2 : nullptr, |
| }; |
| support->callbacks.init_vk(functor, support->data, ¶ms); |
| } |
| |
| void drawVk(int functor, void* data, const uirenderer::VkFunctorDrawParams& draw_vk_params) { |
| SupportData* support = static_cast<SupportData*>(data); |
| float gabcdef[7]; |
| draw_vk_params.color_space_ptr->transferFn(gabcdef); |
| AwDrawFn_DrawVkParams params{ |
| .version = kAwDrawFnVersion, |
| .width = draw_vk_params.width, |
| .height = draw_vk_params.height, |
| .is_layer = draw_vk_params.is_layer, |
| .secondary_command_buffer = draw_vk_params.secondary_command_buffer, |
| .color_attachment_index = draw_vk_params.color_attachment_index, |
| .compatible_render_pass = draw_vk_params.compatible_render_pass, |
| .format = draw_vk_params.format, |
| .transfer_function_g = gabcdef[0], |
| .transfer_function_a = gabcdef[1], |
| .transfer_function_b = gabcdef[2], |
| .transfer_function_c = gabcdef[3], |
| .transfer_function_d = gabcdef[4], |
| .transfer_function_e = gabcdef[5], |
| .transfer_function_f = gabcdef[6], |
| .clip_left = draw_vk_params.clip_left, |
| .clip_top = draw_vk_params.clip_top, |
| .clip_right = draw_vk_params.clip_right, |
| .clip_bottom = draw_vk_params.clip_bottom, |
| }; |
| COMPILE_ASSERT(sizeof(params.color_space_toXYZD50) == sizeof(skcms_Matrix3x3), |
| gamut_transform_size_mismatch); |
| draw_vk_params.color_space_ptr->toXYZD50( |
| reinterpret_cast<skcms_Matrix3x3*>(¶ms.color_space_toXYZD50)); |
| COMPILE_ASSERT(NELEM(params.transform) == NELEM(draw_vk_params.transform), |
| mismatched_transform_matrix_sizes); |
| for (int i = 0; i < NELEM(params.transform); ++i) { |
| params.transform[i] = draw_vk_params.transform[i]; |
| } |
| support->callbacks.draw_vk(functor, support->data, ¶ms); |
| } |
| |
| void postDrawVk(int functor, void* data) { |
| SupportData* support = static_cast<SupportData*>(data); |
| AwDrawFn_PostDrawVkParams params{.version = kAwDrawFnVersion}; |
| support->callbacks.post_draw_vk(functor, support->data, ¶ms); |
| } |
| |
| 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: |
| webview_functor_callbacks.vk.initialize = &initializeVk; |
| webview_functor_callbacks.vk.draw = &drawVk; |
| webview_functor_callbacks.vk.postDraw = &postDrawVk; |
| // TODO(boliu): Remove this once SkiaRecordingCanvas::drawWebViewFunctor |
| // no longer uses GL interop. |
| webview_functor_callbacks.gles.draw = &draw_gl; |
| 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 |