diff options
Diffstat (limited to 'chromium/content/common')
385 files changed, 9400 insertions, 28472 deletions
diff --git a/chromium/content/common/BUILD.gn b/chromium/content/common/BUILD.gn index 0a7e72e321d..cc769b07c45 100644 --- a/chromium/content/common/BUILD.gn +++ b/chromium/content/common/BUILD.gn @@ -126,21 +126,16 @@ if (is_mac) { } source_set("common") { - # Only the public target should depend on this. All other targets (even - # internal content ones) should depend on the public one. - visibility = [ "//content/public/common:common_sources" ] + # Targets external to content should always link to the public API. + # In addition, targets outside of the content component (shell and tests) + # must not link to this because it will duplicate the code in the component + # build. + visibility = [ "//content/*" ] sources = rebase_path(content_common_gypi_values.private_common_sources, ".", "//content") - # These files are only built in a GN build because they bring in - # dependencies that don't build with GYP. - sources += [ - "mojo/mojo_shell_connection_impl.cc", - "mojo/mojo_shell_connection_impl.h", - ] - configs += [ "//content:content_implementation", "//build/config:precompiled_headers", @@ -148,69 +143,77 @@ source_set("common") { ] public_deps = [ + ":mojo_bindings", "//gpu/command_buffer/common", "//ipc", "//third_party/WebKit/public:blink_headers", ] deps = [ "//base", + "//base/third_party/dynamic_annotations", "//build/util:webkit_version", + "//cc", + "//cc/blink", + "//cc/surfaces", "//components/mus/public/interfaces", "//components/tracing", "//components/tracing:startup_tracing", + "//device/bluetooth", + + # TODO: the dependency on gl_in_process_context should be decoupled from + # content and moved to android_webview. See crbug.com/365797. + "//gpu", + "//gpu/blink", + "//gpu/command_buffer/client:gl_in_process_context", + "//gpu/command_buffer/client:gles2_c_lib", + "//gpu/command_buffer/client:gles2_cmd_helper", + "//gpu/command_buffer/client:gles2_implementation", "//gpu/command_buffer/client:gles2_interface", "//gpu/command_buffer/common:gles2_utils", - "//mojo/converters/network", - "//mojo/runner/child:lib", + "//gpu/command_buffer/service", + "//gpu/ipc/client", + "//gpu/ipc/common", + + # TODO(markdittmer): This should be removed once content/common/gpu/media + # is refactored into media/ipc. + "//gpu/ipc/service", + "//gpu/skia_bindings", + "//ipc", + "//ipc/mojo", + "//media", + "//media:shared_memory_support", + "//media/gpu/ipc/client", + "//media/gpu/ipc/common", + "//media/midi", + "//mojo/common:common_base", + "//mojo/edk/system", + "//mojo/shell", "//mojo/shell/public/cpp", + "//mojo/shell/public/interfaces", + "//mojo/shell/runner/common", "//net", + "//sandbox", "//skia", + "//storage/common", + "//third_party/WebKit/public:blink", + "//third_party/boringssl", "//third_party/icu", "//third_party/libjingle", + "//third_party/webrtc/base:rtc_base", "//ui/accessibility", "//ui/base", "//ui/base/ime", - "//ui/events/ipc:events_ipc", + "//ui/events/ipc", "//ui/gfx", "//ui/gfx/geometry", "//ui/gfx/ipc", + "//ui/gfx/ipc/skia", + "//ui/gl", "//ui/shell_dialogs", "//url", + "//url/ipc:url_ipc", ] - if (!is_ios) { - deps += [ - "//cc", - "//device/bluetooth", - "//ipc", - "//ipc/mojo", - - # TODO: the dependency on gl_in_process_context should be decoupled from - # content and moved to android_webview. See crbug.com/365797. - ":mojo_bindings", - "//gpu/blink", - "//gpu/command_buffer/client:gl_in_process_context", - "//gpu/command_buffer/client:gles2_c_lib", - "//gpu/command_buffer/client:gles2_cmd_helper", - "//gpu/command_buffer/client:gles2_implementation", - "//gpu/command_buffer/service", - "//gpu/ipc", - "//gpu/skia_bindings", - "//media", - "//media:shared_memory_support", - "//media/midi", - "//mojo/common:common_base", - "//mojo/environment:chromium", - "//mojo/shell/public/interfaces", - "//sandbox", - "//storage/common", - "//third_party/WebKit/public:blink", - "//third_party/boringssl", - "//third_party/mojo/src/mojo/edk/system", - "//ui/gl", - ] - } - defines = [] include_dirs = [] libs = [] @@ -227,17 +230,13 @@ source_set("common") { if (is_mac) { sources += [ - "gpu/client/gpu_memory_buffer_impl_io_surface.cc", - "gpu/client/gpu_memory_buffer_impl_io_surface.h", - "gpu/gpu_memory_buffer_factory_io_surface.cc", - "gpu/gpu_memory_buffer_factory_io_surface.h", "gpu/media/vt_mac.h", "gpu/media/vt_video_decode_accelerator_mac.cc", "gpu/media/vt_video_decode_accelerator_mac.h", + "gpu/media/vt_video_encode_accelerator_mac.cc", + "gpu/media/vt_video_encode_accelerator_mac.h", ] + get_target_outputs(":libvt_generate_stubs") - sources -= [ "plugin_list_posix.cc" ] - deps += [ ":libvt_generate_stubs", "//content:resources", @@ -248,6 +247,9 @@ source_set("common") { ] lib_dirs = [ "$mac_sdk_path/usr/lib" ] libs += [ + "AVFoundation.framework", + "CoreMedia.framework", + "CoreVideo.framework", "IOSurface.framework", "OpenGL.framework", "QuartzCore.framework", @@ -256,13 +258,6 @@ source_set("common") { } if (is_android) { - sources += [ - "gpu/client/gpu_memory_buffer_impl_surface_texture.cc", - "gpu/client/gpu_memory_buffer_impl_surface_texture.h", - "gpu/gpu_memory_buffer_factory_surface_texture.cc", - "gpu/gpu_memory_buffer_factory_surface_texture.h", - ] - deps += [ "//content/public/android:common_aidl", "//content/public/android:jni", @@ -278,26 +273,12 @@ source_set("common") { deps += [ "//ppapi/proxy:ipc_sources" ] } - if (is_ios) { - sources -= [ "user_agent.cc" ] - assert(false, "Need to add lots of conditions here") - } - if (use_ozone) { - configs += [ "//ui/ozone:vgem_map" ] - - deps += [ - "//ui/ozone:ozone", - "//ui/ozone:ozone_base", - ] + deps += [ "//ui/ozone" ] } else { sources -= [ "cursors/webcursor_ozone.cc", "font_list_ozone.cc", - "gpu/client/gpu_memory_buffer_impl_ozone_native_pixmap.cc", - "gpu/client/gpu_memory_buffer_impl_ozone_native_pixmap.h", - "gpu/gpu_memory_buffer_factory_ozone_native_pixmap.cc", - "gpu/gpu_memory_buffer_factory_ozone_native_pixmap.h", ] } @@ -320,17 +301,6 @@ source_set("common") { sources -= [ "font_list_pango.cc" ] } - if (use_x11) { - configs += [ - "//build/config/linux:xcomposite", - "//third_party/khronos:khronos_headers", - ] - - if (current_cpu != "arm" || !is_chromeos) { - sources += [ "gpu/x_util.h" ] - } - } - if (enable_plugins) { deps += [ "//ppapi/shared_impl" ] } else { @@ -344,7 +314,6 @@ source_set("common") { "pepper_renderer_instance_data.h", "plugin_list.cc", "plugin_list.h", - "plugin_list_posix.cc", "sandbox_util.cc", ] } @@ -373,16 +342,14 @@ source_set("common") { ] } - if (enable_mojo_media == "gpu") { - deps += [ "//media/mojo/services:application" ] + if (mojo_media_host == "gpu") { + deps += [ "//media/mojo/services:cdm_service" ] } } if (is_chromeos) { sources += [ "gpu/media/accelerated_video_decoder.h", - "gpu/media/gpu_arc_video_service.cc", - "gpu/media/gpu_arc_video_service.h", "gpu/media/h264_decoder.cc", "gpu/media/h264_decoder.h", "gpu/media/h264_dpb.cc", @@ -396,7 +363,6 @@ source_set("common") { "gpu/media/vp9_picture.cc", "gpu/media/vp9_picture.h", ] - deps += [ "//components/arc" ] if (use_v4lplugin) { defines += [ "USE_LIBV4L2" ] sources += get_target_outputs(":libv4l2_generate_stubs") @@ -531,30 +497,50 @@ source_set("common") { } } +# See comment at the top of //content/BUILD.gn for how this works. +group("for_content_tests") { + visibility = [ "//content/test/*" ] + if (!is_component_build) { + public_deps = [ + ":common", + ] + } +} + mojom("mojo_bindings") { + # This interface is internal to content. However, this is not exported from + # the content component shared library. Code in content but outside of the + # content component (content/test or content/shell) should link to this + # directly. + visibility = [ "//content/*" ] + sources = [ "application_setup.mojom", "background_sync_service.mojom", - "geolocation_service.mojom", "image_downloader/image_downloader.mojom", - "permission_service.mojom", + "leveldb_wrapper.mojom", "presentation/presentation_service.mojom", "process_control.mojom", "render_frame_setup.mojom", "render_widget_window_tree_client_factory.mojom", - "service_port_service.mojom", "service_worker/embedded_worker_setup.mojom", + "storage_partition_service.mojom", "vr_service.mojom", "wake_lock_service.mojom", ] import_dirs = [ "//mojo/services" ] - deps = [ + typemaps = [ "//url/mojo/origin.typemap" ] + + public_deps = [ + "//components/leveldb/public/interfaces", "//components/mus/public/interfaces", "//content/public/common:mojo_bindings", "//mojo/shell/public/interfaces", "//skia/public/interfaces", + "//third_party/WebKit/public:mojo_bindings", "//ui/mojo/geometry:interfaces", + "//url/mojo:url_mojom_origin", ] } diff --git a/chromium/content/common/DEPS b/chromium/content/common/DEPS index 3ba16c40dc2..caf3f5d1ead 100644 --- a/chromium/content/common/DEPS +++ b/chromium/content/common/DEPS @@ -6,7 +6,7 @@ include_rules = [ # No inclusion of WebKit from the browser, other than strictly enum/POD, # header-only types, and some selected common code. "-third_party/WebKit", - "+third_party/WebKit/public/platform/WebBatteryStatus.h", + "+third_party/WebKit/public/platform/WebAddressSpace.h", "+third_party/WebKit/public/platform/WebCircularGeofencingRegion.h", "+third_party/WebKit/public/platform/WebCString.h", "+third_party/WebKit/public/platform/modules/device_orientation/WebDeviceMotionData.h", @@ -65,10 +65,3 @@ include_rules = [ "+third_party/WebKit/public/web/mac/WebScrollbarTheme.h", "+third_party/WebKit/public/web/win/WebFontRendering.h" ] - -specific_include_rules = { -# Java bridge code passes NPAPI types to the browser process. Crazy! - "java_bridge_messages\.h": [ - "+content/child" - ] -} diff --git a/chromium/content/common/OWNERS b/chromium/content/common/OWNERS index df1d46c544f..8ded209736c 100644 --- a/chromium/content/common/OWNERS +++ b/chromium/content/common/OWNERS @@ -72,8 +72,17 @@ per-file *font_config_ipc_linux*=wfh@chromium.org # Changes to Mojo interfaces require a security review to avoid # introducing new sandbox escapes. per-file *.mojom=set noparent +per-file *.mojom=dcheng@chromium.org +per-file *.mojom=inferno@chromium.org +per-file *.mojom=jln@chromium.org +per-file *.mojom=jschuh@chromium.org +per-file *.mojom=kenrb@chromium.org +per-file *.mojom=mkwst@chromium.org +per-file *.mojom=nasko@chromium.org per-file *.mojom=palmer@chromium.org per-file *.mojom=tsepez@chromium.org +per-file *.mojom=wfh@chromium.org + # Accessibility per-file accessibility_node_data.*=dmazzoni@chromium.org @@ -91,3 +100,7 @@ per-file cc_messages_perftest.cc=danakj@chromium.org # DirectWrite per-file dwrite_font_platform_win*=scottmg@chromium.org per-file font_warmup_win.cc=scottmg@chromium.org + +# Web Notifications +per-file notification_constants.h=peter@chromium.org +per-file notification_constants.h=mvanouwerkerk@chromium.org diff --git a/chromium/content/common/accelerated_surface_buffers_swapped_params_mac.cc b/chromium/content/common/accelerated_surface_buffers_swapped_params_mac.cc new file mode 100644 index 00000000000..c9eb1d204ce --- /dev/null +++ b/chromium/content/common/accelerated_surface_buffers_swapped_params_mac.cc @@ -0,0 +1,14 @@ +// Copyright 2016 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 "content/common/accelerated_surface_buffers_swapped_params_mac.h" + +namespace content { +AcceleratedSurfaceBuffersSwappedParams::AcceleratedSurfaceBuffersSwappedParams() + : surface_id(0), ca_context_id(0), scale_factor(1.f) {} + +AcceleratedSurfaceBuffersSwappedParams:: + ~AcceleratedSurfaceBuffersSwappedParams() {} + +} // namespace content diff --git a/chromium/content/common/accelerated_surface_buffers_swapped_params_mac.h b/chromium/content/common/accelerated_surface_buffers_swapped_params_mac.h new file mode 100644 index 00000000000..71fb4ffd777 --- /dev/null +++ b/chromium/content/common/accelerated_surface_buffers_swapped_params_mac.h @@ -0,0 +1,28 @@ +// Copyright 2016 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 CONTENT_COMMON_ACCELERATED_SURFACE_BUFFERS_SWAPPED_PARAMS_MAC_H_ +#define CONTENT_COMMON_ACCELERATED_SURFACE_BUFFERS_SWAPPED_PARAMS_MAC_H_ + +#include "ui/base/cocoa/remote_layer_api.h" +#include "ui/events/latency_info.h" +#include "ui/gfx/mac/io_surface.h" + +namespace content { + +struct AcceleratedSurfaceBuffersSwappedParams { + AcceleratedSurfaceBuffersSwappedParams(); + ~AcceleratedSurfaceBuffersSwappedParams(); + + int32_t surface_id; + CAContextID ca_context_id; + gfx::ScopedRefCountedIOSurfaceMachPort io_surface; + gfx::Size size; + float scale_factor; + std::vector<ui::LatencyInfo> latency_info; +}; + +} // namespace content + +#endif // CONTENT_COMMON_ACCELERATED_SURFACE_BUFFERS_SWAPPED_PARAMS_MAC_H_ diff --git a/chromium/content/common/accessibility_messages.h b/chromium/content/common/accessibility_messages.h index f30b5e41660..2a300eab93a 100644 --- a/chromium/content/common/accessibility_messages.h +++ b/chromium/content/common/accessibility_messages.h @@ -8,7 +8,6 @@ #include "content/common/ax_content_node_data.h" #include "content/common/content_export.h" #include "content/common/view_message_enums.h" -#include "content/public/common/common_param_traits.h" #include "ipc/ipc_message_macros.h" #include "ipc/ipc_message_utils.h" #include "ipc/ipc_param_traits.h" @@ -16,6 +15,7 @@ #include "third_party/WebKit/public/web/WebAXEnums.h" #include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/ax_tree_update.h" +#include "ui/gfx/transform.h" #undef IPC_MESSAGE_EXPORT #define IPC_MESSAGE_EXPORT CONTENT_EXPORT @@ -30,6 +30,7 @@ IPC_STRUCT_TRAITS_BEGIN(content::AXContentNodeData) IPC_STRUCT_TRAITS_MEMBER(role) IPC_STRUCT_TRAITS_MEMBER(state) IPC_STRUCT_TRAITS_MEMBER(location) + IPC_STRUCT_TRAITS_MEMBER(transform) IPC_STRUCT_TRAITS_MEMBER(string_attributes) IPC_STRUCT_TRAITS_MEMBER(int_attributes) IPC_STRUCT_TRAITS_MEMBER(float_attributes) @@ -43,12 +44,14 @@ IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_BEGIN(content::AXContentTreeData) IPC_STRUCT_TRAITS_MEMBER(tree_id) IPC_STRUCT_TRAITS_MEMBER(parent_tree_id) + IPC_STRUCT_TRAITS_MEMBER(focused_tree_id) IPC_STRUCT_TRAITS_MEMBER(url) IPC_STRUCT_TRAITS_MEMBER(title) IPC_STRUCT_TRAITS_MEMBER(mimetype) IPC_STRUCT_TRAITS_MEMBER(doctype) IPC_STRUCT_TRAITS_MEMBER(loaded) IPC_STRUCT_TRAITS_MEMBER(loading_progress) + IPC_STRUCT_TRAITS_MEMBER(focus_id) IPC_STRUCT_TRAITS_MEMBER(sel_anchor_object_id) IPC_STRUCT_TRAITS_MEMBER(sel_anchor_offset) IPC_STRUCT_TRAITS_MEMBER(sel_focus_object_id) @@ -156,8 +159,13 @@ IPC_MESSAGE_ROUTED2(AccessibilityMsg_SetValue, int /* object id */, base::string16 /* Value */) -// Determine the accessibility object under a given point and reply with -// a AccessibilityHostMsg_HitTestResult with the same id. +// Determine the accessibility object under a given point. +// +// If the target is an object with a child frame (like if the hit test +// result is an iframe element), it responds with +// AccessibilityHostMsg_ChildFrameHitTestResult so that the +// hit test can be performed recursively on the child frame. Otherwise +// it fires an accessibility event of type ui::AX_EVENT_HOVER on the target. IPC_MESSAGE_ROUTED1(AccessibilityMsg_HitTest, gfx::Point /* location to test */) @@ -210,11 +218,16 @@ IPC_MESSAGE_ROUTED1( AccessibilityHostMsg_LocationChanges, std::vector<AccessibilityHostMsg_LocationChangeParams>) -// Sent to update the browser of the location of accessibility objects. +// Sent to update the browser of Find In Page results. IPC_MESSAGE_ROUTED1( AccessibilityHostMsg_FindInPageResult, AccessibilityHostMsg_FindInPageResultParams) +// Sent in response to AccessibilityMsg_HitTest. +IPC_MESSAGE_ROUTED2(AccessibilityHostMsg_ChildFrameHitTestResult, + gfx::Point /* location tested */, + int /* node id of result */) + // Sent in response to AccessibilityMsg_SnapshotTree. The callback id that was // passed to the request will be returned in |callback_id|, along with // a standalone snapshot of the accessibility tree. diff --git a/chromium/content/common/android/address_parser_internal.cc b/chromium/content/common/android/address_parser_internal.cc index 4f114a3f106..9892bd853fb 100644 --- a/chromium/content/common/android/address_parser_internal.cc +++ b/chromium/content/common/android/address_parser_internal.cc @@ -77,6 +77,8 @@ Word::Word(const base::string16::const_iterator& begin, DCHECK(begin <= end); } +Word::Word(const Word& other) = default; + HouseNumberParser::HouseNumberParser() { } diff --git a/chromium/content/common/android/address_parser_internal.h b/chromium/content/common/android/address_parser_internal.h index 5defd08de2a..60c1483fc03 100644 --- a/chromium/content/common/android/address_parser_internal.h +++ b/chromium/content/common/android/address_parser_internal.h @@ -28,6 +28,7 @@ struct CONTENT_EXPORT Word { Word(); Word(const base::string16::const_iterator& begin, const base::string16::const_iterator& end); + Word(const Word& other); }; // Exposed for tests. diff --git a/chromium/content/common/android/media_metadata_android.cc b/chromium/content/common/android/media_metadata_android.cc new file mode 100644 index 00000000000..0bd15631758 --- /dev/null +++ b/chromium/content/common/android/media_metadata_android.cc @@ -0,0 +1,33 @@ +// Copyright 2016 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 "content/common/android/media_metadata_android.h" + +#include "base/android/jni_string.h" +#include "content/public/common/media_metadata.h" +#include "jni/MediaMetadata_jni.h" + +namespace content { + +// static +base::android::ScopedJavaLocalRef<jobject> +MediaMetadataAndroid::CreateJavaObject( + JNIEnv* env, const MediaMetadata& metadata) { + ScopedJavaLocalRef<jstring> j_title( + base::android::ConvertUTF16ToJavaString(env, metadata.title)); + ScopedJavaLocalRef<jstring> j_artist( + base::android::ConvertUTF16ToJavaString(env, metadata.artist)); + ScopedJavaLocalRef<jstring> j_album( + base::android::ConvertUTF16ToJavaString(env, metadata.album)); + + return Java_MediaMetadata_create( + env, j_title.obj(), j_artist.obj(), j_album.obj()); +} + +// static +bool MediaMetadataAndroid::Register(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +} // namespace content diff --git a/chromium/content/common/android/media_metadata_android.h b/chromium/content/common/android/media_metadata_android.h new file mode 100644 index 00000000000..e580e53af0f --- /dev/null +++ b/chromium/content/common/android/media_metadata_android.h @@ -0,0 +1,29 @@ +// Copyright 2016 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 CONTENT_COMMON_ANDROID_MEDIA_METADATA_ANDROID_H_ +#define CONTENT_COMMON_ANDROID_MEDIA_METADATA_ANDROID_H_ + +#include <jni.h> + +#include "base/android/scoped_java_ref.h" + +namespace content { + +struct MediaMetadata; + +class MediaMetadataAndroid { + public: + static base::android::ScopedJavaLocalRef<jobject> CreateJavaObject( + JNIEnv* env, const MediaMetadata& metadata); + + static bool Register(JNIEnv* env); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(MediaMetadataAndroid); +}; + +} // namespace content + +#endif // CONTENT_COMMON_ANDROID_MEDIA_METADATA_ANDROID_H_ diff --git a/chromium/content/common/android/surface_texture_manager.cc b/chromium/content/common/android/surface_texture_manager.cc deleted file mode 100644 index c2cb6eeb983..00000000000 --- a/chromium/content/common/android/surface_texture_manager.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2014 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 "content/common/android/surface_texture_manager.h" - -#include "base/logging.h" - -namespace content { -namespace { - -SurfaceTextureManager* g_instance = NULL; - -} // namespace - -// static -SurfaceTextureManager* SurfaceTextureManager::GetInstance() { - DCHECK(g_instance); - return g_instance; -} - -// static -void SurfaceTextureManager::SetInstance(SurfaceTextureManager* instance) { - DCHECK(!g_instance || !instance); - g_instance = instance; -} - -} // namespace content diff --git a/chromium/content/common/android/surface_texture_manager.h b/chromium/content/common/android/surface_texture_manager.h deleted file mode 100644 index 30a17dc9e15..00000000000 --- a/chromium/content/common/android/surface_texture_manager.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2014 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 CONTENT_COMMON_ANDROID_SURFACE_TEXTURE_MANAGER_H_ -#define CONTENT_COMMON_ANDROID_SURFACE_TEXTURE_MANAGER_H_ - -#include "content/common/content_export.h" -#include "ui/gfx/native_widget_types.h" - -namespace gfx { -class SurfaceTexture; -} - -namespace content { - -class CONTENT_EXPORT SurfaceTextureManager { - public: - static SurfaceTextureManager* GetInstance(); - static void SetInstance(SurfaceTextureManager* instance); - - // Register a surface texture for use in another process. - virtual void RegisterSurfaceTexture(int surface_texture_id, - int client_id, - gfx::SurfaceTexture* surface_texture) = 0; - - // Unregister a surface texture previously registered for use in another - // process. - virtual void UnregisterSurfaceTexture(int surface_texture_id, - int client_id) = 0; - - // Acquire native widget for a registered surface texture. - virtual gfx::AcceleratedWidget AcquireNativeWidgetForSurfaceTexture( - int surface_texture_id) = 0; - - protected: - virtual ~SurfaceTextureManager() {} -}; - -} // namespace content - -#endif // CONTENT_COMMON_ANDROID_SURFACE_TEXTURE_MANAGER_H_ diff --git a/chromium/content/common/android/surface_texture_peer.cc b/chromium/content/common/android/surface_texture_peer.cc deleted file mode 100644 index a6fade45e69..00000000000 --- a/chromium/content/common/android/surface_texture_peer.cc +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2012 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 "content/common/android/surface_texture_peer.h" - -#include "base/logging.h" - -namespace content { - -namespace { -SurfaceTexturePeer* g_instance_ = NULL; -} // namespace - -SurfaceTexturePeer::SurfaceTexturePeer() { -} - -SurfaceTexturePeer::~SurfaceTexturePeer() { -} - -// static -SurfaceTexturePeer* SurfaceTexturePeer::GetInstance() { - DCHECK(g_instance_); - return g_instance_; -} - -// static -void SurfaceTexturePeer::InitInstance(SurfaceTexturePeer* instance) { - DCHECK(!g_instance_); - g_instance_ = instance; -} - -} // namespace content diff --git a/chromium/content/common/android/surface_texture_peer.h b/chromium/content/common/android/surface_texture_peer.h deleted file mode 100644 index 0afe3efcf53..00000000000 --- a/chromium/content/common/android/surface_texture_peer.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_ANDROID_SURFACE_TEXTURE_PEER_H_ -#define CONTENT_COMMON_ANDROID_SURFACE_TEXTURE_PEER_H_ - -#include "base/macros.h" -#include "base/process/process.h" -#include "ui/gl/android/surface_texture.h" - -namespace content { - -class SurfaceTexturePeer { - public: - static SurfaceTexturePeer* GetInstance(); - - static void InitInstance(SurfaceTexturePeer* instance); - - // Establish the producer end for the given surface texture in another - // process. - virtual void EstablishSurfaceTexturePeer( - base::ProcessHandle pid, - scoped_refptr<gfx::SurfaceTexture> surface_texture, - int primary_id, - int secondary_id) = 0; - - protected: - SurfaceTexturePeer(); - virtual ~SurfaceTexturePeer(); - - private: - DISALLOW_COPY_AND_ASSIGN(SurfaceTexturePeer); -}; - -} // namespace content - -#endif // CONTENT_COMMON_ANDROID_SURFACE_TEXTURE_PEER_H_ diff --git a/chromium/content/common/android/sync_compositor_messages.cc b/chromium/content/common/android/sync_compositor_messages.cc index f44415f375f..1423091bd74 100644 --- a/chromium/content/common/android/sync_compositor_messages.cc +++ b/chromium/content/common/android/sync_compositor_messages.cc @@ -8,6 +8,7 @@ namespace content { SyncCompositorCommonBrowserParams::SyncCompositorCommonBrowserParams() : bytes_limit(0u), + output_surface_id_for_returned_resources(0u), update_root_scroll_offset(false), begin_frame_source_paused(false) {} @@ -44,9 +45,9 @@ SyncCompositorCommonRendererParams::SyncCompositorCommonRendererParams() min_page_scale_factor(0.f), max_page_scale_factor(0.f), need_animate_scroll(false), - need_invalidate(false), + need_invalidate_count(0u), need_begin_frame(false), - did_activate_pending_tree(false) {} + did_activate_pending_tree_count(0u) {} SyncCompositorCommonRendererParams::~SyncCompositorCommonRendererParams() {} diff --git a/chromium/content/common/android/sync_compositor_messages.h b/chromium/content/common/android/sync_compositor_messages.h index a91440764b8..0ec4bf4cec5 100644 --- a/chromium/content/common/android/sync_compositor_messages.h +++ b/chromium/content/common/android/sync_compositor_messages.h @@ -14,6 +14,7 @@ #include "content/common/input/input_event_ack_state.h" #include "ipc/ipc_message_macros.h" #include "third_party/WebKit/public/web/WebInputEvent.h" +#include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/scroll_offset.h" #ifndef CONTENT_COMMON_ANDROID_SYNC_COMPOSITOR_MESSAGES_H_ @@ -25,7 +26,8 @@ struct SyncCompositorCommonBrowserParams { SyncCompositorCommonBrowserParams(); ~SyncCompositorCommonBrowserParams(); - size_t bytes_limit; + uint32_t bytes_limit; + uint32_t output_surface_id_for_returned_resources; cc::CompositorFrameAck ack; gfx::ScrollOffset root_scroll_offset; bool update_root_scroll_offset; @@ -54,7 +56,7 @@ struct SyncCompositorDemandDrawHwParams { struct SyncCompositorSetSharedMemoryParams { SyncCompositorSetSharedMemoryParams(); - size_t buffer_size; + uint32_t buffer_size; base::SharedMemoryHandle shm_handle; }; @@ -79,9 +81,9 @@ struct SyncCompositorCommonRendererParams { float min_page_scale_factor; float max_page_scale_factor; bool need_animate_scroll; - bool need_invalidate; + uint32_t need_invalidate_count; bool need_begin_frame; - bool did_activate_pending_tree; + uint32_t did_activate_pending_tree_count; }; } // namespace content @@ -96,6 +98,7 @@ struct SyncCompositorCommonRendererParams { IPC_STRUCT_TRAITS_BEGIN(content::SyncCompositorCommonBrowserParams) IPC_STRUCT_TRAITS_MEMBER(bytes_limit) + IPC_STRUCT_TRAITS_MEMBER(output_surface_id_for_returned_resources) IPC_STRUCT_TRAITS_MEMBER(ack) IPC_STRUCT_TRAITS_MEMBER(root_scroll_offset) IPC_STRUCT_TRAITS_MEMBER(update_root_scroll_offset) @@ -131,12 +134,14 @@ IPC_STRUCT_TRAITS_BEGIN(content::SyncCompositorCommonRendererParams) IPC_STRUCT_TRAITS_MEMBER(min_page_scale_factor) IPC_STRUCT_TRAITS_MEMBER(max_page_scale_factor) IPC_STRUCT_TRAITS_MEMBER(need_animate_scroll) - IPC_STRUCT_TRAITS_MEMBER(need_invalidate) + IPC_STRUCT_TRAITS_MEMBER(need_invalidate_count) IPC_STRUCT_TRAITS_MEMBER(need_begin_frame) - IPC_STRUCT_TRAITS_MEMBER(did_activate_pending_tree) + IPC_STRUCT_TRAITS_MEMBER(did_activate_pending_tree_count) IPC_STRUCT_TRAITS_END() // Messages sent from the browser to the renderer. +// Synchronous IPCs are allowed here to the renderer compositor thread. See +// design doc https://goo.gl/Tn81FW and crbug.com/526842 for details. IPC_SYNC_MESSAGE_ROUTED2_2(SyncCompositorMsg_HandleInputEvent, content::SyncCompositorCommonBrowserParams, @@ -149,15 +154,15 @@ IPC_SYNC_MESSAGE_ROUTED2_1(SyncCompositorMsg_BeginFrame, cc::BeginFrameArgs, content::SyncCompositorCommonRendererParams) -IPC_SYNC_MESSAGE_ROUTED2_1(SyncCompositorMsg_ComputeScroll, - content::SyncCompositorCommonBrowserParams, - base::TimeTicks, - content::SyncCompositorCommonRendererParams) +IPC_MESSAGE_ROUTED2(SyncCompositorMsg_ComputeScroll, + content::SyncCompositorCommonBrowserParams, + base::TimeTicks); -IPC_SYNC_MESSAGE_ROUTED2_2(SyncCompositorMsg_DemandDrawHw, +IPC_SYNC_MESSAGE_ROUTED2_3(SyncCompositorMsg_DemandDrawHw, content::SyncCompositorCommonBrowserParams, content::SyncCompositorDemandDrawHwParams, content::SyncCompositorCommonRendererParams, + uint32_t /* output_surface_id */, cc::CompositorFrame) IPC_SYNC_MESSAGE_ROUTED2_2(SyncCompositorMsg_SetSharedMemory, @@ -178,6 +183,12 @@ IPC_SYNC_MESSAGE_ROUTED2_3(SyncCompositorMsg_DemandDrawSw, IPC_MESSAGE_ROUTED1(SyncCompositorMsg_UpdateState, content::SyncCompositorCommonBrowserParams) +IPC_SYNC_MESSAGE_ROUTED3_1(SyncCompositorMsg_ZoomBy, + content::SyncCompositorCommonBrowserParams, + float /* delta */, + gfx::Point /* anchor */, + content::SyncCompositorCommonRendererParams) + // ----------------------------------------------------------------------------- // Messages sent from the renderer to the browser. diff --git a/chromium/content/common/appcache_interfaces.cc b/chromium/content/common/appcache_interfaces.cc index af0d8c16883..8342a364f0f 100644 --- a/chromium/content/common/appcache_interfaces.cc +++ b/chromium/content/common/appcache_interfaces.cc @@ -31,6 +31,8 @@ AppCacheInfo::AppCacheInfo() is_complete(false) { } +AppCacheInfo::AppCacheInfo(const AppCacheInfo& other) = default; + AppCacheInfo::~AppCacheInfo() { } @@ -46,6 +48,9 @@ AppCacheResourceInfo::AppCacheResourceInfo() response_id(kAppCacheNoResponseId) { } +AppCacheResourceInfo::AppCacheResourceInfo(const AppCacheResourceInfo& other) = + default; + AppCacheResourceInfo::~AppCacheResourceInfo() { } diff --git a/chromium/content/common/appcache_interfaces.h b/chromium/content/common/appcache_interfaces.h index 8ba2da072b9..12cc7c11d5d 100644 --- a/chromium/content/common/appcache_interfaces.h +++ b/chromium/content/common/appcache_interfaces.h @@ -62,6 +62,7 @@ enum AppCacheErrorReason { // Type to hold information about a single appcache resource. struct CONTENT_EXPORT AppCacheResourceInfo { AppCacheResourceInfo(); + AppCacheResourceInfo(const AppCacheResourceInfo& other); ~AppCacheResourceInfo(); GURL url; diff --git a/chromium/content/common/appcache_messages.h b/chromium/content/common/appcache_messages.h index 7e74848e4dd..95964f71c9d 100644 --- a/chromium/content/common/appcache_messages.h +++ b/chromium/content/common/appcache_messages.h @@ -9,6 +9,7 @@ #include <stdint.h> #include "content/common/appcache_interfaces.h" +#include "url/ipc/url_param_traits.h" #define IPC_MESSAGE_START AppCacheMsgStart diff --git a/chromium/content/common/application_setup.mojom b/chromium/content/common/application_setup.mojom index df45c5ac22f..8fb0e174c88 100644 --- a/chromium/content/common/application_setup.mojom +++ b/chromium/content/common/application_setup.mojom @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -module content; +module content.mojom; -import "mojo/shell/public/interfaces/service_provider.mojom"; +import "mojo/shell/public/interfaces/interface_provider.mojom"; interface ApplicationSetup { - ExchangeServiceProviders(mojo.ServiceProvider& services, - mojo.ServiceProvider exposed_services); + ExchangeInterfaceProviders( + mojo.shell.mojom.InterfaceProvider& remote_interfaces, + mojo.shell.mojom.InterfaceProvider local_interfaces); }; diff --git a/chromium/content/common/ax_content_node_data.cc b/chromium/content/common/ax_content_node_data.cc index fda36683ca4..d528727aa87 100644 --- a/chromium/content/common/ax_content_node_data.cc +++ b/chromium/content/common/ax_content_node_data.cc @@ -33,6 +33,8 @@ typename std::vector<std::pair<FirstType, SecondType>>::const_iterator AXContentNodeData::AXContentNodeData() { } +AXContentNodeData::AXContentNodeData(const AXContentNodeData& other) = default; + AXContentNodeData::~AXContentNodeData() { } diff --git a/chromium/content/common/ax_content_node_data.h b/chromium/content/common/ax_content_node_data.h index 00849cdae6a..93ab7191942 100644 --- a/chromium/content/common/ax_content_node_data.h +++ b/chromium/content/common/ax_content_node_data.h @@ -28,6 +28,7 @@ enum AXContentIntAttribute { // content-layer-specific AX attributes. struct CONTENT_EXPORT AXContentNodeData : public ui::AXNodeData { AXContentNodeData(); + AXContentNodeData(const AXContentNodeData& other); ~AXContentNodeData() override; bool HasContentIntAttribute(AXContentIntAttribute attribute) const; diff --git a/chromium/content/common/background_sync_service.mojom b/chromium/content/common/background_sync_service.mojom index d1b0cd1089c..cceb58c31b3 100644 --- a/chromium/content/common/background_sync_service.mojom +++ b/chromium/content/common/background_sync_service.mojom @@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -module content; +module content.mojom; import "content/public/common/background_sync.mojom"; -import "content/public/common/permission_status.mojom"; import "content/public/common/service_worker_event_status.mojom"; enum BackgroundSyncError { @@ -14,17 +13,14 @@ enum BackgroundSyncError { NOT_FOUND, NO_SERVICE_WORKER, NOT_ALLOWED, - MAX=NOT_ALLOWED + PERMISSION_DENIED, + MAX=PERMISSION_DENIED }; enum BackgroundSyncState { PENDING, FIRING, - UNREGISTERED_WHILE_FIRING, REREGISTERED_WHILE_FIRING, - FAILED, - SUCCESS, - UNREGISTERED }; enum BackgroundSyncEventLastChance { @@ -33,28 +29,14 @@ enum BackgroundSyncEventLastChance { }; interface BackgroundSyncService { - Register(SyncRegistration options, int64 service_worker_registration_id, - bool requested_from_service_worker) + Register(SyncRegistration options, int64 service_worker_registration_id) => (BackgroundSyncError err, SyncRegistration options); - GetRegistration(BackgroundSyncPeriodicity periodicity, string tag, - int64 service_worker_registration_id) - => (BackgroundSyncError err, SyncRegistration? registration); - GetRegistrations(BackgroundSyncPeriodicity periodicity, - int64 service_worker_registration_id) + GetRegistrations(int64 service_worker_registration_id) => (BackgroundSyncError err, array<SyncRegistration> registrations); - Unregister(int64 handle_id, int64 service_worker_registration_id) - => (BackgroundSyncError err); - GetPermissionStatus(BackgroundSyncPeriodicity periodicity, - int64 service_worker_registration_id) - => (BackgroundSyncError err, PermissionStatus status); - DuplicateRegistrationHandle(int64 handle_id) - => (BackgroundSyncError err, SyncRegistration? registration); - ReleaseRegistration(int64 handle_id); - NotifyWhenFinished(int64 handle_id) => (BackgroundSyncError err, BackgroundSyncState final_status); }; interface BackgroundSyncServiceClient { - Sync(int64 handle_id, BackgroundSyncEventLastChance last_chance) + Sync(string tag, BackgroundSyncEventLastChance last_chance) => (ServiceWorkerEventStatus status); }; diff --git a/chromium/content/common/bluetooth/bluetooth_messages.h b/chromium/content/common/bluetooth/bluetooth_messages.h index df7695d67f4..68b51e34f61 100644 --- a/chromium/content/common/bluetooth/bluetooth_messages.h +++ b/chromium/content/common/bluetooth/bluetooth_messages.h @@ -129,13 +129,12 @@ IPC_MESSAGE_CONTROL3(BluetoothMsg_RequestDeviceError, blink::WebBluetoothError /* result */) // Informs the renderer that the connection request |request_id| succeeded. -IPC_MESSAGE_CONTROL3(BluetoothMsg_ConnectGATTSuccess, +IPC_MESSAGE_CONTROL2(BluetoothMsg_GATTServerConnectSuccess, int /* thread_id */, - int /* request_id */, - std::string /* device_id */) + int /* request_id */) // Informs the renderer that the connection request |request_id| failed. -IPC_MESSAGE_CONTROL3(BluetoothMsg_ConnectGATTError, +IPC_MESSAGE_CONTROL3(BluetoothMsg_GATTServerConnectError, int /* thread_id */, int /* request_id */, blink::WebBluetoothError /* result */) @@ -165,6 +164,23 @@ IPC_MESSAGE_CONTROL3(BluetoothMsg_GetCharacteristicError, int /* request_id */, blink::WebBluetoothError /* result */) +// Informs the renderer that the multiple-characteristic request |request_id| +// succeeded. +IPC_MESSAGE_CONTROL5( + BluetoothMsg_GetCharacteristicsSuccess, + int /* thread_id */, + int /* request_id */, + std::vector<std::string> /* characteristics_instance_ids */, + std::vector<std::string> /* characteristics_uuids */, + std::vector<uint32_t> /* characteristics_properties */) + +// Informs the renderer that the multiple-characteristic request |request_id| +// failed. +IPC_MESSAGE_CONTROL3(BluetoothMsg_GetCharacteristicsError, + int /* thread_id */, + int /* request_id */, + blink::WebBluetoothError /* result */) + // Informs the renderer that the value has been read. IPC_MESSAGE_CONTROL3(BluetoothMsg_ReadCharacteristicValueSuccess, int /* thread_id */, @@ -177,19 +193,6 @@ IPC_MESSAGE_CONTROL3(BluetoothMsg_ReadCharacteristicValueError, int /* request_id */, blink::WebBluetoothError /* result */) -// Informs the renderer that the value has been successfully written to -// the characteristic. -IPC_MESSAGE_CONTROL2(BluetoothMsg_WriteCharacteristicValueSuccess, - int /* thread_id */, - int /* request_id */) - -// Informs the renderer that an error occurred while writing a value to a -// characteristic. -IPC_MESSAGE_CONTROL3(BluetoothMsg_WriteCharacteristicValueError, - int /* thread_id */, - int /* request_id */, - blink::WebBluetoothError /* result */) - // Informs the renderer that the user has successfully subscribed to // notifications from the device. IPC_MESSAGE_CONTROL2(BluetoothMsg_StartNotificationsSuccess, @@ -226,12 +229,18 @@ IPC_MESSAGE_CONTROL5(BluetoothHostMsg_RequestDevice, std::vector<device::BluetoothUUID> /* optional_services */) // Connects to a bluetooth device. -IPC_MESSAGE_CONTROL4(BluetoothHostMsg_ConnectGATT, +IPC_MESSAGE_CONTROL4(BluetoothHostMsg_GATTServerConnect, int /* thread_id */, int /* request_id */, int /* frame_routing_id */, std::string /* device_id */) +// Disconnect from a device. +IPC_MESSAGE_CONTROL3(BluetoothHostMsg_GATTServerDisconnect, + int /* thread_id */, + int /* frame_routing_id */, + std::string /* device_id */) + // Gets primary service from bluetooth device. IPC_MESSAGE_CONTROL5(BluetoothHostMsg_GetPrimaryService, int /* thread_id */, @@ -248,20 +257,20 @@ IPC_MESSAGE_CONTROL5(BluetoothHostMsg_GetCharacteristic, std::string /* service_instance_id */, std::string /* characteristic_uuid */) -// Reads the characteristics value from a bluetooth device. -IPC_MESSAGE_CONTROL4(BluetoothHostMsg_ReadValue, +// Gets GATT Characteristics within a GATT Service. +IPC_MESSAGE_CONTROL5(BluetoothHostMsg_GetCharacteristics, int /* thread_id */, int /* request_id */, int /* frame_routing_id */, - std::string /* characteristic_instance_id */) + std::string /* service_instance_id */, + std::string /* characteristics_uuid */) -// Writes a value to a bluetooth device's characteristic. -IPC_MESSAGE_CONTROL5(BluetoothHostMsg_WriteValue, +// Reads the characteristics value from a bluetooth device. +IPC_MESSAGE_CONTROL4(BluetoothHostMsg_ReadValue, int /* thread_id */, int /* request_id */, int /* frame_routing_id */, - std::string /* characteristic_instance_id */, - std::vector<uint8_t> /* value */) + std::string /* characteristic_instance_id */) // Subscribes to notifications from a device's characteristic. IPC_MESSAGE_CONTROL4(BluetoothHostMsg_StartNotifications, diff --git a/chromium/content/common/bluetooth/bluetooth_scan_filter.cc b/chromium/content/common/bluetooth/bluetooth_scan_filter.cc index 3ab22aedfa3..2c5a7cb87a9 100644 --- a/chromium/content/common/bluetooth/bluetooth_scan_filter.cc +++ b/chromium/content/common/bluetooth/bluetooth_scan_filter.cc @@ -9,6 +9,9 @@ namespace content { BluetoothScanFilter::BluetoothScanFilter() : services() { } +BluetoothScanFilter::BluetoothScanFilter(const BluetoothScanFilter& other) = + default; + BluetoothScanFilter::~BluetoothScanFilter() { } diff --git a/chromium/content/common/bluetooth/bluetooth_scan_filter.h b/chromium/content/common/bluetooth/bluetooth_scan_filter.h index 257274729d3..6c0bb3374e1 100644 --- a/chromium/content/common/bluetooth/bluetooth_scan_filter.h +++ b/chromium/content/common/bluetooth/bluetooth_scan_filter.h @@ -17,6 +17,7 @@ namespace content { // blink::WebBluetoothScanFilter. struct CONTENT_EXPORT BluetoothScanFilter { BluetoothScanFilter(); + BluetoothScanFilter(const BluetoothScanFilter& other); ~BluetoothScanFilter(); std::vector<device::BluetoothUUID> services; diff --git a/chromium/content/common/browser_plugin/browser_plugin_messages.h b/chromium/content/common/browser_plugin/browser_plugin_messages.h index 1a264ce04a8..eef580508a6 100644 --- a/chromium/content/common/browser_plugin/browser_plugin_messages.h +++ b/chromium/content/common/browser_plugin/browser_plugin_messages.h @@ -12,8 +12,6 @@ #include "content/common/content_param_traits.h" #include "content/common/cursors/webcursor.h" #include "content/common/edit_command.h" -#include "content/common/frame_param_macros.h" -#include "content/public/common/common_param_traits.h" #include "content/public/common/drop_data.h" #include "ipc/ipc_channel_handle.h" #include "ipc/ipc_message_macros.h" @@ -27,7 +25,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/ipc/gfx_param_traits.h" -#include "url/gurl.h" +#include "ui/gfx/ipc/skia/gfx_skia_param_traits.h" #undef IPC_MESSAGE_EXPORT #define IPC_MESSAGE_EXPORT CONTENT_EXPORT @@ -112,18 +110,10 @@ IPC_MESSAGE_CONTROL3(BrowserPluginHostMsg_SetFocus, blink::WebFocusType /* focus_type */) // Sends an input event to the guest. -IPC_MESSAGE_CONTROL3(BrowserPluginHostMsg_HandleInputEvent, +IPC_MESSAGE_CONTROL2(BrowserPluginHostMsg_HandleInputEvent, int /* browser_plugin_instance_id */, - gfx::Rect /* guest_window_rect */, IPC::WebInputEventPointer /* event */) -// Notify the guest renderer that some resources given to the embededer -// are not used any more. -IPC_MESSAGE_CONTROL2( - BrowserPluginHostMsg_ReclaimCompositorResources, - int /* browser_plugin_instance_id */, - FrameHostMsg_ReclaimCompositorResources_Params /* params */) - // Tells the guest it has been shown or hidden. IPC_MESSAGE_CONTROL2(BrowserPluginHostMsg_SetVisibility, int /* browser_plugin_instance_id */, @@ -185,10 +175,6 @@ IPC_MESSAGE_CONTROL2(BrowserPluginMsg_SetCursor, int /* browser_plugin_instance_id */, content::WebCursor /* cursor */) -IPC_MESSAGE_CONTROL2(BrowserPluginMsg_CompositorFrameSwapped, - int /* browser_plugin_instance_id */, - FrameMsg_CompositorFrameSwapped_Params /* params */) - IPC_MESSAGE_CONTROL5(BrowserPluginMsg_SetChildFrameSurface, int /* browser_plugin_instance_id */, cc::SurfaceId /* surface_id */, @@ -205,8 +191,3 @@ IPC_MESSAGE_CONTROL2(BrowserPluginMsg_SetMouseLock, IPC_MESSAGE_CONTROL2(BrowserPluginMsg_SetTooltipText, int /* browser_plugin_instance_id */, base::string16 /* tooltip_text */) - -// Acknowledge that we presented an ubercomp frame. -IPC_MESSAGE_CONTROL2(BrowserPluginHostMsg_CompositorFrameSwappedACK, - int /* browser_plugin_instance_id */, - FrameHostMsg_CompositorFrameSwappedACK_Params /* params */) diff --git a/chromium/content/common/buffer_presented_params_mac.cc b/chromium/content/common/buffer_presented_params_mac.cc new file mode 100644 index 00000000000..795dc08fa4b --- /dev/null +++ b/chromium/content/common/buffer_presented_params_mac.cc @@ -0,0 +1,13 @@ +// Copyright 2016 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 "content/common/buffer_presented_params_mac.h" + +namespace content { + +BufferPresentedParams::BufferPresentedParams() : surface_id(0) {} + +BufferPresentedParams::~BufferPresentedParams() {} + +} // namespace content diff --git a/chromium/content/common/buffer_presented_params_mac.h b/chromium/content/common/buffer_presented_params_mac.h new file mode 100644 index 00000000000..29e0dabf1b4 --- /dev/null +++ b/chromium/content/common/buffer_presented_params_mac.h @@ -0,0 +1,23 @@ +// Copyright 2016 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 CONTENT_COMMON_BUFFER_PRESENTED_PARAMS_MAC_H_ +#define CONTENT_COMMON_BUFFER_PRESENTED_PARAMS_MAC_H_ + +#include "base/time/time.h" + +namespace content { + +struct BufferPresentedParams { + BufferPresentedParams(); + ~BufferPresentedParams(); + + int32_t surface_id; + base::TimeTicks vsync_timebase; + base::TimeDelta vsync_interval; +}; + +} // namespace content + +#endif // CONTENT_COMMON_BUFFER_PRESENTED_PARAMS_MAC_H_ diff --git a/chromium/content/common/cache_storage/cache_storage_messages.h b/chromium/content/common/cache_storage/cache_storage_messages.h index 277f960ee6e..82fe7552d6c 100644 --- a/chromium/content/common/cache_storage/cache_storage_messages.h +++ b/chromium/content/common/cache_storage/cache_storage_messages.h @@ -13,7 +13,7 @@ #include "ipc/ipc_message_macros.h" #include "ipc/ipc_param_traits.h" #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerCacheError.h" -#include "url/gurl.h" +#include "url/origin.h" #undef IPC_MESSAGE_EXPORT #define IPC_MESSAGE_EXPORT CONTENT_EXPORT @@ -51,30 +51,30 @@ IPC_ENUM_TRAITS_MAX_VALUE(blink::WebServiceWorkerCacheError, IPC_MESSAGE_CONTROL4(CacheStorageHostMsg_CacheStorageHas, int /* thread_id */, int /* request_id */, - GURL /* origin */, + url::Origin /* origin */, base::string16 /* fetch_store_name */) IPC_MESSAGE_CONTROL4(CacheStorageHostMsg_CacheStorageOpen, int /* thread_id */, int /* request_id */, - GURL /* origin */, + url::Origin /* origin */, base::string16 /* fetch_store_name */) IPC_MESSAGE_CONTROL4(CacheStorageHostMsg_CacheStorageDelete, int /* thread_id */, int /* request_id */, - GURL /* origin */, + url::Origin /* origin */, base::string16 /* fetch_store_name */) IPC_MESSAGE_CONTROL3(CacheStorageHostMsg_CacheStorageKeys, int /* thread_id */, int /* request_id */, - GURL /* origin */) + url::Origin /* origin */) IPC_MESSAGE_CONTROL5(CacheStorageHostMsg_CacheStorageMatch, int /* thread_id */, int /* request_id */, - GURL /* origin */, + url::Origin /* origin */, content::ServiceWorkerFetchRequest, content::CacheStorageCacheQueryParams) diff --git a/chromium/content/common/cache_storage/cache_storage_types.cc b/chromium/content/common/cache_storage/cache_storage_types.cc index c2e5175d693..198e6eaf300 100644 --- a/chromium/content/common/cache_storage/cache_storage_types.cc +++ b/chromium/content/common/cache_storage/cache_storage_types.cc @@ -13,4 +13,7 @@ CacheStorageCacheQueryParams::CacheStorageCacheQueryParams() CacheStorageBatchOperation::CacheStorageBatchOperation() { } +CacheStorageBatchOperation::CacheStorageBatchOperation( + const CacheStorageBatchOperation& other) = default; + } // namespace content diff --git a/chromium/content/common/cache_storage/cache_storage_types.h b/chromium/content/common/cache_storage/cache_storage_types.h index bd292966c0e..22e91c0636a 100644 --- a/chromium/content/common/cache_storage/cache_storage_types.h +++ b/chromium/content/common/cache_storage/cache_storage_types.h @@ -39,6 +39,7 @@ enum CacheStorageCacheOperationType { // A single batch operation for the Cache API. struct CONTENT_EXPORT CacheStorageBatchOperation { CacheStorageBatchOperation(); + CacheStorageBatchOperation(const CacheStorageBatchOperation& other); CacheStorageCacheOperationType operation_type; ServiceWorkerFetchRequest request; @@ -53,7 +54,9 @@ enum CacheStorageError { CACHE_STORAGE_ERROR_EXISTS, CACHE_STORAGE_ERROR_STORAGE, CACHE_STORAGE_ERROR_NOT_FOUND, - CACHE_STORAGE_ERROR_LAST = CACHE_STORAGE_ERROR_NOT_FOUND + CACHE_STORAGE_ERROR_QUOTA_EXCEEDED, + CACHE_STORAGE_ERROR_CACHE_NAME_NOT_FOUND, + CACHE_STORAGE_ERROR_LAST = CACHE_STORAGE_ERROR_CACHE_NAME_NOT_FOUND }; } // namespace content diff --git a/chromium/content/common/cc_messages.cc b/chromium/content/common/cc_messages.cc index 70729469c7c..f5c688ebd36 100644 --- a/chromium/content/common/cc_messages.cc +++ b/chromium/content/common/cc_messages.cc @@ -7,6 +7,7 @@ #include <stddef.h> #include <utility> +#include "base/numerics/safe_conversions.h" #include "cc/output/compositor_frame.h" #include "cc/output/filter_operations.h" #include "cc/quads/draw_quad.h" @@ -15,12 +16,11 @@ #include "content/public/common/common_param_traits.h" #include "third_party/skia/include/core/SkData.h" #include "third_party/skia/include/core/SkFlattenableSerialization.h" -#include "ui/gfx/transform.h" namespace IPC { -void ParamTraits<cc::FilterOperation>::Write( - Message* m, const param_type& p) { +void ParamTraits<cc::FilterOperation>::Write(base::Pickle* m, + const param_type& p) { WriteParam(m, p.type()); switch (p.type()) { case cc::FilterOperation::GRAYSCALE: @@ -57,7 +57,7 @@ void ParamTraits<cc::FilterOperation>::Write( } } -bool ParamTraits<cc::FilterOperation>::Read(const Message* m, +bool ParamTraits<cc::FilterOperation>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { cc::FilterOperation::FilterType type; @@ -184,18 +184,18 @@ void ParamTraits<cc::FilterOperation>::Log( l->append(")"); } -void ParamTraits<cc::FilterOperations>::Write( - Message* m, const param_type& p) { - WriteParam(m, p.size()); +void ParamTraits<cc::FilterOperations>::Write(base::Pickle* m, + const param_type& p) { + WriteParam(m, base::checked_cast<uint32_t>(p.size())); for (std::size_t i = 0; i < p.size(); ++i) { WriteParam(m, p.at(i)); } } -bool ParamTraits<cc::FilterOperations>::Read(const Message* m, +bool ParamTraits<cc::FilterOperations>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { - size_t count; + uint32_t count; if (!ReadParam(m, iter, &count)) return false; @@ -219,19 +219,18 @@ void ParamTraits<cc::FilterOperations>::Log( l->append(")"); } -void ParamTraits<skia::RefPtr<SkImageFilter> >::Write( - Message* m, const param_type& p) { +void ParamTraits<skia::RefPtr<SkImageFilter>>::Write(base::Pickle* m, + const param_type& p) { SkImageFilter* filter = p.get(); if (filter) { - skia::RefPtr<SkData> data = - skia::AdoptRef(SkValidatingSerializeFlattenable(filter)); + sk_sp<SkData> data(SkValidatingSerializeFlattenable(filter)); m->WriteData(static_cast<const char*>(data->data()), data->size()); } else { m->WriteData(0, 0); } } -bool ParamTraits<skia::RefPtr<SkImageFilter>>::Read(const Message* m, +bool ParamTraits<skia::RefPtr<SkImageFilter>>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char* data = 0; @@ -255,55 +254,13 @@ void ParamTraits<skia::RefPtr<SkImageFilter> >::Log( l->append(")"); } -void ParamTraits<gfx::Transform>::Write( - Message* m, const param_type& p) { -#ifdef SK_MSCALAR_IS_FLOAT - float column_major_data[16]; - p.matrix().asColMajorf(column_major_data); -#else - double column_major_data[16]; - p.matrix().asColMajord(column_major_data); -#endif - m->WriteBytes(&column_major_data, sizeof(SkMScalar) * 16); -} - -bool ParamTraits<gfx::Transform>::Read(const Message* m, - base::PickleIterator* iter, - param_type* r) { - const char* column_major_data; - if (!iter->ReadBytes(&column_major_data, sizeof(SkMScalar) * 16)) - return false; - r->matrix().setColMajor( - reinterpret_cast<const SkMScalar*>(column_major_data)); - return true; -} - -void ParamTraits<gfx::Transform>::Log( - const param_type& p, std::string* l) { -#ifdef SK_MSCALAR_IS_FLOAT - float row_major_data[16]; - p.matrix().asRowMajorf(row_major_data); -#else - double row_major_data[16]; - p.matrix().asRowMajord(row_major_data); -#endif - l->append("("); - for (int i = 0; i < 16; ++i) { - if (i > 0) - l->append(", "); - LogParam(row_major_data[i], l); - } - l->append(") "); -} - -void ParamTraits<cc::RenderPass>::Write( - Message* m, const param_type& p) { +void ParamTraits<cc::RenderPass>::Write(base::Pickle* m, const param_type& p) { WriteParam(m, p.id); WriteParam(m, p.output_rect); WriteParam(m, p.damage_rect); WriteParam(m, p.transform_to_root_target); WriteParam(m, p.has_transparent_background); - WriteParam(m, p.quad_list.size()); + WriteParam(m, base::checked_cast<uint32_t>(p.quad_list.size())); cc::SharedQuadStateList::ConstIterator shared_quad_state_iter = p.shared_quad_state_list.begin(); @@ -390,7 +347,7 @@ static size_t ReserveSizeForRenderPassWrite(const cc::RenderPass& p) { } template <typename QuadType> -static cc::DrawQuad* ReadDrawQuad(const Message* m, +static cc::DrawQuad* ReadDrawQuad(const base::Pickle* m, base::PickleIterator* iter, cc::RenderPass* render_pass) { QuadType* quad = render_pass->CreateAndAppendDrawQuad<QuadType>(); @@ -399,7 +356,7 @@ static cc::DrawQuad* ReadDrawQuad(const Message* m, return quad; } -bool ParamTraits<cc::RenderPass>::Read(const Message* m, +bool ParamTraits<cc::RenderPass>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* p) { cc::RenderPassId id; @@ -407,7 +364,7 @@ bool ParamTraits<cc::RenderPass>::Read(const Message* m, gfx::Rect damage_rect; gfx::Transform transform_to_root_target; bool has_transparent_background; - size_t quad_list_size; + uint32_t quad_list_size; if (!ReadParam(m, iter, &id) || !ReadParam(m, iter, &output_rect) || !ReadParam(m, iter, &damage_rect) || @@ -422,7 +379,7 @@ bool ParamTraits<cc::RenderPass>::Read(const Message* m, transform_to_root_target, has_transparent_background); - for (size_t i = 0; i < quad_list_size; ++i) { + for (uint32_t i = 0; i < quad_list_size; ++i) { cc::DrawQuad::Material material; base::PickleIterator temp_iter = *iter; if (!ReadParam(m, &temp_iter, &material)) @@ -566,7 +523,7 @@ namespace { }; } -void ParamTraits<cc::CompositorFrame>::Write(Message* m, +void ParamTraits<cc::CompositorFrame>::Write(base::Pickle* m, const param_type& p) { WriteParam(m, p.metadata); if (p.delegated_frame_data) { @@ -581,7 +538,7 @@ void ParamTraits<cc::CompositorFrame>::Write(Message* m, } } -bool ParamTraits<cc::CompositorFrame>::Read(const Message* m, +bool ParamTraits<cc::CompositorFrame>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* p) { if (!ReadParam(m, iter, &p->metadata)) @@ -622,7 +579,7 @@ void ParamTraits<cc::CompositorFrame>::Log(const param_type& p, l->append(")"); } -void ParamTraits<cc::CompositorFrameAck>::Write(Message* m, +void ParamTraits<cc::CompositorFrameAck>::Write(base::Pickle* m, const param_type& p) { WriteParam(m, p.resources); if (p.gl_frame_data) { @@ -633,7 +590,7 @@ void ParamTraits<cc::CompositorFrameAck>::Write(Message* m, } } -bool ParamTraits<cc::CompositorFrameAck>::Read(const Message* m, +bool ParamTraits<cc::CompositorFrameAck>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* p) { if (!ReadParam(m, iter, &p->resources)) @@ -667,7 +624,7 @@ void ParamTraits<cc::CompositorFrameAck>::Log(const param_type& p, l->append(")"); } -void ParamTraits<cc::DelegatedFrameData>::Write(Message* m, +void ParamTraits<cc::DelegatedFrameData>::Write(base::Pickle* m, const param_type& p) { DCHECK_NE(0u, p.render_pass_list.size()); @@ -681,15 +638,16 @@ void ParamTraits<cc::DelegatedFrameData>::Write(Message* m, WriteParam(m, p.device_scale_factor); WriteParam(m, p.resource_list); - WriteParam(m, p.render_pass_list.size()); + WriteParam(m, base::checked_cast<uint32_t>(p.render_pass_list.size())); for (const auto& pass : p.render_pass_list) { - WriteParam(m, pass->quad_list.size()); - WriteParam(m, pass->shared_quad_state_list.size()); + WriteParam(m, base::checked_cast<uint32_t>(pass->quad_list.size())); + WriteParam(m, base::checked_cast<uint32_t>( + pass->shared_quad_state_list.size())); WriteParam(m, *pass); } } -bool ParamTraits<cc::DelegatedFrameData>::Read(const Message* m, +bool ParamTraits<cc::DelegatedFrameData>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* p) { if (!ReadParam(m, iter, &p->device_scale_factor)) @@ -701,21 +659,23 @@ bool ParamTraits<cc::DelegatedFrameData>::Read(const Message* m, std::set<cc::RenderPassId> pass_set; - size_t num_render_passes; + uint32_t num_render_passes; if (!ReadParam(m, iter, &p->resource_list) || !ReadParam(m, iter, &num_render_passes) || num_render_passes > kMaxRenderPasses || num_render_passes == 0) return false; - for (size_t i = 0; i < num_render_passes; ++i) { - size_t quad_list_size; - size_t shared_quad_state_list_size; + for (uint32_t i = 0; i < num_render_passes; ++i) { + uint32_t quad_list_size; + uint32_t shared_quad_state_list_size; if (!ReadParam(m, iter, &quad_list_size) || !ReadParam(m, iter, &shared_quad_state_list_size) || quad_list_size > kMaxQuadListSize || shared_quad_state_list_size > kMaxSharedQuadStateListSize) return false; scoped_ptr<cc::RenderPass> render_pass = - cc::RenderPass::Create(shared_quad_state_list_size, quad_list_size); + cc::RenderPass::Create( + static_cast<size_t>(shared_quad_state_list_size), + static_cast<size_t>(quad_list_size)); if (!ReadParam(m, iter, render_pass.get())) return false; // Validate that each RenderPassDrawQuad points at a valid RenderPass @@ -748,7 +708,7 @@ void ParamTraits<cc::DelegatedFrameData>::Log(const param_type& p, l->append("])"); } -void ParamTraits<cc::DrawQuad::Resources>::Write(Message* m, +void ParamTraits<cc::DrawQuad::Resources>::Write(base::Pickle* m, const param_type& p) { DCHECK_LE(p.count, cc::DrawQuad::Resources::kMaxResourceIdCount); WriteParam(m, p.count); @@ -756,7 +716,7 @@ void ParamTraits<cc::DrawQuad::Resources>::Write(Message* m, WriteParam(m, p.ids[i]); } -bool ParamTraits<cc::DrawQuad::Resources>::Read(const Message* m, +bool ParamTraits<cc::DrawQuad::Resources>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* p) { if (!ReadParam(m, iter, &p->count)) @@ -789,7 +749,7 @@ void ParamTraits<cc::DrawQuad::Resources>::Log(const param_type& p, } void ParamTraits<cc::StreamVideoDrawQuad::OverlayResources>::Write( - Message* m, + base::Pickle* m, const param_type& p) { for (size_t i = 0; i < cc::DrawQuad::Resources::kMaxResourceIdCount; ++i) { WriteParam(m, p.size_in_pixels[i]); @@ -797,7 +757,7 @@ void ParamTraits<cc::StreamVideoDrawQuad::OverlayResources>::Write( } bool ParamTraits<cc::StreamVideoDrawQuad::OverlayResources>::Read( - const Message* m, + const base::Pickle* m, base::PickleIterator* iter, param_type* p) { for (size_t i = 0; i < cc::DrawQuad::Resources::kMaxResourceIdCount; ++i) { @@ -820,7 +780,7 @@ void ParamTraits<cc::StreamVideoDrawQuad::OverlayResources>::Log( } void ParamTraits<cc::TextureDrawQuad::OverlayResources>::Write( - Message* m, + base::Pickle* m, const param_type& p) { for (size_t i = 0; i < cc::DrawQuad::Resources::kMaxResourceIdCount; ++i) { WriteParam(m, p.size_in_pixels[i]); @@ -828,7 +788,7 @@ void ParamTraits<cc::TextureDrawQuad::OverlayResources>::Write( } bool ParamTraits<cc::TextureDrawQuad::OverlayResources>::Read( - const Message* m, + const base::Pickle* m, base::PickleIterator* iter, param_type* p) { for (size_t i = 0; i < cc::DrawQuad::Resources::kMaxResourceIdCount; ++i) { diff --git a/chromium/content/common/cc_messages.h b/chromium/content/common/cc_messages.h index 9f2e84ece39..0a6c213ae98 100644 --- a/chromium/content/common/cc_messages.h +++ b/chromium/content/common/cc_messages.h @@ -28,9 +28,10 @@ #include "cc/surfaces/surface_id.h" #include "cc/surfaces/surface_sequence.h" #include "content/common/content_export.h" -#include "gpu/ipc/gpu_command_buffer_traits.h" +#include "gpu/ipc/common/gpu_command_buffer_traits.h" #include "ipc/ipc_message_macros.h" #include "ui/gfx/ipc/gfx_param_traits.h" +#include "ui/gfx/ipc/skia/gfx_skia_param_traits.h" #ifndef CONTENT_COMMON_CC_MESSAGES_H_ #define CONTENT_COMMON_CC_MESSAGES_H_ @@ -48,88 +49,100 @@ namespace IPC { template <> struct ParamTraits<cc::FilterOperation> { typedef cc::FilterOperation param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct ParamTraits<cc::FilterOperations> { typedef cc::FilterOperations param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct ParamTraits<skia::RefPtr<SkImageFilter> > { typedef skia::RefPtr<SkImageFilter> param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); - static void Log(const param_type& p, std::string* l); -}; - -template <> -struct ParamTraits<gfx::Transform> { - typedef gfx::Transform param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct CONTENT_EXPORT ParamTraits<cc::RenderPass> { typedef cc::RenderPass param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; template<> struct CONTENT_EXPORT ParamTraits<cc::CompositorFrame> { typedef cc::CompositorFrame param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* p); static void Log(const param_type& p, std::string* l); }; template<> struct CONTENT_EXPORT ParamTraits<cc::CompositorFrameAck> { typedef cc::CompositorFrameAck param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* p); static void Log(const param_type& p, std::string* l); }; template<> struct CONTENT_EXPORT ParamTraits<cc::DelegatedFrameData> { typedef cc::DelegatedFrameData param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* p); static void Log(const param_type& p, std::string* l); }; template <> struct CONTENT_EXPORT ParamTraits<cc::DrawQuad::Resources> { typedef cc::DrawQuad::Resources param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* p); static void Log(const param_type& p, std::string* l); }; template <> struct CONTENT_EXPORT ParamTraits<cc::StreamVideoDrawQuad::OverlayResources> { typedef cc::StreamVideoDrawQuad::OverlayResources param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* p); static void Log(const param_type& p, std::string* l); }; template <> struct CONTENT_EXPORT ParamTraits<cc::TextureDrawQuad::OverlayResources> { typedef cc::TextureDrawQuad::OverlayResources param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* p); static void Log(const param_type& p, std::string* l); }; @@ -246,6 +259,8 @@ IPC_STRUCT_TRAITS_BEGIN(cc::YUVVideoDrawQuad) IPC_STRUCT_TRAITS_MEMBER(ya_tex_size) IPC_STRUCT_TRAITS_MEMBER(uv_tex_size) IPC_STRUCT_TRAITS_MEMBER(color_space) + IPC_STRUCT_TRAITS_MEMBER(resource_offset) + IPC_STRUCT_TRAITS_MEMBER(resource_multiplier) IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_BEGIN(cc::SharedQuadState) diff --git a/chromium/content/common/cc_messages_unittest.cc b/chromium/content/common/cc_messages_unittest.cc index 799c39ff450..423bfffaa6b 100644 --- a/chromium/content/common/cc_messages_unittest.cc +++ b/chromium/content/common/cc_messages_unittest.cc @@ -433,7 +433,7 @@ TEST_F(CCMessagesTest, AllQuads) { arbitrary_rect1_inside_rect1, arbitrary_bool1, arbitrary_rectf1, arbitrary_rectf2, arbitrary_size1, arbitrary_size2, arbitrary_resourceid1, arbitrary_resourceid2, arbitrary_resourceid3, arbitrary_resourceid4, - arbitrary_color_space); + arbitrary_color_space, arbitrary_float1, arbitrary_float2); pass_cmp->CopyFromAndAppendDrawQuad(yuvvideo_in, yuvvideo_in->shared_quad_state); @@ -617,8 +617,14 @@ TEST_F(CCMessagesTest, UnusedSharedQuadStates) { TEST_F(CCMessagesTest, Resources) { IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); gfx::Size arbitrary_size(757, 1281); - gpu::SyncToken arbitrary_token1(71234838); - gpu::SyncToken arbitrary_token2(53589793); + gpu::SyncToken arbitrary_token1(gpu::CommandBufferNamespace::GPU_IO, 0, + gpu::CommandBufferId::FromUnsafeValue(0x123), + 71234838); + arbitrary_token1.SetVerifyFlush(); + gpu::SyncToken arbitrary_token2(gpu::CommandBufferNamespace::GPU_IO, 0, + gpu::CommandBufferId::FromUnsafeValue(0x123), + 53589793); + arbitrary_token2.SetVerifyFlush(); GLbyte arbitrary_mailbox1[GL_MAILBOX_SIZE_CHROMIUM] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, diff --git a/chromium/content/common/child_process_host_impl.cc b/chromium/content/common/child_process_host_impl.cc index d69d5352a28..1aa93b52987 100644 --- a/chromium/content/common/child_process_host_impl.cc +++ b/chromium/content/common/child_process_host_impl.cc @@ -11,6 +11,7 @@ #include "base/files/file_path.h" #include "base/hash.h" #include "base/logging.h" +#include "base/message_loop/message_loop.h" #include "base/metrics/histogram.h" #include "base/numerics/safe_math.h" #include "base/path_service.h" @@ -21,10 +22,10 @@ #include "base/third_party/dynamic_annotations/dynamic_annotations.h" #include "build/build_config.h" #include "content/common/child_process_messages.h" -#include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h" #include "content/public/common/child_process_host_delegate.h" #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" +#include "gpu/ipc/client/gpu_memory_buffer_impl_shared_memory.h" #include "ipc/attachment_broker.h" #include "ipc/attachment_broker_privileged.h" #include "ipc/ipc_channel.h" @@ -88,7 +89,7 @@ ChildProcessHostImpl::ChildProcessHostImpl(ChildProcessHostDelegate* delegate) #endif #if USE_ATTACHMENT_BROKER -#if defined(OS_MACOSX) && !defined(OS_IOS) +#if defined(OS_MACOSX) // On Mac, the privileged AttachmentBroker needs a reference to the Mach port // Provider, which is only available in the chrome/ module. The attachment // broker must already be created. @@ -97,7 +98,7 @@ ChildProcessHostImpl::ChildProcessHostImpl(ChildProcessHostDelegate* delegate) // Construct the privileged attachment broker early in the life cycle of a // child process. IPC::AttachmentBrokerPrivileged::CreateBrokerIfNeeded(); -#endif // defined(OS_MACOSX) && !defined(OS_IOS) +#endif // defined(OS_MACOSX) #endif // USE_ATTACHMENT_BROKER } @@ -132,12 +133,17 @@ void ChildProcessHostImpl::ForceShutdown() { std::string ChildProcessHostImpl::CreateChannel() { channel_id_ = IPC::Channel::GenerateVerifiedChannelID(std::string()); channel_ = IPC::Channel::CreateServer(channel_id_, this); - if (!channel_->Connect()) - return std::string(); #if USE_ATTACHMENT_BROKER IPC::AttachmentBroker::GetGlobal()->RegisterCommunicationChannel( - channel_.get()); + channel_.get(), base::MessageLoopForIO::current()->task_runner()); +#endif + if (!channel_->Connect()) { +#if USE_ATTACHMENT_BROKER + IPC::AttachmentBroker::GetGlobal()->DeregisterCommunicationChannel( + channel_.get()); #endif + return std::string(); + } for (size_t i = 0; i < filters_.size(); ++i) filters_[i]->OnFilterAdded(channel_.get()); @@ -316,8 +322,8 @@ void ChildProcessHostImpl::OnAllocateGpuMemoryBuffer( // AllocateForChildProcess() will check if |width| and |height| are valid // and handle failure in a controlled way when not. We just need to make // sure |usage| is supported here. - if (GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage)) { - *handle = GpuMemoryBufferImplSharedMemory::AllocateForChildProcess( + if (gpu::GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage)) { + *handle = gpu::GpuMemoryBufferImplSharedMemory::AllocateForChildProcess( id, gfx::Size(width, height), format, peer_process_.Handle()); } } diff --git a/chromium/content/common/child_process_messages.h b/chromium/content/common/child_process_messages.h index b4ee49f122d..fd5fac49351 100644 --- a/chromium/content/common/child_process_messages.h +++ b/chromium/content/common/child_process_messages.h @@ -16,12 +16,20 @@ #include "build/build_config.h" #include "cc/resources/shared_bitmap_manager.h" #include "content/common/content_export.h" +#include "content/common/content_param_traits_macros.h" +#include "content/common/gpu_process_launch_causes.h" #include "content/common/host_discardable_shared_memory_manager.h" #include "gpu/command_buffer/common/sync_token.h" +#include "gpu/ipc/common/gpu_param_traits_macros.h" +#include "ipc/ipc_channel_handle.h" #include "ipc/ipc_message_macros.h" #include "ipc/ipc_platform_file.h" #include "ui/gfx/gpu_memory_buffer.h" #include "ui/gfx/ipc/gfx_param_traits.h" +#include "ui/gfx/ipc/skia/gfx_skia_param_traits.h" + +IPC_ENUM_TRAITS_MAX_VALUE(content::CauseForGpuLaunch, + content::CAUSE_FOR_GPU_LAUNCH_MAX_ENUM - 1) IPC_ENUM_TRAITS_MAX_VALUE(tracked_objects::ThreadData::Status, tracked_objects::ThreadData::STATUS_LAST) @@ -62,26 +70,6 @@ IPC_STRUCT_TRAITS_BEGIN(tracked_objects::ProcessDataSnapshot) IPC_STRUCT_TRAITS_MEMBER(process_id) IPC_STRUCT_TRAITS_END() -IPC_ENUM_TRAITS_MAX_VALUE(gfx::GpuMemoryBufferType, - gfx::GPU_MEMORY_BUFFER_TYPE_LAST) - -IPC_STRUCT_TRAITS_BEGIN(gfx::GpuMemoryBufferHandle) - IPC_STRUCT_TRAITS_MEMBER(id) - IPC_STRUCT_TRAITS_MEMBER(type) - IPC_STRUCT_TRAITS_MEMBER(handle) - IPC_STRUCT_TRAITS_MEMBER(offset) - IPC_STRUCT_TRAITS_MEMBER(stride) -#if defined(USE_OZONE) - IPC_STRUCT_TRAITS_MEMBER(native_pixmap_handle) -#elif defined(OS_MACOSX) - IPC_STRUCT_TRAITS_MEMBER(mach_port) -#endif -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(gfx::GpuMemoryBufferId) - IPC_STRUCT_TRAITS_MEMBER(id) -IPC_STRUCT_TRAITS_END() - #undef IPC_MESSAGE_EXPORT #define IPC_MESSAGE_EXPORT CONTENT_EXPORT @@ -114,8 +102,16 @@ IPC_MESSAGE_CONTROL2(ChildProcessMsg_GetChildProfilerData, IPC_MESSAGE_CONTROL1(ChildProcessMsg_ProfilingPhaseCompleted, int /* profiling_phase */) +// Sent to set the shared memory buffer to be used for storing histograms that +// are to be reported by the browser process to UMA. The following message +// (GetChildNonPersistentHistogramData) will return any histograms created +// before this message is received but not any histograms created afterward. +IPC_MESSAGE_CONTROL2(ChildProcessMsg_SetHistogramMemory, + base::SharedMemoryHandle /* shm_handle */, + int /* shm_size */) + // Send to all the child processes to send back histogram data. -IPC_MESSAGE_CONTROL1(ChildProcessMsg_GetChildHistogramData, +IPC_MESSAGE_CONTROL1(ChildProcessMsg_GetChildNonPersistentHistogramData, int /* sequence_number */) // Sent to child processes to tell them to enter or leave background mode. @@ -126,15 +122,22 @@ IPC_MESSAGE_CONTROL1(ChildProcessMsg_SetProcessBackgrounded, IPC_MESSAGE_CONTROL1(ChildProcessMsg_SetMojoParentPipeHandle, IPC::PlatformFileForTransit /* handle */) -#if defined(USE_OZONE) -// Sent to child processes to initialize ClientNativePixmapFactory using -// a device file descriptor. -IPC_MESSAGE_CONTROL1(ChildProcessMsg_InitializeClientNativePixmapFactory, - base::FileDescriptor /* device_fd */) -#endif //////////////////////////////////////////////////////////////////////////////// // Messages sent from the child process to the browser. +// A renderer sends this when it wants to create a connection to the GPU +// process. The browser will create the GPU process if necessary, and will +// return a handle to the channel via a GpuChannelEstablished message. +IPC_SYNC_MESSAGE_CONTROL1_3(ChildProcessHostMsg_EstablishGpuChannel, + content::CauseForGpuLaunch, + int /* client id */, + IPC::ChannelHandle /* handle to channel */, + gpu::GPUInfo /* stats about GPU process*/) + +// A renderer sends this when it wants to know whether a gpu process exists. +IPC_SYNC_MESSAGE_CONTROL0_1(ChildProcessHostMsg_HasGpuProcess, + bool /* result */) + IPC_MESSAGE_CONTROL0(ChildProcessHostMsg_ShutdownRequest) // Send back profiler data (ThreadData in tracked_objects). diff --git a/chromium/content/common/child_process_sandbox_support_impl_linux.h b/chromium/content/common/child_process_sandbox_support_impl_linux.h index 97221f6e838..e2e973d9771 100644 --- a/chromium/content/common/child_process_sandbox_support_impl_linux.h +++ b/chromium/content/common/child_process_sandbox_support_impl_linux.h @@ -30,8 +30,9 @@ void GetFallbackFontForCharacter(const int32_t character, // |size_and_style| stores the bold setting in its least-significant bit, the // italic setting in its second-least-significant bit, and holds the requested // size in pixels into its remaining bits. -// TODO(derat): Update WebSandboxSupport's getRenderStyleForStrike() method to -// pass the style and size separately instead of packing them into an int. +// TODO(derat): Update WebSandboxSupport's getWebFontRenderStyleForStrike() +// method to pass the style and size separately instead of packing them into an +// int. void GetRenderStyleForStrike(const char* family, int size_and_style, blink::WebFontRenderStyle* out); diff --git a/chromium/content/common/clipboard_messages.h b/chromium/content/common/clipboard_messages.h index 00a198c1f6a..36877f0a241 100644 --- a/chromium/content/common/clipboard_messages.h +++ b/chromium/content/common/clipboard_messages.h @@ -10,13 +10,16 @@ #include <string> #include <vector> +#include "build/build_config.h" #include "base/memory/shared_memory.h" #include "base/strings/string16.h" #include "build/build_config.h" #include "content/common/clipboard_format.h" -#include "content/public/common/common_param_traits.h" +#include "content/common/content_export.h" #include "ipc/ipc_message_macros.h" +#include "ipc/param_traits_macros.h" #include "ui/base/clipboard/clipboard.h" +#include "url/ipc/url_param_traits.h" // Singly-included section for types and/or struct declarations. #ifndef CONTENT_COMMON_CLIPBOARD_MESSAGES_H_ diff --git a/chromium/content/common/common.sb b/chromium/content/common/common.sb index 1d9a8ac1c89..49c654c35fd 100644 --- a/chromium/content/common/common.sb +++ b/chromium/content/common/common.sb @@ -16,7 +16,6 @@ ; Define constants for all of the parameter strings passed in. (define disable-sandbox-denial-logging "DISABLE_SANDBOX_DENIAL_LOGGING") (define enable-logging "ENABLE_LOGGING") -(define component-build-workaround "COMPONENT_BUILD_WORKAROUND") (define permitted-dir "PERMITTED_DIR") (define homedir-as-literal "USER_HOMEDIR_AS_LITERAL") (define lion-or-later "LION_OR_LATER") @@ -50,9 +49,3 @@ ; Allow direct access to /dev/urandom, similar to Linux/POSIX, to allow ; third party code (eg: bits of Adobe Flash and NSS) to function properly. (allow file-read-data file-read-metadata (literal "/dev/urandom")) - -; Enables reading file metadata for the Chrome bundle and its parent paths. -; https://crbug.com/127465 -(if (and (param-defined? component-build-workaround) - (param-true? component-build-workaround)) - (allow file-read-metadata )) diff --git a/chromium/content/common/common_param_traits_unittest.cc b/chromium/content/common/common_param_traits_unittest.cc index 03c19a08731..546834bd9fb 100644 --- a/chromium/content/common/common_param_traits_unittest.cc +++ b/chromium/content/common/common_param_traits_unittest.cc @@ -20,68 +20,7 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/ipc/gfx_param_traits.h" -#include "url/gurl.h" - -// Tests that serialize/deserialize correctly understand each other -TEST(IPCMessageTest, Serialize) { - const char* serialize_cases[] = { - "http://www.google.com/", - "http://user:pass@host.com:888/foo;bar?baz#nop", - }; - - for (size_t i = 0; i < arraysize(serialize_cases); i++) { - GURL input(serialize_cases[i]); - IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); - IPC::ParamTraits<GURL>::Write(&msg, input); - - GURL output; - base::PickleIterator iter(msg); - EXPECT_TRUE(IPC::ParamTraits<GURL>::Read(&msg, &iter, &output)); - - // We want to test each component individually to make sure its range was - // correctly serialized and deserialized, not just the spec. - EXPECT_EQ(input.possibly_invalid_spec(), output.possibly_invalid_spec()); - EXPECT_EQ(input.is_valid(), output.is_valid()); - EXPECT_EQ(input.scheme(), output.scheme()); - EXPECT_EQ(input.username(), output.username()); - EXPECT_EQ(input.password(), output.password()); - EXPECT_EQ(input.host(), output.host()); - EXPECT_EQ(input.port(), output.port()); - EXPECT_EQ(input.path(), output.path()); - EXPECT_EQ(input.query(), output.query()); - EXPECT_EQ(input.ref(), output.ref()); - } - - // Test an excessively long GURL. - { - const std::string url = std::string("http://example.org/").append( - content::kMaxURLChars + 1, 'a'); - GURL input(url.c_str()); - IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); - IPC::ParamTraits<GURL>::Write(&msg, input); - - GURL output; - base::PickleIterator iter(msg); - EXPECT_TRUE(IPC::ParamTraits<GURL>::Read(&msg, &iter, &output)); - EXPECT_TRUE(output.is_empty()); - } - - // Test an invalid GURL. - { - IPC::Message msg; - msg.WriteString("#inva://idurl/"); - GURL output; - base::PickleIterator iter(msg); - EXPECT_FALSE(IPC::ParamTraits<GURL>::Read(&msg, &iter, &output)); - } - - // Also test the corrupt case. - IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); - msg.WriteInt(99); - GURL output; - base::PickleIterator iter(msg); - EXPECT_FALSE(IPC::ParamTraits<GURL>::Read(&msg, &iter, &output)); -} +#include "ui/gfx/ipc/skia/gfx_skia_param_traits.h" // Tests std::pair serialization TEST(IPCMessageTest, Pair) { diff --git a/chromium/content/common/content_constants_internal.cc b/chromium/content/common/content_constants_internal.cc index 7b8b68ae3f7..ec623ac2c4b 100644 --- a/chromium/content/common/content_constants_internal.cc +++ b/chromium/content/common/content_constants_internal.cc @@ -18,16 +18,11 @@ const int64_t kHungRendererDelayMs = 30000; const int64_t kNewContentRenderingDelayMs = 4000; -const uint16_t kMaxPluginSideLength = 1 << 15; -// 8m pixels. -const uint32_t kMaxPluginSize = 8 << 20; - // 20MiB const size_t kMaxLengthOfDataURLString = 1024 * 1024 * 20; const int kTraceEventBrowserProcessSortIndex = -6; const int kTraceEventRendererProcessSortIndex = -5; -const int kTraceEventPluginProcessSortIndex = -4; const int kTraceEventPpapiProcessSortIndex = -3; const int kTraceEventPpapiBrokerProcessSortIndex = -2; const int kTraceEventGpuProcessSortIndex = -1; diff --git a/chromium/content/common/content_constants_internal.h b/chromium/content/common/content_constants_internal.h index 46f351b401c..a3584b0d8b4 100644 --- a/chromium/content/common/content_constants_internal.h +++ b/chromium/content/common/content_constants_internal.h @@ -19,19 +19,12 @@ CONTENT_EXPORT extern const int64_t kHungRendererDelayMs; // before clearing previously displayed graphics. extern const int64_t kNewContentRenderingDelayMs; -// The maximum plugin width and height. -extern const uint16_t kMaxPluginSideLength; -// The maximum plugin size, defined as the number of pixels occupied by the -// plugin. -extern const uint32_t kMaxPluginSize; - // The maximum length of string as data url. extern const size_t kMaxLengthOfDataURLString; // Constants used to organize content processes in about:tracing. CONTENT_EXPORT extern const int kTraceEventBrowserProcessSortIndex; CONTENT_EXPORT extern const int kTraceEventRendererProcessSortIndex; -CONTENT_EXPORT extern const int kTraceEventPluginProcessSortIndex; CONTENT_EXPORT extern const int kTraceEventPpapiProcessSortIndex; CONTENT_EXPORT extern const int kTraceEventPpapiBrokerProcessSortIndex; CONTENT_EXPORT extern const int kTraceEventGpuProcessSortIndex; diff --git a/chromium/content/common/content_message_generator.h b/chromium/content/common/content_message_generator.h index 3d49ab228a3..c26352d010c 100644 --- a/chromium/content/common/content_message_generator.h +++ b/chromium/content/common/content_message_generator.h @@ -28,7 +28,7 @@ #include "content/common/frame_messages.h" #include "content/common/gamepad_messages.h" #include "content/common/geofencing_messages.h" -#include "content/common/gpu/gpu_messages.h" +#include "content/common/gpu_host_messages.h" #include "content/common/indexed_db/indexed_db_messages.h" #include "content/common/input_messages.h" #include "content/common/manifest_manager_messages.h" @@ -36,20 +36,20 @@ #include "content/common/media/audio_messages.h" // TODO(xhwang): Move this to a new ifdef block. #include "content/common/media/cdm_messages.h" +#include "content/common/media/media_player_delegate_messages.h" #include "content/common/media/media_stream_messages.h" #include "content/common/media/media_stream_track_metrics_host_messages.h" #include "content/common/media/midi_messages.h" #include "content/common/media/peer_connection_tracker_messages.h" #include "content/common/media/video_capture_messages.h" #include "content/common/media/webrtc_identity_messages.h" -#include "content/common/memory_benchmark_messages.h" #include "content/common/memory_messages.h" #include "content/common/message_port_messages.h" #include "content/common/mime_registry_messages.h" #include "content/common/mojo/mojo_messages.h" +#include "content/common/page_messages.h" #include "content/common/pepper_messages.h" #include "content/common/platform_notification_messages.h" -#include "content/common/plugin_process_messages.h" #include "content/common/power_monitor_messages.h" #include "content/common/push_messaging_messages.h" #include "content/common/quota_messages.h" @@ -74,6 +74,7 @@ #include "content/common/gin_java_bridge_messages.h" #include "content/common/media/media_player_messages_android.h" #include "content/common/media/media_session_messages_android.h" +#include "content/common/media/surface_view_manager_messages_android.h" #endif // defined(OS_ANDROID) #if defined(OS_WIN) diff --git a/chromium/content/common/content_param_traits.cc b/chromium/content/common/content_param_traits.cc index 0c60380e281..07e1a239bfd 100644 --- a/chromium/content/common/content_param_traits.cc +++ b/chromium/content/common/content_param_traits.cc @@ -12,11 +12,12 @@ namespace IPC { -void ParamTraits<WebInputEventPointer>::Write(Message* m, const param_type& p) { +void ParamTraits<WebInputEventPointer>::Write(base::Pickle* m, + const param_type& p) { m->WriteData(reinterpret_cast<const char*>(p), p->size); } -bool ParamTraits<WebInputEventPointer>::Read(const Message* m, +bool ParamTraits<WebInputEventPointer>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char* data; diff --git a/chromium/content/common/content_param_traits.h b/chromium/content/common/content_param_traits.h index e90a14bd05c..61107aa06e1 100644 --- a/chromium/content/common/content_param_traits.h +++ b/chromium/content/common/content_param_traits.h @@ -27,12 +27,10 @@ namespace IPC { template <> struct ParamTraits<content::WebCursor> { typedef content::WebCursor param_type; - static void Write(Message* m, const param_type& p) { - p.Serialize(m); - } - static bool Read(const Message* m, + static void Write(base::Pickle* m, const param_type& p) { p.Serialize(m); } + static bool Read(const base::Pickle* m, base::PickleIterator* iter, - param_type* r) { + param_type* r) { return r->Deserialize(iter); } static void Log(const param_type& p, std::string* l) { @@ -44,9 +42,11 @@ typedef const blink::WebInputEvent* WebInputEventPointer; template <> struct ParamTraits<WebInputEventPointer> { typedef WebInputEventPointer param_type; - static void Write(Message* m, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); // Note: upon read, the event has the lifetime of the message. - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; diff --git a/chromium/content/common/content_param_traits_macros.h b/chromium/content/common/content_param_traits_macros.h index 762436de718..753947bf530 100644 --- a/chromium/content/common/content_param_traits_macros.h +++ b/chromium/content/common/content_param_traits_macros.h @@ -14,11 +14,13 @@ #include "content/public/common/request_context_type.h" #include "content/public/common/resource_type.h" #include "ipc/ipc_message_macros.h" +#include "third_party/WebKit/public/platform/WebAddressSpace.h" #include "third_party/WebKit/public/platform/WebPageVisibilityState.h" #include "third_party/WebKit/public/web/WebCompositionUnderline.h" #include "third_party/WebKit/public/web/WebContentSecurityPolicy.h" #include "third_party/WebKit/public/web/WebInputEvent.h" #include "third_party/WebKit/public/web/WebSharedWorkerCreationContextType.h" +#include "ui/gfx/gpu_memory_buffer.h" #undef IPC_MESSAGE_EXPORT #define IPC_MESSAGE_EXPORT CONTENT_EXPORT @@ -33,6 +35,7 @@ IPC_ENUM_TRAITS_MAX_VALUE(content::RequestContextFrameType, content::REQUEST_CONTEXT_FRAME_TYPE_LAST) IPC_ENUM_TRAITS_MAX_VALUE(blink::WebContentSecurityPolicyType, blink::WebContentSecurityPolicyTypeLast) +IPC_ENUM_TRAITS_MAX_VALUE(blink::WebAddressSpace, blink::WebAddressSpaceLast) IPC_ENUM_TRAITS_MAX_VALUE(blink::WebSharedWorkerCreationContextType, blink::WebSharedWorkerCreationContextTypeLast) IPC_ENUM_TRAITS_MIN_MAX_VALUE(blink::WebInputEvent::Type, diff --git a/chromium/content/common/content_switches_internal.cc b/chromium/content/common/content_switches_internal.cc index f496c504f59..d0d5ec7e933 100644 --- a/chromium/content/common/content_switches_internal.cc +++ b/chromium/content/common/content_switches_internal.cc @@ -20,9 +20,9 @@ namespace content { namespace { -#if defined(OS_WIN) -static bool g_win32k_renderer_lockdown_disabled = false; -#endif +bool IsUseZoomForDSFEnabledByDefault() { + return false; +} } // namespace @@ -30,29 +30,13 @@ bool IsPinchToZoomEnabled() { const base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); - // --disable-pinch should always disable pinch - if (command_line.HasSwitch(switches::kDisablePinch)) - return false; - -#if defined(OS_WIN) - return base::win::GetVersion() >= base::win::VERSION_WIN8; -#elif defined(OS_CHROMEOS) - return true; -#else - return command_line.HasSwitch(switches::kEnableViewport) || - command_line.HasSwitch(switches::kEnablePinch); -#endif + // Enable pinch everywhere unless it's been explicitly disabled. + return !command_line.HasSwitch(switches::kDisablePinch); } #if defined(OS_WIN) -void DisableWin32kRendererLockdown() { - g_win32k_renderer_lockdown_disabled = true; -} - bool IsWin32kRendererLockdownEnabled() { - if (g_win32k_renderer_lockdown_disabled) - return false; if (base::win::GetVersion() < base::win::VERSION_WIN8) return false; if (!gfx::win::ShouldUseDirectWrite()) @@ -84,8 +68,15 @@ V8CacheOptions GetV8CacheOptions() { } bool IsUseZoomForDSFEnabled() { - static bool enabled = base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableUseZoomForDSF); + static bool use_zoom_for_dsf_enabled_by_default = + IsUseZoomForDSFEnabledByDefault(); + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + bool enabled = + (command_line->HasSwitch(switches::kEnableUseZoomForDSF) || + use_zoom_for_dsf_enabled_by_default) && + command_line->GetSwitchValueASCII( + switches::kEnableUseZoomForDSF) != "false"; + return enabled; } diff --git a/chromium/content/common/content_switches_internal.h b/chromium/content/common/content_switches_internal.h index 990070c4ccd..aacd9426e58 100644 --- a/chromium/content/common/content_switches_internal.h +++ b/chromium/content/common/content_switches_internal.h @@ -6,21 +6,19 @@ #define CONTENT_COMMON_CONTENT_SWITCHES_INTERNAL_H_ #include "build/build_config.h" +#include "content/common/content_export.h" #include "content/public/common/web_preferences.h" namespace content { bool IsPinchToZoomEnabled(); #if defined(OS_WIN) -// Disables Win32k Renderer lockdown for any future renderer child processes. -void DisableWin32kRendererLockdown(); - // Returns whether Win32k Renderer lockdown is enabled or not. bool IsWin32kRendererLockdownEnabled(); #endif V8CacheOptions GetV8CacheOptions(); -bool IsUseZoomForDSFEnabled(); +CONTENT_EXPORT bool IsUseZoomForDSFEnabled(); } // namespace content diff --git a/chromium/content/common/database_identifier_unittest.cc b/chromium/content/common/database_identifier_unittest.cc index f866b7639ef..dac125a9bba 100644 --- a/chromium/content/common/database_identifier_unittest.cc +++ b/chromium/content/common/database_identifier_unittest.cc @@ -35,6 +35,9 @@ TEST(DatabaseIdentifierTest, CreateIdentifierFromOrigin) { {"data:", "__0"}, {"about:blank", "__0"}, {"non-standard://foobar.com", "__0"}, + {"http://[::1]:8080", "http_[__1]_8080"}, + {"http://[3ffe:2a00:100:7031::1]", "http_[3ffe_2a00_100_7031__1]_0"}, + {"http://[::ffff:8190:3426]", "http_[__ffff_8190_3426]_0"}, }; for (size_t i = 0; i < arraysize(cases); ++i) { @@ -203,6 +206,13 @@ TEST(DatabaseIdentifierTest, ExtractOriginDataFromIdentifier) { {"http_dot.com_0", "http", "dot.com", 0, GURL("http://dot.com"), false}, {"http_escaped%3Dfun.com_0", "http", "escaped%3dfun.com", 0, GURL("http://escaped%3dfun.com"), false}, + {"http_[__1]_8080", + "http", "[::1]", 8080, GURL("http://[::1]:8080"), false}, + {"http_[3ffe_2a00_100_7031__1]_0", + "http", "[3ffe:2a00:100:7031::1]", 0, + GURL("http://[3ffe:2a00:100:7031::1]"), false}, + {"http_[__ffff_8190_3426]_0", + "http", "[::ffff:8190:3426]", 0, GURL("http://[::ffff:8190:3426]"), false}, }; for (size_t i = 0; i < arraysize(valid_cases); ++i) { @@ -245,5 +255,33 @@ TEST(DatabaseIdentifierTest, ExtractOriginDataFromIdentifier) { } } +static GURL ToAndFromOriginIdentifier(const GURL origin_url) { + std::string id = storage::GetIdentifierFromOrigin(origin_url); + return storage::GetOriginFromIdentifier(id); +} + +static void TestValidOriginIdentifier(bool expected_result, + const std::string& id) { + EXPECT_EQ(expected_result, + storage::IsValidOriginIdentifier(id)); +} + +TEST(DatabaseIdentifierTest, OriginIdentifiers) { + const GURL kFileOrigin(GURL("file:///").GetOrigin()); + const GURL kHttpOrigin(GURL("http://bar/").GetOrigin()); + EXPECT_EQ(kFileOrigin, ToAndFromOriginIdentifier(kFileOrigin)); + EXPECT_EQ(kHttpOrigin, ToAndFromOriginIdentifier(kHttpOrigin)); +} + +TEST(DatabaseIdentifierTest, IsValidOriginIdentifier) { + TestValidOriginIdentifier(true, "http_bar_0"); + TestValidOriginIdentifier(false, ""); + TestValidOriginIdentifier(false, "bad..id"); + TestValidOriginIdentifier(false, "bad/id"); + TestValidOriginIdentifier(false, "bad\\id"); + TestValidOriginIdentifier(false, "http_bad:0_2"); + TestValidOriginIdentifier(false, std::string("bad\0id", 6)); +} + } // namespace } // namespace content diff --git a/chromium/content/common/devtools_messages.h b/chromium/content/common/devtools_messages.h index 7edc617df96..4c7c24a089d 100644 --- a/chromium/content/common/devtools_messages.h +++ b/chromium/content/common/devtools_messages.h @@ -43,7 +43,6 @@ #include <string> #include "content/common/content_export.h" -#include "content/public/common/common_param_traits.h" #include "content/public/common/console_message_level.h" #include "ipc/ipc_message_macros.h" @@ -103,6 +102,19 @@ IPC_MESSAGE_ROUTED2(DevToolsAgentMsg_InspectElement, int /* x */, int /* y */) +// ACK for DevToolsAgentHostMsg_RequestNewWindow message. +IPC_MESSAGE_ROUTED1(DevToolsAgentMsg_RequestNewWindow_ACK, + bool /* success */) + +//----------------------------------------------------------------------------- +// These are messages sent from renderer's DevToolsAgent to browser. + +// Requests new DevTools window being opened for frame in the same process +// with given routing id. +IPC_MESSAGE_ROUTED1(DevToolsAgentHostMsg_RequestNewWindow, + int /* frame_route_id */) + + //----------------------------------------------------------------------------- // These are messages sent from the browser to the renderer. diff --git a/chromium/content/common/discardable_shared_memory_heap.cc b/chromium/content/common/discardable_shared_memory_heap.cc index 263f83b24ad..3e39216cbc1 100644 --- a/chromium/content/common/discardable_shared_memory_heap.cc +++ b/chromium/content/common/discardable_shared_memory_heap.cc @@ -418,12 +418,14 @@ void DiscardableSharedMemoryHeap::OnMemoryDump( // to avoid double-counting segments when both browser and child process emit // them. In the special case of single-process-mode, this will be the only // dumper active and the single ownership edge will become a no-op in the UI. + // The global dump is created as a weak dump so that the segment is removed if + // the browser does not dump it (segment was purged). const uint64_t tracing_process_id = base::trace_event::MemoryDumpManager::GetInstance() ->GetTracingProcessId(); base::trace_event::MemoryAllocatorDumpGuid shared_segment_guid = GetSegmentGUIDForTracing(tracing_process_id, segment_id); - pmd->CreateSharedGlobalAllocatorDump(shared_segment_guid); + pmd->CreateWeakSharedGlobalAllocatorDump(shared_segment_guid); // The size is added to the global dump so that it gets propagated to both the // dumps associated. diff --git a/chromium/content/common/dom_storage/dom_storage_messages.h b/chromium/content/common/dom_storage/dom_storage_messages.h index 7fd4426a766..59d22c9641b 100644 --- a/chromium/content/common/dom_storage/dom_storage_messages.h +++ b/chromium/content/common/dom_storage/dom_storage_messages.h @@ -7,11 +7,11 @@ #include <stdint.h> #include "content/common/dom_storage/dom_storage_types.h" -#include "content/public/common/common_param_traits.h" #include "ipc/ipc_message_macros.h" #include "ipc/ipc_param_traits.h" #include "third_party/WebKit/public/platform/WebStorageArea.h" #include "url/gurl.h" +#include "url/ipc/url_param_traits.h" #define IPC_MESSAGE_START DOMStorageMsgStart diff --git a/chromium/content/common/drag_messages.h b/chromium/content/common/drag_messages.h index 455bbffa067..8d2fd772370 100644 --- a/chromium/content/common/drag_messages.h +++ b/chromium/content/common/drag_messages.h @@ -6,7 +6,6 @@ // Multiply-included message file, hence no include guard. #include "content/common/drag_event_source_info.h" -#include "content/public/common/common_param_traits.h" #include "content/public/common/drop_data.h" #include "ipc/ipc_message_macros.h" #include "third_party/WebKit/public/web/WebDragOperation.h" diff --git a/chromium/content/common/dwrite_font_platform_win.cc b/chromium/content/common/dwrite_font_platform_win.cc deleted file mode 100644 index 56140f421aa..00000000000 --- a/chromium/content/common/dwrite_font_platform_win.cc +++ /dev/null @@ -1,1282 +0,0 @@ -// Copyright 2014 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 "content/public/common/dwrite_font_platform_win.h" - -#include <windows.h> -#include <stddef.h> -#include <stdint.h> - -#include <dwrite.h> -#include <wrl/implements.h> -#include <wrl/wrappers/corewrappers.h> - -#include <limits> -#include <map> -#include <string> -#include <utility> -#include <vector> - -#include "base/command_line.h" -#include "base/debug/alias.h" -#include "base/debug/crash_logging.h" -#include "base/files/file_enumerator.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/memory_mapped_file.h" -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/shared_memory.h" -#include "base/metrics/field_trial.h" -#include "base/metrics/histogram.h" -#include "base/path_service.h" -#include "base/process/process_handle.h" -#include "base/stl_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/synchronization/lock.h" -#include "base/time/time.h" -#include "base/trace_event/trace_event.h" -#include "base/win/registry.h" -#include "base/win/scoped_comptr.h" -#include "content/public/common/content_switches.h" - -namespace { - -// Font Cache implementation short story: -// Due to our sandboxing restrictions, we cannot connect to Windows font cache -// service from Renderer and need to use DirectWrite isolated font loading -// mechanism. -// DirectWrite needs to be initialized before any of the API could be used. -// During initialization DirectWrite loads all font files and populates -// internal cache, we refer this phase as enumeration and we are trying -// to optimize this phase in our cache approach. Using cache during -// initialization will help improve on startup latency in each renderer -// instance. -// During enumeration DirectWrite reads various fragments from .ttf/.ttc -// font files. Our assumption is that these fragments are being read to -// cache information such as font families, supported sizes etc. -// For reading fragments DirectWrite calls ReadFragment of our FontFileStream -// implementation with parameters start_offset and length. We cache these -// parameters along with associated data chunk. -// Here is small example of how segments are read -// start_offset: 0, length: 16 -// start_offset: 0, length: 12 -// start_offset: 0, length: 117 -// For better cache management we collapse segments if they overlap or are -// adjacent. - -namespace mswr = Microsoft::WRL; - -const char kFontKeyName[] = "font_key_name"; - -// We use this value to determine whether to cache file fragments -// or not. In our trials we observed that for some font files -// direct write ends up reading almost entire file during enumeration -// phase. If we don't use this percentile formula we will end up -// increasing significant cache size by caching entire file contents -// for some of the font files. -const double kMaxPercentileOfFontFileSizeToCache = 0.6; - -// With current implementation we map entire shared section into memory during -// renderer startup. This causes increase in working set of Chrome. As first -// step we want to see if caching is really improving any performance for our -// users, so we are putting arbitrary limit on cache file size. There are -// multiple ways we can tune our working size, like mapping only required part -// of section at any given time. -const double kArbitraryCacheFileSizeLimit = (30 * 1024 * 1024); - -// We have chosen current font file length arbitrarily. In our logic -// if we don't find file we are looking for in cache we end up loading -// that file directly from system fonts folder. -const unsigned int kMaxFontFileNameLength = 34; - -const DWORD kCacheFileVersion = 103; -const DWORD kFileSignature = 0x4D4F5243; // CROM -const DWORD kMagicCompletionSignature = 0x454E4F44; // DONE - -const DWORD kUndefinedDWORDS = 36; - -// Make sure that all structure sizes align with 8 byte boundary otherwise -// dr. memory test may complain. -#pragma pack(push, 8) -// Cache file header, includes signature, completion bits and version. -struct CacheFileHeader { - CacheFileHeader() { - file_signature = kFileSignature; - magic_completion_signature = 0; - version = kCacheFileVersion; - ::ZeroMemory(undefined, sizeof(undefined)); - } - - DWORD file_signature; - DWORD magic_completion_signature; - DWORD version; - BYTE undefined[kUndefinedDWORDS]; -}; - -// Entry for a particular font file within this cache. -struct CacheFileEntry { - CacheFileEntry() { - file_size = 0; - entry_count = 0; - ::ZeroMemory(file_name, sizeof(file_name)); - } - - UINT64 file_size; - DWORD entry_count; - wchar_t file_name[kMaxFontFileNameLength]; -}; - -// Offsets or data chunks that are cached for particular font file. -struct CacheFileOffsetEntry { - CacheFileOffsetEntry() { - start_offset = 0; - length = 0; - } - - UINT64 start_offset; - UINT64 length; - /* BYTE blob_[]; // Place holder for the blob that follows. */ -}; -#pragma pack(pop) - -bool ValidateFontCacheHeader(CacheFileHeader* header) { - return (header->file_signature == kFileSignature && - header->magic_completion_signature == kMagicCompletionSignature && - header->version == kCacheFileVersion); -} - -class FontCacheWriter; - -// This class implements main interface required for loading custom font -// collection as specified by DirectWrite. We also use this class for storing -// some state information as this is one of the centralized entity. -class FontCollectionLoader - : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>, - IDWriteFontCollectionLoader> { - public: - FontCollectionLoader() - : in_collection_building_mode_(false), - create_static_cache_(false) {} - - ~FontCollectionLoader() override; - - HRESULT RuntimeClassInitialize() { - return S_OK; - } - - // IDWriteFontCollectionLoader methods. - HRESULT STDMETHODCALLTYPE - CreateEnumeratorFromKey(IDWriteFactory* factory, - void const* key, - UINT32 key_size, - IDWriteFontFileEnumerator** file_enumerator) override; - - // Does all the initialization for required loading fonts from registry. - static HRESULT Initialize(IDWriteFactory* factory); - - // Returns font cache map size. - UINT32 GetFontMapSize(); - - // Returns font name string when given font index. - base::string16 GetFontNameFromKey(UINT32 idx); - - // Loads internal structure with fonts from registry. - bool LoadFontListFromRegistry(); - - // Loads restricted web safe fonts as fallback method to registry fonts. - bool LoadRestrictedFontList(); - - // Puts class in collection building mode. In collection building mode - // we use static cache if it is available as a look aside buffer. - void EnableCollectionBuildingMode(bool enable); - - // Returns current state of collection building. - bool InCollectionBuildingMode(); - - // Loads static cache file. - bool LoadCacheFile(); - - // Unloads cache file and related data. - void UnloadCacheFile(); - - // Puts class in static cache creating mode. In this mode we record all - // direct write requests and store chunks of font data. - void EnterStaticCacheMode(const WCHAR* file_name); - - // Gets out of static cache building mode. - void LeaveStaticCacheMode(); - - // Returns if class is currently in static cache building mode. - bool IsBuildStaticCacheMode(); - - // Validates cache file for consistency. - bool ValidateCacheFile(base::File* file); - - private: - // Structure to represent each chunk within font file that we load in memory. - struct CacheTableOffsetEntry { - UINT64 start_offset; - UINT64 length; - BYTE* inside_file_ptr; - }; - - typedef std::vector<CacheTableOffsetEntry> OffsetVector; - - // Structure representing each font entry with cache. - struct CacheTableEntry { - UINT64 file_size; - OffsetVector offset_entries; - }; - - public: - // Returns whether file we have particular font entry within cache or not. - bool IsFileCached(UINT32 font_key); - // Returns cache fragment corresponding to specific font key. - void* GetCachedFragment(UINT32 font_key, UINT64 start_offset, UINT64 length); - // Returns actual font file size at the time of caching. - UINT64 GetCachedFileSize(UINT32 font_key); - - // Returns instance of font cache writer. This class manages actual font - // file format. - FontCacheWriter* GetFontCacheWriter(); - - private: - // Functions validates and loads cache into internal map. - bool ValidateAndLoadCacheMap(); - - mswr::ComPtr<IDWriteFontFileLoader> file_loader_; - - std::vector<base::string16> reg_fonts_; - bool in_collection_building_mode_; - bool create_static_cache_; - scoped_ptr<base::SharedMemory> cache_; - scoped_ptr<FontCacheWriter> cache_writer_; - - typedef std::map<base::string16, CacheTableEntry*> CacheMap; - CacheMap cache_map_; - - DISALLOW_COPY_AND_ASSIGN(FontCollectionLoader); -}; - -mswr::ComPtr<FontCollectionLoader> g_font_loader; -base::win::ScopedHandle g_shared_font_cache; - -// Class responsible for handling font cache file format details as well as -// tracking various cache region requests by direct write. -class FontCacheWriter { - public: - FontCacheWriter() : count_font_entries_ignored_(0), cookie_counter_(0) {} - - ~FontCacheWriter() { - if (static_cache_.get()) { - static_cache_->Close(); - } - } - - public: - // Holds data related to individual region as requested by direct write. - struct CacheRegion { - UINT64 start_offset; - UINT64 length; - const BYTE* ptr; - /* BYTE blob_[]; // Place holder for the blob that follows. */ - }; - - // Function to create static font cache file. - bool Create(const wchar_t* file_name) { - static_cache_.reset(new base::File(base::FilePath(file_name), - base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE | - base::File::FLAG_EXCLUSIVE_WRITE)); - if (!static_cache_->IsValid()) { - static_cache_.reset(); - return false; - } - CacheFileHeader header; - - // At offset 0 write cache version - static_cache_->Write(0, - reinterpret_cast<const char*>(&header), - sizeof(header)); - - static_cache_->Flush(); - return true; - } - - // Closes static font cache file. Also writes completion signature to mark - // it as completely written. - void Close() { - if (static_cache_.get()) { - CacheFileHeader header; - header.magic_completion_signature = kMagicCompletionSignature; - // At offset 0 write cache version - int bytes_written = static_cache_->Write(0, - reinterpret_cast<const char*>(&header), - sizeof(header)); - DCHECK_NE(bytes_written, -1); - - UMA_HISTOGRAM_MEMORY_KB("DirectWrite.Fonts.BuildCache.File.Size", - static_cache_->GetLength() / 1024); - - UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.BuildCache.Ignored", - count_font_entries_ignored_); - - static_cache_->Close(); - static_cache_.reset(NULL); - } - } - - private: - typedef std::vector<CacheRegion> RegionVector; - - // Structure to track various regions requested by direct write for particular - // font file. - struct FontEntryInternal { - FontEntryInternal(const wchar_t* name, UINT64 size) - : file_name(name), - file_size(size) { - } - - base::string16 file_name; - UINT64 file_size; - RegionVector regions; - }; - - public: - // Starts up new font entry to be tracked, returns cookie to identify this - // particular entry. - UINT NewFontEntry(const wchar_t* file_name, UINT64 file_size) { - base::AutoLock lock(lock_); - UINT old_counter = cookie_counter_; - FontEntryInternal* font_entry = new FontEntryInternal(file_name, file_size); - cookie_map_[cookie_counter_].reset(font_entry); - cookie_counter_++; - return old_counter; - } - - // AddRegion function lets caller add various regions to be cached for - // particular font file. Once enumerating that particular font file is done - // (based on uniquely identifying cookie) changes could be committed using - // CommitFontEntry - bool AddRegion(UINT64 cookie, UINT64 start, UINT64 length, const BYTE* ptr) { - base::AutoLock lock(lock_); - if (cookie_map_.find(cookie) == cookie_map_.end()) - return false; - RegionVector& regions = cookie_map_[cookie].get()->regions; - CacheRegion region; - region.start_offset = start; - region.length = length; - region.ptr = ptr; - regions.push_back(region); - return true; - } - - // Function which commits after merging all collected regions into cache file. - bool CommitFontEntry(UINT cookie) { - base::AutoLock lock(lock_); - if (cookie_map_.find(cookie) == cookie_map_.end()) - return false; - - // We will skip writing entries beyond allowed limit. Following condition - // doesn't enforce hard file size. We need to write complete font entry. - int64_t length = static_cache_->GetLength(); - if (length == -1 || length >= kArbitraryCacheFileSizeLimit) { - count_font_entries_ignored_++; - return false; - } - - FontEntryInternal* font_entry = cookie_map_[cookie].get(); - RegionVector& regions = font_entry->regions; - std::sort(regions.begin(), regions.end(), SortCacheRegions); - - // At this point, we have collected all regions to be cached. These regions - // are tuples of start, length, data for particular data segment. - // These tuples can overlap. - // e.g. (0, 12, data), (0, 117, data), (21, 314, data), (335, 15, data) - // In this case as you can see first three segments overlap and - // 4th is adjacent. If we cache them individually then we will end up - // caching duplicate data, so we merge these segments together to find - // superset for the cache. In above example our algorithm should - // produce (cache) single segment starting at offset 0 with length 350. - RegionVector merged_regions; - RegionVector::iterator iter; - int idx = 0; - for (iter = regions.begin(); iter != regions.end(); iter++) { - if (iter == regions.begin()) { - merged_regions.push_back(*iter); - continue; - } - CacheRegion& base_region = merged_regions[idx]; - if (IsOverlap(&base_region, &(*iter))) { - UINT64 end1 = base_region.start_offset + base_region.length; - UINT64 end2 = iter->start_offset + iter->length; - if (base_region.start_offset > iter->start_offset) { - base_region.start_offset = iter->start_offset; - base_region.ptr = iter->ptr; - } - base_region.length = std::max(end1, end2) - base_region.start_offset; - } else { - merged_regions.push_back(*iter); - idx++; - } - } - - UINT64 total_merged_cache_in_bytes = 0; - for (iter = merged_regions.begin(); iter != merged_regions.end(); iter++) { - total_merged_cache_in_bytes += iter->length; - } - - // We want to adjust following parameter based on experiments. But general - // logic here is that if we are going to end up caching most of the contents - // for a file (e.g. simsunb.ttf > 90%) then we should avoid caching that - // file. - double percentile = static_cast<double>(total_merged_cache_in_bytes) / - font_entry->file_size; - if (percentile > kMaxPercentileOfFontFileSizeToCache) { - count_font_entries_ignored_++; - return false; - } - - CacheFileEntry entry; - wcsncpy_s(entry.file_name, kMaxFontFileNameLength, - font_entry->file_name.c_str(), _TRUNCATE); - entry.file_size = font_entry->file_size; - entry.entry_count = merged_regions.size(); - static_cache_->WriteAtCurrentPos( - reinterpret_cast<const char*>(&entry), - sizeof(entry)); - for (iter = merged_regions.begin(); iter != merged_regions.end(); iter++) { - CacheFileOffsetEntry offset_entry; - offset_entry.start_offset = iter->start_offset; - offset_entry.length = iter->length; - static_cache_->WriteAtCurrentPos( - reinterpret_cast<const char*>(&offset_entry), - sizeof(offset_entry)); - static_cache_->WriteAtCurrentPos( - reinterpret_cast<const char*>(iter->ptr), - iter->length); - } - return true; - } - - private: - // This is the count of font entries that we reject based on size to be - // cached. - unsigned int count_font_entries_ignored_; - scoped_ptr<base::File> static_cache_; - std::map<UINT, scoped_ptr<FontEntryInternal>> cookie_map_; - UINT cookie_counter_; - - // Lock is required to protect internal data structures and access to file, - // According to MSDN documentation on ReadFileFragment and based on our - // experiments so far, there is possibility of ReadFileFragment getting called - // from multiple threads. - base::Lock lock_; - - // Function checks if two regions overlap or are adjacent. - bool IsOverlap(CacheRegion* region1, CacheRegion* region2) { - return - !((region1->start_offset + region1->length) < region2->start_offset || - region1->start_offset > (region2->start_offset + region2->length)); - } - - // Function to sort cached regions. - static bool SortCacheRegions(const CacheRegion& region1, - const CacheRegion& region2) { - return - region1.start_offset == region2.start_offset ? - region1.length < region2.length : - region1.start_offset < region2.start_offset; - } - - DISALLOW_COPY_AND_ASSIGN(FontCacheWriter); -}; - -// Class implements IDWriteFontFileStream interface as required by direct write. -class FontFileStream - : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>, - IDWriteFontFileStream> { - public: - // IDWriteFontFileStream methods. - HRESULT STDMETHODCALLTYPE ReadFileFragment( - void const** fragment_start, - UINT64 file_offset, - UINT64 fragment_size, - void** context) override { - if (cached_data_) { - *fragment_start = g_font_loader->GetCachedFragment(font_key_, - file_offset, - fragment_size); - if (*fragment_start == NULL) { - DCHECK(false); - } - *context = NULL; - return *fragment_start != NULL ? S_OK : E_FAIL; - } - if (!memory_.get() || !memory_->IsValid() || - file_offset >= memory_->length() || - (file_offset + fragment_size) > memory_->length()) - return E_FAIL; - - *fragment_start = static_cast<BYTE const*>(memory_->data()) + - static_cast<size_t>(file_offset); - *context = NULL; - if (g_font_loader->IsBuildStaticCacheMode()) { - FontCacheWriter* cache_writer = g_font_loader->GetFontCacheWriter(); - cache_writer->AddRegion(writer_cookie_, - file_offset, - fragment_size, - static_cast<const BYTE*>(*fragment_start)); - } - return S_OK; - } - - void STDMETHODCALLTYPE ReleaseFileFragment(void* context) override {} - - HRESULT STDMETHODCALLTYPE GetFileSize(UINT64* file_size) override { - if (cached_data_) { - *file_size = g_font_loader->GetCachedFileSize(font_key_); - return S_OK; - } - - if (!memory_.get() || !memory_->IsValid()) - return E_FAIL; - - *file_size = memory_->length(); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE GetLastWriteTime(UINT64* last_write_time) override { - if (cached_data_) { - *last_write_time = 0; - return S_OK; - } - - if (!memory_.get() || !memory_->IsValid()) - return E_FAIL; - - // According to MSDN article http://goo.gl/rrSYzi the "last modified time" - // is used by DirectWrite font selection algorithms to determine whether - // one font resource is more up to date than another one. - // So by returning 0 we are assuming that it will treat all fonts to be - // equally up to date. - // TODO(shrikant): We should further investigate this. - *last_write_time = 0; - return S_OK; - } - - FontFileStream() : font_key_(0), cached_data_(false) {} - - HRESULT RuntimeClassInitialize(UINT32 font_key) { - if (g_font_loader->InCollectionBuildingMode() && - g_font_loader->IsFileCached(font_key)) { - cached_data_ = true; - font_key_ = font_key; - return S_OK; - } - - base::FilePath path; - PathService::Get(base::DIR_WINDOWS_FONTS, &path); - base::string16 font_key_name(g_font_loader->GetFontNameFromKey(font_key)); - path = path.Append(font_key_name.c_str()); - memory_.reset(new base::MemoryMappedFile()); - - // Put some debug information on stack. - WCHAR font_name[MAX_PATH]; - path.value().copy(font_name, arraysize(font_name)); - base::debug::Alias(font_name); - - if (!memory_->Initialize(path)) { - memory_.reset(); - return E_FAIL; - } - - font_key_ = font_key; - - base::debug::SetCrashKeyValue(kFontKeyName, - base::WideToUTF8(font_key_name)); - - if (g_font_loader->IsBuildStaticCacheMode()) { - FontCacheWriter* cache_writer = g_font_loader->GetFontCacheWriter(); - writer_cookie_ = cache_writer->NewFontEntry(font_key_name.c_str(), - memory_->length()); - } - return S_OK; - } - - ~FontFileStream() override { - if (g_font_loader->IsBuildStaticCacheMode()) { - FontCacheWriter* cache_writer = g_font_loader->GetFontCacheWriter(); - cache_writer->CommitFontEntry(writer_cookie_); - } - } - - private: - UINT32 font_key_; - scoped_ptr<base::MemoryMappedFile> memory_; - bool cached_data_; - UINT writer_cookie_; - - DISALLOW_COPY_AND_ASSIGN(FontFileStream); -}; - -// Implements IDWriteFontFileLoader as required by FontFileLoader. -class FontFileLoader - : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>, - IDWriteFontFileLoader> { - public: - // IDWriteFontFileLoader methods. - HRESULT STDMETHODCALLTYPE - CreateStreamFromKey(void const* ref_key, - UINT32 ref_key_size, - IDWriteFontFileStream** stream) override { - if (ref_key_size != sizeof(UINT32)) - return E_FAIL; - - UINT32 font_key = *static_cast<const UINT32*>(ref_key); - mswr::ComPtr<FontFileStream> font_stream; - HRESULT hr = mswr::MakeAndInitialize<FontFileStream>(&font_stream, - font_key); - if (SUCCEEDED(hr)) { - *stream = font_stream.Detach(); - return S_OK; - } - return E_FAIL; - } - - FontFileLoader() {} - ~FontFileLoader() override {} - - private: - DISALLOW_COPY_AND_ASSIGN(FontFileLoader); -}; - -// Implements IDWriteFontFileEnumerator as required by direct write. -class FontFileEnumerator - : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>, - IDWriteFontFileEnumerator> { - public: - // IDWriteFontFileEnumerator methods. - HRESULT STDMETHODCALLTYPE MoveNext(BOOL* has_current_file) override { - *has_current_file = FALSE; - - if (current_file_) - current_file_.ReleaseAndGetAddressOf(); - - if (font_idx_ < g_font_loader->GetFontMapSize()) { - HRESULT hr = - factory_->CreateCustomFontFileReference(&font_idx_, - sizeof(UINT32), - file_loader_.Get(), - current_file_.GetAddressOf()); - DCHECK(SUCCEEDED(hr)); - *has_current_file = TRUE; - font_idx_++; - } - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - GetCurrentFontFile(IDWriteFontFile** font_file) override { - if (!current_file_) { - *font_file = NULL; - return E_FAIL; - } - - *font_file = current_file_.Detach(); - return S_OK; - } - - FontFileEnumerator(const void* keys, - UINT32 buffer_size, - IDWriteFactory* factory, - IDWriteFontFileLoader* file_loader) - : factory_(factory), file_loader_(file_loader), font_idx_(0) {} - - ~FontFileEnumerator() override {} - - mswr::ComPtr<IDWriteFactory> factory_; - mswr::ComPtr<IDWriteFontFile> current_file_; - mswr::ComPtr<IDWriteFontFileLoader> file_loader_; - UINT32 font_idx_; - - private: - DISALLOW_COPY_AND_ASSIGN(FontFileEnumerator); -}; - -// IDWriteFontCollectionLoader methods. -HRESULT STDMETHODCALLTYPE FontCollectionLoader::CreateEnumeratorFromKey( - IDWriteFactory* factory, - void const* key, - UINT32 key_size, - IDWriteFontFileEnumerator** file_enumerator) { - *file_enumerator = mswr::Make<FontFileEnumerator>( - key, key_size, factory, file_loader_.Get()).Detach(); - return S_OK; -} - -// static -HRESULT FontCollectionLoader::Initialize(IDWriteFactory* factory) { - DCHECK(g_font_loader == NULL); - - HRESULT result; - result = mswr::MakeAndInitialize<FontCollectionLoader>(&g_font_loader); - if (FAILED(result) || !g_font_loader) { - DCHECK(false); - return E_FAIL; - } - - CHECK(g_font_loader->LoadFontListFromRegistry()); - - g_font_loader->file_loader_ = mswr::Make<FontFileLoader>().Detach(); - - factory->RegisterFontFileLoader(g_font_loader->file_loader_.Get()); - factory->RegisterFontCollectionLoader(g_font_loader.Get()); - - return S_OK; -} - -FontCollectionLoader::~FontCollectionLoader() { - STLDeleteContainerPairSecondPointers(cache_map_.begin(), cache_map_.end()); -} - -UINT32 FontCollectionLoader::GetFontMapSize() { - return reg_fonts_.size(); -} - -base::string16 FontCollectionLoader::GetFontNameFromKey(UINT32 idx) { - DCHECK(idx < reg_fonts_.size()); - return reg_fonts_[idx]; -} - -const base::FilePath::CharType* kFontExtensionsToIgnore[] { - FILE_PATH_LITERAL(".FON"), // Bitmap or vector - FILE_PATH_LITERAL(".PFM"), // Adobe Type 1 - FILE_PATH_LITERAL(".PFB"), // Adobe Type 1 -}; - -const wchar_t* kFontsToIgnore[] = { - // "Gill Sans Ultra Bold" turns into an Ultra Bold weight "Gill Sans" in - // DirectWrite, but most users don't have any other weights. The regular - // weight font is named "Gill Sans MT", but that ends up in a different - // family with that name. On Mac, there's a "Gill Sans" with various weights, - // so CSS authors use { 'font-family': 'Gill Sans', 'Gill Sans MT', ... } and - // because of the DirectWrite family futzing, they end up with an Ultra Bold - // font, when they just wanted "Gill Sans". Mozilla implemented a more - // complicated hack where they effectively rename the Ultra Bold font to - // "Gill Sans MT Ultra Bold", but because the Ultra Bold font is so ugly - // anyway, we simply ignore it. See - // http://www.microsoft.com/typography/fonts/font.aspx?FMID=978 for a picture - // of the font, and the file name. We also ignore "Gill Sans Ultra Bold - // Condensed". - L"gilsanub.ttf", - L"gillubcd.ttf", -}; - -bool FontCollectionLoader::LoadFontListFromRegistry() { - const wchar_t kFontsRegistry[] = - L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; - CHECK(reg_fonts_.empty()); - base::win::RegKey regkey; - if (regkey.Open(HKEY_LOCAL_MACHINE, kFontsRegistry, KEY_READ) != - ERROR_SUCCESS) { - return false; - } - - base::FilePath system_font_path; - PathService::Get(base::DIR_WINDOWS_FONTS, &system_font_path); - - base::string16 name; - base::string16 value; - for (DWORD idx = 0; idx < regkey.GetValueCount(); idx++) { - if (regkey.GetValueNameAt(idx, &name) == ERROR_SUCCESS && - regkey.ReadValue(name.c_str(), &value) == ERROR_SUCCESS) { - base::FilePath path(value.c_str()); - // We need to check if path in registry is absolute, if it is then - // we check if it is same as DIR_WINDOWS_FONTS otherwise we ignore. - bool absolute = path.IsAbsolute(); - if (absolute && - !base::FilePath::CompareEqualIgnoreCase(system_font_path.value(), - path.DirName().value())) { - continue; - } - - // Ignore if path ends with a separator. - if (path.EndsWithSeparator()) - continue; - - if (absolute) - value = path.BaseName().value(); - - bool should_ignore = false; - for (const auto& ignore : kFontsToIgnore) { - if (base::FilePath::CompareEqualIgnoreCase(value, ignore)) { - should_ignore = true; - break; - } - } - // DirectWrite doesn't support bitmap/vector fonts and Adobe type 1 - // fonts, we will ignore those font extensions. - // MSDN article: http://goo.gl/TfCOA - if (!should_ignore) { - for (const auto& ignore : kFontExtensionsToIgnore) { - if (path.MatchesExtension(ignore)) { - should_ignore = true; - break; - } - } - } - - if (!should_ignore) - reg_fonts_.push_back(value.c_str()); - } - } - UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.Loaded", reg_fonts_.size()); - UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.Ignored", - regkey.GetValueCount() - reg_fonts_.size()); - return true; -} - -// This list is mainly based on prefs/prefs_tab_helper.cc kFontDefaults. -const wchar_t* kRestrictedFontSet[] = { - // These are the "Web Safe" fonts. - L"times.ttf", // IDS_STANDARD_FONT_FAMILY - L"timesbd.ttf", // IDS_STANDARD_FONT_FAMILY - L"timesbi.ttf", // IDS_STANDARD_FONT_FAMILY - L"timesi.ttf", // IDS_STANDARD_FONT_FAMILY - L"cour.ttf", // IDS_FIXED_FONT_FAMILY - L"courbd.ttf", // IDS_FIXED_FONT_FAMILY - L"courbi.ttf", // IDS_FIXED_FONT_FAMILY - L"couri.ttf", // IDS_FIXED_FONT_FAMILY - L"consola.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN - L"consolab.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN - L"consolai.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN - L"consolaz.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN - L"arial.ttf", // IDS_SANS_SERIF_FONT_FAMILY - L"arialbd.ttf", // IDS_SANS_SERIF_FONT_FAMILY - L"arialbi.ttf", // IDS_SANS_SERIF_FONT_FAMILY - L"ariali.ttf", // IDS_SANS_SERIF_FONT_FAMILY - L"comic.ttf", // IDS_CURSIVE_FONT_FAMILY - L"comicbd.ttf", // IDS_CURSIVE_FONT_FAMILY - L"comici.ttf", // IDS_CURSIVE_FONT_FAMILY - L"comicz.ttf", // IDS_CURSIVE_FONT_FAMILY - L"impact.ttf", // IDS_FANTASY_FONT_FAMILY - L"georgia.ttf", - L"georgiab.ttf", - L"georgiai.ttf", - L"georgiaz.ttf", - L"trebuc.ttf", - L"trebucbd.ttf", - L"trebucbi.ttf", - L"trebucit.ttf", - L"verdana.ttf", - L"verdanab.ttf", - L"verdanai.ttf", - L"verdanaz.ttf", - L"segoeui.ttf", // IDS_PICTOGRAPH_FONT_FAMILY - L"segoeuib.ttf", // IDS_PICTOGRAPH_FONT_FAMILY - L"segoeuii.ttf", // IDS_PICTOGRAPH_FONT_FAMILY - L"msgothic.ttc", // IDS_STANDARD_FONT_FAMILY_JAPANESE - L"msmincho.ttc", // IDS_SERIF_FONT_FAMILY_JAPANESE - L"gulim.ttc", // IDS_FIXED_FONT_FAMILY_KOREAN - L"batang.ttc", // IDS_SERIF_FONT_FAMILY_KOREAN - L"simsun.ttc", // IDS_STANDARD_FONT_FAMILY_SIMPLIFIED_HAN - L"mingliu.ttc", // IDS_SERIF_FONT_FAMILY_TRADITIONAL_HAN - - // These are from the Blink fallback list. - L"david.ttf", // USCRIPT_HEBREW - L"davidbd.ttf", // USCRIPT_HEBREW - L"euphemia.ttf", // USCRIPT_CANADIAN_ABORIGINAL - L"gautami.ttf", // USCRIPT_TELUGU - L"gautamib.ttf", // USCRIPT_TELUGU - L"latha.ttf", // USCRIPT_TAMIL - L"lathab.ttf", // USCRIPT_TAMIL - L"mangal.ttf", // USCRIPT_DEVANAGARI - L"mangalb.ttf", // USCRIPT_DEVANAGARI - L"monbaiti.ttf", // USCRIPT_MONGOLIAN - L"mvboli.ttf", // USCRIPT_THAANA - L"plantc.ttf", // USCRIPT_CHEROKEE - L"raavi.ttf", // USCRIPT_GURMUKHI - L"raavib.ttf", // USCRIPT_GURMUKHI - L"shruti.ttf", // USCRIPT_GUJARATI - L"shrutib.ttf", // USCRIPT_GUJARATI - L"sylfaen.ttf", // USCRIPT_GEORGIAN and USCRIPT_ARMENIAN - L"tahoma.ttf", // USCRIPT_ARABIC, - L"tahomabd.ttf", // USCRIPT_ARABIC, - L"tunga.ttf", // USCRIPT_KANNADA - L"tungab.ttf", // USCRIPT_KANNADA - L"vrinda.ttf", // USCRIPT_BENGALI - L"vrindab.ttf", // USCRIPT_BENGALI -}; - -bool FontCollectionLoader::LoadRestrictedFontList() { - reg_fonts_.clear(); - reg_fonts_.assign(kRestrictedFontSet, - kRestrictedFontSet + _countof(kRestrictedFontSet)); - return true; -} - -void FontCollectionLoader::EnableCollectionBuildingMode(bool enable) { - in_collection_building_mode_ = enable; -} - -bool FontCollectionLoader::InCollectionBuildingMode() { - return in_collection_building_mode_; -} - -bool FontCollectionLoader::IsFileCached(UINT32 font_key) { - if (!cache_.get() || cache_->memory() == NULL) { - return false; - } - CacheMap::iterator iter = cache_map_.find( - GetFontNameFromKey(font_key).c_str()); - return iter != cache_map_.end(); -} - -bool FontCollectionLoader::LoadCacheFile() { - TRACE_EVENT0("startup", "FontCollectionLoader::LoadCacheFile"); - - std::string font_cache_handle_string = - base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kFontCacheSharedHandle); - if (font_cache_handle_string.empty()) - return false; - - unsigned int handle_uint; - base::StringToUint(font_cache_handle_string, &handle_uint); - DCHECK(handle_uint); - if (handle_uint > static_cast<unsigned int>(std::numeric_limits<long>::max())) - return false; - base::SharedMemoryHandle font_cache_handle(LongToHandle(handle_uint), - base::GetCurrentProcId()); - - base::SharedMemory* shared_mem = new base::SharedMemory( - font_cache_handle, true); - // Map the cache file into memory. - shared_mem->Map(0); - - cache_.reset(shared_mem); - - if (base::StartsWith(base::FieldTrialList::FindFullName("LightSpeed"), - "PrefetchDWriteFontCache", - base::CompareCase::SENSITIVE)) { - // Prefetch the cache, to avoid unordered IO when it is used. - // PrefetchVirtualMemory() is loaded dynamically because it is only - // available from Win8. - decltype(PrefetchVirtualMemory)* prefetch_virtual_memory = - reinterpret_cast<decltype(PrefetchVirtualMemory)*>(::GetProcAddress( - ::GetModuleHandle(L"kernel32.dll"), "PrefetchVirtualMemory")); - if (prefetch_virtual_memory != NULL) { - WIN32_MEMORY_RANGE_ENTRY memory_range; - memory_range.VirtualAddress = shared_mem->memory(); - memory_range.NumberOfBytes = shared_mem->mapped_size(); - prefetch_virtual_memory(::GetCurrentProcess(), 1, &memory_range, 0); - } - } - - if (!ValidateAndLoadCacheMap()) { - cache_.reset(); - return false; - } - - return true; -} - -void FontCollectionLoader::UnloadCacheFile() { - cache_.reset(); - STLDeleteContainerPairSecondPointers(cache_map_.begin(), cache_map_.end()); - cache_map_.clear(); -} - -void FontCollectionLoader::EnterStaticCacheMode(const WCHAR* file_name) { - cache_writer_.reset(new FontCacheWriter()); - if (cache_writer_->Create(file_name)) - create_static_cache_ = true; -} - -void FontCollectionLoader::LeaveStaticCacheMode() { - cache_writer_->Close(); - cache_writer_.reset(NULL); - create_static_cache_ = false; -} - -bool FontCollectionLoader::IsBuildStaticCacheMode() { - return create_static_cache_; -} - -bool FontCollectionLoader::ValidateAndLoadCacheMap() { - BYTE* mem_file_start = static_cast<BYTE*>(cache_->memory()); - BYTE* mem_file_end = mem_file_start + cache_->mapped_size(); - - BYTE* current_ptr = mem_file_start; - CacheFileHeader* file_header = - reinterpret_cast<CacheFileHeader*>(current_ptr); - if (!ValidateFontCacheHeader(file_header)) - return false; - - current_ptr = current_ptr + sizeof(CacheFileHeader); - if (current_ptr >= mem_file_end) - return false; - - while ((current_ptr + sizeof(CacheFileEntry)) < mem_file_end) { - CacheFileEntry* entry = reinterpret_cast<CacheFileEntry*>(current_ptr); - current_ptr += sizeof(CacheFileEntry); - WCHAR file_name[kMaxFontFileNameLength]; - wcsncpy_s(file_name, - kMaxFontFileNameLength, - entry->file_name, - _TRUNCATE); - CacheTableEntry* table_entry = NULL; - CacheMap::iterator iter = cache_map_.find(file_name); - if (iter == cache_map_.end()) { - table_entry = new CacheTableEntry(); - cache_map_[file_name] = table_entry; - } else { - table_entry = iter->second; - } - table_entry->file_size = entry->file_size; - for (DWORD idx = 0; - (current_ptr + sizeof(CacheFileOffsetEntry)) < mem_file_end && - idx < entry->entry_count; - idx++) { - CacheFileOffsetEntry* offset_entry = - reinterpret_cast<CacheFileOffsetEntry*>(current_ptr); - CacheTableOffsetEntry table_offset_entry; - table_offset_entry.start_offset = offset_entry->start_offset; - table_offset_entry.length = offset_entry->length; - table_offset_entry.inside_file_ptr = - current_ptr + sizeof(CacheFileOffsetEntry); - table_entry->offset_entries.push_back(table_offset_entry); - current_ptr += sizeof(CacheFileOffsetEntry); - current_ptr += offset_entry->length; - } - } - - return true; -} - -void* FontCollectionLoader::GetCachedFragment(UINT32 font_key, - UINT64 start_offset, - UINT64 length) { - UINT64 just_past_end = start_offset + length; - CacheMap::iterator iter = cache_map_.find( - GetFontNameFromKey(font_key).c_str()); - if (iter != cache_map_.end()) { - CacheTableEntry* entry = iter->second; - OffsetVector::iterator offset_iter = entry->offset_entries.begin(); - while (offset_iter != entry->offset_entries.end()) { - UINT64 available_just_past_end = - offset_iter->start_offset + offset_iter->length; - if (offset_iter->start_offset <= start_offset && - just_past_end <= available_just_past_end) { - return offset_iter->inside_file_ptr + - (start_offset - offset_iter->start_offset); - } - offset_iter++; - } - } - return NULL; -} - -UINT64 FontCollectionLoader::GetCachedFileSize(UINT32 font_key) { - CacheMap::iterator iter = cache_map_.find( - GetFontNameFromKey(font_key).c_str()); - if (iter != cache_map_.end()) { - return iter->second->file_size; - } - return 0; -} - -FontCacheWriter* FontCollectionLoader::GetFontCacheWriter() { - return cache_writer_.get(); -} - -} // namespace - -namespace content { - -const char kFontCacheSharedSectionName[] = "ChromeDWriteFontCache"; - -mswr::ComPtr<IDWriteFontCollection> g_font_collection; - -IDWriteFontCollection* GetCustomFontCollection(IDWriteFactory* factory) { - if (g_font_collection.Get() != NULL) - return g_font_collection.Get(); - - TRACE_EVENT0("startup", "content::GetCustomFontCollection"); - - base::TimeTicks start_tick = base::TimeTicks::Now(); - - FontCollectionLoader::Initialize(factory); - - bool cache_file_loaded = g_font_loader->LoadCacheFile(); - - // Arbitrary threshold to stop loading enormous number of fonts. Usual - // side effect of loading large number of fonts results in renderer getting - // killed as it appears to hang. - const UINT32 kMaxFontThreshold = 1750; - HRESULT hr = E_FAIL; - if (cache_file_loaded || - g_font_loader->GetFontMapSize() < kMaxFontThreshold) { - g_font_loader->EnableCollectionBuildingMode(true); - hr = factory->CreateCustomFontCollection( - g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf()); - g_font_loader->UnloadCacheFile(); - g_font_loader->EnableCollectionBuildingMode(false); - } - bool loading_restricted = false; - if (FAILED(hr) || !g_font_collection.Get()) { - loading_restricted = true; - // We will try here just one more time with restricted font set. - g_font_loader->LoadRestrictedFontList(); - hr = factory->CreateCustomFontCollection( - g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf()); - } - - base::TimeDelta time_delta = base::TimeTicks::Now() - start_tick; - int64_t delta = time_delta.ToInternalValue(); - base::debug::Alias(&delta); - UINT32 size = g_font_loader->GetFontMapSize(); - base::debug::Alias(&size); - base::debug::Alias(&loading_restricted); - - CHECK(SUCCEEDED(hr)); - CHECK(g_font_collection.Get() != NULL); - - if (cache_file_loaded) - UMA_HISTOGRAM_TIMES("DirectWrite.Fonts.LoadTime.Cached", time_delta); - else - UMA_HISTOGRAM_TIMES("DirectWrite.Fonts.LoadTime", time_delta); - - base::debug::ClearCrashKey(kFontKeyName); - - return g_font_collection.Get(); -} - -bool BuildFontCacheInternal(const WCHAR* file_name) { - typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc; - HMODULE dwrite_dll = LoadLibraryW(L"dwrite.dll"); - if (!dwrite_dll) { - DWORD load_library_get_last_error = GetLastError(); - base::debug::Alias(&dwrite_dll); - base::debug::Alias(&load_library_get_last_error); - CHECK(false); - } - - DWriteCreateFactoryProc dwrite_create_factory_proc = - reinterpret_cast<DWriteCreateFactoryProc>( - GetProcAddress(dwrite_dll, "DWriteCreateFactory")); - - if (!dwrite_create_factory_proc) { - DWORD get_proc_address_get_last_error = GetLastError(); - base::debug::Alias(&dwrite_create_factory_proc); - base::debug::Alias(&get_proc_address_get_last_error); - CHECK(false); - } - - mswr::ComPtr<IDWriteFactory> factory; - - CHECK(SUCCEEDED( - dwrite_create_factory_proc( - DWRITE_FACTORY_TYPE_ISOLATED, - __uuidof(IDWriteFactory), - reinterpret_cast<IUnknown**>(factory.GetAddressOf())))); - - base::TimeTicks start_tick = base::TimeTicks::Now(); - - FontCollectionLoader::Initialize(factory.Get()); - - g_font_loader->EnterStaticCacheMode(file_name); - - mswr::ComPtr<IDWriteFontCollection> font_collection; - - HRESULT hr = E_FAIL; - g_font_loader->EnableCollectionBuildingMode(true); - hr = factory->CreateCustomFontCollection( - g_font_loader.Get(), NULL, 0, font_collection.GetAddressOf()); - g_font_loader->EnableCollectionBuildingMode(false); - - bool loading_restricted = false; - if (FAILED(hr) || !font_collection.Get()) { - loading_restricted = true; - // We will try here just one more time with restricted font set. - g_font_loader->LoadRestrictedFontList(); - hr = factory->CreateCustomFontCollection( - g_font_loader.Get(), NULL, 0, font_collection.GetAddressOf()); - } - - g_font_loader->LeaveStaticCacheMode(); - - base::TimeDelta time_delta = base::TimeTicks::Now() - start_tick; - int64_t delta = time_delta.ToInternalValue(); - base::debug::Alias(&delta); - UINT32 size = g_font_loader->GetFontMapSize(); - base::debug::Alias(&size); - base::debug::Alias(&loading_restricted); - - CHECK(SUCCEEDED(hr)); - CHECK(font_collection.Get() != NULL); - - base::debug::ClearCrashKey(kFontKeyName); - - return true; -} - -bool ValidateFontCacheFile(base::File* file) { - DCHECK(file != NULL); - CacheFileHeader file_header; - if (file->Read(0, reinterpret_cast<char*>(&file_header), sizeof(file_header)) - == -1) { - return false; - } - return ValidateFontCacheHeader(&file_header); -} - -bool LoadFontCache(const base::FilePath& path) { - scoped_ptr<base::File> file(new base::File(path, - base::File::FLAG_OPEN | base::File::FLAG_READ)); - if (!file->IsValid()) - return false; - - if (!ValidateFontCacheFile(file.get())) - return false; - - base::string16 name(base::ASCIIToUTF16(content::kFontCacheSharedSectionName)); - name.append(base::UintToString16(base::GetCurrentProcId())); - HANDLE mapping = ::CreateFileMapping( - file->GetPlatformFile(), - NULL, - PAGE_READONLY, - 0, - 0, - name.c_str()); - if (mapping == INVALID_HANDLE_VALUE) - return false; - - if (::GetLastError() == ERROR_ALREADY_EXISTS) { - CloseHandle(mapping); - // We crash here, as no one should have created this mapping except Chrome. - CHECK(false); - return false; - } - - DCHECK(!g_shared_font_cache.IsValid()); - g_shared_font_cache.Set(mapping); - - return true; -} - -bool BuildFontCache(const base::FilePath& file) { - return BuildFontCacheInternal(file.value().c_str()); -} - -bool ShouldUseDirectWriteFontProxyFieldTrial() { - return base::StartsWith( - base::FieldTrialList::FindFullName("DirectWriteFontProxy"), - "UseDirectWriteFontProxy", base::CompareCase::SENSITIVE); -} - -} // namespace content diff --git a/chromium/content/common/dwrite_font_platform_win_unittest.cc b/chromium/content/common/dwrite_font_platform_win_unittest.cc deleted file mode 100644 index 4e517feedf6..00000000000 --- a/chromium/content/common/dwrite_font_platform_win_unittest.cc +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2014 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 "content/public/common/dwrite_font_platform_win.h" - -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/logging.h" -#include "base/path_service.h" -#include "content/public/common/content_paths.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/win/direct_write.h" - -namespace content { - -class DWriteFontCacheTest : public testing::Test { - public: - DWriteFontCacheTest() { } - - void SetUp() override { - base::FilePath data_path; - ASSERT_TRUE(PathService::Get(content::DIR_TEST_DATA, &data_path)); - arial_cache_path_ = - data_path.AppendASCII("font/dwrite_font_cache_arial.dat"); - - corrupt_cache_path_ = - data_path.AppendASCII("font/dwrite_font_cache_corrupt.dat"); - - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - cache_file_path_ = temp_dir_.path().AppendASCII("dwrite_font_cache.dat"); - } - - protected: - base::FilePath arial_cache_path_; - base::FilePath corrupt_cache_path_; - base::ScopedTempDir temp_dir_; - base::FilePath cache_file_path_; -}; - -TEST_F(DWriteFontCacheTest, BuildCacheTest) { - if (gfx::win::ShouldUseDirectWrite()) { - DLOG(INFO) << __FUNCTION__ << ": " << cache_file_path_.value().c_str(); - EXPECT_TRUE(BuildFontCache(cache_file_path_)); - ASSERT_TRUE(base::PathExists(cache_file_path_)); - } -} - -TEST_F(DWriteFontCacheTest, ValidCacheTest) { - if (gfx::win::ShouldUseDirectWrite()) { - DLOG(INFO) << __FUNCTION__ << ": " << arial_cache_path_.value().c_str(); - scoped_ptr<base::File> file(new base::File(arial_cache_path_, - base::File::FLAG_OPEN | base::File::FLAG_READ)); - ASSERT_TRUE(file->IsValid()); - - EXPECT_TRUE(ValidateFontCacheFile(file.get())); - } -} - -TEST_F(DWriteFontCacheTest, CorruptCacheTest) { - if (gfx::win::ShouldUseDirectWrite()) { - DLOG(INFO) << __FUNCTION__ << ": " << corrupt_cache_path_.value().c_str(); - scoped_ptr<base::File> file(new base::File(corrupt_cache_path_, - base::File::FLAG_OPEN | base::File::FLAG_READ)); - ASSERT_TRUE(file->IsValid()); - - EXPECT_FALSE(ValidateFontCacheFile(file.get())); - } -} - -} // content diff --git a/chromium/content/common/establish_channel_params.cc b/chromium/content/common/establish_channel_params.cc new file mode 100644 index 00000000000..6ca5ac6a7bc --- /dev/null +++ b/chromium/content/common/establish_channel_params.cc @@ -0,0 +1,18 @@ +// Copyright 2016 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 "content/common/establish_channel_params.h" + +namespace content { + +EstablishChannelParams::EstablishChannelParams() + : client_id(0), + client_tracing_id(0), + preempts(false), + allow_view_command_buffers(false), + allow_real_time_streams(false) {} + +EstablishChannelParams::~EstablishChannelParams() {} + +} // namespace content diff --git a/chromium/content/common/establish_channel_params.h b/chromium/content/common/establish_channel_params.h new file mode 100644 index 00000000000..f77b1bd8e48 --- /dev/null +++ b/chromium/content/common/establish_channel_params.h @@ -0,0 +1,27 @@ +// Copyright 2016 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 CONTENT_COMMON_ESTABLISH_CHANNEL_PARAMS_H_ +#define CONTENT_COMMON_ESTABLISH_CHANNEL_PARAMS_H_ + +#include <stdint.h> + +#include "content/common/content_export.h" + +namespace content { + +struct CONTENT_EXPORT EstablishChannelParams { + EstablishChannelParams(); + ~EstablishChannelParams(); + + int client_id; + uint64_t client_tracing_id; + bool preempts; + bool allow_view_command_buffers; + bool allow_real_time_streams; +}; + +} // namespace content + +#endif // CONTENT_COMMON_ESTABLISH_CHANNEL_PARAMS_H_ diff --git a/chromium/content/common/experiments/api_key.cc b/chromium/content/common/experiments/api_key.cc deleted file mode 100644 index 9199d5d776f..00000000000 --- a/chromium/content/common/experiments/api_key.cc +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2015 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 "content/common/experiments/api_key.h" - -#include <openssl/curve25519.h> - -#include <vector> - -#include "base/base64.h" -#include "base/macros.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" -#include "url/origin.h" - -namespace content { - -namespace { - -// This is the default public key used for validating signatures. -// TODO(iclelland): Move this to the embedder, and provide a mechanism to allow -// for multiple signing keys. https://crbug.com/543220 -static const uint8_t kPublicKey[] = { - 0x7c, 0xc4, 0xb8, 0x9a, 0x93, 0xba, 0x6e, 0xe2, 0xd0, 0xfd, 0x03, - 0x1d, 0xfb, 0x32, 0x66, 0xc7, 0x3b, 0x72, 0xfd, 0x54, 0x3a, 0x07, - 0x51, 0x14, 0x66, 0xaa, 0x02, 0x53, 0x4e, 0x33, 0xa1, 0x15, -}; - -const char* kApiKeyFieldSeparator = "|"; - -} // namespace - -ApiKey::~ApiKey() {} - -scoped_ptr<ApiKey> ApiKey::Parse(const std::string& key_text) { - if (key_text.empty()) { - return nullptr; - } - - // API Key should resemble: - // signature|origin|api_name|expiry_timestamp - // TODO(iclelland): Add version code to API key format to identify key algo - // https://crbug.com/570684 - std::vector<std::string> parts = - SplitString(key_text, kApiKeyFieldSeparator, base::KEEP_WHITESPACE, - base::SPLIT_WANT_ALL); - if (parts.size() != 4) { - return nullptr; - } - - const std::string& signature = parts[0]; - const std::string& origin_string = parts[1]; - const std::string& api_name = parts[2]; - const std::string& expiry_string = parts[3]; - - uint64_t expiry_timestamp; - if (!base::StringToUint64(expiry_string, &expiry_timestamp)) { - return nullptr; - } - - // Ensure that the origin is a valid (non-unique) origin URL - GURL origin_url(origin_string); - if (url::Origin(origin_url).unique()) { - return nullptr; - } - - // signed data is (origin + "|" + api_name + "|" + expiry). - std::string data = key_text.substr(signature.length() + 1); - - return make_scoped_ptr( - new ApiKey(signature, data, origin_url, api_name, expiry_timestamp)); -} - -ApiKey::ApiKey(const std::string& signature, - const std::string& data, - const GURL& origin, - const std::string& api_name, - uint64_t expiry_timestamp) - : signature_(signature), - data_(data), - origin_(origin), - api_name_(api_name), - expiry_timestamp_(expiry_timestamp) {} - -bool ApiKey::IsAppropriate(const std::string& origin, - const std::string& api_name) const { - return ValidateOrigin(origin) && ValidateApiName(api_name); -} - -bool ApiKey::IsValid(const base::Time& now) const { - // TODO(iclelland): Allow for multiple signing keys, and iterate over all - // active keys here. https://crbug.com/543220 - return ValidateDate(now) && - ValidateSignature(base::StringPiece( - reinterpret_cast<const char*>(kPublicKey), arraysize(kPublicKey))); -} - -bool ApiKey::ValidateOrigin(const std::string& origin) const { - return GURL(origin) == origin_; -} - -bool ApiKey::ValidateApiName(const std::string& api_name) const { - return base::EqualsCaseInsensitiveASCII(api_name, api_name_); -} - -bool ApiKey::ValidateDate(const base::Time& now) const { - base::Time expiry_time = base::Time::FromDoubleT((double)expiry_timestamp_); - return expiry_time > now; -} - -bool ApiKey::ValidateSignature(const base::StringPiece& public_key) const { - return ValidateSignature(signature_, data_, public_key); -} - -// static -bool ApiKey::ValidateSignature(const std::string& signature_text, - const std::string& data, - const base::StringPiece& public_key) { - // Public key must be 32 bytes long for Ed25519. - CHECK_EQ(public_key.length(), 32UL); - - std::string signature; - // signature_text is base64-encoded; decode first. - if (!base::Base64Decode(signature_text, &signature)) { - return false; - } - - // Signature must be 64 bytes long - if (signature.length() != 64) { - return false; - } - - int result = ED25519_verify( - reinterpret_cast<const uint8_t*>(data.data()), data.length(), - reinterpret_cast<const uint8_t*>(signature.data()), - reinterpret_cast<const uint8_t*>(public_key.data())); - return (result != 0); -} - -} // namespace content diff --git a/chromium/content/common/experiments/api_key.h b/chromium/content/common/experiments/api_key.h deleted file mode 100644 index 1ad575a15e9..00000000000 --- a/chromium/content/common/experiments/api_key.h +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2015 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 CONTENT_COMMON_EXPERIMENTS_API_KEY_H_ -#define CONTENT_COMMON_EXPERIMENTS_API_KEY_H_ - -#include <string> - -#include "base/memory/scoped_ptr.h" -#include "base/strings/string_piece.h" -#include "base/time/time.h" -#include "content/common/content_export.h" -#include "url/gurl.h" - -namespace content { - -// The Experimental Framework (EF) provides limited access to experimental APIs, -// on a per-origin basis. This class defines the API key data structure, used -// to securely provide access to an experimental API. -// -// Experimental APIs are defined by string names, provided by the implementers. -// The EF code does not maintain an enum or constant list for experiment names. -// Instead, the EF validates the name provided by the API implementation against -// any provided API keys. -// -// More documentation on the key format can be found at -// https://docs.google.com/document/d/1v5fi0EUV_QHckVHVF2K4P72iNywnrJtNhNZ6i2NPt0M - -class CONTENT_EXPORT ApiKey { - public: - ~ApiKey(); - - // Returns a key object if the string represents a well-formed key, or - // nullptr otherwise. (This does not mean that the key is valid, just that it - // can be parsed.) - static scoped_ptr<ApiKey> Parse(const std::string& key_text); - - // Returns true if this API is appropriate for use by the given origin, for - // the given API name. This does not check whether the signature is valid, or - // whether the key itself has expired. - bool IsAppropriate(const std::string& origin, - const std::string& apiName) const; - - // Returns true if this API key has a valid signature, and has not expired. - bool IsValid(const base::Time& now) const; - - std::string signature() { return signature_; } - std::string data() { return data_; } - GURL origin() { return origin_; } - std::string api_name() { return api_name_; } - uint64_t expiry_timestamp() { return expiry_timestamp_; } - - protected: - friend class ApiKeyTest; - - bool ValidateOrigin(const std::string& origin) const; - bool ValidateApiName(const std::string& api_name) const; - bool ValidateDate(const base::Time& now) const; - bool ValidateSignature(const base::StringPiece& public_key) const; - - static bool ValidateSignature(const std::string& signature_text, - const std::string& data, - const base::StringPiece& public_key); - - private: - ApiKey(const std::string& signature, - const std::string& data, - const GURL& origin, - const std::string& api_name, - uint64_t expiry_timestamp); - - // The base64-encoded-signature portion of the key. For the key to be valid, - // this must be a valid signature for the data portion of the key, as verified - // by the public key in api_key.cc. - std::string signature_; - - // The portion of the key string which is signed, and whose signature is - // contained in the signature_ member. - std::string data_; - - // The origin for which this key is valid. Must be a secure origin. - GURL origin_; - - // The name of the API experiment which this key enables. - std::string api_name_; - - // The time until which this key should be considered valid, in UTC, as - // seconds since the Unix epoch. - uint64_t expiry_timestamp_; -}; - -} // namespace content - -#endif // CONTENT_COMMON_EXPERIMENTS_API_KEY_H_ diff --git a/chromium/content/common/experiments/api_key_unittest.cc b/chromium/content/common/experiments/api_key_unittest.cc deleted file mode 100644 index a70ffcc92cf..00000000000 --- a/chromium/content/common/experiments/api_key_unittest.cc +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2015 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 "content/common/experiments/api_key.h" - -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/string_util.h" -#include "base/test/simple_test_clock.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace content { - -namespace { - -// This is a sample public key for testing the API. The corresponding private -// key (use this to generate new samples for this test file) is: -// -// 0x83, 0x67, 0xf4, 0xcd, 0x2a, 0x1f, 0x0e, 0x04, 0x0d, 0x43, 0x13, -// 0x4c, 0x67, 0xc4, 0xf4, 0x28, 0xc9, 0x90, 0x15, 0x02, 0xe2, 0xba, -// 0xfd, 0xbb, 0xfa, 0xbc, 0x92, 0x76, 0x8a, 0x2c, 0x4b, 0xc7, 0x75, -// 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, 0x9a, -// 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, 0x64, -// 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0 -const uint8_t kTestPublicKey[] = { - 0x75, 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, - 0x9a, 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, - 0x64, 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0, -}; - -// This is a good key, signed with the above test private key. -const char* kSampleAPIKey = - "UsEO0cNxoUtBnHDJdGPWTlXuLENjXcEIPL7Bs7sbvicPCcvAtyqhQuTJ9h/u1R3VZpWigtI+S" - "dUwk7Dyk/qbDw==|https://valid.example.com|Frobulate|1458766277"; -const char* kExpectedAPIKeySignature = - "UsEO0cNxoUtBnHDJdGPWTlXuLENjXcEIPL7Bs7sbvicPCcvAtyqhQuTJ9h/u1R3VZpWigtI+S" - "dUwk7Dyk/qbDw=="; -const char* kExpectedAPIKeyData = - "https://valid.example.com|Frobulate|1458766277"; -const char* kExpectedAPIName = "Frobulate"; -const char* kExpectedOrigin = "https://valid.example.com"; -const uint64_t kExpectedExpiry = 1458766277; - -// The key should not be valid for this origin, or for this API. -const char* kInvalidOrigin = "https://invalid.example.com"; -const char* kInsecureOrigin = "http://valid.example.com"; -const char* kInvalidAPIName = "Grokalyze"; - -// The key should be valid if the current time is kValidTimestamp or earlier. -double kValidTimestamp = 1458766276.0; - -// The key should be invalid if the current time is kInvalidTimestamp or later. -double kInvalidTimestamp = 1458766278.0; - -// Well-formed API key with an invalid signature. -const char* kInvalidSignatureAPIKey = - "CO8hDne98QeFeOJ0DbRZCBN3uE0nyaPgaLlkYhSWnbRoDfEAg+TXELaYfQPfEvKYFauBg/hnx" - "mba765hz0mXMc==|https://valid.example.com|Frobulate|1458766277"; - -// Various ill-formed API keys. These should all fail to parse. -const char* kInvalidAPIKeys[] = { - // Invalid - only one part - "abcde", - // Not enough parts - "https://valid.example.com|APIName|1458766277", - // Delimiter in API Name - "Signature|https://valid.example.com|API|Name|1458766277", - // Extra string field - "Signature|https://valid.example.com|APIName|1458766277|SomethingElse", - // Extra numeric field - "Signature|https://valid.example.com|APIName|1458766277|1458766277", - // Non-numeric expiry timestamp - "Signature|https://valid.example.com|APIName|abcdefghij", - "Signature|https://valid.example.com|APIName|1458766277x", - // Negative expiry timestamp - "Signature|https://valid.example.com|APIName|-1458766277", - // Origin not a proper origin URL - "Signature|abcdef|APIName|1458766277", - "Signature|data:text/plain,abcdef|APIName|1458766277", - "Signature|javascript:alert(1)|APIName|1458766277"}; -const size_t kNumInvalidAPIKeys = arraysize(kInvalidAPIKeys); - -} // namespace - -class ApiKeyTest : public testing::Test { - public: - ApiKeyTest() - : public_key_( - base::StringPiece(reinterpret_cast<const char*>(kTestPublicKey), - arraysize(kTestPublicKey))) {} - - protected: - bool ValidateOrigin(ApiKey* api_key, const char* origin) { - return api_key->ValidateOrigin(origin); - } - - bool ValidateApiName(ApiKey* api_key, const char* api_name) { - return api_key->ValidateApiName(api_name); - } - - bool ValidateDate(ApiKey* api_key, const base::Time& now) { - return api_key->ValidateDate(now); - } - - bool ValidateSignature(ApiKey* api_key, const base::StringPiece& public_key) { - return api_key->ValidateSignature(public_key); - } - - const base::StringPiece& public_key() { return public_key_; }; - - private: - base::StringPiece public_key_; -}; - -TEST_F(ApiKeyTest, ParseEmptyString) { - scoped_ptr<ApiKey> empty_key = ApiKey::Parse(""); - EXPECT_FALSE(empty_key); -} - -TEST_F(ApiKeyTest, ParseInvalidStrings) { - for (size_t i = 0; i < kNumInvalidAPIKeys; ++i) { - scoped_ptr<ApiKey> empty_key = ApiKey::Parse(kInvalidAPIKeys[i]); - EXPECT_FALSE(empty_key) << "Invalid API Key should not parse: " - << kInvalidAPIKeys[i]; - } -} - -TEST_F(ApiKeyTest, ParseValidKeyString) { - scoped_ptr<ApiKey> key = ApiKey::Parse(kSampleAPIKey); - ASSERT_TRUE(key); - EXPECT_EQ(kExpectedAPIName, key->api_name()); - EXPECT_EQ(kExpectedAPIKeySignature, key->signature()); - EXPECT_EQ(kExpectedAPIKeyData, key->data()); - EXPECT_EQ(GURL(kExpectedOrigin), key->origin()); - EXPECT_EQ(kExpectedExpiry, key->expiry_timestamp()); -} - -TEST_F(ApiKeyTest, ValidateValidKey) { - scoped_ptr<ApiKey> key = ApiKey::Parse(kSampleAPIKey); - ASSERT_TRUE(key); - EXPECT_TRUE(ValidateOrigin(key.get(), kExpectedOrigin)); - EXPECT_FALSE(ValidateOrigin(key.get(), kInvalidOrigin)); - EXPECT_FALSE(ValidateOrigin(key.get(), kInsecureOrigin)); - EXPECT_TRUE(ValidateApiName(key.get(), kExpectedAPIName)); - EXPECT_FALSE(ValidateApiName(key.get(), kInvalidAPIName)); - EXPECT_TRUE( - ValidateDate(key.get(), base::Time::FromDoubleT(kValidTimestamp))); - EXPECT_FALSE( - ValidateDate(key.get(), base::Time::FromDoubleT(kInvalidTimestamp))); -} - -TEST_F(ApiKeyTest, KeyIsAppropriateForOriginAndAPI) { - scoped_ptr<ApiKey> key = ApiKey::Parse(kSampleAPIKey); - ASSERT_TRUE(key); - EXPECT_TRUE(key->IsAppropriate(kExpectedOrigin, kExpectedAPIName)); - EXPECT_TRUE(key->IsAppropriate(kExpectedOrigin, - base::ToUpperASCII(kExpectedAPIName))); - EXPECT_TRUE(key->IsAppropriate(kExpectedOrigin, - base::ToLowerASCII(kExpectedAPIName))); - EXPECT_FALSE(key->IsAppropriate(kInvalidOrigin, kExpectedAPIName)); - EXPECT_FALSE(key->IsAppropriate(kInsecureOrigin, kExpectedAPIName)); - EXPECT_FALSE(key->IsAppropriate(kExpectedOrigin, kInvalidAPIName)); -} - -TEST_F(ApiKeyTest, ValidateValidSignature) { - scoped_ptr<ApiKey> key = ApiKey::Parse(kSampleAPIKey); - ASSERT_TRUE(key); - EXPECT_TRUE(ValidateSignature(key.get(), public_key())); -} - -TEST_F(ApiKeyTest, ValidateInvalidSignature) { - scoped_ptr<ApiKey> key = ApiKey::Parse(kInvalidSignatureAPIKey); - ASSERT_TRUE(key); - EXPECT_FALSE(ValidateSignature(key.get(), public_key())); -} - -TEST_F(ApiKeyTest, ValidateSignatureOnWrongKey) { - scoped_ptr<ApiKey> key = ApiKey::Parse(kSampleAPIKey); - ASSERT_TRUE(key); - // Signature will be invalid if tested against the real public key - EXPECT_FALSE(key->IsValid(base::Time::FromDoubleT(kValidTimestamp))); -} - -TEST_F(ApiKeyTest, ValidateWhenNotExpired) { - scoped_ptr<ApiKey> key = ApiKey::Parse(kSampleAPIKey); - ASSERT_TRUE(key); -} - -} // namespace content diff --git a/chromium/content/common/fileapi/webblob_messages.h b/chromium/content/common/fileapi/webblob_messages.h index a836fd4f5ae..85dbf8c976c 100644 --- a/chromium/content/common/fileapi/webblob_messages.h +++ b/chromium/content/common/fileapi/webblob_messages.h @@ -7,29 +7,81 @@ #include <stddef.h> +#include <set> + +#include "base/memory/shared_memory.h" #include "content/common/content_export.h" -#include "content/public/common/common_param_traits.h" #include "ipc/ipc_message_macros.h" +#include "ipc/ipc_message_utils.h" +#include "ipc/ipc_param_traits.h" +#include "ipc/ipc_platform_file.h" +#include "storage/common/blob_storage/blob_item_bytes_request.h" +#include "storage/common/blob_storage/blob_item_bytes_response.h" +#include "storage/common/blob_storage/blob_storage_constants.h" #include "storage/common/data_element.h" +#include "url/ipc/url_param_traits.h" #undef IPC_MESSAGE_EXPORT #define IPC_MESSAGE_EXPORT CONTENT_EXPORT #define IPC_MESSAGE_START BlobMsgStart -// Blob messages sent from the renderer to the browser. - -IPC_MESSAGE_CONTROL1(BlobHostMsg_StartBuilding, - std::string /*uuid */) -IPC_MESSAGE_CONTROL2(BlobHostMsg_AppendBlobDataItem, +// Trait definitions for async blob transport messages. + +IPC_ENUM_TRAITS_MAX_VALUE(storage::IPCBlobItemRequestStrategy, + storage::IPCBlobItemRequestStrategy::LAST) +IPC_ENUM_TRAITS_MAX_VALUE(storage::IPCBlobCreationCancelCode, + storage::IPCBlobCreationCancelCode::LAST) + +IPC_STRUCT_TRAITS_BEGIN(storage::BlobItemBytesRequest) + IPC_STRUCT_TRAITS_MEMBER(request_number) + IPC_STRUCT_TRAITS_MEMBER(transport_strategy) + IPC_STRUCT_TRAITS_MEMBER(renderer_item_index) + IPC_STRUCT_TRAITS_MEMBER(renderer_item_offset) + IPC_STRUCT_TRAITS_MEMBER(size) + IPC_STRUCT_TRAITS_MEMBER(handle_index) + IPC_STRUCT_TRAITS_MEMBER(handle_offset) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(storage::BlobItemBytesResponse) + IPC_STRUCT_TRAITS_MEMBER(request_number) + IPC_STRUCT_TRAITS_MEMBER(inline_data) + IPC_STRUCT_TRAITS_MEMBER(time_file_modified) +IPC_STRUCT_TRAITS_END() + +// This message is to tell the browser that we will be building a blob. +IPC_MESSAGE_CONTROL4(BlobStorageMsg_RegisterBlobUUID, std::string /* uuid */, - storage::DataElement) -IPC_SYNC_MESSAGE_CONTROL3_0(BlobHostMsg_SyncAppendSharedMemory, - std::string /*uuid*/, - base::SharedMemoryHandle, - size_t /* buffer size */) -IPC_MESSAGE_CONTROL2(BlobHostMsg_FinishBuilding, + std::string /* content_type */, + std::string /* content_disposition */, + std::set<std::string> /* referenced_blob_uuids */) + +// The DataElements are used to: +// * describe & transport non-memory resources (blobs, files, etc) +// * describe the size of memory items +// * 'shortcut' transport the memory up to the IPC limit so the browser can use +// it if it's not currently full. +// See https://bit.ly/BlobStorageRefactor +IPC_MESSAGE_CONTROL2(BlobStorageMsg_StartBuildingBlob, std::string /* uuid */, - std::string /* content_type */) + std::vector<storage::DataElement> /* item_descriptions */) + +IPC_MESSAGE_CONTROL4( + BlobStorageMsg_RequestMemoryItem, + std::string /* uuid */, + std::vector<storage::BlobItemBytesRequest> /* requests */, + std::vector<base::SharedMemoryHandle> /* memory_handles */, + std::vector<IPC::PlatformFileForTransit> /* file_handles */) + +IPC_MESSAGE_CONTROL2( + BlobStorageMsg_MemoryItemResponse, + std::string /* uuid */, + std::vector<storage::BlobItemBytesResponse> /* responses */) + +IPC_MESSAGE_CONTROL2(BlobStorageMsg_CancelBuildingBlob, + std::string /* uuid */, + storage::IPCBlobCreationCancelCode /* code */) + +IPC_MESSAGE_CONTROL1(BlobStorageMsg_DoneBuildingBlob, std::string /* uuid */) IPC_MESSAGE_CONTROL1(BlobHostMsg_IncrementRefCount, std::string /* uuid */) @@ -57,7 +109,7 @@ IPC_MESSAGE_CONTROL2(StreamHostMsg_AppendBlobDataItem, IPC_SYNC_MESSAGE_CONTROL3_0(StreamHostMsg_SyncAppendSharedMemory, GURL /* url */, base::SharedMemoryHandle, - size_t /* buffer size */) + uint32_t /* buffer size */) // Flushes contents buffered in the stream. IPC_MESSAGE_CONTROL1(StreamHostMsg_Flush, diff --git a/chromium/content/common/font_config_ipc_linux.cc b/chromium/content/common/font_config_ipc_linux.cc index d1dd8ca187f..294bcf83fbf 100644 --- a/chromium/content/common/font_config_ipc_linux.cc +++ b/chromium/content/common/font_config_ipc_linux.cc @@ -13,9 +13,12 @@ #include <sys/uio.h> #include <unistd.h> +#include <functional> + #include "base/files/file_util.h" #include "base/files/memory_mapped_file.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/pickle.h" #include "base/posix/unix_domain_socket_linux.h" #include "base/threading/thread_restrictions.h" @@ -26,13 +29,12 @@ #include "third_party/skia/include/core/SkStream.h" #include "third_party/skia/include/core/SkTypeface.h" +namespace content { -namespace BASE_HASH_NAMESPACE { - -std::size_t hash<SkFontConfigInterface::FontIdentity>::operator()( +std::size_t SkFontConfigInterfaceFontIdentityHash::operator()( const SkFontConfigInterface::FontIdentity& sp) const { - hash<std::string> stringhash; - hash<int> inthash; + std::hash<std::string> stringhash; + std::hash<int> inthash; size_t r = inthash(sp.fID); r = r * 41 + inthash(sp.fTTCIndex); r = r * 41 + stringhash(sp.fString.c_str()); @@ -42,10 +44,6 @@ std::size_t hash<SkFontConfigInterface::FontIdentity>::operator()( return r; } -} // namespace BASE_HASH_NAMESPACE - -namespace content { - // Wikpedia's main country selection page activates 21 fallback fonts, // doubling this we should be on the generous side as an upper bound, // but nevertheless not have the mapped typefaces cache grow excessively. diff --git a/chromium/content/common/font_config_ipc_linux.h b/chromium/content/common/font_config_ipc_linux.h index 472c2f1aab4..5e969cd2f12 100644 --- a/chromium/content/common/font_config_ipc_linux.h +++ b/chromium/content/common/font_config_ipc_linux.h @@ -20,18 +20,14 @@ class SkString; -namespace BASE_HASH_NAMESPACE { -template <> -struct hash<SkFontConfigInterface::FontIdentity> { - std::size_t operator()(const SkFontConfigInterface::FontIdentity& sp) const; -}; -} - namespace content { +struct SkFontConfigInterfaceFontIdentityHash { + std::size_t operator()(const SkFontConfigInterface::FontIdentity& sp) const; +}; // FontConfig implementation for Skia that proxies out of process to get out -// of the sandbox. See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC +// of the sandbox. See https://chromium.googlesource.com/chromium/src/+/master/docs/linux_sandbox_ipc.md class FontConfigIPC : public SkFontConfigInterface { public: explicit FontConfigIPC(int fd); @@ -74,7 +70,9 @@ class FontConfigIPC : public SkFontConfigInterface { // ttc-indices or styles but the same fontconfig interface id. Since the usage // frequency of ttc indices is very low, and style is not used by clients of // this API, this seems okay. - base::HashingMRUCache<FontIdentity, skia::RefPtr<SkTypeface>> + base::HashingMRUCache<FontIdentity, + skia::RefPtr<SkTypeface>, + SkFontConfigInterfaceFontIdentityHash> mapped_typefaces_; DISALLOW_COPY_AND_ASSIGN(FontConfigIPC); diff --git a/chromium/content/common/font_list_win.cc b/chromium/content/common/font_list_win.cc index 2e07efa0689..62717ec3d24 100644 --- a/chromium/content/common/font_list_win.cc +++ b/chromium/content/common/font_list_win.cc @@ -50,7 +50,7 @@ scoped_ptr<base::ListValue> GetFontList_SlowBlocking() { font_item->Append(new base::StringValue(*iter)); font_list->Append(font_item); } - return font_list.Pass(); + return font_list; } } // namespace content diff --git a/chromium/content/common/font_warmup_win.cc b/chromium/content/common/font_warmup_win.cc deleted file mode 100644 index cdd1d0f2dba..00000000000 --- a/chromium/content/common/font_warmup_win.cc +++ /dev/null @@ -1,526 +0,0 @@ -// Copyright 2014 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 "content/common/font_warmup_win.h" - -#include <dwrite.h> -#include <stdint.h> -#include <map> - -#include "base/debug/alias.h" -#include "base/files/file_path.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/numerics/safe_conversions.h" -#include "base/numerics/safe_math.h" -#include "base/strings/utf_string_conversions.h" -#include "base/synchronization/lock.h" -#include "base/sys_byteorder.h" -#include "base/trace_event/trace_event.h" -#include "base/win/iat_patch_function.h" -#include "base/win/windows_version.h" -#include "content/public/common/dwrite_font_platform_win.h" -#include "ppapi/shared_impl/proxy_lock.h" -#include "skia/ext/fontmgr_default_win.h" -#include "skia/ext/refptr.h" -#include "third_party/WebKit/public/web/win/WebFontRendering.h" -#include "third_party/skia/include/core/SkPaint.h" -#include "third_party/skia/include/ports/SkFontMgr.h" -#include "third_party/skia/include/ports/SkTypeface_win.h" - -namespace content { - -namespace { - -// The Skia font manager, used for the life of the process (leaked at the end). -SkFontMgr* g_warmup_fontmgr = nullptr; - -base::win::IATPatchFunction g_iat_patch_open_sc_manager; -base::win::IATPatchFunction g_iat_patch_close_service_handle; -base::win::IATPatchFunction g_iat_patch_open_service; -base::win::IATPatchFunction g_iat_patch_start_service; -base::win::IATPatchFunction g_iat_patch_nt_connect_port; - -// These are from ntddk.h -#if !defined(STATUS_ACCESS_DENIED) -#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) -#endif - -typedef LONG NTSTATUS; - -const uintptr_t kFakeSCMHandle = 0xdead0001; -const uintptr_t kFakeServiceHandle = 0xdead0002; - -SC_HANDLE WINAPI OpenSCManagerWPatch(const wchar_t* machine_name, - const wchar_t* database_name, - DWORD access_mask) { - ::SetLastError(0); - return reinterpret_cast<SC_HANDLE>(kFakeSCMHandle); -} - -SC_HANDLE WINAPI OpenServiceWPatch(SC_HANDLE sc_manager, - const wchar_t* service_name, - DWORD access_mask) { - ::SetLastError(0); - return reinterpret_cast<SC_HANDLE>(kFakeServiceHandle); -} - -BOOL WINAPI CloseServiceHandlePatch(SC_HANDLE service_handle) { - if (service_handle != reinterpret_cast<SC_HANDLE>(kFakeServiceHandle) && - service_handle != reinterpret_cast<SC_HANDLE>(kFakeSCMHandle)) - CHECK(false); - ::SetLastError(0); - return TRUE; -} - -BOOL WINAPI StartServiceWPatch(SC_HANDLE service, - DWORD args, - const wchar_t** arg_vectors) { - if (service != reinterpret_cast<SC_HANDLE>(kFakeServiceHandle)) - CHECK(false); - ::SetLastError(ERROR_ACCESS_DENIED); - return FALSE; -} - -NTSTATUS WINAPI NtALpcConnectPortPatch(HANDLE* port_handle, - void* port_name, - void* object_attribs, - void* port_attribs, - DWORD flags, - void* server_sid, - void* message, - DWORD* buffer_length, - void* out_message_attributes, - void* in_message_attributes, - void* time_out) { - return STATUS_ACCESS_DENIED; -} - -// Windows-only DirectWrite support. These warm up the DirectWrite paths -// before sandbox lock down to allow Skia access to the Font Manager service. -void CreateDirectWriteFactory(IDWriteFactory** factory) { - typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc; - HMODULE dwrite_dll = LoadLibraryW(L"dwrite.dll"); - // TODO(scottmg): Temporary code to track crash in http://crbug.com/387867. - if (!dwrite_dll) { - DWORD load_library_get_last_error = GetLastError(); - base::debug::Alias(&dwrite_dll); - base::debug::Alias(&load_library_get_last_error); - CHECK(false); - } - - PatchServiceManagerCalls(); - - DWriteCreateFactoryProc dwrite_create_factory_proc = - reinterpret_cast<DWriteCreateFactoryProc>( - GetProcAddress(dwrite_dll, "DWriteCreateFactory")); - // TODO(scottmg): Temporary code to track crash in http://crbug.com/387867. - if (!dwrite_create_factory_proc) { - DWORD get_proc_address_get_last_error = GetLastError(); - base::debug::Alias(&dwrite_create_factory_proc); - base::debug::Alias(&get_proc_address_get_last_error); - CHECK(false); - } - CHECK(SUCCEEDED(dwrite_create_factory_proc( - DWRITE_FACTORY_TYPE_ISOLATED, __uuidof(IDWriteFactory), - reinterpret_cast<IUnknown**>(factory)))); -} - -HRESULT STDMETHODCALLTYPE StubFontCollection(IDWriteFactory* factory, - IDWriteFontCollection** col, - BOOL checkUpdates) { - // We always return pre-created font collection from here. - IDWriteFontCollection* custom_collection = GetCustomFontCollection(factory); - DCHECK(custom_collection != nullptr); - *col = custom_collection; - return S_OK; -} - -void PatchDWriteFactory(IDWriteFactory* factory) { - const unsigned int kGetSystemFontCollectionVTableIndex = 3; - - PROC* vtable = *reinterpret_cast<PROC**>(factory); - PROC* function_ptr = &vtable[kGetSystemFontCollectionVTableIndex]; - void* stub_function = &StubFontCollection; - base::win::ModifyCode(function_ptr, &stub_function, sizeof(PROC)); -} - -// Class to fake out a DC or a Font object. Maintains a reference to a -// SkTypeFace to emulate the simple operation of a DC and Font. -class FakeGdiObject : public base::RefCountedThreadSafe<FakeGdiObject> { - public: - FakeGdiObject(uint32_t magic, void* handle) - : handle_(handle), magic_(magic) {} - - void set_typeface(const skia::RefPtr<SkTypeface>& typeface) { - typeface_ = typeface; - } - - skia::RefPtr<SkTypeface> typeface() { return typeface_; } - void* handle() { return handle_; } - uint32_t magic() { return magic_; } - - private: - friend class base::RefCountedThreadSafe<FakeGdiObject>; - ~FakeGdiObject() {} - - void* handle_; - uint32_t magic_; - skia::RefPtr<SkTypeface> typeface_; - - DISALLOW_COPY_AND_ASSIGN(FakeGdiObject); -}; - -// This class acts as a factory for creating new fake GDI objects. It also maps -// the new instances of the FakeGdiObject class to an incrementing handle value -// which is passed to the caller of the emulated GDI function for later -// reference. We can't be sure that this won't be used in a multi-threaded -// environment so we need to ensure a lock is taken before accessing the map of -// issued objects. -class FakeGdiObjectFactory { - public: - FakeGdiObjectFactory() : curr_handle_(0) {} - - // Find a corresponding fake GDI object and verify its magic value. - // The returned value is either nullptr or the validated object. - scoped_refptr<FakeGdiObject> Validate(void* obj, uint32_t magic) { - if (obj) { - base::AutoLock scoped_lock(objects_lock_); - auto handle_entry = objects_.find(obj); - if (handle_entry != objects_.end() && - handle_entry->second->magic() == magic) { - return handle_entry->second; - } - } - return nullptr; - } - - scoped_refptr<FakeGdiObject> Create(uint32_t magic) { - base::AutoLock scoped_lock(objects_lock_); - curr_handle_++; - // We don't support wrapping the fake handle value. - void* handle = reinterpret_cast<void*>(curr_handle_.ValueOrDie()); - scoped_refptr<FakeGdiObject> object(new FakeGdiObject(magic, handle)); - objects_[handle] = object; - return object; - } - - bool DeleteObject(void* obj, uint32_t magic) { - base::AutoLock scoped_lock(objects_lock_); - auto handle_entry = objects_.find(obj); - if (handle_entry != objects_.end() && - handle_entry->second->magic() == magic) { - objects_.erase(handle_entry); - return true; - } - return false; - } - - size_t GetObjectCount() { - base::AutoLock scoped_lock(objects_lock_); - return objects_.size(); - } - - void ResetObjectHandles() { - base::AutoLock scoped_lock(objects_lock_); - curr_handle_ = 0; - objects_.clear(); - } - - private: - base::CheckedNumeric<uintptr_t> curr_handle_; - std::map<void*, scoped_refptr<FakeGdiObject>> objects_; - base::Lock objects_lock_; - - DISALLOW_COPY_AND_ASSIGN(FakeGdiObjectFactory); -}; - -base::LazyInstance<FakeGdiObjectFactory>::Leaky g_fake_gdi_object_factory = - LAZY_INSTANCE_INITIALIZER; - -// Magic values for the fake GDI objects. -const uint32_t kFakeDCMagic = 'fkdc'; -const uint32_t kFakeFontMagic = 'fkft'; - -skia::RefPtr<SkTypeface> GetTypefaceFromLOGFONT(const LOGFONTW* log_font) { - CHECK(g_warmup_fontmgr); - int weight = log_font->lfWeight; - if (weight == FW_DONTCARE) - weight = SkFontStyle::kNormal_Weight; - - SkFontStyle style(weight, log_font->lfWidth, - log_font->lfItalic ? SkFontStyle::kItalic_Slant - : SkFontStyle::kUpright_Slant); - - std::string family_name = base::WideToUTF8(log_font->lfFaceName); - ppapi::ProxyAutoLock lock; // Needed for DirectWrite font proxy. - return skia::AdoptRef( - g_warmup_fontmgr->matchFamilyStyle(family_name.c_str(), style)); -} - -HDC WINAPI CreateCompatibleDCPatch(HDC dc_handle) { - scoped_refptr<FakeGdiObject> ret = - g_fake_gdi_object_factory.Get().Create(kFakeDCMagic); - return static_cast<HDC>(ret->handle()); -} - -HFONT WINAPI CreateFontIndirectWPatch(const LOGFONTW* log_font) { - if (!log_font) - return nullptr; - - skia::RefPtr<SkTypeface> typeface = GetTypefaceFromLOGFONT(log_font); - if (!typeface) - return nullptr; - - scoped_refptr<FakeGdiObject> ret = - g_fake_gdi_object_factory.Get().Create(kFakeFontMagic); - ret->set_typeface(typeface); - - return static_cast<HFONT>(ret->handle()); -} - -BOOL WINAPI DeleteDCPatch(HDC dc_handle) { - return g_fake_gdi_object_factory.Get().DeleteObject(dc_handle, kFakeDCMagic); -} - -BOOL WINAPI DeleteObjectPatch(HGDIOBJ object_handle) { - return g_fake_gdi_object_factory.Get().DeleteObject(object_handle, - kFakeFontMagic); -} - -int WINAPI EnumFontFamiliesExWPatch(HDC dc_handle, - LPLOGFONTW log_font, - FONTENUMPROCW enum_callback, - LPARAM callback_param, - DWORD flags) { - scoped_refptr<FakeGdiObject> dc_obj = - g_fake_gdi_object_factory.Get().Validate(dc_handle, kFakeDCMagic); - if (!dc_obj) - return 1; - - if (!log_font || !enum_callback) - return 1; - - skia::RefPtr<SkTypeface> typeface = GetTypefaceFromLOGFONT(log_font); - if (!typeface) - return 1; - - ENUMLOGFONTEXDVW enum_log_font = {}; - enum_log_font.elfEnumLogfontEx.elfLogFont = *log_font; - // TODO: Fill in the rest of the text metric structure. Not yet needed for - // Flash support but might be in the future. - NEWTEXTMETRICEXW text_metric = {}; - text_metric.ntmTm.ntmFlags = NTM_PS_OPENTYPE; - - return enum_callback(&enum_log_font.elfEnumLogfontEx.elfLogFont, - reinterpret_cast<TEXTMETRIC*>(&text_metric), - TRUETYPE_FONTTYPE, callback_param); -} - -DWORD WINAPI GetFontDataPatch(HDC dc_handle, - DWORD table_tag, - DWORD table_offset, - LPVOID buffer, - DWORD buffer_length) { - scoped_refptr<FakeGdiObject> dc_obj = - g_fake_gdi_object_factory.Get().Validate(dc_handle, kFakeDCMagic); - if (!dc_obj) - return GDI_ERROR; - - skia::RefPtr<SkTypeface> typeface = dc_obj->typeface(); - if (!typeface) - return GDI_ERROR; - - // |getTableData| handles |buffer| being nullptr. However if it is nullptr - // then set the size to INT32_MAX otherwise |getTableData| will return the - // minimum value between the table entry size and the size passed in. The - // common Windows idiom is to pass 0 as |buffer_length| when passing nullptr, - // which would in this case result in |getTableData| returning 0 which isn't - // the correct answer for emulating GDI. |table_tag| must also have its - // byte order swapped to counter the swap which occurs in the called method. - size_t length = typeface->getTableData( - base::ByteSwap(base::strict_cast<uint32_t>(table_tag)), table_offset, - buffer ? buffer_length : INT32_MAX, buffer); - // We can't distinguish between an empty table and an error. - if (length == 0) - return GDI_ERROR; - - return base::checked_cast<DWORD>(length); -} - -HGDIOBJ WINAPI SelectObjectPatch(HDC dc_handle, HGDIOBJ object_handle) { - scoped_refptr<FakeGdiObject> dc_obj = - g_fake_gdi_object_factory.Get().Validate(dc_handle, kFakeDCMagic); - if (!dc_obj) - return nullptr; - - scoped_refptr<FakeGdiObject> font_obj = - g_fake_gdi_object_factory.Get().Validate(object_handle, kFakeFontMagic); - if (!font_obj) - return nullptr; - - // Construct a new fake font object to handle the old font if there's one. - scoped_refptr<FakeGdiObject> new_font_obj; - skia::RefPtr<SkTypeface> old_typeface = dc_obj->typeface(); - if (old_typeface) { - new_font_obj = g_fake_gdi_object_factory.Get().Create(kFakeFontMagic); - new_font_obj->set_typeface(old_typeface); - } - dc_obj->set_typeface(font_obj->typeface()); - - if (new_font_obj) - return static_cast<HGDIOBJ>(new_font_obj->handle()); - return nullptr; -} - -void DoSingleGdiPatch(base::win::IATPatchFunction& patch, - const base::FilePath& path, - const char* function_name, - void* new_function) { - patch.Patch(path.value().c_str(), "gdi32.dll", function_name, new_function); -} - -class GdiFontPatchDataImpl : public content::GdiFontPatchData { - public: - GdiFontPatchDataImpl(const base::FilePath& path); - - private: - base::win::IATPatchFunction create_compatible_dc_patch_; - base::win::IATPatchFunction create_font_indirect_patch_; - base::win::IATPatchFunction create_delete_dc_patch_; - base::win::IATPatchFunction create_delete_object_patch_; - base::win::IATPatchFunction create_enum_font_families_patch_; - base::win::IATPatchFunction create_get_font_data_patch_; - base::win::IATPatchFunction create_select_object_patch_; -}; - -GdiFontPatchDataImpl::GdiFontPatchDataImpl(const base::FilePath& path) { - DoSingleGdiPatch(create_compatible_dc_patch_, path, "CreateCompatibleDC", - CreateCompatibleDCPatch); - DoSingleGdiPatch(create_font_indirect_patch_, path, "CreateFontIndirectW", - CreateFontIndirectWPatch); - DoSingleGdiPatch(create_delete_dc_patch_, path, "DeleteDC", DeleteDCPatch); - DoSingleGdiPatch(create_delete_object_patch_, path, "DeleteObject", - DeleteObjectPatch); - DoSingleGdiPatch(create_enum_font_families_patch_, path, - "EnumFontFamiliesExW", EnumFontFamiliesExWPatch); - DoSingleGdiPatch(create_get_font_data_patch_, path, "GetFontData", - GetFontDataPatch); - DoSingleGdiPatch(create_select_object_patch_, path, "SelectObject", - SelectObjectPatch); -} - -} // namespace - -// Directwrite connects to the font cache service to retrieve information about -// fonts installed on the system etc. This works well outside the sandbox and -// within the sandbox as long as the lpc connection maintained by the current -// process with the font cache service remains valid. It appears that there -// are cases when this connection is dropped after which directwrite is unable -// to connect to the font cache service which causes problems with characters -// disappearing. -// Directwrite has fallback code to enumerate fonts if it is unable to connect -// to the font cache service. We need to intercept the following APIs to -// ensure that it does not connect to the font cache service. -// NtALpcConnectPort -// OpenSCManagerW -// OpenServiceW -// StartServiceW -// CloseServiceHandle. -// These are all IAT patched. -void PatchServiceManagerCalls() { - static bool is_patched = false; - if (is_patched) - return; - const char* service_provider_dll = - (base::win::GetVersion() >= base::win::VERSION_WIN8 - ? "api-ms-win-service-management-l1-1-0.dll" - : "advapi32.dll"); - - is_patched = true; - - DWORD patched = - g_iat_patch_open_sc_manager.Patch(L"dwrite.dll", service_provider_dll, - "OpenSCManagerW", OpenSCManagerWPatch); - DCHECK(patched == 0); - - patched = g_iat_patch_close_service_handle.Patch( - L"dwrite.dll", service_provider_dll, "CloseServiceHandle", - CloseServiceHandlePatch); - DCHECK(patched == 0); - - patched = g_iat_patch_open_service.Patch(L"dwrite.dll", service_provider_dll, - "OpenServiceW", OpenServiceWPatch); - DCHECK(patched == 0); - - patched = g_iat_patch_start_service.Patch( - L"dwrite.dll", service_provider_dll, "StartServiceW", StartServiceWPatch); - DCHECK(patched == 0); - - patched = g_iat_patch_nt_connect_port.Patch( - L"dwrite.dll", "ntdll.dll", "NtAlpcConnectPort", NtALpcConnectPortPatch); - DCHECK(patched == 0); -} - -void DoPreSandboxWarmupForTypeface(SkTypeface* typeface) { - SkPaint paint_warmup; - paint_warmup.setTypeface(typeface); - wchar_t glyph = L'S'; - paint_warmup.measureText(&glyph, 2); -} - -SkFontMgr* GetPreSandboxWarmupFontMgr() { - if (!g_warmup_fontmgr) { - IDWriteFactory* factory; - CreateDirectWriteFactory(&factory); - - GetCustomFontCollection(factory); - - PatchDWriteFactory(factory); - - blink::WebFontRendering::setDirectWriteFactory(factory); - g_warmup_fontmgr = SkFontMgr_New_DirectWrite(factory); - } - return g_warmup_fontmgr; -} - -GdiFontPatchData* PatchGdiFontEnumeration(const base::FilePath& path) { - if (ShouldUseDirectWriteFontProxyFieldTrial() && !g_warmup_fontmgr) - g_warmup_fontmgr = SkFontMgr_New_DirectWrite(); - // If not using the font proxy, we assume |g_warmup_fontmgr| is already - // initialized before this function is called. - DCHECK(g_warmup_fontmgr); - return new GdiFontPatchDataImpl(path); -} - -size_t GetEmulatedGdiHandleCountForTesting() { - return g_fake_gdi_object_factory.Get().GetObjectCount(); -} - -void ResetEmulatedGdiHandlesForTesting() { - g_fake_gdi_object_factory.Get().ResetObjectHandles(); -} - -void SetPreSandboxWarmupFontMgrForTesting(SkFontMgr* fontmgr) { - g_warmup_fontmgr = fontmgr; -} - -void WarmupDirectWrite() { - TRACE_EVENT0("startup", "content::WarmupDirectWrite"); - - // The objects used here are intentionally not freed as we want the Skia - // code to use these objects after warmup. - SetDefaultSkiaFactory(GetPreSandboxWarmupFontMgr()); - - // We need to warm up *some* font for DirectWrite. Note that we don't use - // a monospace as would be nice in an attempt to avoid a small startup time - // regression, see http://crbug.com/463613. - skia::RefPtr<SkTypeface> hud_typeface = skia::AdoptRef( - GetPreSandboxWarmupFontMgr()->legacyCreateTypeface("Times New Roman", 0)); - DoPreSandboxWarmupForTypeface(hud_typeface.get()); -} - -} // namespace content diff --git a/chromium/content/common/font_warmup_win.h b/chromium/content/common/font_warmup_win.h deleted file mode 100644 index 8539b9ec0b2..00000000000 --- a/chromium/content/common/font_warmup_win.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2014 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 CONTENT_COMMON_FONT_WARMUP_WIN_H_ -#define CONTENT_COMMON_FONT_WARMUP_WIN_H_ - -#include <stddef.h> - -#include "base/files/file_path.h" -#include "base/macros.h" -#include "content/common/content_export.h" - -class SkFontMgr; -class SkTypeface; - -namespace content { - -// Make necessary calls to cache the data for a given font, used before -// sandbox lockdown. -CONTENT_EXPORT void DoPreSandboxWarmupForTypeface(SkTypeface* typeface); - -// Get the shared font manager used during pre-sandbox warmup for DirectWrite -// fonts. -CONTENT_EXPORT SkFontMgr* GetPreSandboxWarmupFontMgr(); - -class GdiFontPatchData { - public: - virtual ~GdiFontPatchData() {} - - protected: - GdiFontPatchData() {} - - private: - DISALLOW_COPY_AND_ASSIGN(GdiFontPatchData); -}; - -// Hook a module's imported GDI font functions to reimplement font enumeration -// and font data retrieval for DLLs which can't be easily modified. -CONTENT_EXPORT GdiFontPatchData* PatchGdiFontEnumeration( - const base::FilePath& path); - -// Testing method to get the number of in-flight emulated GDI handles. -CONTENT_EXPORT size_t GetEmulatedGdiHandleCountForTesting(); - -// Testing method to reset the table of emulated GDI handles. -CONTENT_EXPORT void ResetEmulatedGdiHandlesForTesting(); - -// Sets the pre-sandbox warmup font manager directly. This should only be used -// for testing the implementation. -CONTENT_EXPORT void SetPreSandboxWarmupFontMgrForTesting(SkFontMgr* fontmgr); - -// Warmup the direct write font manager for content processes. -CONTENT_EXPORT void WarmupDirectWrite(); - -// Directwrite connects to the font cache service to retrieve information about -// fonts installed on the system etc. This works well outside the sandbox and -// within the sandbox as long as the lpc connection maintained by the current -// process with the font cache service remains valid. It appears that there -// are cases when this connection is dropped after which directwrite is unable -// to connect to the font cache service which causes problems with characters -// disappearing. -// Directwrite has fallback code to enumerate fonts if it is unable to connect -// to the font cache service. We need to intercept the following APIs to -// ensure that it does not connect to the font cache service. -// NtALpcConnectPort -// OpenSCManagerW -// OpenServiceW -// StartServiceW -// CloseServiceHandle. -// These are all IAT patched. -CONTENT_EXPORT void PatchServiceManagerCalls(); - -} // namespace content - -#endif // CONTENT_COMMON_FONT_WARMUP_WIN_H_ diff --git a/chromium/content/common/font_warmup_win_unittest.cc b/chromium/content/common/font_warmup_win_unittest.cc deleted file mode 100644 index 362373fd25f..00000000000 --- a/chromium/content/common/font_warmup_win_unittest.cc +++ /dev/null @@ -1,435 +0,0 @@ -// Copyright 2015 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 "content/common/font_warmup_win.h" - -#include <stddef.h> -#include <stdint.h> - -#include <vector> - -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/sys_byteorder.h" -#include "base/win/windows_version.h" -#include "skia/ext/refptr.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/skia/include/core/SkString.h" -#include "third_party/skia/include/core/SkTypeface.h" -#include "third_party/skia/include/ports/SkFontMgr.h" - -namespace content { - -namespace { - -class TestSkTypeface : public SkTypeface { - public: - TestSkTypeface(const SkFontStyle& style, - const char* familyName, - SkFontTableTag tag, - const char* data, - size_t dataLength) - : SkTypeface(style, 0), - familyName_(familyName), - tag_(tag), - data_(data, data + dataLength) {} - - protected: - SkScalerContext* onCreateScalerContext(const SkDescriptor*) const override { - ADD_FAILURE(); - return nullptr; - } - void onFilterRec(SkScalerContextRec*) const override { ADD_FAILURE(); } - SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( - PerGlyphInfo, - const uint32_t* glyphIDs, - uint32_t glyphIDsCount) const override { - ADD_FAILURE(); - return nullptr; - } - - SkStreamAsset* onOpenStream(int* ttcIndex) const override { - ADD_FAILURE(); - return nullptr; - } - - SkFontData* onCreateFontData() const override { - ADD_FAILURE(); - return nullptr; - } - - void onGetFontDescriptor(SkFontDescriptor*, bool* isLocal) const override { - ADD_FAILURE(); - } - - int onCharsToGlyphs(const void* chars, - Encoding, - uint16_t glyphs[], - int glyphCount) const override { - ADD_FAILURE(); - return 0; - } - - int onCountGlyphs() const override { - ADD_FAILURE(); - return 0; - } - - int onGetUPEM() const override { - ADD_FAILURE(); - return 0; - } - bool onGetKerningPairAdjustments(const uint16_t glyphs[], - int count, - int32_t adjustments[]) const override { - ADD_FAILURE(); - return false; - } - - void onGetFamilyName(SkString* familyName) const override { - *familyName = familyName_; - } - - LocalizedStrings* onCreateFamilyNameIterator() const override { - ADD_FAILURE(); - return nullptr; - } - - int onGetTableTags(SkFontTableTag tags[]) const override { - ADD_FAILURE(); - return 0; - } - - size_t onGetTableData(SkFontTableTag tag, - size_t offset, - size_t length, - void* data) const override { - size_t retsize = 0; - if (tag == tag_) { - retsize = length > data_.size() ? data_.size() : length; - if (data) - memcpy(data, &data_[0], retsize); - } - return retsize; - } - - bool onComputeBounds(SkRect*) const override { - ADD_FAILURE(); - return false; - } - - private: - SkString familyName_; - SkFontTableTag tag_; - std::vector<char> data_; -}; - -const char* kTestFontFamily = "GDITest"; -const wchar_t* kTestFontFamilyW = L"GDITest"; -const SkFontTableTag kTestFontTableTag = 0x11223344; -const char* kTestFontData = "GDITestGDITest"; -const wchar_t* kTestFontFamilyInvalid = L"InvalidFont"; - -class TestSkFontMgr : public SkFontMgr { - public: - TestSkFontMgr() { content::SetPreSandboxWarmupFontMgrForTesting(this); } - ~TestSkFontMgr() override { - content::SetPreSandboxWarmupFontMgrForTesting(nullptr); - } - - protected: - int onCountFamilies() const override { return 1; } - - void onGetFamilyName(int index, SkString* familyName) const override { - if (index == 0) - *familyName = kTestFontFamily; - } - - SkFontStyleSet* onCreateStyleSet(int index) const override { - ADD_FAILURE(); - return nullptr; - } - - SkFontStyleSet* onMatchFamily(const char familyName[]) const override { - ADD_FAILURE(); - return nullptr; - } - - SkTypeface* onMatchFamilyStyle(const char familyName[], - const SkFontStyle&) const override { - if (strcmp(familyName, kTestFontFamily) == 0) - return createTypeface(); - return nullptr; - } - - SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], - const SkFontStyle&, - const char* bcp47[], - int bcp47Count, - SkUnichar character) const override { - ADD_FAILURE(); - return nullptr; - } - - SkTypeface* onMatchFaceStyle(const SkTypeface*, - const SkFontStyle&) const override { - ADD_FAILURE(); - return nullptr; - } - - SkTypeface* onCreateFromData(SkData*, int ttcIndex) const override { - ADD_FAILURE(); - return nullptr; - } - - SkTypeface* onCreateFromStream(SkStreamAsset*, int ttcIndex) const override { - ADD_FAILURE(); - return nullptr; - } - - SkTypeface* onCreateFromFontData(SkFontData*) const override { - ADD_FAILURE(); - return nullptr; - } - - SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override { - ADD_FAILURE(); - return nullptr; - } - - SkTypeface* onLegacyCreateTypeface(const char familyName[], - unsigned styleBits) const override { - ADD_FAILURE(); - return nullptr; - } - - private: - SkTypeface* createTypeface() const { - SkFontStyle style(400, 100, SkFontStyle::kUpright_Slant); - - return new TestSkTypeface(style, kTestFontFamily, - base::ByteSwap(kTestFontTableTag), kTestFontData, - strlen(kTestFontData)); - } -}; - -void InitLogFont(LOGFONTW* logfont, const wchar_t* fontname) { - size_t length = std::min(sizeof(logfont->lfFaceName), - (wcslen(fontname) + 1) * sizeof(wchar_t)); - memcpy(logfont->lfFaceName, fontname, length); -} - -content::GdiFontPatchData* SetupTest() { - HMODULE module_handle; - if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - reinterpret_cast<LPCWSTR>(SetupTest), - &module_handle)) { - WCHAR module_path[MAX_PATH]; - - if (GetModuleFileNameW(module_handle, module_path, MAX_PATH) > 0) { - base::FilePath path(module_path); - content::ResetEmulatedGdiHandlesForTesting(); - return content::PatchGdiFontEnumeration(path); - } - } - return nullptr; -} - -int CALLBACK EnumFontCallbackTest(const LOGFONT* log_font, - const TEXTMETRIC* text_metric, - DWORD font_type, - LPARAM param) { - const NEWTEXTMETRICEX* new_text_metric = - reinterpret_cast<const NEWTEXTMETRICEX*>(text_metric); - - return !(font_type & TRUETYPE_FONTTYPE) && - !(new_text_metric->ntmTm.ntmFlags & NTM_PS_OPENTYPE); -} - -} // namespace - -TEST(GDIFontEmulationTest, CreateDeleteDCSuccess) { - if (base::win::GetVersion() < base::win::VERSION_WIN8) - return; - TestSkFontMgr fontmgr; - scoped_ptr<GdiFontPatchData> patch_data(SetupTest()); - EXPECT_FALSE(!patch_data); - - HDC hdc = CreateCompatibleDC(0); - EXPECT_NE(hdc, nullptr); - EXPECT_EQ(1u, GetEmulatedGdiHandleCountForTesting()); - EXPECT_TRUE(DeleteDC(hdc)); - EXPECT_EQ(0u, GetEmulatedGdiHandleCountForTesting()); -} - -TEST(GDIFontEmulationTest, CreateUniqueDCSuccess) { - if (base::win::GetVersion() < base::win::VERSION_WIN8) - return; - TestSkFontMgr fontmgr; - scoped_ptr<GdiFontPatchData> patch_data(SetupTest()); - EXPECT_NE(patch_data, nullptr); - - HDC hdc1 = CreateCompatibleDC(0); - EXPECT_NE(hdc1, nullptr); - HDC hdc2 = CreateCompatibleDC(0); - EXPECT_NE(hdc2, nullptr); - EXPECT_NE(hdc1, hdc2); - EXPECT_TRUE(DeleteDC(hdc2)); - EXPECT_EQ(1u, GetEmulatedGdiHandleCountForTesting()); - EXPECT_TRUE(DeleteDC(hdc1)); - EXPECT_EQ(0u, GetEmulatedGdiHandleCountForTesting()); -} - -TEST(GDIFontEmulationTest, CreateFontSuccess) { - if (base::win::GetVersion() < base::win::VERSION_WIN8) - return; - TestSkFontMgr fontmgr; - scoped_ptr<GdiFontPatchData> patch_data(SetupTest()); - EXPECT_NE(patch_data, nullptr); - LOGFONTW logfont = {0}; - InitLogFont(&logfont, kTestFontFamilyW); - HFONT font = CreateFontIndirectW(&logfont); - EXPECT_NE(font, nullptr); - EXPECT_TRUE(DeleteObject(font)); - EXPECT_EQ(0u, GetEmulatedGdiHandleCountForTesting()); -} - -TEST(GDIFontEmulationTest, CreateFontFailure) { - if (base::win::GetVersion() < base::win::VERSION_WIN8) - return; - TestSkFontMgr fontmgr; - scoped_ptr<GdiFontPatchData> patch_data(SetupTest()); - EXPECT_NE(patch_data, nullptr); - LOGFONTW logfont = {0}; - InitLogFont(&logfont, kTestFontFamilyInvalid); - HFONT font = CreateFontIndirectW(&logfont); - EXPECT_EQ(font, nullptr); -} - -TEST(GDIFontEmulationTest, EnumFontFamilySuccess) { - if (base::win::GetVersion() < base::win::VERSION_WIN8) - return; - TestSkFontMgr fontmgr; - scoped_ptr<GdiFontPatchData> patch_data(SetupTest()); - EXPECT_NE(patch_data, nullptr); - HDC hdc = CreateCompatibleDC(0); - EXPECT_NE(hdc, nullptr); - LOGFONTW logfont = {0}; - InitLogFont(&logfont, kTestFontFamilyW); - int res = EnumFontFamiliesExW(hdc, &logfont, EnumFontCallbackTest, 0, 0); - EXPECT_FALSE(res); - EXPECT_TRUE(DeleteDC(hdc)); -} - -TEST(GDIFontEmulationTest, EnumFontFamilyFailure) { - if (base::win::GetVersion() < base::win::VERSION_WIN8) - return; - TestSkFontMgr fontmgr; - scoped_ptr<GdiFontPatchData> patch_data(SetupTest()); - EXPECT_NE(patch_data, nullptr); - HDC hdc = CreateCompatibleDC(0); - EXPECT_NE(hdc, nullptr); - LOGFONTW logfont = {0}; - InitLogFont(&logfont, kTestFontFamilyInvalid); - int res = EnumFontFamiliesExW(hdc, &logfont, EnumFontCallbackTest, 0, 0); - EXPECT_TRUE(res); - EXPECT_TRUE(DeleteDC(hdc)); -} - -TEST(GDIFontEmulationTest, DeleteDCFailure) { - if (base::win::GetVersion() < base::win::VERSION_WIN8) - return; - TestSkFontMgr fontmgr; - scoped_ptr<GdiFontPatchData> patch_data(SetupTest()); - EXPECT_NE(patch_data, nullptr); - HDC hdc = reinterpret_cast<HDC>(0x55667788); - EXPECT_FALSE(DeleteDC(hdc)); -} - -TEST(GDIFontEmulationTest, DeleteObjectFailure) { - if (base::win::GetVersion() < base::win::VERSION_WIN8) - return; - TestSkFontMgr fontmgr; - scoped_ptr<GdiFontPatchData> patch_data(SetupTest()); - EXPECT_NE(patch_data, nullptr); - HFONT font = reinterpret_cast<HFONT>(0x88aabbcc); - EXPECT_FALSE(DeleteObject(font)); -} - -TEST(GDIFontEmulationTest, GetFontDataSizeSuccess) { - if (base::win::GetVersion() < base::win::VERSION_WIN8) - return; - TestSkFontMgr fontmgr; - scoped_ptr<GdiFontPatchData> patch_data(SetupTest()); - EXPECT_NE(patch_data, nullptr); - HDC hdc = CreateCompatibleDC(0); - EXPECT_NE(hdc, nullptr); - LOGFONTW logfont = {0}; - InitLogFont(&logfont, kTestFontFamilyW); - HFONT font = CreateFontIndirectW(&logfont); - EXPECT_NE(font, nullptr); - EXPECT_EQ(SelectObject(hdc, font), nullptr); - DWORD size = GetFontData(hdc, kTestFontTableTag, 0, nullptr, 0); - DWORD data_size = static_cast<DWORD>(strlen(kTestFontData)); - EXPECT_EQ(size, data_size); - EXPECT_TRUE(DeleteObject(font)); - EXPECT_TRUE(DeleteDC(hdc)); -} - -TEST(GDIFontEmulationTest, GetFontDataInvalidTagSuccess) { - if (base::win::GetVersion() < base::win::VERSION_WIN8) - return; - TestSkFontMgr fontmgr; - scoped_ptr<GdiFontPatchData> patch_data(SetupTest()); - EXPECT_NE(patch_data, nullptr); - HDC hdc = CreateCompatibleDC(0); - EXPECT_NE(hdc, nullptr); - LOGFONTW logfont = {0}; - InitLogFont(&logfont, kTestFontFamilyW); - HFONT font = CreateFontIndirectW(&logfont); - EXPECT_NE(font, nullptr); - EXPECT_EQ(SelectObject(hdc, font), nullptr); - DWORD size = GetFontData(hdc, kTestFontTableTag + 1, 0, nullptr, 0); - EXPECT_EQ(size, GDI_ERROR); - EXPECT_TRUE(DeleteObject(font)); - EXPECT_TRUE(DeleteDC(hdc)); -} - -TEST(GDIFontEmulationTest, GetFontDataInvalidFontSuccess) { - if (base::win::GetVersion() < base::win::VERSION_WIN8) - return; - TestSkFontMgr fontmgr; - scoped_ptr<GdiFontPatchData> patch_data(SetupTest()); - EXPECT_NE(patch_data, nullptr); - HDC hdc = CreateCompatibleDC(0); - EXPECT_NE(hdc, nullptr); - DWORD size = GetFontData(hdc, kTestFontTableTag, 0, nullptr, 0); - EXPECT_EQ(size, GDI_ERROR); - EXPECT_TRUE(DeleteDC(hdc)); -} - -TEST(GDIFontEmulationTest, GetFontDataDataSuccess) { - if (base::win::GetVersion() < base::win::VERSION_WIN8) - return; - TestSkFontMgr fontmgr; - scoped_ptr<GdiFontPatchData> patch_data(SetupTest()); - EXPECT_NE(patch_data, nullptr); - HDC hdc = CreateCompatibleDC(0); - EXPECT_NE(hdc, nullptr); - LOGFONTW logfont = {0}; - InitLogFont(&logfont, kTestFontFamilyW); - HFONT font = CreateFontIndirectW(&logfont); - EXPECT_NE(font, nullptr); - EXPECT_EQ(SelectObject(hdc, font), nullptr); - DWORD data_size = static_cast<DWORD>(strlen(kTestFontData)); - std::vector<char> data(data_size); - DWORD size = GetFontData(hdc, kTestFontTableTag, 0, &data[0], data.size()); - EXPECT_EQ(size, data_size); - EXPECT_EQ(memcmp(&data[0], kTestFontData, data.size()), 0); - EXPECT_TRUE(DeleteObject(font)); - EXPECT_TRUE(DeleteDC(hdc)); -} - -} // namespace content diff --git a/chromium/content/common/frame_message_enums.h b/chromium/content/common/frame_message_enums.h index b93120607f5..27e98433c75 100644 --- a/chromium/content/common/frame_message_enums.h +++ b/chromium/content/common/frame_message_enums.h @@ -10,11 +10,11 @@ struct FrameMsg_Navigate_Type { public: enum Value { - // Reload the page. + // Reload the page, validating cache entries. RELOAD, - // Reload the page, ignoring any cache entries. - RELOAD_IGNORING_CACHE, + // Reload the page, bypassing any cache entries. + RELOAD_BYPASSING_CACHE, // Reload the page using the original request URL. RELOAD_ORIGINAL_REQUEST_URL, diff --git a/chromium/content/common/frame_messages.h b/chromium/content/common/frame_messages.h index 18892e8df15..7d1f562997a 100644 --- a/chromium/content/common/frame_messages.h +++ b/chromium/content/common/frame_messages.h @@ -19,7 +19,6 @@ #include "content/common/content_export.h" #include "content/common/content_param_traits.h" #include "content/common/frame_message_enums.h" -#include "content/common/frame_param.h" #include "content/common/frame_replication_state.h" #include "content/common/navigation_gesture.h" #include "content/common/navigation_params.h" @@ -35,14 +34,19 @@ #include "content/public/common/page_importance_signals.h" #include "content/public/common/page_state.h" #include "content/public/common/resource_response.h" +#include "content/public/common/stop_find_action.h" #include "content/public/common/three_d_api_types.h" #include "content/public/common/transition_element.h" #include "ipc/ipc_message_macros.h" #include "ipc/ipc_platform_file.h" #include "third_party/WebKit/public/platform/WebFocusType.h" +#include "third_party/WebKit/public/web/WebFindOptions.h" #include "third_party/WebKit/public/web/WebFrameOwnerProperties.h" #include "third_party/WebKit/public/web/WebTreeScopeType.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/ipc/gfx_param_traits.h" +#include "ui/gfx/ipc/skia/gfx_skia_param_traits.h" #include "url/gurl.h" #include "url/origin.h" @@ -54,8 +58,10 @@ #ifndef CONTENT_COMMON_FRAME_MESSAGES_H_ #define CONTENT_COMMON_FRAME_MESSAGES_H_ -using FrameMsg_GetSerializedHtmlWithLocalLinks_Map = +using FrameMsg_GetSerializedHtmlWithLocalLinks_UrlMap = std::map<GURL, base::FilePath>; +using FrameMsg_GetSerializedHtmlWithLocalLinks_FrameRoutingIdMap = + std::map<int, base::FilePath>; using FrameMsg_SerializeAsMHTML_FrameRoutingIdToContentIdMap = std::map<int, std::string>; @@ -84,6 +90,8 @@ IPC_ENUM_TRAITS_MAX_VALUE(blink::WebContextMenuData::InputFieldType, IPC_ENUM_TRAITS_MAX_VALUE(blink::WebFocusType, blink::WebFocusTypeLast) IPC_ENUM_TRAITS_MAX_VALUE(blink::WebFrameOwnerProperties::ScrollingMode, blink::WebFrameOwnerProperties::ScrollingMode::Last) +IPC_ENUM_TRAITS_MAX_VALUE(content::StopFindAction, + content::STOP_FIND_ACTION_LAST) IPC_ENUM_TRAITS(blink::WebSandboxFlags) // Bitmask. IPC_ENUM_TRAITS_MAX_VALUE(blink::WebTreeScopeType, blink::WebTreeScopeType::Last) @@ -92,6 +100,12 @@ IPC_ENUM_TRAITS_MIN_MAX_VALUE(content::LoFiState, content::LOFI_UNSPECIFIED, content::LOFI_ON) +IPC_STRUCT_TRAITS_BEGIN(blink::WebFindOptions) + IPC_STRUCT_TRAITS_MEMBER(forward) + IPC_STRUCT_TRAITS_MEMBER(matchCase) + IPC_STRUCT_TRAITS_MEMBER(findNext) +IPC_STRUCT_TRAITS_END() + IPC_STRUCT_TRAITS_BEGIN(content::ColorSuggestion) IPC_STRUCT_TRAITS_MEMBER(color) IPC_STRUCT_TRAITS_MEMBER(label) @@ -208,6 +222,9 @@ IPC_STRUCT_BEGIN_WITH_PARENT(FrameHostMsg_DidCommitProvisionalLoad_Params, // Whether this commit created a new entry. IPC_STRUCT_MEMBER(bool, did_create_new_entry) + // Whether this commit should replace the current entry. + IPC_STRUCT_MEMBER(bool, should_replace_current_entry) + // Information regarding the security of the connection (empty if the // connection was not secure). IPC_STRUCT_MEMBER(std::string, security_info) @@ -274,6 +291,13 @@ IPC_STRUCT_BEGIN_WITH_PARENT(FrameHostMsg_DidCommitProvisionalLoad_Params, // True if the document for the load is enforcing strict mixed content // checking. IPC_STRUCT_MEMBER(bool, should_enforce_strict_mixed_content_checking) + + // True if the document for the load is a unique origin that should be + // considered potentially trustworthy. + IPC_STRUCT_MEMBER(bool, has_potentially_trustworthy_unique_origin) + + // True if the navigation originated as an srcdoc attribute. + IPC_STRUCT_MEMBER(bool, is_srcdoc) IPC_STRUCT_END() IPC_STRUCT_BEGIN(FrameMsg_PostMessage_Params) @@ -314,10 +338,10 @@ IPC_STRUCT_TRAITS_BEGIN(content::CommonNavigationParams) IPC_STRUCT_TRAITS_MEMBER(history_url_for_data_url) IPC_STRUCT_TRAITS_MEMBER(lofi_state) IPC_STRUCT_TRAITS_MEMBER(navigation_start) + IPC_STRUCT_TRAITS_MEMBER(method) IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_BEGIN(content::BeginNavigationParams) - IPC_STRUCT_TRAITS_MEMBER(method) IPC_STRUCT_TRAITS_MEMBER(headers) IPC_STRUCT_TRAITS_MEMBER(load_flags) IPC_STRUCT_TRAITS_MEMBER(has_user_gesture) @@ -326,7 +350,6 @@ IPC_STRUCT_TRAITS_BEGIN(content::BeginNavigationParams) IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_BEGIN(content::StartNavigationParams) - IPC_STRUCT_TRAITS_MEMBER(is_post) IPC_STRUCT_TRAITS_MEMBER(extra_headers) IPC_STRUCT_TRAITS_MEMBER(browser_initiated_post_data) #if defined(OS_ANDROID) @@ -363,6 +386,10 @@ IPC_STRUCT_TRAITS_BEGIN(content::FrameReplicationState) IPC_STRUCT_TRAITS_MEMBER(origin) IPC_STRUCT_TRAITS_MEMBER(sandbox_flags) IPC_STRUCT_TRAITS_MEMBER(name) + IPC_STRUCT_TRAITS_MEMBER(unique_name) + IPC_STRUCT_TRAITS_MEMBER(scope) + IPC_STRUCT_TRAITS_MEMBER(should_enforce_strict_mixed_content_checking) + IPC_STRUCT_TRAITS_MEMBER(has_potentially_trustworthy_unique_origin) IPC_STRUCT_TRAITS_END() IPC_STRUCT_BEGIN(FrameMsg_NewFrame_WidgetParams) @@ -490,6 +517,26 @@ IPC_STRUCT_BEGIN(FrameMsg_SerializeAsMHTML_Params) IPC_STRUCT_MEMBER(bool, is_last_frame) IPC_STRUCT_END() +// This message is used to send hittesting data from the renderer in order +// to perform hittesting on the browser process. +IPC_STRUCT_BEGIN(FrameHostMsg_HittestData_Params) + // |surface_id| represents the surface used by this remote frame. + IPC_STRUCT_MEMBER(cc::SurfaceId, surface_id) + + // If |ignored_for_hittest| then this surface should be ignored during + // hittesting. + IPC_STRUCT_MEMBER(bool, ignored_for_hittest) +IPC_STRUCT_END() + +IPC_STRUCT_BEGIN(FrameHostMsg_CreateChildFrame_Params) + IPC_STRUCT_MEMBER(int32_t, parent_routing_id) + IPC_STRUCT_MEMBER(blink::WebTreeScopeType, scope) + IPC_STRUCT_MEMBER(std::string, frame_name) + IPC_STRUCT_MEMBER(std::string, frame_unique_name) + IPC_STRUCT_MEMBER(blink::WebSandboxFlags, sandbox_flags) + IPC_STRUCT_MEMBER(blink::WebFrameOwnerProperties, frame_owner_properties) +IPC_STRUCT_END() + #if defined(OS_MACOSX) || defined(OS_ANDROID) // This message is used for supporting popup menus on Mac OS X and Android using // native controls. See the FrameHostMsg_ShowPopup message. @@ -530,15 +577,6 @@ IPC_STRUCT_TRAITS_END() // ----------------------------------------------------------------------------- // Messages sent from the browser to the renderer. -// Notifies the embedding frame that a new CompositorFrame is ready to be -// presented. When the frame finishes presenting, a matching -// FrameHostMsg_CompositorFrameSwappedACK should be sent back to the -// RenderViewHost that was produced the CompositorFrame. -// -// This is used in the ubercomp compositing path. -IPC_MESSAGE_ROUTED1(FrameMsg_CompositorFrameSwapped, - FrameMsg_CompositorFrameSwapped_Params /* params */) - IPC_MESSAGE_ROUTED4(FrameMsg_SetChildFrameSurface, cc::SurfaceId /* surface_id */, gfx::Size /* frame_size */, @@ -554,6 +592,10 @@ IPC_MESSAGE_ROUTED0(FrameMsg_ChildFrameProcessGone) IPC_MESSAGE_ROUTED1(FrameMsg_ContextMenuClosed, content::CustomContextMenuContext /* custom_context */) +// Reloads all the Lo-Fi images in the RenderFrame. Ignores the cache and +// reloads from the network. +IPC_MESSAGE_ROUTED0(FrameMsg_ReloadLoFiImages) + // Executes custom context menu action that was provided from Blink. IPC_MESSAGE_ROUTED2(FrameMsg_CustomContextMenuAction, content::CustomContextMenuContext /* custom_context */, @@ -685,10 +727,10 @@ IPC_MESSAGE_ROUTED1(FrameMsg_HideTransitionElements, IPC_MESSAGE_ROUTED1(FrameMsg_ShowTransitionElements, std::string /* css_selector */) -// Tells the renderer to reload the frame, optionally ignoring the cache while +// Tells the renderer to reload the frame, optionally bypassing the cache while // doing so. IPC_MESSAGE_ROUTED1(FrameMsg_Reload, - bool /* ignore_cache */) + bool /* bypass_cache */) // Notifies the color chooser client that the user selected a color. IPC_MESSAGE_ROUTED2(FrameMsg_DidChooseColorResponse, unsigned, SkColor) @@ -703,7 +745,7 @@ IPC_MESSAGE_ROUTED0(FrameMsg_DeleteProxy) // Request the text surrounding the selection with a |max_length|. The response // will be sent via FrameHostMsg_TextSurroundingSelectionResponse. IPC_MESSAGE_ROUTED1(FrameMsg_TextSurroundingSelectionRequest, - size_t /* max_length */) + uint32_t /* max_length */) // Tells the renderer to insert a link to the specified stylesheet. This is // needed to support navigation transitions. @@ -721,7 +763,9 @@ IPC_MESSAGE_ROUTED1(FrameMsg_DidUpdateSandboxFlags, blink::WebSandboxFlags) // Update a proxy's window.name property. Used when the frame's name is // changed in another process. -IPC_MESSAGE_ROUTED1(FrameMsg_DidUpdateName, std::string /* name */) +IPC_MESSAGE_ROUTED2(FrameMsg_DidUpdateName, + std::string /* name */, + std::string /* unique_name */) // Update a proxy's replicated enforcement of strict mixed content // checking. Used when the frame's mixed content setting is changed in @@ -731,7 +775,9 @@ IPC_MESSAGE_ROUTED1(FrameMsg_EnforceStrictMixedContentChecking, // Update a proxy's replicated origin. Used when the frame is navigated to a // new origin. -IPC_MESSAGE_ROUTED1(FrameMsg_DidUpdateOrigin, url::Origin /* origin */) +IPC_MESSAGE_ROUTED2(FrameMsg_DidUpdateOrigin, + url::Origin /* origin */, + bool /* is potentially trustworthy unique origin */) // Notifies this frame or proxy that it is now focused. This is used to // support cross-process focused frame changes. @@ -746,6 +792,17 @@ IPC_MESSAGE_ROUTED1(FrameMsg_SetTextTrackSettings, IPC_MESSAGE_ROUTED1(FrameMsg_PostMessageEvent, FrameMsg_PostMessage_Params) #if defined(OS_ANDROID) +// Sent when the browser wants the bounding boxes of the current find matches. +// +// If match rects are already cached on the browser side, |current_version| +// should be the version number from the FrameHostMsg_FindMatchRects_Reply +// they came in, so the renderer can tell if it needs to send updated rects. +// Otherwise just pass -1 to always receive the list of rects. +// +// There must be an active search string (it is probably most useful to call +// this immediately after a FrameHostMsg_Find_Reply message arrives with +// final_update set to true). +IPC_MESSAGE_ROUTED1(FrameMsg_FindMatchRects, int /* current_version */) // External popup menus. IPC_MESSAGE_ROUTED2(FrameMsg_SelectPopupMenuItems, @@ -785,8 +842,9 @@ IPC_MESSAGE_ROUTED0(FrameMsg_GetSavableResourceLinks) // Get html data by serializing the target frame and replacing all resource // links with a path to the local copy passed in the message payload. -IPC_MESSAGE_ROUTED1(FrameMsg_GetSerializedHtmlWithLocalLinks, - FrameMsg_GetSerializedHtmlWithLocalLinks_Map) +IPC_MESSAGE_ROUTED2(FrameMsg_GetSerializedHtmlWithLocalLinks, + FrameMsg_GetSerializedHtmlWithLocalLinks_UrlMap, + FrameMsg_GetSerializedHtmlWithLocalLinks_FrameRoutingIdMap) // Serialize target frame and its resources into MHTML and write it into the // provided destination file handle. Note that when serializing multiple @@ -806,12 +864,30 @@ IPC_MESSAGE_ROUTED2(FrameMsg_AdvanceFocus, blink::WebFocusType /* type */, int32_t /* source_routing_id */) +// Sent when the user wants to search for a word on the page (find-in-page). +IPC_MESSAGE_ROUTED3(FrameMsg_Find, + int /* request_id */, + base::string16 /* search_text */, + blink::WebFindOptions) + +// This message notifies the renderer that the user has closed the find-in-page +// window (and what action to take regarding the selection). +IPC_MESSAGE_ROUTED1(FrameMsg_StopFinding, content::StopFindAction /* action */) + #if defined(ENABLE_PLUGINS) // Notifies the renderer of updates to the Plugin Power Saver origin whitelist. IPC_MESSAGE_ROUTED1(FrameMsg_UpdatePluginContentOriginWhitelist, std::set<url::Origin> /* origin_whitelist */) #endif // defined(ENABLE_PLUGINS) +// Used to instruct the RenderFrame to go into "view source" mode. This should +// only be sent to the main frame. +IPC_MESSAGE_ROUTED0(FrameMsg_EnableViewSourceMode) + +// Tells the frame to suppress any further modal dialogs. This ensures that no +// ScopedPageLoadDeferrer is on the stack for SwapOut. +IPC_MESSAGE_ROUTED0(FrameMsg_SuppressFurtherDialogs) + // ----------------------------------------------------------------------------- // Messages sent from the renderer to the browser. @@ -827,14 +903,9 @@ IPC_MESSAGE_ROUTED4(FrameHostMsg_AddMessageToConsole, // // Each of these messages will have a corresponding FrameHostMsg_Detach message // sent when the frame is detached from the DOM. -IPC_SYNC_MESSAGE_CONTROL5_1( - FrameHostMsg_CreateChildFrame, - int32_t /* parent_routing_id */, - blink::WebTreeScopeType /* scope */, - std::string /* frame_name */, - blink::WebSandboxFlags /* sandbox flags */, - blink::WebFrameOwnerProperties /* frame_owner_properties */, - int32_t /* new_routing_id */) +IPC_SYNC_MESSAGE_CONTROL1_1(FrameHostMsg_CreateChildFrame, + FrameHostMsg_CreateChildFrame_Params, + int32_t /* new_routing_id */) // Sent by the renderer to the parent RenderFrameHost when a child frame is // detached from the DOM. @@ -873,9 +944,6 @@ IPC_MESSAGE_ROUTED4(FrameHostMsg_DidFailLoadWithError, base::string16 /* error_description */, bool /* was_ignored_by_handler */) -// Sent when the renderer decides to ignore a navigation. -IPC_MESSAGE_ROUTED0(FrameHostMsg_DidDropNavigation) - // Sent when the renderer starts loading the page. |to_different_document| will // be true unless the load is a fragment navigation, or triggered by // history.pushState/replaceState. @@ -889,7 +957,9 @@ IPC_MESSAGE_ROUTED0(FrameHostMsg_DidStopLoading) IPC_MESSAGE_ROUTED1(FrameHostMsg_UpdateState, content::PageState /* state */) // Sent when the frame changes its window.name. -IPC_MESSAGE_ROUTED1(FrameHostMsg_DidChangeName, std::string /* name */) +IPC_MESSAGE_ROUTED2(FrameHostMsg_DidChangeName, + std::string /* name */, + std::string /* unique_name */) // Sent when the frame starts enforcing strict mixed content // checking. Sending this information in DidCommitProvisionalLoad isn't @@ -898,6 +968,13 @@ IPC_MESSAGE_ROUTED1(FrameHostMsg_DidChangeName, std::string /* name */) // checking to be enforced. IPC_MESSAGE_ROUTED0(FrameHostMsg_EnforceStrictMixedContentChecking) +// Sent when the frame is set to a unique origin. TODO(estark): this IPC +// only exists to support dynamic sandboxing via a CSP delivered in a +// <meta> tag. This is not supposed to be allowed per the CSP spec and +// should be ripped out. https://crbug.com/594645 +IPC_MESSAGE_ROUTED1(FrameHostMsg_UpdateToUniqueOrigin, + bool /* is potentially trustworthy unique origin */) + // Sent when the renderer changed the progress of a load. IPC_MESSAGE_ROUTED1(FrameHostMsg_DidChangeLoadProgress, double /* load_progress */) @@ -994,14 +1071,6 @@ IPC_SYNC_MESSAGE_CONTROL3_1(FrameHostMsg_Are3DAPIsBlocked, content::ThreeDAPIType /* requester */, bool /* blocked */) -// Sent by the renderer process to indicate that a context was lost by -// client 3D content (Pepper 3D, WebGL) running on the page at the -// given URL. -IPC_MESSAGE_CONTROL3(FrameHostMsg_DidLose3DContext, - GURL /* top_origin_url */, - content::ThreeDAPIType /* context_type */, - int /* arb_robustness_status_code */) - #if defined(ENABLE_PLUGINS) // Notification sent from a renderer to the browser that a Pepper plugin // instance is created in the DOM. @@ -1054,18 +1123,6 @@ IPC_SYNC_MESSAGE_CONTROL4_3(FrameHostMsg_GetPluginInfo, IPC_MESSAGE_ROUTED1(FrameHostMsg_PluginContentOriginAllowed, url::Origin /* content_origin */) -// A renderer sends this to the browser process when it wants to -// create a plugin. The browser will create the plugin process if -// necessary, and will return a handle to the channel on success. -// On error an empty string is returned. -IPC_SYNC_MESSAGE_CONTROL4_2(FrameHostMsg_OpenChannelToPlugin, - int /* render_frame_id */, - GURL /* url */, - GURL /* page_url */, - std::string /* mime_type */, - IPC::ChannelHandle /* channel_handle */, - content::WebPluginInfo /* info */) - // A renderer sends this to the browser process when it wants to create a ppapi // plugin. The browser will create the plugin process if necessary, and will // return a handle to the channel on success. @@ -1138,12 +1195,6 @@ IPC_MESSAGE_CONTROL3(FrameHostMsg_PluginInstanceThrottleStateChange, bool /* is_throttled */) #endif // defined(ENABLE_PLUGINS) -// Acknowledge that we presented an ubercomp frame. -// -// See FrameMsg_CompositorFrameSwapped -IPC_MESSAGE_ROUTED1(FrameHostMsg_CompositorFrameSwappedACK, - FrameHostMsg_CompositorFrameSwappedACK_Params /* params */) - // Satisfies a Surface destruction dependency associated with |sequence|. IPC_MESSAGE_ROUTED1(FrameHostMsg_SatisfySequence, cc::SurfaceSequence /* sequence */) @@ -1165,9 +1216,6 @@ IPC_MESSAGE_ROUTED3(FrameHostMsg_BeforeUnload_ACK, // Indicates that the current frame has swapped out, after a SwapOut message. IPC_MESSAGE_ROUTED0(FrameHostMsg_SwapOut_ACK) -IPC_MESSAGE_ROUTED1(FrameHostMsg_ReclaimCompositorResources, - FrameHostMsg_ReclaimCompositorResources_Params /* params */) - // Forwards an input event to a child. // TODO(nick): Temporary bridge, revisit once the browser process can route // input directly to subframes. http://crbug.com/339659 @@ -1214,9 +1262,8 @@ IPC_SYNC_MESSAGE_ROUTED4_2(FrameHostMsg_RunJavaScriptMessage, // Displays a dialog to confirm that the user wants to navigate away from the // page. Replies true if yes, and false otherwise. The reply string is ignored, // but is included so that we can use OnJavaScriptMessageBoxClosed. -IPC_SYNC_MESSAGE_ROUTED3_2(FrameHostMsg_RunBeforeUnloadConfirm, +IPC_SYNC_MESSAGE_ROUTED2_2(FrameHostMsg_RunBeforeUnloadConfirm, GURL, /* in - originating frame URL */ - base::string16 /* in - alert message */, bool /* in - is a reload */, bool /* out - success */, base::string16 /* out - This is ignored.*/) @@ -1235,16 +1282,6 @@ IPC_MESSAGE_ROUTED2(FrameHostMsg_SetSelectedColorInColorChooser, int /* id */, SkColor /* color */) -// Notifies the browser that media has started/stopped playing. -IPC_MESSAGE_ROUTED4(FrameHostMsg_MediaPlayingNotification, - int64_t /* player_cookie, distinguishes instances */, - bool /* has_video */, - bool /* has_audio */, - bool /* is_remote */) - -IPC_MESSAGE_ROUTED1(FrameHostMsg_MediaPausedNotification, - int64_t /* player_cookie, distinguishes instances */) - // Notify browser the theme color has been changed. IPC_MESSAGE_ROUTED1(FrameHostMsg_DidChangeThemeColor, SkColor /* theme_color */) @@ -1253,8 +1290,8 @@ IPC_MESSAGE_ROUTED1(FrameHostMsg_DidChangeThemeColor, // |endOffset| are the offsets of the selection in the returned |content|. IPC_MESSAGE_ROUTED3(FrameHostMsg_TextSurroundingSelectionResponse, base::string16, /* content */ - size_t, /* startOffset */ - size_t /* endOffset */) + uint32_t, /* startOffset */ + uint32_t/* endOffset */) // Register a new handler for URL requests with the given scheme. IPC_MESSAGE_ROUTED4(FrameHostMsg_RegisterProtocolHandler, @@ -1361,6 +1398,22 @@ IPC_MESSAGE_ROUTED2(FrameHostMsg_AdvanceFocus, blink::WebFocusType /* type */, int32_t /* source_routing_id */) +// Result of string search in the document. +// Response to FrameMsg_Find with the results of the requested find-in-page +// search, the number of matches found and the selection rect (in screen +// coordinates) for the string found. If |final_update| is false, it signals +// that this is not the last Find_Reply message - more will be sent as the +// scoping effort continues. +IPC_MESSAGE_ROUTED5(FrameHostMsg_Find_Reply, + int /* request_id */, + int /* number of matches */, + gfx::Rect /* selection_rect */, + int /* active_match_ordinal */, + bool /* final_update */) + +// Sends hittesting data needed to perform hittesting on the browser process. +IPC_MESSAGE_ROUTED1(FrameHostMsg_HittestData, FrameHostMsg_HittestData_Params) + #if defined(OS_MACOSX) || defined(OS_ANDROID) // Message to show/hide a popup menu using native controls. @@ -1370,6 +1423,28 @@ IPC_MESSAGE_ROUTED0(FrameHostMsg_HidePopup) #endif +#if defined(OS_ANDROID) +// Response to FrameMsg_FindMatchRects. +// +// |version| will contain the current version number of the renderer's find +// match list (incremented whenever they change), which should be passed in the +// next call to FrameMsg_FindMatchRects. +// +// |rects| will either contain a list of the enclosing rects of all matches +// found by the most recent Find operation, or will be empty if |version| is not +// greater than the |current_version| passed to FrameMsg_FindMatchRects (hence +// your locally cached rects should still be valid). The rect coords will be +// custom normalized fractions of the document size. The rects will be sorted by +// frame traversal order starting in the main frame, then by dom order. +// +// |active_rect| will contain the bounding box of the active find-in-page match +// marker, in similarly normalized coords (or an empty rect if there isn't one). +IPC_MESSAGE_ROUTED3(FrameHostMsg_FindMatchRects_Reply, + int /* version */, + std::vector<gfx::RectF> /* rects */, + gfx::RectF /* active_rect */) +#endif + // Adding a new message? Stick to the sort order above: first platform // independent FrameMsg, then ifdefs for platform specific FrameMsg, then // platform independent FrameHostMsg, then ifdefs for platform specific diff --git a/chromium/content/common/frame_param.cc b/chromium/content/common/frame_param.cc deleted file mode 100644 index dbeaaa72023..00000000000 --- a/chromium/content/common/frame_param.cc +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2014 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 "content/common/frame_param.h" -#include "content/common/cc_messages.h" - -#define IPC_MESSAGE_IMPL -#include "content/common/frame_param_macros.h" - -// Generate constructors. -#include "ipc/struct_constructor_macros.h" -#undef CONTENT_COMMON_FRAME_PARAM_MACROS_H_ -#include "content/common/frame_param_macros.h" - -// Generate destructors. -#include "ipc/struct_destructor_macros.h" -#undef CONTENT_COMMON_FRAME_PARAM_MACROS_H_ -#include "content/common/frame_param_macros.h" - -// Generate param traits write methods. -#include "ipc/param_traits_write_macros.h" -namespace IPC { -#undef CONTENT_COMMON_FRAME_PARAM_MACROS_H_ -#include "content/common/frame_param_macros.h" -} // namespace IPC - -// Generate param traits read methods. -#include "ipc/param_traits_read_macros.h" -namespace IPC { -#undef CONTENT_COMMON_FRAME_PARAM_MACROS_H_ -#include "content/common/frame_param_macros.h" -} // namespace IPC - -// Generate param traits log methods. -#include "ipc/param_traits_log_macros.h" -namespace IPC { -#undef CONTENT_COMMON_FRAME_PARAM_MACROS_H_ -#include "content/common/frame_param_macros.h" -} // namespace IPC diff --git a/chromium/content/common/frame_param.h b/chromium/content/common/frame_param.h deleted file mode 100644 index 29c4010d2aa..00000000000 --- a/chromium/content/common/frame_param.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2014 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 CONTENT_COMMON_FRAME_PARAM_H_ -#define CONTENT_COMMON_FRAME_PARAM_H_ - -#include "content/common/frame_param_macros.h" - -#endif // CONTENT_COMMON_FRAME_PARAM_H_ diff --git a/chromium/content/common/frame_param_macros.h b/chromium/content/common/frame_param_macros.h deleted file mode 100644 index fd2256d7eec..00000000000 --- a/chromium/content/common/frame_param_macros.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2014 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. - -// Allows for sharing of IPC param structures between BrowserPlugin code and -// RenderFrame code. All these should be folded directly back into the IPCs in -// frame_messages.h once BrowserPlugin has been fully converted over to use -// the RenderFrame infrastructure. -// -// TODO(ajwong): Remove once BrowserPlugin has been converted to use -// RenderFrames. http://crbug.com/330264 - -#ifndef CONTENT_COMMON_FRAME_PARAM_MACROS_H_ -#define CONTENT_COMMON_FRAME_PARAM_MACROS_H_ - -#include <stdint.h> - -#include "cc/output/compositor_frame.h" -#include "cc/output/compositor_frame_ack.h" -#include "content/public/common/common_param_traits.h" -#include "ipc/ipc_message_macros.h" -#include "ui/gfx/ipc/gfx_param_traits.h" - -#undef IPC_MESSAGE_EXPORT -#define IPC_MESSAGE_EXPORT CONTENT_EXPORT - -IPC_STRUCT_BEGIN(FrameMsg_BuffersSwapped_Params) - IPC_STRUCT_MEMBER(int, gpu_host_id) - IPC_STRUCT_MEMBER(int, gpu_route_id) - IPC_STRUCT_MEMBER(gpu::Mailbox, mailbox) - IPC_STRUCT_MEMBER(gfx::Size, size) -IPC_STRUCT_END() - -IPC_STRUCT_BEGIN(FrameMsg_CompositorFrameSwapped_Params) - // Specifies which RenderWidget produced the CompositorFrame. - IPC_STRUCT_MEMBER(int, producing_host_id) - IPC_STRUCT_MEMBER(int, producing_route_id) - - IPC_STRUCT_MEMBER(cc::CompositorFrame, frame) - IPC_STRUCT_MEMBER(uint32_t, output_surface_id) - IPC_STRUCT_MEMBER(base::SharedMemoryHandle, shared_memory_handle) -IPC_STRUCT_END() - -IPC_STRUCT_BEGIN(FrameHostMsg_CompositorFrameSwappedACK_Params) - // Specifies which RenderWidget produced the CompositorFrame. - IPC_STRUCT_MEMBER(int, producing_host_id) - IPC_STRUCT_MEMBER(int, producing_route_id) - - IPC_STRUCT_MEMBER(uint32_t, output_surface_id) - IPC_STRUCT_MEMBER(cc::CompositorFrameAck, ack) -IPC_STRUCT_END() - -IPC_STRUCT_BEGIN(FrameHostMsg_ReclaimCompositorResources_Params) - IPC_STRUCT_MEMBER(int, route_id) - IPC_STRUCT_MEMBER(uint32_t, output_surface_id) - IPC_STRUCT_MEMBER(int, renderer_host_id) - IPC_STRUCT_MEMBER(cc::CompositorFrameAck, ack) -IPC_STRUCT_END() - -#endif // CONTENT_COMMON_FRAME_PARAM_MACROS_H_ diff --git a/chromium/content/common/frame_replication_state.cc b/chromium/content/common/frame_replication_state.cc index 0046466d7f1..00e835f5b92 100644 --- a/chromium/content/common/frame_replication_state.cc +++ b/chromium/content/common/frame_replication_state.cc @@ -11,19 +11,28 @@ namespace content { FrameReplicationState::FrameReplicationState() : sandbox_flags(blink::WebSandboxFlags::None), scope(blink::WebTreeScopeType::Document), - should_enforce_strict_mixed_content_checking(false) {} + should_enforce_strict_mixed_content_checking(false), + has_potentially_trustworthy_unique_origin(false) {} FrameReplicationState::FrameReplicationState( blink::WebTreeScopeType scope, const std::string& name, + const std::string& unique_name, blink::WebSandboxFlags sandbox_flags, - bool should_enforce_strict_mixed_content_checking) + bool should_enforce_strict_mixed_content_checking, + bool has_potentially_trustworthy_unique_origin) : origin(), sandbox_flags(sandbox_flags), name(name), + unique_name(unique_name), scope(scope), should_enforce_strict_mixed_content_checking( - should_enforce_strict_mixed_content_checking) {} + should_enforce_strict_mixed_content_checking), + has_potentially_trustworthy_unique_origin( + has_potentially_trustworthy_unique_origin) {} + +FrameReplicationState::FrameReplicationState( + const FrameReplicationState& other) = default; FrameReplicationState::~FrameReplicationState() { } diff --git a/chromium/content/common/frame_replication_state.h b/chromium/content/common/frame_replication_state.h index 88978490e3f..f6373491a19 100644 --- a/chromium/content/common/frame_replication_state.h +++ b/chromium/content/common/frame_replication_state.h @@ -21,8 +21,11 @@ struct CONTENT_EXPORT FrameReplicationState { FrameReplicationState(); FrameReplicationState(blink::WebTreeScopeType scope, const std::string& name, + const std::string& unique_name, blink::WebSandboxFlags sandbox_flags, - bool should_enforce_strict_mixed_content_checking); + bool should_enforce_strict_mixed_content_checking, + bool has_potentially_trustworthy_unique_origin); + FrameReplicationState(const FrameReplicationState& other); ~FrameReplicationState(); // Current origin of the frame. This field is updated whenever a frame @@ -37,20 +40,21 @@ struct CONTENT_EXPORT FrameReplicationState { // compromized renderer. url::Origin origin; - // Current sandbox flags of the frame. |sandbox_flags| are initialized for - // new child frames using the value of the <iframe> element's "sandbox" - // attribute. They are updated dynamically whenever a parent frame updates an - // <iframe>'s sandbox attribute via JavaScript. + // Sandbox flags currently in effect for the frame. |sandbox_flags| are + // initialized for new child frames using the value of the <iframe> element's + // "sandbox" attribute, combined with any sandbox flags in effect for the + // parent frame. // - // Updates to |sandbox_flags| are sent to proxies, but only after a - // subsequent navigation of the (sandboxed) frame, since the flags only take - // effect on navigation (see also FrameTreeNode::effective_sandbox_flags_). - // The proxies need updated flags so that they can be inherited properly if a - // proxy ever becomes a parent of a local frame. + // When a parent frame updates an <iframe>'s sandbox attribute via + // JavaScript, |sandbox_flags| are updated only after the child frame commits + // a navigation that makes the updated flags take effect. This is also the + // point at which updates are sent to proxies (see + // CommitPendingSandboxFlags()). The proxies need updated flags so that they + // can be inherited properly if a proxy ever becomes a parent of a local + // frame. blink::WebSandboxFlags sandbox_flags; - // The assigned name of the frame. This name can be empty, unlike the unique - // name generated internally in the DOM tree. + // The assigned name of the frame (see WebFrame::assignedName()). // // |name| is set when a new child frame is created using the value of the // <iframe> element's "name" attribute (see @@ -62,6 +66,19 @@ struct CONTENT_EXPORT FrameReplicationState { // frame using its updated name (e.g., using window.open(url, frame_name)). std::string name; + // Unique name of the frame (see WebFrame::uniqueName()). + // + // |unique_name| is used in heuristics that try to identify the same frame + // across different, unrelated navigations (i.e. to refer to the frame + // when going back/forward in session history OR when refering to the frame + // in layout tests results). + // + // |unique_name| needs to be replicated to ensure that unique name for a given + // frame is the same across all renderers - without replication a renderer + // might arrive at a different value when recalculating the unique name from + // scratch. + std::string unique_name; + // Whether the frame is in a document tree or a shadow tree, per the Shadow // DOM spec: https://w3c.github.io/webcomponents/spec/shadow/ // Note: This should really be const, as it can never change once a frame is @@ -75,6 +92,10 @@ struct CONTENT_EXPORT FrameReplicationState { // frames live in different processes. bool should_enforce_strict_mixed_content_checking; + // True if a frame's origin is unique and should be considered potentially + // trustworthy. + bool has_potentially_trustworthy_unique_origin; + // TODO(alexmos): Eventually, this structure can also hold other state that // needs to be replicated, such as frame sizing info. }; diff --git a/chromium/content/common/gamepad_param_traits.cc b/chromium/content/common/gamepad_param_traits.cc index 095154d8e4e..5a343fa1e06 100644 --- a/chromium/content/common/gamepad_param_traits.cc +++ b/chromium/content/common/gamepad_param_traits.cc @@ -33,13 +33,11 @@ void LogWebUCharString( namespace IPC { -void ParamTraits<WebGamepad>::Write( - Message* m, - const WebGamepad& p) { +void ParamTraits<WebGamepad>::Write(base::Pickle* m, const WebGamepad& p) { m->WriteData(reinterpret_cast<const char*>(&p), sizeof(WebGamepad)); } -bool ParamTraits<WebGamepad>::Read(const Message* m, +bool ParamTraits<WebGamepad>::Read(const base::Pickle* m, base::PickleIterator* iter, WebGamepad* p) { int length; diff --git a/chromium/content/common/gamepad_param_traits.h b/chromium/content/common/gamepad_param_traits.h index 212c3063150..99576803b62 100644 --- a/chromium/content/common/gamepad_param_traits.h +++ b/chromium/content/common/gamepad_param_traits.h @@ -10,6 +10,7 @@ #include "ipc/ipc_param_traits.h" namespace base { +class Pickle; class PickleIterator; } @@ -22,8 +23,8 @@ class Message; template <> struct ParamTraits<blink::WebGamepad> { typedef blink::WebGamepad param_type; - static void Write(Message* m, const blink::WebGamepad& p); - static bool Read(const Message* m, + static void Write(base::Pickle* m, const blink::WebGamepad& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, blink::WebGamepad* p); static void Log(const blink::WebGamepad& p, std::string* l); diff --git a/chromium/content/common/geolocation_service.mojom b/chromium/content/common/geolocation_service.mojom deleted file mode 100644 index a9c4e488646..00000000000 --- a/chromium/content/common/geolocation_service.mojom +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 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. - -module content; - -import "content/public/common/mojo_geoposition.mojom"; - -// The Geolocation service provides updates on the device's location. By -// default, it provides updates with low accuracy, but |SetHighAccuracy()| may -// be called to change this. -interface GeolocationService { - SetHighAccuracy(bool high_accuracy); - - // Position is reported once it changes or immediately (to report the initial - // position) if this is the first call to QueryNextPosition on this instance. - // Position updates may be throttled by the service. Overlapping calls to - // this method are prohibited and will be treated as a connection error. - QueryNextPosition() => (MojoGeoposition geoposition); -}; diff --git a/chromium/content/common/gpu/DEPS b/chromium/content/common/gpu/DEPS index 2c01d5f2d7b..56ee2c3e9b8 100644 --- a/chromium/content/common/gpu/DEPS +++ b/chromium/content/common/gpu/DEPS @@ -2,9 +2,6 @@ include_rules = [ "+gpu/command_buffer", "+libEGL", "+libGLESv2", - "+media/video/jpeg_decode_accelerator.h", - "+media/video/video_decode_accelerator.h", - "+media/video/video_encode_accelerator.h", "+skia", "+third_party/mesa", ] diff --git a/chromium/content/common/gpu/ca_layer_partial_damage_tree_mac.h b/chromium/content/common/gpu/ca_layer_partial_damage_tree_mac.h deleted file mode 100644 index f52000d6ddf..00000000000 --- a/chromium/content/common/gpu/ca_layer_partial_damage_tree_mac.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2016 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 CONTENT_COMMON_GPU_CA_LAYER_PARTIAL_DAMAGE_TREE_MAC_H_ -#define CONTENT_COMMON_GPU_CA_LAYER_PARTIAL_DAMAGE_TREE_MAC_H_ - -#include <IOSurface/IOSurface.h> -#include <QuartzCore/QuartzCore.h> -#include <deque> - -#include "base/mac/scoped_cftyperef.h" -#include "base/memory/scoped_ptr.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/rect_f.h" - -namespace content { - -class CALayerPartialDamageTree { - public: - CALayerPartialDamageTree(bool allow_partial_swap, - base::ScopedCFTypeRef<IOSurfaceRef> io_surface, - const gfx::Rect& pixel_frame_rect); - ~CALayerPartialDamageTree(); - - base::ScopedCFTypeRef<IOSurfaceRef> RootLayerIOSurface(); - void CommitCALayers(CALayer* superlayer, - scoped_ptr<CALayerPartialDamageTree> old_tree, - float scale_factor, - const gfx::Rect& pixel_damage_rect); - - private: - class OverlayPlane; - - // This will populate |partial_damage_planes_|, potentially re-using the - // CALayers and |partial_damage_planes_| from |old_tree|. After this function - // completes, the back() of |partial_damage_planes_| is the plane that will - // be updated this frame (and if it is empty, then the root plane will be - // updated). - void UpdatePartialDamagePlanes(CALayerPartialDamageTree* old_tree, - const gfx::Rect& pixel_damage_rect); - - void UpdateRootAndPartialDamagePlanes( - scoped_ptr<CALayerPartialDamageTree> old_tree, - const gfx::Rect& pixel_damage_rect); - - void UpdateCALayers(CALayer* superlayer, float scale_factor); - - const bool allow_partial_swap_; - scoped_ptr<OverlayPlane> root_plane_; - std::deque<scoped_ptr<OverlayPlane>> partial_damage_planes_; -}; - -} // content - -#endif // CONTENT_COMMON_GPU_CA_LAYER_PARTIAL_DAMAGE_TREE_MAC_H_ diff --git a/chromium/content/common/gpu/ca_layer_partial_damage_tree_mac.mm b/chromium/content/common/gpu/ca_layer_partial_damage_tree_mac.mm deleted file mode 100644 index f42738947a0..00000000000 --- a/chromium/content/common/gpu/ca_layer_partial_damage_tree_mac.mm +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright 2016 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 "content/common/gpu/ca_layer_partial_damage_tree_mac.h" - -#include "base/command_line.h" -#include "base/mac/scoped_nsobject.h" -#include "base/mac/sdk_forward_declarations.h" -#include "base/trace_event/trace_event.h" -#include "ui/base/ui_base_switches.h" -#include "ui/gfx/transform.h" - -@interface CALayer(Private) --(void)setContentsChanged; -@end - -namespace content { -namespace { - -// When selecting a CALayer to re-use for partial damage, this is the maximum -// fraction of the merged layer's pixels that may be not-updated by the swap -// before we consider the CALayer to not be a good enough match, and create a -// new one. -const float kMaximumPartialDamageWasteFraction = 1.2f; - -// The maximum number of partial damage layers that may be created before we -// give up and remove them all (doing full damage in the process). -const size_t kMaximumPartialDamageLayers = 8; - -} // namespace - -class CALayerPartialDamageTree::OverlayPlane { - public: - OverlayPlane(base::ScopedCFTypeRef<IOSurfaceRef> io_surface, - const gfx::Rect& pixel_frame_rect, - const gfx::RectF& contents_rect) - : io_surface(io_surface), - contents_rect(contents_rect), - pixel_frame_rect(pixel_frame_rect), - layer_needs_update(true) {} - - ~OverlayPlane() { - [ca_layer setContents:nil]; - [ca_layer removeFromSuperlayer]; - ca_layer.reset(); - } - - const base::ScopedCFTypeRef<IOSurfaceRef> io_surface; - const gfx::RectF contents_rect; - const gfx::Rect pixel_frame_rect; - bool layer_needs_update; - base::scoped_nsobject<CALayer> ca_layer; - - void TakeCALayerFrom(OverlayPlane* other_plane) { - ca_layer.swap(other_plane->ca_layer); - } - - void UpdateProperties(float scale_factor) { - if (layer_needs_update) { - [ca_layer setOpaque:YES]; - - id new_contents = static_cast<id>(io_surface.get()); - if ([ca_layer contents] == new_contents) - [ca_layer setContentsChanged]; - else - [ca_layer setContents:new_contents]; - [ca_layer setContentsRect:contents_rect.ToCGRect()]; - - [ca_layer setAnchorPoint:CGPointZero]; - - if ([ca_layer respondsToSelector:(@selector(setContentsScale:))]) - [ca_layer setContentsScale:scale_factor]; - gfx::RectF dip_frame_rect = gfx::RectF(pixel_frame_rect); - dip_frame_rect.Scale(1 / scale_factor); - [ca_layer setBounds:CGRectMake(0, 0, dip_frame_rect.width(), - dip_frame_rect.height())]; - [ca_layer - setPosition:CGPointMake(dip_frame_rect.x(), dip_frame_rect.y())]; - } - static bool show_borders = - base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kShowMacOverlayBorders); - if (show_borders) { - base::ScopedCFTypeRef<CGColorRef> color; - if (!layer_needs_update) { - // Green represents contents that are unchanged across frames. - color.reset(CGColorCreateGenericRGB(0, 1, 0, 1)); - } else { - // Red represents damaged contents. - color.reset(CGColorCreateGenericRGB(1, 0, 0, 1)); - } - [ca_layer setBorderWidth:1]; - [ca_layer setBorderColor:color]; - } - layer_needs_update = false; - } - - private: -}; - -void CALayerPartialDamageTree::UpdatePartialDamagePlanes( - CALayerPartialDamageTree* old_tree, - const gfx::Rect& pixel_damage_rect) { - // Don't create partial damage layers if partial swap is disabled. - if (!allow_partial_swap_) - return; - // Only create partial damage layers when building on top of an existing tree. - if (!old_tree) - return; - // If the frame size has changed, discard all of the old partial damage - // layers. - if (old_tree->root_plane_->pixel_frame_rect != root_plane_->pixel_frame_rect) - return; - // If there is full damage, discard all of the old partial damage layers. - if (pixel_damage_rect == root_plane_->pixel_frame_rect) - return; - - // If there is no damage, don't change anything. - if (pixel_damage_rect.IsEmpty()) { - std::swap(partial_damage_planes_, old_tree->partial_damage_planes_); - return; - } - - // Find the last partial damage plane to re-use the CALayer from. Grow the - // new rect for this layer to include this damage, and all nearby partial - // damage layers. - scoped_ptr<OverlayPlane> plane_for_swap; - { - auto plane_to_reuse_iter = old_tree->partial_damage_planes_.end(); - gfx::Rect plane_to_reuse_enlarged_pixel_damage_rect; - - for (auto old_plane_iter = old_tree->partial_damage_planes_.begin(); - old_plane_iter != old_tree->partial_damage_planes_.end(); - ++old_plane_iter) { - gfx::Rect enlarged_pixel_damage_rect = - (*old_plane_iter)->pixel_frame_rect; - enlarged_pixel_damage_rect.Union(pixel_damage_rect); - - // Compute the fraction of the pixels that would not be updated by this - // swap. If it is too big, try another layer. - float waste_fraction = enlarged_pixel_damage_rect.size().GetArea() * 1.f / - pixel_damage_rect.size().GetArea(); - if (waste_fraction > kMaximumPartialDamageWasteFraction) - continue; - - plane_to_reuse_iter = old_plane_iter; - plane_to_reuse_enlarged_pixel_damage_rect.Union( - enlarged_pixel_damage_rect); - } - if (plane_to_reuse_iter != old_tree->partial_damage_planes_.end()) { - gfx::RectF enlarged_contents_rect = - gfx::RectF(plane_to_reuse_enlarged_pixel_damage_rect); - enlarged_contents_rect.Scale(1. / root_plane_->pixel_frame_rect.width(), - 1. / root_plane_->pixel_frame_rect.height()); - - plane_for_swap.reset(new OverlayPlane( - root_plane_->io_surface, plane_to_reuse_enlarged_pixel_damage_rect, - enlarged_contents_rect)); - - plane_for_swap->TakeCALayerFrom((*plane_to_reuse_iter).get()); - if (*plane_to_reuse_iter != old_tree->partial_damage_planes_.back()) { - CALayer* superlayer = [plane_for_swap->ca_layer superlayer]; - [plane_for_swap->ca_layer removeFromSuperlayer]; - [superlayer addSublayer:plane_for_swap->ca_layer]; - } - } - } - - // If we haven't found an appropriate layer to re-use, create a new one, if - // we haven't already created too many. - if (!plane_for_swap.get() && - old_tree->partial_damage_planes_.size() < kMaximumPartialDamageLayers) { - gfx::RectF contents_rect = gfx::RectF(pixel_damage_rect); - contents_rect.Scale(1. / root_plane_->pixel_frame_rect.width(), - 1. / root_plane_->pixel_frame_rect.height()); - plane_for_swap.reset(new OverlayPlane(root_plane_->io_surface, - pixel_damage_rect, contents_rect)); - } - - // And if we still don't have a layer, do full damage. - if (!plane_for_swap.get()) - return; - - // Walk all old partial damage planes. Remove anything that is now completely - // covered, and move everything else into the new |partial_damage_planes_|. - for (auto& old_plane : old_tree->partial_damage_planes_) { - if (!old_plane.get()) - continue; - // Intersect the planes' frames with the new root plane to ensure that - // they don't get kept alive inappropriately. - gfx::Rect old_plane_frame_rect = old_plane->pixel_frame_rect; - old_plane_frame_rect.Intersect(root_plane_->pixel_frame_rect); - - bool old_plane_covered_by_swap = false; - if (plane_for_swap.get() && - plane_for_swap->pixel_frame_rect.Contains(old_plane_frame_rect)) { - old_plane_covered_by_swap = true; - } - if (!old_plane_covered_by_swap) { - DCHECK(old_plane->ca_layer); - partial_damage_planes_.push_back(std::move(old_plane)); - } - } - - partial_damage_planes_.push_back(std::move(plane_for_swap)); -} - -void CALayerPartialDamageTree::UpdateRootAndPartialDamagePlanes( - scoped_ptr<CALayerPartialDamageTree> old_tree, - const gfx::Rect& pixel_damage_rect) { - // First update the partial damage tree. - UpdatePartialDamagePlanes(old_tree.get(), pixel_damage_rect); - if (old_tree) { - if (partial_damage_planes_.empty()) { - // If there are no partial damage planes, then we will be updating the - // root layer. Take the CALayer from the old tree. - root_plane_->TakeCALayerFrom(old_tree->root_plane_.get()); - } else { - // If there is a partial damage tree, then just take the old plane - // from the previous frame, so that there is no update to it. - root_plane_.swap(old_tree->root_plane_); - } - } -} - -void CALayerPartialDamageTree::UpdateCALayers(CALayer* superlayer, - float scale_factor) { - if (!allow_partial_swap_) { - DCHECK(partial_damage_planes_.empty()); - return; - } - - // Allocate and update CALayers for the backbuffer and partial damage layers. - if (!root_plane_->ca_layer) { - DCHECK(partial_damage_planes_.empty()); - root_plane_->ca_layer.reset([[CALayer alloc] init]); - [superlayer setSublayers:nil]; - [superlayer addSublayer:root_plane_->ca_layer]; - } - // Excessive logging to debug white screens (crbug.com/583805). - // TODO(ccameron): change this back to a DLOG. - if ([root_plane_->ca_layer superlayer] != superlayer) { - LOG(ERROR) << "CALayerPartialDamageTree root layer not attached to tree."; - } - for (auto& plane : partial_damage_planes_) { - if (!plane->ca_layer) { - DCHECK(plane == partial_damage_planes_.back()); - plane->ca_layer.reset([[CALayer alloc] init]); - } - if (![plane->ca_layer superlayer]) { - DCHECK(plane == partial_damage_planes_.back()); - [superlayer addSublayer:plane->ca_layer]; - } - } - root_plane_->UpdateProperties(scale_factor); - for (auto& plane : partial_damage_planes_) - plane->UpdateProperties(scale_factor); -} - -CALayerPartialDamageTree::CALayerPartialDamageTree( - bool allow_partial_swap, - base::ScopedCFTypeRef<IOSurfaceRef> io_surface, - const gfx::Rect& pixel_frame_rect) - : allow_partial_swap_(allow_partial_swap) { - root_plane_.reset( - new OverlayPlane(io_surface, pixel_frame_rect, gfx::RectF(0, 0, 1, 1))); -} - -CALayerPartialDamageTree::~CALayerPartialDamageTree() {} - -base::ScopedCFTypeRef<IOSurfaceRef> -CALayerPartialDamageTree::RootLayerIOSurface() { - return root_plane_->io_surface; -} - -void CALayerPartialDamageTree::CommitCALayers( - CALayer* superlayer, - scoped_ptr<CALayerPartialDamageTree> old_tree, - float scale_factor, - const gfx::Rect& pixel_damage_rect) { - TRACE_EVENT0("gpu", "CALayerPartialDamageTree::CommitCALayers"); - UpdateRootAndPartialDamagePlanes(std::move(old_tree), pixel_damage_rect); - UpdateCALayers(superlayer, scale_factor); -} - -} // namespace content diff --git a/chromium/content/common/gpu/ca_layer_tree_mac.h b/chromium/content/common/gpu/ca_layer_tree_mac.h deleted file mode 100644 index d20bdb0d8be..00000000000 --- a/chromium/content/common/gpu/ca_layer_tree_mac.h +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2016 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 CONTENT_COMMON_GPU_CA_LAYER_TREE_MAC_H_ -#define CONTENT_COMMON_GPU_CA_LAYER_TREE_MAC_H_ - -#include <IOSurface/IOSurface.h> -#include <QuartzCore/QuartzCore.h> -#include <deque> -#include <vector> - -#include "base/mac/scoped_cftyperef.h" -#include "base/mac/scoped_nsobject.h" -#include "base/memory/scoped_ptr.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/rect_f.h" -#include "ui/gfx/transform.h" - -namespace content { - -// The CALayerTree will construct a hierarchy of CALayers from a linear list, -// using the algorithm and structure referenced described in -// https://docs.google.com/document/d/1DtSN9zzvCF44_FQPM7ie01UxGHagQ66zfF5L9HnigQY/edit?usp=sharing -class CALayerTree { - public: - CALayerTree(); - - // This will remove all CALayers from this tree from their superlayer. - ~CALayerTree(); - - // Append the description of a new CALayer to the tree. This will not - // create any new CALayers until CommitScheduledCALayers is called. This - // cannot be called anymore after CommitScheduledCALayers has been called. - bool ScheduleCALayer(bool is_clipped, - const gfx::Rect& clip_rect, - unsigned sorting_context_id, - const gfx::Transform& transform, - base::ScopedCFTypeRef<IOSurfaceRef> io_surface, - const gfx::RectF& contents_rect, - const gfx::Rect& rect, - unsigned background_color, - unsigned edge_aa_mask, - float opacity); - - // Create a CALayer tree for the scheduled layers, and set |superlayer| to - // have only this tree as its sublayers. If |old_tree| is non-null, then try - // to re-use the CALayers of |old_tree| as much as possible. |old_tree| will - // be destroyed at the end of the function, and any CALayers in it which were - // not re-used by |this| will be removed from the CALayer hierarchy. - void CommitScheduledCALayers(CALayer* superlayer, - scoped_ptr<CALayerTree> old_tree, - float scale_factor); - - private: - struct RootLayer; - struct ClipAndSortingLayer; - struct TransformLayer; - struct ContentLayer; - - struct RootLayer { - RootLayer(); - - // This will remove |ca_layer| from its superlayer, if |ca_layer| is - // non-nil. - ~RootLayer(); - - // Append a new content layer, without modifying the actual CALayer - // structure. - bool AddContentLayer(bool is_clipped, - const gfx::Rect& clip_rect, - unsigned sorting_context_id, - const gfx::Transform& transform, - base::ScopedCFTypeRef<IOSurfaceRef> io_surface, - const gfx::RectF& contents_rect, - const gfx::Rect& rect, - unsigned background_color, - unsigned edge_aa_mask, - float opacity); - - // Allocate CALayers for this layer and its children, and set their - // properties appropriately. Re-use the CALayers from |old_layer| if - // possible. If re-using a CALayer from |old_layer|, reset its |ca_layer| - // to nil, so that its destructor will not remove an active CALayer. - void CommitToCA(CALayer* superlayer, - RootLayer* old_layer, - float scale_factor); - - std::vector<ClipAndSortingLayer> clip_and_sorting_layers; - base::scoped_nsobject<CALayer> ca_layer; - - private: - DISALLOW_COPY_AND_ASSIGN(RootLayer); - }; - struct ClipAndSortingLayer { - ClipAndSortingLayer(bool is_clipped, - gfx::Rect clip_rect, - unsigned sorting_context_id, - bool is_singleton_sorting_context); - ClipAndSortingLayer(ClipAndSortingLayer&& layer); - - // See the behavior of RootLayer for the effects of these functions on the - // |ca_layer| member and |old_layer| argument. - ~ClipAndSortingLayer(); - void AddContentLayer(const gfx::Transform& transform, - base::ScopedCFTypeRef<IOSurfaceRef> io_surface, - const gfx::RectF& contents_rect, - const gfx::Rect& rect, - unsigned background_color, - unsigned edge_aa_mask, - float opacity); - void CommitToCA(CALayer* superlayer, - ClipAndSortingLayer* old_layer, - float scale_factor); - - std::vector<TransformLayer> transform_layers; - bool is_clipped = false; - gfx::Rect clip_rect; - unsigned sorting_context_id = 0; - bool is_singleton_sorting_context = false; - base::scoped_nsobject<CALayer> ca_layer; - - private: - DISALLOW_COPY_AND_ASSIGN(ClipAndSortingLayer); - }; - struct TransformLayer { - TransformLayer(const gfx::Transform& transform); - TransformLayer(TransformLayer&& layer); - - // See the behavior of RootLayer for the effects of these functions on the - // |ca_layer| member and |old_layer| argument. - ~TransformLayer(); - void AddContentLayer(base::ScopedCFTypeRef<IOSurfaceRef> io_surface, - const gfx::RectF& contents_rect, - const gfx::Rect& rect, - unsigned background_color, - unsigned edge_aa_mask, - float opacity); - void CommitToCA(CALayer* superlayer, - TransformLayer* old_layer, - float scale_factor); - - gfx::Transform transform; - std::vector<ContentLayer> content_layers; - base::scoped_nsobject<CALayer> ca_layer; - - private: - DISALLOW_COPY_AND_ASSIGN(TransformLayer); - }; - struct ContentLayer { - ContentLayer(base::ScopedCFTypeRef<IOSurfaceRef> io_surface, - const gfx::RectF& contents_rect, - const gfx::Rect& rect, - unsigned background_color, - unsigned edge_aa_mask, - float opacity); - ContentLayer(ContentLayer&& layer); - - // See the behavior of RootLayer for the effects of these functions on the - // |ca_layer| member and |old_layer| argument. - ~ContentLayer(); - void CommitToCA(CALayer* parent, - ContentLayer* old_layer, - float scale_factor); - - const base::ScopedCFTypeRef<IOSurfaceRef> io_surface; - gfx::RectF contents_rect; - gfx::Rect rect; - unsigned background_color = 0; - // Note that the CoreAnimation edge antialiasing mask is not the same as - // the edge antialiasing mask passed to the constructor. - CAEdgeAntialiasingMask ca_edge_aa_mask = 0; - float opacity = 1; - base::scoped_nsobject<CALayer> ca_layer; - - private: - DISALLOW_COPY_AND_ASSIGN(ContentLayer); - }; - - RootLayer root_layer_; - float scale_factor_ = 1; - bool has_committed_ = false; - - private: - DISALLOW_COPY_AND_ASSIGN(CALayerTree); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_CA_LAYER_TREE_MAC_H_ diff --git a/chromium/content/common/gpu/ca_layer_tree_mac.mm b/chromium/content/common/gpu/ca_layer_tree_mac.mm deleted file mode 100644 index 8c7d93886a5..00000000000 --- a/chromium/content/common/gpu/ca_layer_tree_mac.mm +++ /dev/null @@ -1,455 +0,0 @@ -// Copyright 2016 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 "content/common/gpu/ca_layer_tree_mac.h" - -#include "base/command_line.h" -#include "base/mac/sdk_forward_declarations.h" -#include "base/trace_event/trace_event.h" -#include "gpu/GLES2/gl2extchromium.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/base/cocoa/animation_utils.h" -#include "ui/base/ui_base_switches.h" -#include "ui/gfx/geometry/dip_util.h" - -namespace content { - -CALayerTree::CALayerTree() {} -CALayerTree::~CALayerTree() {} - -bool CALayerTree::ScheduleCALayer( - bool is_clipped, - const gfx::Rect& clip_rect, - unsigned sorting_context_id, - const gfx::Transform& transform, - base::ScopedCFTypeRef<IOSurfaceRef> io_surface, - const gfx::RectF& contents_rect, - const gfx::Rect& rect, - unsigned background_color, - unsigned edge_aa_mask, - float opacity) { - // Excessive logging to debug white screens (crbug.com/583805). - // TODO(ccameron): change this back to a DLOG. - if (has_committed_) { - LOG(ERROR) << "ScheduleCALayer called after CommitScheduledCALayers."; - return false; - } - return root_layer_.AddContentLayer(is_clipped, clip_rect, sorting_context_id, - transform, io_surface, contents_rect, rect, - background_color, edge_aa_mask, opacity); -} - -void CALayerTree::CommitScheduledCALayers(CALayer* superlayer, - scoped_ptr<CALayerTree> old_tree, - float scale_factor) { - TRACE_EVENT0("gpu", "CALayerTree::CommitScheduledCALayers"); - RootLayer* old_root_layer = nullptr; - if (old_tree) { - DCHECK(old_tree->has_committed_); - if (old_tree->scale_factor_ == scale_factor) - old_root_layer = &old_tree->root_layer_; - } - - root_layer_.CommitToCA(superlayer, old_root_layer, scale_factor); - // If there are any extra CALayers in |old_tree| that were not stolen by this - // tree, they will be removed from the CALayer tree in this deallocation. - old_tree.reset(); - has_committed_ = true; - scale_factor_ = scale_factor; -} - -CALayerTree::RootLayer::RootLayer() {} - -// Note that for all destructors, the the CALayer will have been reset to nil if -// another layer has taken it. -CALayerTree::RootLayer::~RootLayer() { - [ca_layer removeFromSuperlayer]; -} - -CALayerTree::ClipAndSortingLayer::ClipAndSortingLayer( - bool is_clipped, - gfx::Rect clip_rect, - unsigned sorting_context_id, - bool is_singleton_sorting_context) - : is_clipped(is_clipped), - clip_rect(clip_rect), - sorting_context_id(sorting_context_id), - is_singleton_sorting_context(is_singleton_sorting_context) {} - -CALayerTree::ClipAndSortingLayer::ClipAndSortingLayer( - ClipAndSortingLayer&& layer) - : transform_layers(std::move(layer.transform_layers)), - is_clipped(layer.is_clipped), - clip_rect(layer.clip_rect), - sorting_context_id(layer.sorting_context_id), - is_singleton_sorting_context( - layer.is_singleton_sorting_context), - ca_layer(layer.ca_layer) { - // Ensure that the ca_layer be reset, so that when the destructor is called, - // the layer hierarchy is unaffected. - // TODO(ccameron): Add a move constructor for scoped_nsobject to do this - // automatically. - layer.ca_layer.reset(); -} - -CALayerTree::ClipAndSortingLayer::~ClipAndSortingLayer() { - [ca_layer removeFromSuperlayer]; -} - -CALayerTree::TransformLayer::TransformLayer(const gfx::Transform& transform) - : transform(transform) {} - -CALayerTree::TransformLayer::TransformLayer(TransformLayer&& layer) - : transform(layer.transform), - content_layers(std::move(layer.content_layers)), - ca_layer(layer.ca_layer) { - layer.ca_layer.reset(); -} - -CALayerTree::TransformLayer::~TransformLayer() { - [ca_layer removeFromSuperlayer]; -} - -CALayerTree::ContentLayer::ContentLayer( - base::ScopedCFTypeRef<IOSurfaceRef> io_surface, - const gfx::RectF& contents_rect, - const gfx::Rect& rect, - unsigned background_color, - unsigned edge_aa_mask, - float opacity) - : io_surface(io_surface), - contents_rect(contents_rect), - rect(rect), - background_color(background_color), - ca_edge_aa_mask(0), - opacity(opacity) { - // Because the root layer has setGeometryFlipped:YES, there is some ambiguity - // about what exactly top and bottom mean. This ambiguity is resolved in - // different ways for solid color CALayers and for CALayers that have content - // (surprise!). For CALayers with IOSurface content, the top edge in the AA - // mask refers to what appears as the bottom edge on-screen. For CALayers - // without content (solid color layers), the top edge in the AA mask is the - // top edge on-screen. - // http://crbug.com/567946 - if (edge_aa_mask & GL_CA_LAYER_EDGE_LEFT_CHROMIUM) - ca_edge_aa_mask |= kCALayerLeftEdge; - if (edge_aa_mask & GL_CA_LAYER_EDGE_RIGHT_CHROMIUM) - ca_edge_aa_mask |= kCALayerRightEdge; - if (io_surface) { - if (edge_aa_mask & GL_CA_LAYER_EDGE_TOP_CHROMIUM) - ca_edge_aa_mask |= kCALayerBottomEdge; - if (edge_aa_mask & GL_CA_LAYER_EDGE_BOTTOM_CHROMIUM) - ca_edge_aa_mask |= kCALayerTopEdge; - } else { - if (edge_aa_mask & GL_CA_LAYER_EDGE_TOP_CHROMIUM) - ca_edge_aa_mask |= kCALayerTopEdge; - if (edge_aa_mask & GL_CA_LAYER_EDGE_BOTTOM_CHROMIUM) - ca_edge_aa_mask |= kCALayerBottomEdge; - } - - // Ensure that the IOSurface be in use as soon as it is added to a - // ContentLayer, so that, by the time that the call to SwapBuffers completes, - // all IOSurfaces that can be used as CALayer contents in the future will be - // marked as InUse. - if (io_surface) - IOSurfaceIncrementUseCount(io_surface); -} - -CALayerTree::ContentLayer::ContentLayer(ContentLayer&& layer) - : io_surface(layer.io_surface), - contents_rect(layer.contents_rect), - rect(layer.rect), - background_color(layer.background_color), - ca_edge_aa_mask(layer.ca_edge_aa_mask), - opacity(layer.opacity), - ca_layer(layer.ca_layer) { - DCHECK(!layer.ca_layer); - layer.ca_layer.reset(); - // See remarks in the non-move constructor. - if (io_surface) - IOSurfaceIncrementUseCount(io_surface); -} - -CALayerTree::ContentLayer::~ContentLayer() { - [ca_layer removeFromSuperlayer]; - // By the time the destructor is called, the IOSurface will have been passed - // to the WindowServer, and will remain InUse by the WindowServer as long as - // is needed to avoid recycling bugs. - if (io_surface) - IOSurfaceDecrementUseCount(io_surface); -} - -bool CALayerTree::RootLayer::AddContentLayer( - bool is_clipped, - const gfx::Rect& clip_rect, - unsigned sorting_context_id, - const gfx::Transform& transform, - base::ScopedCFTypeRef<IOSurfaceRef> io_surface, - const gfx::RectF& contents_rect, - const gfx::Rect& rect, - unsigned background_color, - unsigned edge_aa_mask, - float opacity) { - bool needs_new_clip_and_sorting_layer = true; - - // In sorting_context_id 0, all quads are listed in back-to-front order. - // This is accomplished by having the CALayers be siblings of each other. - // If a quad has a 3D transform, it is necessary to put it in its own sorting - // context, so that it will not intersect with quads before and after it. - bool is_singleton_sorting_context = - !sorting_context_id && !transform.IsFlat(); - - if (!clip_and_sorting_layers.empty()) { - ClipAndSortingLayer& current_layer = clip_and_sorting_layers.back(); - // It is in error to change the clipping settings within a non-zero sorting - // context. The result will be incorrect layering and intersection. - if (sorting_context_id && - current_layer.sorting_context_id == sorting_context_id && - (current_layer.is_clipped != is_clipped || - current_layer.clip_rect != clip_rect)) { - // Excessive logging to debug white screens (crbug.com/583805). - // TODO(ccameron): change this back to a DLOG. - LOG(ERROR) << "CALayer changed clip inside non-zero sorting context."; - return false; - } - if (!is_singleton_sorting_context && - !current_layer.is_singleton_sorting_context && - current_layer.is_clipped == is_clipped && - current_layer.clip_rect == clip_rect && - current_layer.sorting_context_id == sorting_context_id) { - needs_new_clip_and_sorting_layer = false; - } - } - if (needs_new_clip_and_sorting_layer) { - clip_and_sorting_layers.push_back( - ClipAndSortingLayer(is_clipped, clip_rect, sorting_context_id, - is_singleton_sorting_context)); - } - clip_and_sorting_layers.back().AddContentLayer( - transform, io_surface, contents_rect, rect, background_color, - edge_aa_mask, opacity); - return true; -} - -void CALayerTree::ClipAndSortingLayer::AddContentLayer( - const gfx::Transform& transform, - base::ScopedCFTypeRef<IOSurfaceRef> io_surface, - const gfx::RectF& contents_rect, - const gfx::Rect& rect, - unsigned background_color, - unsigned edge_aa_mask, - float opacity) { - bool needs_new_transform_layer = true; - if (!transform_layers.empty()) { - const TransformLayer& current_layer = transform_layers.back(); - if (current_layer.transform == transform) - needs_new_transform_layer = false; - } - if (needs_new_transform_layer) - transform_layers.push_back(TransformLayer(transform)); - transform_layers.back().AddContentLayer( - io_surface, contents_rect, rect, background_color, edge_aa_mask, opacity); -} - -void CALayerTree::TransformLayer::AddContentLayer( - base::ScopedCFTypeRef<IOSurfaceRef> io_surface, - const gfx::RectF& contents_rect, - const gfx::Rect& rect, - unsigned background_color, - unsigned edge_aa_mask, - float opacity) { - content_layers.push_back(ContentLayer(io_surface, contents_rect, rect, - background_color, edge_aa_mask, - opacity)); -} - -void CALayerTree::RootLayer::CommitToCA(CALayer* superlayer, - RootLayer* old_layer, - float scale_factor) { - if (old_layer) { - DCHECK(old_layer->ca_layer); - std::swap(ca_layer, old_layer->ca_layer); - } else { - ca_layer.reset([[CALayer alloc] init]); - [ca_layer setAnchorPoint:CGPointZero]; - [superlayer setSublayers:nil]; - [superlayer addSublayer:ca_layer]; - [superlayer setBorderWidth:0]; - } - // Excessive logging to debug white screens (crbug.com/583805). - // TODO(ccameron): change this back to a DCHECK. - if ([ca_layer superlayer] != superlayer) { - LOG(ERROR) << "CALayerTree root layer not attached to tree."; - } - - for (size_t i = 0; i < clip_and_sorting_layers.size(); ++i) { - ClipAndSortingLayer* old_clip_and_sorting_layer = nullptr; - if (old_layer && i < old_layer->clip_and_sorting_layers.size()) { - old_clip_and_sorting_layer = &old_layer->clip_and_sorting_layers[i]; - } - clip_and_sorting_layers[i].CommitToCA( - ca_layer.get(), old_clip_and_sorting_layer, scale_factor); - } -} - -void CALayerTree::ClipAndSortingLayer::CommitToCA( - CALayer* superlayer, - ClipAndSortingLayer* old_layer, - float scale_factor) { - bool update_is_clipped = true; - bool update_clip_rect = true; - if (old_layer) { - DCHECK(old_layer->ca_layer); - std::swap(ca_layer, old_layer->ca_layer); - update_is_clipped = old_layer->is_clipped != is_clipped; - update_clip_rect = old_layer->clip_rect != clip_rect; - } else { - ca_layer.reset([[CALayer alloc] init]); - [ca_layer setAnchorPoint:CGPointZero]; - [superlayer addSublayer:ca_layer]; - } - // Excessive logging to debug white screens (crbug.com/583805). - // TODO(ccameron): change this back to a DCHECK. - if ([ca_layer superlayer] != superlayer) { - LOG(ERROR) << "CALayerTree root layer not attached to tree."; - } - - if (update_is_clipped) - [ca_layer setMasksToBounds:is_clipped]; - - if (update_clip_rect) { - if (is_clipped) { - gfx::RectF dip_clip_rect = gfx::RectF(clip_rect); - dip_clip_rect.Scale(1 / scale_factor); - [ca_layer setPosition:CGPointMake(dip_clip_rect.x(), dip_clip_rect.y())]; - [ca_layer setBounds:CGRectMake(0, 0, dip_clip_rect.width(), - dip_clip_rect.height())]; - [ca_layer - setSublayerTransform:CATransform3DMakeTranslation( - -dip_clip_rect.x(), -dip_clip_rect.y(), 0)]; - } else { - [ca_layer setPosition:CGPointZero]; - [ca_layer setBounds:CGRectZero]; - [ca_layer setSublayerTransform:CATransform3DIdentity]; - } - } - - for (size_t i = 0; i < transform_layers.size(); ++i) { - TransformLayer* old_transform_layer = nullptr; - if (old_layer && i < old_layer->transform_layers.size()) - old_transform_layer = &old_layer->transform_layers[i]; - transform_layers[i].CommitToCA(ca_layer.get(), old_transform_layer, - scale_factor); - } -} - -void CALayerTree::TransformLayer::CommitToCA(CALayer* superlayer, - TransformLayer* old_layer, - float scale_factor) { - bool update_transform = true; - if (old_layer) { - DCHECK(old_layer->ca_layer); - std::swap(ca_layer, old_layer->ca_layer); - update_transform = old_layer->transform != transform; - } else { - ca_layer.reset([[CATransformLayer alloc] init]); - [superlayer addSublayer:ca_layer]; - } - DCHECK_EQ([ca_layer superlayer], superlayer); - - if (update_transform) { - gfx::Transform pre_scale; - gfx::Transform post_scale; - pre_scale.Scale(1 / scale_factor, 1 / scale_factor); - post_scale.Scale(scale_factor, scale_factor); - gfx::Transform conjugated_transform = pre_scale * transform * post_scale; - - CATransform3D ca_transform; - conjugated_transform.matrix().asColMajord(&ca_transform.m11); - [ca_layer setTransform:ca_transform]; - } - - for (size_t i = 0; i < content_layers.size(); ++i) { - ContentLayer* old_content_layer = nullptr; - if (old_layer && i < old_layer->content_layers.size()) - old_content_layer = &old_layer->content_layers[i]; - content_layers[i].CommitToCA(ca_layer.get(), old_content_layer, - scale_factor); - } -} - -void CALayerTree::ContentLayer::CommitToCA(CALayer* superlayer, - ContentLayer* old_layer, - float scale_factor) { - bool update_contents = true; - bool update_contents_rect = true; - bool update_rect = true; - bool update_background_color = true; - bool update_ca_edge_aa_mask = true; - bool update_opacity = true; - if (old_layer) { - DCHECK(old_layer->ca_layer); - std::swap(ca_layer, old_layer->ca_layer); - update_contents = old_layer->io_surface != io_surface; - update_contents_rect = old_layer->contents_rect != contents_rect; - update_rect = old_layer->rect != rect; - update_background_color = old_layer->background_color != background_color; - update_ca_edge_aa_mask = old_layer->ca_edge_aa_mask != ca_edge_aa_mask; - update_opacity = old_layer->opacity != opacity; - } else { - ca_layer.reset([[CALayer alloc] init]); - [ca_layer setAnchorPoint:CGPointZero]; - [superlayer addSublayer:ca_layer]; - } - DCHECK_EQ([ca_layer superlayer], superlayer); - bool update_anything = update_contents || update_contents_rect || - update_rect || update_background_color || - update_ca_edge_aa_mask || update_opacity; - - if (update_contents) { - [ca_layer setContents:static_cast<id>(io_surface.get())]; - if ([ca_layer respondsToSelector:(@selector(setContentsScale:))]) - [ca_layer setContentsScale:scale_factor]; - } - if (update_contents_rect) - [ca_layer setContentsRect:contents_rect.ToCGRect()]; - if (update_rect) { - gfx::RectF dip_rect = gfx::RectF(rect); - dip_rect.Scale(1 / scale_factor); - [ca_layer setPosition:CGPointMake(dip_rect.x(), dip_rect.y())]; - [ca_layer setBounds:CGRectMake(0, 0, dip_rect.width(), dip_rect.height())]; - } - if (update_background_color) { - CGFloat rgba_color_components[4] = { - SkColorGetR(background_color) / 255., - SkColorGetG(background_color) / 255., - SkColorGetB(background_color) / 255., - SkColorGetA(background_color) / 255., - }; - base::ScopedCFTypeRef<CGColorRef> srgb_background_color(CGColorCreate( - CGColorSpaceCreateWithName(kCGColorSpaceSRGB), rgba_color_components)); - [ca_layer setBackgroundColor:srgb_background_color]; - } - if (update_ca_edge_aa_mask) - [ca_layer setEdgeAntialiasingMask:ca_edge_aa_mask]; - if (update_opacity) - [ca_layer setOpacity:opacity]; - - static bool show_borders = base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kShowMacOverlayBorders); - if (show_borders) { - base::ScopedCFTypeRef<CGColorRef> color; - if (update_anything) { - // Pink represents a CALayer that changed this frame. - color.reset(CGColorCreateGenericRGB(1, 0, 1, 1)); - } else { - // Grey represents a CALayer that has not changed. - color.reset(CGColorCreateGenericRGB(0, 0, 0, 0.1)); - } - [ca_layer setBorderWidth:1]; - [ca_layer setBorderColor:color]; - } -} - -} // namespace content diff --git a/chromium/content/common/gpu/child_window_surface_win.cc b/chromium/content/common/gpu/child_window_surface_win.cc deleted file mode 100644 index 738caea87ad..00000000000 --- a/chromium/content/common/gpu/child_window_surface_win.cc +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2015 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 "content/common/gpu/child_window_surface_win.h" - -#include "base/compiler_specific.h" -#include "base/win/scoped_hdc.h" -#include "base/win/wrapped_window_proc.h" -#include "content/common/gpu/gpu_channel_manager.h" -#include "content/common/gpu/gpu_messages.h" -#include "ui/base/win/hidden_window.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gfx/win/hwnd_util.h" -#include "ui/gl/egl_util.h" -#include "ui/gl/gl_context.h" -#include "ui/gl/gl_surface_egl.h" -#include "ui/gl/scoped_make_current.h" - -namespace content { - -namespace { - -ATOM g_window_class; - -LRESULT CALLBACK IntermediateWindowProc(HWND window, - UINT message, - WPARAM w_param, - LPARAM l_param) { - switch (message) { - case WM_ERASEBKGND: - // Prevent windows from erasing the background. - return 1; - case WM_PAINT: - PAINTSTRUCT paint; - if (BeginPaint(window, &paint)) { - ChildWindowSurfaceWin* window_surface = - reinterpret_cast<ChildWindowSurfaceWin*>( - gfx::GetWindowUserData(window)); - DCHECK(window_surface); - - // Wait to clear the contents until a GL draw occurs, as otherwise an - // unsightly black flash may happen if the GL contents are still - // transparent. - window_surface->InvalidateWindowRect(gfx::Rect(paint.rcPaint)); - EndPaint(window, &paint); - } - return 0; - default: - return DefWindowProc(window, message, w_param, l_param); - } -} - -void InitializeWindowClass() { - if (g_window_class) - return; - - WNDCLASSEX intermediate_class; - base::win::InitializeWindowClass( - L"Intermediate D3D Window", - &base::win::WrappedWindowProc<IntermediateWindowProc>, CS_OWNDC, 0, 0, - nullptr, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), nullptr, - nullptr, nullptr, &intermediate_class); - g_window_class = RegisterClassEx(&intermediate_class); - if (!g_window_class) { - LOG(ERROR) << "RegisterClass failed."; - return; - } -} -} - -ChildWindowSurfaceWin::ChildWindowSurfaceWin(GpuChannelManager* manager, - HWND parent_window) - : gfx::NativeViewGLSurfaceEGL(0), - parent_window_(parent_window), - manager_(manager) { - // Don't use EGL_ANGLE_window_fixed_size so that we can avoid recreating the - // window surface, which can cause flicker on DirectComposition. - enable_fixed_size_angle_ = false; -} - -EGLConfig ChildWindowSurfaceWin::GetConfig() { - if (!config_) { - int alpha_size = alpha_ ? 8 : EGL_DONT_CARE; - - EGLint config_attribs[] = {EGL_ALPHA_SIZE, - alpha_size, - EGL_BLUE_SIZE, - 8, - EGL_GREEN_SIZE, - 8, - EGL_RED_SIZE, - 8, - EGL_RENDERABLE_TYPE, - EGL_OPENGL_ES2_BIT, - EGL_SURFACE_TYPE, - EGL_WINDOW_BIT | EGL_PBUFFER_BIT, - EGL_NONE}; - - EGLDisplay display = GetHardwareDisplay(); - EGLint num_configs; - if (!eglChooseConfig(display, config_attribs, &config_, 1, &num_configs)) { - LOG(ERROR) << "eglChooseConfig failed with error " - << ui::GetLastEGLErrorString(); - return NULL; - } - } - - return config_; -} - -bool ChildWindowSurfaceWin::InitializeNativeWindow() { - if (window_) - return true; - InitializeWindowClass(); - DCHECK(g_window_class); - - RECT windowRect; - GetClientRect(parent_window_, &windowRect); - - window_ = CreateWindowEx( - WS_EX_NOPARENTNOTIFY, reinterpret_cast<wchar_t*>(g_window_class), L"", - WS_CHILDWINDOW | WS_DISABLED | WS_VISIBLE, 0, 0, - windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, - ui::GetHiddenWindow(), NULL, NULL, NULL); - gfx::SetWindowUserData(window_, this); - manager_->Send(new GpuHostMsg_AcceleratedSurfaceCreatedChildWindow( - parent_window_, window_)); - return true; -} - -bool ChildWindowSurfaceWin::Resize(const gfx::Size& size, - float scale_factor, - bool has_alpha) { - if (!SupportsPostSubBuffer()) { - if (!MoveWindow(window_, 0, 0, size.width(), size.height(), FALSE)) { - return false; - } - return gfx::NativeViewGLSurfaceEGL::Resize(size, scale_factor, has_alpha); - } else { - if (size == GetSize() && has_alpha == alpha_) - return true; - - if (!MoveWindow(window_, 0, 0, size.width(), size.height(), FALSE)) { - return false; - } - size_ = size; - if (has_alpha == alpha_) { - // A 0-size PostSubBuffer doesn't swap but forces the swap chain to resize - // to match the window. - PostSubBuffer(0, 0, 0, 0); - } else { - alpha_ = has_alpha; - config_ = nullptr; - - scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current; - gfx::GLContext* current_context = gfx::GLContext::GetCurrent(); - bool was_current = current_context && current_context->IsCurrent(this); - if (was_current) { - scoped_make_current.reset( - new ui::ScopedMakeCurrent(current_context, this)); - current_context->ReleaseCurrent(this); - } - - Destroy(); - - if (!Initialize()) { - LOG(ERROR) << "Failed to resize window."; - return false; - } - } - return true; - } -} - -gfx::SwapResult ChildWindowSurfaceWin::SwapBuffers() { - gfx::SwapResult result = NativeViewGLSurfaceEGL::SwapBuffers(); - ClearInvalidContents(); - return result; -} - -gfx::SwapResult ChildWindowSurfaceWin::PostSubBuffer(int x, - int y, - int width, - int height) { - gfx::SwapResult result = - NativeViewGLSurfaceEGL::PostSubBuffer(x, y, width, height); - ClearInvalidContents(); - return result; -} - -void ChildWindowSurfaceWin::InvalidateWindowRect(const gfx::Rect& rect) { - rect_to_clear_.Union(rect); -} - -void ChildWindowSurfaceWin::ClearInvalidContents() { - if (!rect_to_clear_.IsEmpty()) { - base::win::ScopedGetDC dc(window_); - - RECT rect = rect_to_clear_.ToRECT(); - - // DirectComposition composites with the contents under the SwapChain, - // so ensure that's cleared. GDI treats black as transparent. - FillRect(dc, &rect, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH))); - rect_to_clear_ = gfx::Rect(); - } -} - -ChildWindowSurfaceWin::~ChildWindowSurfaceWin() { - gfx::SetWindowUserData(window_, nullptr); - DestroyWindow(window_); -} - -} // namespace content diff --git a/chromium/content/common/gpu/child_window_surface_win.h b/chromium/content/common/gpu/child_window_surface_win.h deleted file mode 100644 index 83acd88ae49..00000000000 --- a/chromium/content/common/gpu/child_window_surface_win.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2015 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 CONTENT_COMMON_GPU_CHILD_WINDOW_SURFACE_WIN_H_ -#define CONTENT_COMMON_GPU_CHILD_WINDOW_SURFACE_WIN_H_ -#include "ui/gl/gl_surface_egl.h" - -#include <windows.h> - -namespace content { - -class GpuChannelManager; - -class ChildWindowSurfaceWin : public gfx::NativeViewGLSurfaceEGL { - public: - ChildWindowSurfaceWin(GpuChannelManager* manager, HWND parent_window); - - // GLSurface implementation. - EGLConfig GetConfig() override; - bool Resize(const gfx::Size& size, - float scale_factor, - bool has_alpha) override; - bool InitializeNativeWindow() override; - gfx::SwapResult SwapBuffers() override; - gfx::SwapResult PostSubBuffer(int x, int y, int width, int height) override; - - void InvalidateWindowRect(const gfx::Rect& rect); - - protected: - ~ChildWindowSurfaceWin() override; - - private: - void ClearInvalidContents(); - - HWND parent_window_; - GpuChannelManager* manager_; - gfx::Rect rect_to_clear_; - - DISALLOW_COPY_AND_ASSIGN(ChildWindowSurfaceWin); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_CHILD_WINDOW_SURFACE_WIN_H_ diff --git a/chromium/content/common/gpu/client/DEPS b/chromium/content/common/gpu/client/DEPS index 1aea6635f14..409909c2df0 100644 --- a/chromium/content/common/gpu/client/DEPS +++ b/chromium/content/common/gpu/client/DEPS @@ -1,10 +1,3 @@ include_rules = [ "+cc/blink", ] - -specific_include_rules = { - # Tests can make use of content/browser/ infrastructure. - ".*browsertest\.cc": [ - "+content/browser" - ] -} diff --git a/chromium/content/common/gpu/client/command_buffer_metrics.cc b/chromium/content/common/gpu/client/command_buffer_metrics.cc index 38590c36c08..2ff84f8b1f8 100644 --- a/chromium/content/common/gpu/client/command_buffer_metrics.cc +++ b/chromium/content/common/gpu/client/command_buffer_metrics.cc @@ -75,7 +75,7 @@ CommandBufferContextLostReason GetContextLostReason( void RecordContextLost(CommandBufferContextType type, CommandBufferContextLostReason reason) { switch (type) { - case BROWSER_COMPOSITOR_ONSCREEN_CONTEXT: + case DISPLAY_COMPOSITOR_ONSCREEN_CONTEXT: UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.BrowserCompositor", reason, CONTEXT_LOST_REASON_MAX_ENUM); break; @@ -124,8 +124,8 @@ std::string CommandBufferContextTypeToString(CommandBufferContextType type) { switch (type) { case OFFSCREEN_CONTEXT_FOR_TESTING: return "Context-For-Testing"; - case BROWSER_COMPOSITOR_ONSCREEN_CONTEXT: - return "Compositor"; + case DISPLAY_COMPOSITOR_ONSCREEN_CONTEXT: + return "DisplayCompositor"; case BROWSER_OFFSCREEN_MAINTHREAD_CONTEXT: return "Offscreen-MainThread"; case BROWSER_WORKER_CONTEXT: diff --git a/chromium/content/common/gpu/client/command_buffer_metrics.h b/chromium/content/common/gpu/client/command_buffer_metrics.h index 0b4790cd4b0..0cd62bb2209 100644 --- a/chromium/content/common/gpu/client/command_buffer_metrics.h +++ b/chromium/content/common/gpu/client/command_buffer_metrics.h @@ -12,7 +12,7 @@ namespace content { enum CommandBufferContextType { - BROWSER_COMPOSITOR_ONSCREEN_CONTEXT, + DISPLAY_COMPOSITOR_ONSCREEN_CONTEXT, BROWSER_OFFSCREEN_MAINTHREAD_CONTEXT, BROWSER_WORKER_CONTEXT, RENDER_COMPOSITOR_CONTEXT, diff --git a/chromium/content/common/gpu/client/command_buffer_proxy_impl.cc b/chromium/content/common/gpu/client/command_buffer_proxy_impl.cc deleted file mode 100644 index 1b5d14b2ff4..00000000000 --- a/chromium/content/common/gpu/client/command_buffer_proxy_impl.cc +++ /dev/null @@ -1,820 +0,0 @@ -// Copyright (c) 2012 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 "content/common/gpu/client/command_buffer_proxy_impl.h" - -#include <utility> -#include <vector> - -#include "base/callback.h" -#include "base/logging.h" -#include "base/memory/shared_memory.h" -#include "base/stl_util.h" -#include "base/trace_event/trace_event.h" -#include "content/common/child_process_messages.h" -#include "content/common/gpu/client/gpu_channel_host.h" -#include "content/common/gpu/client/gpu_video_decode_accelerator_host.h" -#include "content/common/gpu/client/gpu_video_encode_accelerator_host.h" -#include "content/common/gpu/gpu_messages.h" -#include "content/common/view_messages.h" -#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" -#include "gpu/command_buffer/common/cmd_buffer_common.h" -#include "gpu/command_buffer/common/command_buffer_shared.h" -#include "gpu/command_buffer/common/gpu_memory_allocation.h" -#include "gpu/command_buffer/common/sync_token.h" -#include "gpu/command_buffer/service/image_factory.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gl/gl_bindings.h" - -namespace content { - -namespace { - -uint64_t CommandBufferProxyID(int channel_id, int32_t route_id) { - return (static_cast<uint64_t>(channel_id) << 32) | route_id; -} - -} // namespace - -CommandBufferProxyImpl::CommandBufferProxyImpl(GpuChannelHost* channel, - int32_t route_id, - int32_t stream_id) - : lock_(nullptr), - channel_(channel), - command_buffer_id_(CommandBufferProxyID(channel->channel_id(), route_id)), - route_id_(route_id), - stream_id_(stream_id), - flush_count_(0), - last_put_offset_(-1), - last_barrier_put_offset_(-1), - next_fence_sync_release_(1), - flushed_fence_sync_release_(0), - verified_fence_sync_release_(0), - next_signal_id_(0), - weak_this_(AsWeakPtr()), - callback_thread_(base::ThreadTaskRunnerHandle::Get()) { - DCHECK(channel); - DCHECK(stream_id); -} - -CommandBufferProxyImpl::~CommandBufferProxyImpl() { - FOR_EACH_OBSERVER(DeletionObserver, - deletion_observers_, - OnWillDeleteImpl()); - if (channel_) { - channel_->DestroyCommandBuffer(this); - channel_ = nullptr; - } -} - -bool CommandBufferProxyImpl::OnMessageReceived(const IPC::Message& message) { - scoped_ptr<base::AutoLock> lock; - if (lock_) - lock.reset(new base::AutoLock(*lock_)); - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(CommandBufferProxyImpl, message) - IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_Destroyed, OnDestroyed); - IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_ConsoleMsg, OnConsoleMessage); - IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SignalAck, - OnSignalAck); - IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SwapBuffersCompleted, - OnSwapBuffersCompleted); - IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_UpdateVSyncParameters, - OnUpdateVSyncParameters); - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - - if (!handled) { - DLOG(ERROR) << "Gpu process sent invalid message."; - InvalidGpuMessage(); - } - return handled; -} - -void CommandBufferProxyImpl::OnChannelError() { - scoped_ptr<base::AutoLock> lock; - if (lock_) - lock.reset(new base::AutoLock(*lock_)); - - gpu::error::ContextLostReason context_lost_reason = - gpu::error::kGpuChannelLost; - if (shared_state_shm_ && shared_state_shm_->memory()) { - TryUpdateState(); - // The GPU process might have intentionally been crashed - // (exit_on_context_lost), so try to find out the original reason. - if (last_state_.error == gpu::error::kLostContext) - context_lost_reason = last_state_.context_lost_reason; - } - OnDestroyed(context_lost_reason, gpu::error::kLostContext); -} - -void CommandBufferProxyImpl::OnDestroyed(gpu::error::ContextLostReason reason, - gpu::error::Error error) { - CheckLock(); - // Prevent any further messages from being sent. - if (channel_) { - channel_->DestroyCommandBuffer(this); - channel_ = nullptr; - } - - // When the client sees that the context is lost, they should delete this - // CommandBufferProxyImpl and create a new one. - last_state_.error = error; - last_state_.context_lost_reason = reason; - - if (!context_lost_callback_.is_null()) { - context_lost_callback_.Run(); - // Avoid calling the error callback more than once. - context_lost_callback_.Reset(); - } -} - -void CommandBufferProxyImpl::OnConsoleMessage( - const GPUCommandBufferConsoleMessage& message) { - if (!console_message_callback_.is_null()) { - console_message_callback_.Run(message.message, message.id); - } -} - -void CommandBufferProxyImpl::AddDeletionObserver(DeletionObserver* observer) { - scoped_ptr<base::AutoLock> lock; - if (lock_) - lock.reset(new base::AutoLock(*lock_)); - deletion_observers_.AddObserver(observer); -} - -void CommandBufferProxyImpl::RemoveDeletionObserver( - DeletionObserver* observer) { - scoped_ptr<base::AutoLock> lock; - if (lock_) - lock.reset(new base::AutoLock(*lock_)); - deletion_observers_.RemoveObserver(observer); -} - -void CommandBufferProxyImpl::OnSignalAck(uint32_t id) { - SignalTaskMap::iterator it = signal_tasks_.find(id); - if (it == signal_tasks_.end()) { - DLOG(ERROR) << "Gpu process sent invalid SignalAck."; - InvalidGpuMessage(); - return; - } - base::Closure callback = it->second; - signal_tasks_.erase(it); - callback.Run(); -} - -void CommandBufferProxyImpl::SetContextLostCallback( - const base::Closure& callback) { - CheckLock(); - context_lost_callback_ = callback; -} - -bool CommandBufferProxyImpl::Initialize() { - TRACE_EVENT0("gpu", "CommandBufferProxyImpl::Initialize"); - shared_state_shm_.reset(channel_->factory()->AllocateSharedMemory( - sizeof(*shared_state())).release()); - if (!shared_state_shm_) - return false; - - if (!shared_state_shm_->Map(sizeof(*shared_state()))) - return false; - - shared_state()->Initialize(); - - // This handle is owned by the GPU process and must be passed to it or it - // will leak. In otherwords, do not early out on error between here and the - // sending of the Initialize IPC below. - base::SharedMemoryHandle handle = - channel_->ShareToGpuProcess(shared_state_shm_->handle()); - if (!base::SharedMemory::IsHandleValid(handle)) - return false; - - bool result = false; - if (!Send(new GpuCommandBufferMsg_Initialize( - route_id_, handle, &result, &capabilities_))) { - LOG(ERROR) << "Could not send GpuCommandBufferMsg_Initialize."; - return false; - } - - if (!result) { - LOG(ERROR) << "Failed to initialize command buffer service."; - return false; - } - - capabilities_.image = true; - - return true; -} - -gpu::CommandBuffer::State CommandBufferProxyImpl::GetLastState() { - return last_state_; -} - -int32_t CommandBufferProxyImpl::GetLastToken() { - TryUpdateState(); - return last_state_.token; -} - -void CommandBufferProxyImpl::Flush(int32_t put_offset) { - CheckLock(); - if (last_state_.error != gpu::error::kNoError) - return; - - TRACE_EVENT1("gpu", - "CommandBufferProxyImpl::Flush", - "put_offset", - put_offset); - - bool put_offset_changed = last_put_offset_ != put_offset; - last_put_offset_ = put_offset; - last_barrier_put_offset_ = put_offset; - - if (channel_) { - const uint32_t flush_id = channel_->OrderingBarrier( - route_id_, stream_id_, put_offset, ++flush_count_, latency_info_, - put_offset_changed, true); - if (put_offset_changed) { - DCHECK(flush_id); - const uint64_t fence_sync_release = next_fence_sync_release_ - 1; - if (fence_sync_release > flushed_fence_sync_release_) { - flushed_fence_sync_release_ = fence_sync_release; - flushed_release_flush_id_.push( - std::make_pair(fence_sync_release, flush_id)); - } - } - } - - if (put_offset_changed) - latency_info_.clear(); -} - -void CommandBufferProxyImpl::OrderingBarrier(int32_t put_offset) { - if (last_state_.error != gpu::error::kNoError) - return; - - TRACE_EVENT1("gpu", "CommandBufferProxyImpl::OrderingBarrier", "put_offset", - put_offset); - - bool put_offset_changed = last_barrier_put_offset_ != put_offset; - last_barrier_put_offset_ = put_offset; - - if (channel_) { - const uint32_t flush_id = channel_->OrderingBarrier( - route_id_, stream_id_, put_offset, ++flush_count_, latency_info_, - put_offset_changed, false); - if (put_offset_changed) { - DCHECK(flush_id); - const uint64_t fence_sync_release = next_fence_sync_release_ - 1; - if (fence_sync_release > flushed_fence_sync_release_) { - flushed_fence_sync_release_ = fence_sync_release; - flushed_release_flush_id_.push( - std::make_pair(fence_sync_release, flush_id)); - } - } - } - - if (put_offset_changed) - latency_info_.clear(); -} - -void CommandBufferProxyImpl::SetLatencyInfo( - const std::vector<ui::LatencyInfo>& latency_info) { - CheckLock(); - for (size_t i = 0; i < latency_info.size(); i++) - latency_info_.push_back(latency_info[i]); -} - -void CommandBufferProxyImpl::SetSwapBuffersCompletionCallback( - const SwapBuffersCompletionCallback& callback) { - CheckLock(); - swap_buffers_completion_callback_ = callback; -} - -void CommandBufferProxyImpl::SetUpdateVSyncParametersCallback( - const UpdateVSyncParametersCallback& callback) { - CheckLock(); - update_vsync_parameters_completion_callback_ = callback; -} - -void CommandBufferProxyImpl::WaitForTokenInRange(int32_t start, int32_t end) { - CheckLock(); - TRACE_EVENT2("gpu", - "CommandBufferProxyImpl::WaitForToken", - "start", - start, - "end", - end); - TryUpdateState(); - if (!InRange(start, end, last_state_.token) && - last_state_.error == gpu::error::kNoError) { - gpu::CommandBuffer::State state; - if (Send(new GpuCommandBufferMsg_WaitForTokenInRange( - route_id_, start, end, &state))) - OnUpdateState(state); - } - if (!InRange(start, end, last_state_.token) && - last_state_.error == gpu::error::kNoError) { - DLOG(ERROR) << "GPU state invalid after WaitForTokenInRange."; - InvalidGpuReply(); - } -} - -void CommandBufferProxyImpl::WaitForGetOffsetInRange(int32_t start, - int32_t end) { - CheckLock(); - TRACE_EVENT2("gpu", - "CommandBufferProxyImpl::WaitForGetOffset", - "start", - start, - "end", - end); - TryUpdateState(); - if (!InRange(start, end, last_state_.get_offset) && - last_state_.error == gpu::error::kNoError) { - gpu::CommandBuffer::State state; - if (Send(new GpuCommandBufferMsg_WaitForGetOffsetInRange( - route_id_, start, end, &state))) - OnUpdateState(state); - } - if (!InRange(start, end, last_state_.get_offset) && - last_state_.error == gpu::error::kNoError) { - DLOG(ERROR) << "GPU state invalid after WaitForGetOffsetInRange."; - InvalidGpuReply(); - } -} - -void CommandBufferProxyImpl::SetGetBuffer(int32_t shm_id) { - CheckLock(); - if (last_state_.error != gpu::error::kNoError) - return; - - Send(new GpuCommandBufferMsg_SetGetBuffer(route_id_, shm_id)); - last_put_offset_ = -1; -} - -scoped_refptr<gpu::Buffer> CommandBufferProxyImpl::CreateTransferBuffer( - size_t size, - int32_t* id) { - CheckLock(); - *id = -1; - - if (last_state_.error != gpu::error::kNoError) - return NULL; - - int32_t new_id = channel_->ReserveTransferBufferId(); - - scoped_ptr<base::SharedMemory> shared_memory( - channel_->factory()->AllocateSharedMemory(size)); - if (!shared_memory) { - if (last_state_.error == gpu::error::kNoError) - last_state_.error = gpu::error::kOutOfBounds; - return NULL; - } - - DCHECK(!shared_memory->memory()); - if (!shared_memory->Map(size)) { - if (last_state_.error == gpu::error::kNoError) - last_state_.error = gpu::error::kOutOfBounds; - return NULL; - } - - // This handle is owned by the GPU process and must be passed to it or it - // will leak. In otherwords, do not early out on error between here and the - // sending of the RegisterTransferBuffer IPC below. - base::SharedMemoryHandle handle = - channel_->ShareToGpuProcess(shared_memory->handle()); - if (!base::SharedMemory::IsHandleValid(handle)) { - if (last_state_.error == gpu::error::kNoError) - last_state_.error = gpu::error::kLostContext; - return NULL; - } - - if (!Send(new GpuCommandBufferMsg_RegisterTransferBuffer(route_id_, - new_id, - handle, - size))) { - return NULL; - } - - *id = new_id; - scoped_refptr<gpu::Buffer> buffer( - gpu::MakeBufferFromSharedMemory(std::move(shared_memory), size)); - return buffer; -} - -void CommandBufferProxyImpl::DestroyTransferBuffer(int32_t id) { - CheckLock(); - if (last_state_.error != gpu::error::kNoError) - return; - - Send(new GpuCommandBufferMsg_DestroyTransferBuffer(route_id_, id)); -} - -gpu::Capabilities CommandBufferProxyImpl::GetCapabilities() { - return capabilities_; -} - -int32_t CommandBufferProxyImpl::CreateImage(ClientBuffer buffer, - size_t width, - size_t height, - unsigned internal_format) { - CheckLock(); - if (last_state_.error != gpu::error::kNoError) - return -1; - - int32_t new_id = channel_->ReserveImageId(); - - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager = - channel_->gpu_memory_buffer_manager(); - gfx::GpuMemoryBuffer* gpu_memory_buffer = - gpu_memory_buffer_manager->GpuMemoryBufferFromClientBuffer(buffer); - DCHECK(gpu_memory_buffer); - - // This handle is owned by the GPU process and must be passed to it or it - // will leak. In otherwords, do not early out on error between here and the - // sending of the CreateImage IPC below. - bool requires_sync_token = false; - gfx::GpuMemoryBufferHandle handle = - channel_->ShareGpuMemoryBufferToGpuProcess(gpu_memory_buffer->GetHandle(), - &requires_sync_token); - - uint64_t image_fence_sync = 0; - if (requires_sync_token) { - image_fence_sync = GenerateFenceSyncRelease(); - - // Make sure fence syncs were flushed before CreateImage() was called. - DCHECK_LE(image_fence_sync - 1, flushed_fence_sync_release_); - } - - DCHECK(gpu::ImageFactory::IsGpuMemoryBufferFormatSupported( - gpu_memory_buffer->GetFormat(), capabilities_)); - DCHECK(gpu::ImageFactory::IsImageSizeValidForGpuMemoryBufferFormat( - gfx::Size(width, height), gpu_memory_buffer->GetFormat())); - DCHECK(gpu::ImageFactory::IsImageFormatCompatibleWithGpuMemoryBufferFormat( - internal_format, gpu_memory_buffer->GetFormat())); - - GpuCommandBufferMsg_CreateImage_Params params; - params.id = new_id; - params.gpu_memory_buffer = handle; - params.size = gfx::Size(width, height); - params.format = gpu_memory_buffer->GetFormat(); - params.internal_format = internal_format; - params.image_release_count = image_fence_sync; - - if (!Send(new GpuCommandBufferMsg_CreateImage(route_id_, params))) - return -1; - - if (image_fence_sync) { - gpu::SyncToken sync_token(GetNamespaceID(), GetExtraCommandBufferData(), - GetCommandBufferID(), image_fence_sync); - - // Force a synchronous IPC to validate sync token. - EnsureWorkVisible(); - sync_token.SetVerifyFlush(); - - gpu_memory_buffer_manager->SetDestructionSyncToken(gpu_memory_buffer, - sync_token); - } - - return new_id; -} - -void CommandBufferProxyImpl::DestroyImage(int32_t id) { - CheckLock(); - if (last_state_.error != gpu::error::kNoError) - return; - - Send(new GpuCommandBufferMsg_DestroyImage(route_id_, id)); -} - -int32_t CommandBufferProxyImpl::CreateGpuMemoryBufferImage( - size_t width, - size_t height, - unsigned internal_format, - unsigned usage) { - CheckLock(); - scoped_ptr<gfx::GpuMemoryBuffer> buffer( - channel_->gpu_memory_buffer_manager()->AllocateGpuMemoryBuffer( - gfx::Size(width, height), - gpu::ImageFactory::DefaultBufferFormatForImageFormat(internal_format), - gfx::BufferUsage::SCANOUT)); - if (!buffer) - return -1; - - return CreateImage(buffer->AsClientBuffer(), width, height, internal_format); -} - -uint32_t CommandBufferProxyImpl::CreateStreamTexture(uint32_t texture_id) { - CheckLock(); - if (last_state_.error != gpu::error::kNoError) - return 0; - - int32_t stream_id = channel_->GenerateRouteID(); - bool succeeded = false; - Send(new GpuCommandBufferMsg_CreateStreamTexture( - route_id_, texture_id, stream_id, &succeeded)); - if (!succeeded) { - DLOG(ERROR) << "GpuCommandBufferMsg_CreateStreamTexture returned failure"; - return 0; - } - return stream_id; -} - -void CommandBufferProxyImpl::SetLock(base::Lock* lock) { - lock_ = lock; -} - -bool CommandBufferProxyImpl::IsGpuChannelLost() { - return !channel_ || channel_->IsLost(); -} - -void CommandBufferProxyImpl::EnsureWorkVisible() { - if (channel_) - channel_->ValidateFlushIDReachedServer(stream_id_, true); -} - -gpu::CommandBufferNamespace CommandBufferProxyImpl::GetNamespaceID() const { - return gpu::CommandBufferNamespace::GPU_IO; -} - -uint64_t CommandBufferProxyImpl::GetCommandBufferID() const { - return command_buffer_id_; -} - -int32_t CommandBufferProxyImpl::GetExtraCommandBufferData() const { - return stream_id_; -} - -uint64_t CommandBufferProxyImpl::GenerateFenceSyncRelease() { - return next_fence_sync_release_++; -} - -bool CommandBufferProxyImpl::IsFenceSyncRelease(uint64_t release) { - return release != 0 && release < next_fence_sync_release_; -} - -bool CommandBufferProxyImpl::IsFenceSyncFlushed(uint64_t release) { - return release != 0 && release <= flushed_fence_sync_release_; -} - -bool CommandBufferProxyImpl::IsFenceSyncFlushReceived(uint64_t release) { - CheckLock(); - if (last_state_.error != gpu::error::kNoError) - return false; - - if (release <= verified_fence_sync_release_) - return true; - - // Check if we have actually flushed the fence sync release. - if (release <= flushed_fence_sync_release_) { - DCHECK(!flushed_release_flush_id_.empty()); - // Check if it has already been validated by another context. - UpdateVerifiedReleases(channel_->GetHighestValidatedFlushID(stream_id_)); - if (release <= verified_fence_sync_release_) - return true; - - // Has not been validated, validate it now. - UpdateVerifiedReleases( - channel_->ValidateFlushIDReachedServer(stream_id_, false)); - return release <= verified_fence_sync_release_; - } - - return false; -} - -void CommandBufferProxyImpl::SignalSyncToken(const gpu::SyncToken& sync_token, - const base::Closure& callback) { - CheckLock(); - if (last_state_.error != gpu::error::kNoError) - return; - - uint32_t signal_id = next_signal_id_++; - if (!Send(new GpuCommandBufferMsg_SignalSyncToken(route_id_, - sync_token, - signal_id))) { - return; - } - - signal_tasks_.insert(std::make_pair(signal_id, callback)); -} - -bool CommandBufferProxyImpl::CanWaitUnverifiedSyncToken( - const gpu::SyncToken* sync_token) { - // Can only wait on an unverified sync token if it is from the same channel. - const uint64_t token_channel = sync_token->command_buffer_id() >> 32; - const uint64_t channel = command_buffer_id_ >> 32; - if (sync_token->namespace_id() != gpu::CommandBufferNamespace::GPU_IO || - token_channel != channel) { - return false; - } - - // If waiting on a different stream, flush pending commands on that stream. - const int32_t release_stream_id = sync_token->extra_data_field(); - if (release_stream_id == 0) - return false; - - if (release_stream_id != stream_id_) - channel_->FlushPendingStream(release_stream_id); - - return true; -} - -uint32_t CommandBufferProxyImpl::InsertSyncPoint() { - CheckLock(); - if (last_state_.error != gpu::error::kNoError) - return 0; - - uint32_t sync_point = 0; - Send(new GpuCommandBufferMsg_InsertSyncPoint(route_id_, true, &sync_point)); - return sync_point; -} - -uint32_t CommandBufferProxyImpl::InsertFutureSyncPoint() { - CheckLock(); - if (last_state_.error != gpu::error::kNoError) - return 0; - - uint32_t sync_point = 0; - Send(new GpuCommandBufferMsg_InsertSyncPoint(route_id_, false, &sync_point)); - return sync_point; -} - -void CommandBufferProxyImpl::RetireSyncPoint(uint32_t sync_point) { - CheckLock(); - if (last_state_.error != gpu::error::kNoError) - return; - - Send(new GpuCommandBufferMsg_RetireSyncPoint(route_id_, sync_point)); -} - -void CommandBufferProxyImpl::SignalSyncPoint(uint32_t sync_point, - const base::Closure& callback) { - CheckLock(); - if (last_state_.error != gpu::error::kNoError) - return; - - uint32_t signal_id = next_signal_id_++; - if (!Send(new GpuCommandBufferMsg_SignalSyncPoint(route_id_, - sync_point, - signal_id))) { - return; - } - - signal_tasks_.insert(std::make_pair(signal_id, callback)); -} - -void CommandBufferProxyImpl::SignalQuery(uint32_t query, - const base::Closure& callback) { - CheckLock(); - if (last_state_.error != gpu::error::kNoError) - return; - - // Signal identifiers are hidden, so nobody outside of this class will see - // them. (And thus, they cannot save them.) The IDs themselves only last - // until the callback is invoked, which will happen as soon as the GPU - // catches upwith the command buffer. - // A malicious caller trying to create a collision by making next_signal_id - // would have to make calls at an astounding rate (300B/s) and even if they - // could do that, all they would do is to prevent some callbacks from getting - // called, leading to stalled threads and/or memory leaks. - uint32_t signal_id = next_signal_id_++; - if (!Send(new GpuCommandBufferMsg_SignalQuery(route_id_, - query, - signal_id))) { - return; - } - - signal_tasks_.insert(std::make_pair(signal_id, callback)); -} - -bool CommandBufferProxyImpl::ProduceFrontBuffer(const gpu::Mailbox& mailbox) { - CheckLock(); - if (last_state_.error != gpu::error::kNoError) - return false; - - return Send(new GpuCommandBufferMsg_ProduceFrontBuffer(route_id_, mailbox)); -} - -scoped_ptr<media::VideoDecodeAccelerator> -CommandBufferProxyImpl::CreateVideoDecoder() { - if (!channel_) - return scoped_ptr<media::VideoDecodeAccelerator>(); - return scoped_ptr<media::VideoDecodeAccelerator>( - new GpuVideoDecodeAcceleratorHost(channel_, this)); -} - -scoped_ptr<media::VideoEncodeAccelerator> -CommandBufferProxyImpl::CreateVideoEncoder() { - if (!channel_) - return scoped_ptr<media::VideoEncodeAccelerator>(); - return scoped_ptr<media::VideoEncodeAccelerator>( - new GpuVideoEncodeAcceleratorHost(channel_, this)); -} - -gpu::error::Error CommandBufferProxyImpl::GetLastError() { - return last_state_.error; -} - -bool CommandBufferProxyImpl::Send(IPC::Message* msg) { - // Caller should not intentionally send a message if the context is lost. - DCHECK(last_state_.error == gpu::error::kNoError); - - if (channel_) { - if (channel_->Send(msg)) { - return true; - } else { - // Flag the command buffer as lost. Defer deleting the channel until - // OnChannelError is called after returning to the message loop in case - // it is referenced elsewhere. - DVLOG(1) << "CommandBufferProxyImpl::Send failed. Losing context."; - last_state_.error = gpu::error::kLostContext; - return false; - } - } - - // Callee takes ownership of message, regardless of whether Send is - // successful. See IPC::Sender. - delete msg; - return false; -} - -void CommandBufferProxyImpl::OnUpdateState( - const gpu::CommandBuffer::State& state) { - // Handle wraparound. It works as long as we don't have more than 2B state - // updates in flight across which reordering occurs. - if (state.generation - last_state_.generation < 0x80000000U) - last_state_ = state; -} - -void CommandBufferProxyImpl::SetOnConsoleMessageCallback( - const GpuConsoleMessageCallback& callback) { - CheckLock(); - console_message_callback_ = callback; -} - -void CommandBufferProxyImpl::TryUpdateState() { - if (last_state_.error == gpu::error::kNoError) - shared_state()->Read(&last_state_); -} - -void CommandBufferProxyImpl::UpdateVerifiedReleases(uint32_t verified_flush) { - while (!flushed_release_flush_id_.empty()) { - const std::pair<uint64_t, uint32_t>& front_item = - flushed_release_flush_id_.front(); - if (front_item.second > verified_flush) - break; - verified_fence_sync_release_ = front_item.first; - flushed_release_flush_id_.pop(); - } -} - -gpu::CommandBufferSharedState* CommandBufferProxyImpl::shared_state() const { - return reinterpret_cast<gpu::CommandBufferSharedState*>( - shared_state_shm_->memory()); -} - -void CommandBufferProxyImpl::OnSwapBuffersCompleted( - const std::vector<ui::LatencyInfo>& latency_info, - gfx::SwapResult result) { - if (!swap_buffers_completion_callback_.is_null()) { - if (!ui::LatencyInfo::Verify( - latency_info, "CommandBufferProxyImpl::OnSwapBuffersCompleted")) { - swap_buffers_completion_callback_.Run(std::vector<ui::LatencyInfo>(), - result); - return; - } - swap_buffers_completion_callback_.Run(latency_info, result); - } -} - -void CommandBufferProxyImpl::OnUpdateVSyncParameters(base::TimeTicks timebase, - base::TimeDelta interval) { - if (!update_vsync_parameters_completion_callback_.is_null()) - update_vsync_parameters_completion_callback_.Run(timebase, interval); -} - -void CommandBufferProxyImpl::InvalidGpuMessage() { - LOG(ERROR) << "Received invalid message from the GPU process."; - OnDestroyed(gpu::error::kInvalidGpuMessage, gpu::error::kLostContext); -} - -void CommandBufferProxyImpl::InvalidGpuReply() { - CheckLock(); - LOG(ERROR) << "Received invalid reply from the GPU process."; - last_state_.error = gpu::error::kLostContext; - last_state_.context_lost_reason = gpu::error::kInvalidGpuMessage; - callback_thread_->PostTask( - FROM_HERE, - base::Bind(&CommandBufferProxyImpl::InvalidGpuReplyOnClientThread, - weak_this_)); -} - -void CommandBufferProxyImpl::InvalidGpuReplyOnClientThread() { - scoped_ptr<base::AutoLock> lock; - if (lock_) - lock.reset(new base::AutoLock(*lock_)); - OnDestroyed(gpu::error::kInvalidGpuMessage, gpu::error::kLostContext); -} - -} // namespace content diff --git a/chromium/content/common/gpu/client/command_buffer_proxy_impl.h b/chromium/content/common/gpu/client/command_buffer_proxy_impl.h deleted file mode 100644 index 17589a7538e..00000000000 --- a/chromium/content/common/gpu/client/command_buffer_proxy_impl.h +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_GPU_CLIENT_COMMAND_BUFFER_PROXY_IMPL_H_ -#define CONTENT_COMMON_GPU_CLIENT_COMMAND_BUFFER_PROXY_IMPL_H_ - -#include <stddef.h> -#include <stdint.h> - -#include <map> -#include <queue> -#include <string> - -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/containers/hash_tables.h" -#include "base/containers/scoped_ptr_hash_map.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/observer_list.h" -#include "gpu/command_buffer/client/gpu_control.h" -#include "gpu/command_buffer/common/command_buffer.h" -#include "gpu/command_buffer/common/command_buffer_shared.h" -#include "gpu/command_buffer/common/gpu_memory_allocation.h" -#include "ipc/ipc_listener.h" -#include "ui/events/latency_info.h" -#include "ui/gfx/swap_result.h" - -struct GPUCommandBufferConsoleMessage; - -namespace base { -class SharedMemory; -} - -namespace gpu { -struct Mailbox; -struct SyncToken; -} - -namespace media { -class VideoDecodeAccelerator; -class VideoEncodeAccelerator; -} - -namespace content { -class GpuChannelHost; - -// Client side proxy that forwards messages synchronously to a -// CommandBufferStub. -class CommandBufferProxyImpl - : public gpu::CommandBuffer, - public gpu::GpuControl, - public IPC::Listener, - public base::SupportsWeakPtr<CommandBufferProxyImpl> { - public: - class DeletionObserver { - public: - // Called during the destruction of the CommandBufferProxyImpl. - virtual void OnWillDeleteImpl() = 0; - - protected: - virtual ~DeletionObserver() {} - }; - - typedef base::Callback<void( - const std::string& msg, int id)> GpuConsoleMessageCallback; - - CommandBufferProxyImpl(GpuChannelHost* channel, - int32_t route_id, - int32_t stream_id); - ~CommandBufferProxyImpl() override; - - // Sends an IPC message to create a GpuVideoDecodeAccelerator. Creates and - // returns it as an owned pointer to a media::VideoDecodeAccelerator. Returns - // NULL on failure to create the GpuVideoDecodeAcceleratorHost. - // Note that the GpuVideoDecodeAccelerator may still fail to be created in - // the GPU process, even if this returns non-NULL. In this case the VDA client - // is notified of an error later, after Initialize(). - scoped_ptr<media::VideoDecodeAccelerator> CreateVideoDecoder(); - - // Sends an IPC message to create a GpuVideoEncodeAccelerator. Creates and - // returns it as an owned pointer to a media::VideoEncodeAccelerator. Returns - // NULL on failure to create the GpuVideoEncodeAcceleratorHost. - // Note that the GpuVideoEncodeAccelerator may still fail to be created in - // the GPU process, even if this returns non-NULL. In this case the VEA client - // is notified of an error later, after Initialize(); - scoped_ptr<media::VideoEncodeAccelerator> CreateVideoEncoder(); - - // IPC::Listener implementation: - bool OnMessageReceived(const IPC::Message& message) override; - void OnChannelError() override; - - // CommandBuffer implementation: - bool Initialize() override; - State GetLastState() override; - int32_t GetLastToken() override; - void Flush(int32_t put_offset) override; - void OrderingBarrier(int32_t put_offset) override; - void WaitForTokenInRange(int32_t start, int32_t end) override; - void WaitForGetOffsetInRange(int32_t start, int32_t end) override; - void SetGetBuffer(int32_t shm_id) override; - scoped_refptr<gpu::Buffer> CreateTransferBuffer(size_t size, - int32_t* id) override; - void DestroyTransferBuffer(int32_t id) override; - - // gpu::GpuControl implementation: - gpu::Capabilities GetCapabilities() override; - int32_t CreateImage(ClientBuffer buffer, - size_t width, - size_t height, - unsigned internal_format) override; - void DestroyImage(int32_t id) override; - int32_t CreateGpuMemoryBufferImage(size_t width, - size_t height, - unsigned internal_format, - unsigned usage) override; - uint32_t InsertSyncPoint() override; - uint32_t InsertFutureSyncPoint() override; - void RetireSyncPoint(uint32_t sync_point) override; - void SignalSyncPoint(uint32_t sync_point, - const base::Closure& callback) override; - void SignalQuery(uint32_t query, const base::Closure& callback) override; - void SetLock(base::Lock* lock) override; - bool IsGpuChannelLost() override; - void EnsureWorkVisible() override; - gpu::CommandBufferNamespace GetNamespaceID() const override; - uint64_t GetCommandBufferID() const override; - int32_t GetExtraCommandBufferData() const override; - uint64_t GenerateFenceSyncRelease() override; - bool IsFenceSyncRelease(uint64_t release) override; - bool IsFenceSyncFlushed(uint64_t release) override; - bool IsFenceSyncFlushReceived(uint64_t release) override; - void SignalSyncToken(const gpu::SyncToken& sync_token, - const base::Closure& callback) override; - bool CanWaitUnverifiedSyncToken(const gpu::SyncToken* sync_token) override; - - bool ProduceFrontBuffer(const gpu::Mailbox& mailbox); - void SetContextLostCallback(const base::Closure& callback); - - void AddDeletionObserver(DeletionObserver* observer); - void RemoveDeletionObserver(DeletionObserver* observer); - - bool EnsureBackbuffer(); - - void SetOnConsoleMessageCallback( - const GpuConsoleMessageCallback& callback); - - void SetLatencyInfo(const std::vector<ui::LatencyInfo>& latency_info); - using SwapBuffersCompletionCallback = - base::Callback<void(const std::vector<ui::LatencyInfo>& latency_info, - gfx::SwapResult result)>; - void SetSwapBuffersCompletionCallback( - const SwapBuffersCompletionCallback& callback); - - using UpdateVSyncParametersCallback = - base::Callback<void(base::TimeTicks timebase, base::TimeDelta interval)>; - void SetUpdateVSyncParametersCallback( - const UpdateVSyncParametersCallback& callback); - - // TODO(apatrick): this is a temporary optimization while skia is calling - // ContentGLContext::MakeCurrent prior to every GL call. It saves returning 6 - // ints redundantly when only the error is needed for the - // CommandBufferProxyImpl implementation. - gpu::error::Error GetLastError() override; - - int32_t route_id() const { return route_id_; } - - int32_t stream_id() const { return stream_id_; } - - GpuChannelHost* channel() const { return channel_; } - - base::SharedMemoryHandle GetSharedStateHandle() const { - return shared_state_shm_->handle(); - } - uint32_t CreateStreamTexture(uint32_t texture_id); - - private: - typedef std::map<int32_t, scoped_refptr<gpu::Buffer>> TransferBufferMap; - typedef base::hash_map<uint32_t, base::Closure> SignalTaskMap; - - void CheckLock() { - if (lock_) - lock_->AssertAcquired(); - } - - // Send an IPC message over the GPU channel. This is private to fully - // encapsulate the channel; all callers of this function must explicitly - // verify that the context has not been lost. - bool Send(IPC::Message* msg); - - // Message handlers: - void OnUpdateState(const gpu::CommandBuffer::State& state); - void OnDestroyed(gpu::error::ContextLostReason reason, - gpu::error::Error error); - void OnConsoleMessage(const GPUCommandBufferConsoleMessage& message); - void OnSignalAck(uint32_t id); - void OnSwapBuffersCompleted(const std::vector<ui::LatencyInfo>& latency_info, - gfx::SwapResult result); - void OnUpdateVSyncParameters(base::TimeTicks timebase, - base::TimeDelta interval); - - // Try to read an updated copy of the state from shared memory. - void TryUpdateState(); - - // Updates the highest verified release fence sync. - void UpdateVerifiedReleases(uint32_t verified_flush); - - // Loses the context after we received an invalid message from the GPU - // process. Will call the lost context callback reentrantly if any. - void InvalidGpuMessage(); - - // Loses the context after we received an invalid reply from the GPU - // process. Will post a task to call the lost context callback if any. - void InvalidGpuReply(); - - void InvalidGpuReplyOnClientThread(); - - // The shared memory area used to update state. - gpu::CommandBufferSharedState* shared_state() const; - - base::Lock* lock_; - - // Unowned list of DeletionObservers. - base::ObserverList<DeletionObserver> deletion_observers_; - - // The last cached state received from the service. - State last_state_; - - // The shared memory area used to update state. - scoped_ptr<base::SharedMemory> shared_state_shm_; - - // |*this| is owned by |*channel_| and so is always outlived by it, so using a - // raw pointer is ok. - GpuChannelHost* channel_; - const uint64_t command_buffer_id_; - const int32_t route_id_; - const int32_t stream_id_; - uint32_t flush_count_; - int32_t last_put_offset_; - int32_t last_barrier_put_offset_; - - // Next generated fence sync. - uint64_t next_fence_sync_release_; - - // Unverified flushed fence syncs with their corresponding flush id. - std::queue<std::pair<uint64_t, uint32_t>> flushed_release_flush_id_; - - // Last flushed fence sync release, same as last item in queue if not empty. - uint64_t flushed_fence_sync_release_; - - // Last verified fence sync. - uint64_t verified_fence_sync_release_; - - base::Closure context_lost_callback_; - - GpuConsoleMessageCallback console_message_callback_; - - // Tasks to be invoked in SignalSyncPoint responses. - uint32_t next_signal_id_; - SignalTaskMap signal_tasks_; - - gpu::Capabilities capabilities_; - - std::vector<ui::LatencyInfo> latency_info_; - - SwapBuffersCompletionCallback swap_buffers_completion_callback_; - UpdateVSyncParametersCallback update_vsync_parameters_completion_callback_; - - base::WeakPtr<CommandBufferProxyImpl> weak_this_; - scoped_refptr<base::SequencedTaskRunner> callback_thread_; - - DISALLOW_COPY_AND_ASSIGN(CommandBufferProxyImpl); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_CLIENT_COMMAND_BUFFER_PROXY_IMPL_H_ diff --git a/chromium/content/common/gpu/client/context_provider_command_buffer.cc b/chromium/content/common/gpu/client/context_provider_command_buffer.cc index 2560d78067b..7ef9e73294e 100644 --- a/chromium/content/common/gpu/client/context_provider_command_buffer.cc +++ b/chromium/content/common/gpu/client/context_provider_command_buffer.cc @@ -12,7 +12,7 @@ #include "base/callback_helpers.h" #include "base/strings/stringprintf.h" #include "cc/output/managed_memory_policy.h" -#include "content/common/gpu/client/grcontext_for_webgraphicscontext3d.h" +#include "content/common/gpu/client/grcontext_for_gles2_interface.h" #include "gpu/command_buffer/client/gles2_implementation.h" #include "third_party/skia/include/gpu/GrContext.h" @@ -23,11 +23,11 @@ class ContextProviderCommandBuffer::LostContextCallbackProxy public: explicit LostContextCallbackProxy(ContextProviderCommandBuffer* provider) : provider_(provider) { - provider_->WebContext3DNoChecks()->setContextLostCallback(this); + provider_->context3d_->setContextLostCallback(this); } ~LostContextCallbackProxy() override { - provider_->WebContext3DNoChecks()->setContextLostCallback(NULL); + provider_->context3d_->setContextLostCallback(NULL); } void onContextLost() override { provider_->OnLostContext(); } @@ -49,12 +49,11 @@ ContextProviderCommandBuffer::Create( ContextProviderCommandBuffer::ContextProviderCommandBuffer( scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d, CommandBufferContextType type) - : context_type_(type), + : context3d_(std::move(context3d)), + context_type_(type), debug_name_(CommandBufferContextTypeToString(type)) { - gr_interface_ = skia::AdoptRef( - new GrGLInterfaceForWebGraphicsContext3D(std::move(context3d))); DCHECK(main_thread_checker_.CalledOnValidThread()); - DCHECK(gr_interface_->WebContext3D()); + DCHECK(context3d_); context_thread_checker_.DetachFromThread(); } @@ -63,52 +62,42 @@ ContextProviderCommandBuffer::~ContextProviderCommandBuffer() { context_thread_checker_.CalledOnValidThread()); // Destroy references to the context3d_ before leaking it. - if (WebContext3DNoChecks()->GetCommandBufferProxy()) - WebContext3DNoChecks()->GetCommandBufferProxy()->SetLock(nullptr); + if (context3d_->GetCommandBufferProxy()) + context3d_->GetCommandBufferProxy()->SetLock(nullptr); lost_context_callback_proxy_.reset(); } - -CommandBufferProxyImpl* ContextProviderCommandBuffer::GetCommandBufferProxy() { - return WebContext3DNoChecks()->GetCommandBufferProxy(); +gpu::CommandBufferProxyImpl* +ContextProviderCommandBuffer::GetCommandBufferProxy() { + return context3d_->GetCommandBufferProxy(); } WebGraphicsContext3DCommandBufferImpl* ContextProviderCommandBuffer::WebContext3D() { - DCHECK(gr_interface_); - DCHECK(gr_interface_->WebContext3D()); + DCHECK(context3d_); DCHECK(lost_context_callback_proxy_); // Is bound to thread. DCHECK(context_thread_checker_.CalledOnValidThread()); - return WebContext3DNoChecks(); -} - -WebGraphicsContext3DCommandBufferImpl* - ContextProviderCommandBuffer::WebContext3DNoChecks() { - DCHECK(gr_interface_); - return static_cast<WebGraphicsContext3DCommandBufferImpl*>( - gr_interface_->WebContext3D()); + return context3d_.get(); } bool ContextProviderCommandBuffer::BindToCurrentThread() { // This is called on the thread the context will be used. DCHECK(context_thread_checker_.CalledOnValidThread()); - DCHECK(gr_interface_ && gr_interface_->WebContext3D()); if (lost_context_callback_proxy_) return true; - WebContext3DNoChecks()->SetContextType(context_type_); - if (!WebContext3DNoChecks()->InitializeOnCurrentThread()) + context3d_->SetContextType(context_type_); + if (!context3d_->InitializeOnCurrentThread()) return false; - gr_interface_->BindToCurrentThread(); InitializeCapabilities(); std::string unique_context_name = - base::StringPrintf("%s-%p", debug_name_.c_str(), WebContext3DNoChecks()); - WebContext3DNoChecks()->traceBeginCHROMIUM("gpu_toplevel", - unique_context_name.c_str()); + base::StringPrintf("%s-%p", debug_name_.c_str(), context3d_.get()); + context3d_->GetGLInterface()->TraceBeginCHROMIUM("gpu_toplevel", + unique_context_name.c_str()); lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this)); return true; @@ -119,13 +108,15 @@ void ContextProviderCommandBuffer::DetachFromThread() { } gpu::gles2::GLES2Interface* ContextProviderCommandBuffer::ContextGL() { + DCHECK(context3d_); DCHECK(lost_context_callback_proxy_); // Is bound to thread. + DCHECK(context_thread_checker_.CalledOnValidThread()); - return WebContext3D()->GetImplementation(); + return context3d_->GetImplementation(); } gpu::ContextSupport* ContextProviderCommandBuffer::ContextSupport() { - return WebContext3DNoChecks()->GetContextSupport(); + return context3d_->GetContextSupport(); } class GrContext* ContextProviderCommandBuffer::GrContext() { @@ -135,7 +126,8 @@ class GrContext* ContextProviderCommandBuffer::GrContext() { if (gr_context_) return gr_context_->get(); - gr_context_.reset(new GrContextForWebGraphicsContext3D(gr_interface_)); + gr_context_.reset( + new GrContextForGLES2Interface(context3d_->GetGLInterface())); // If GlContext is already lost, also abandon the new GrContext. if (gr_context_->get() && @@ -154,7 +146,8 @@ void ContextProviderCommandBuffer::InvalidateGrContext(uint32_t state) { } void ContextProviderCommandBuffer::SetupLock() { - WebContext3D()->GetCommandBufferProxy()->SetLock(&context_lock_); + DCHECK(context3d_); + context3d_->GetCommandBufferProxy()->SetLock(&context_lock_); } base::Lock* ContextProviderCommandBuffer::GetLock() { @@ -187,9 +180,9 @@ void ContextProviderCommandBuffer::OnLostContext() { void ContextProviderCommandBuffer::InitializeCapabilities() { Capabilities caps; - caps.gpu = WebContext3DNoChecks()->GetImplementation()->capabilities(); + caps.gpu = context3d_->GetImplementation()->capabilities(); - size_t mapped_memory_limit = WebContext3DNoChecks()->GetMappedMemoryLimit(); + size_t mapped_memory_limit = context3d_->GetMappedMemoryLimit(); caps.max_transfer_buffer_usage_bytes = mapped_memory_limit == WebGraphicsContext3DCommandBufferImpl::kNoLimit ? std::numeric_limits<size_t>::max() : mapped_memory_limit; diff --git a/chromium/content/common/gpu/client/context_provider_command_buffer.h b/chromium/content/common/gpu/client/context_provider_command_buffer.h index 564e76c4040..65b0e50dc7e 100644 --- a/chromium/content/common/gpu/client/context_provider_command_buffer.h +++ b/chromium/content/common/gpu/client/context_provider_command_buffer.h @@ -16,12 +16,10 @@ #include "content/common/content_export.h" #include "content/common/gpu/client/command_buffer_metrics.h" #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" -#include "skia/ext/refptr.h" namespace content { -class GrContextForWebGraphicsContext3D; -class GrGLInterfaceForWebGraphicsContext3D; +class GrContextForGLES2Interface; // Implementation of cc::ContextProvider that provides a // WebGraphicsContext3DCommandBufferImpl context and a GrContext. @@ -32,7 +30,7 @@ class CONTENT_EXPORT ContextProviderCommandBuffer scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d, CommandBufferContextType type); - CommandBufferProxyImpl* GetCommandBufferProxy(); + gpu::CommandBufferProxyImpl* GetCommandBufferProxy(); // cc_blink::ContextProviderWebContext implementation. WebGraphicsContext3DCommandBufferImpl* WebContext3D() override; @@ -60,14 +58,13 @@ class CONTENT_EXPORT ContextProviderCommandBuffer void OnLostContext(); private: - WebGraphicsContext3DCommandBufferImpl* WebContext3DNoChecks(); void InitializeCapabilities(); base::ThreadChecker main_thread_checker_; base::ThreadChecker context_thread_checker_; - skia::RefPtr<GrGLInterfaceForWebGraphicsContext3D> gr_interface_; - scoped_ptr<GrContextForWebGraphicsContext3D> gr_context_; + scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d_; + scoped_ptr<GrContextForGLES2Interface> gr_context_; cc::ContextProvider::Capabilities capabilities_; CommandBufferContextType context_type_; @@ -78,7 +75,6 @@ class CONTENT_EXPORT ContextProviderCommandBuffer base::Lock context_lock_; class LostContextCallbackProxy; - friend class LostContextCallbackProxy; scoped_ptr<LostContextCallbackProxy> lost_context_callback_proxy_; }; diff --git a/chromium/content/common/gpu/client/gl_helper.cc b/chromium/content/common/gpu/client/gl_helper.cc deleted file mode 100644 index 5549caaacb8..00000000000 --- a/chromium/content/common/gpu/client/gl_helper.cc +++ /dev/null @@ -1,1391 +0,0 @@ -// Copyright (c) 2012 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 "content/common/gpu/client/gl_helper.h" - -#include <stddef.h> -#include <stdint.h> - -#include <queue> -#include <string> - -#include "base/bind.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "base/strings/string_util.h" -#include "base/time/time.h" -#include "base/trace_event/trace_event.h" -#include "content/common/gpu/client/gl_helper_readback_support.h" -#include "content/common/gpu/client/gl_helper_scaling.h" -#include "gpu/GLES2/gl2extchromium.h" -#include "gpu/command_buffer/client/context_support.h" -#include "gpu/command_buffer/common/mailbox.h" -#include "gpu/command_buffer/common/mailbox_holder.h" -#include "media/base/video_frame.h" -#include "media/base/video_util.h" -#include "third_party/skia/include/core/SkRegion.h" -#include "ui/gfx/geometry/point.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/size.h" - -using gpu::gles2::GLES2Interface; - -namespace { - -class ScopedFlush { - public: - explicit ScopedFlush(gpu::gles2::GLES2Interface* gl) : gl_(gl) {} - - ~ScopedFlush() { gl_->Flush(); } - - private: - gpu::gles2::GLES2Interface* gl_; - - DISALLOW_COPY_AND_ASSIGN(ScopedFlush); -}; - -// Helper class for allocating and holding an RGBA texture of a given -// size and an associated framebuffer. -class TextureFrameBufferPair { - public: - TextureFrameBufferPair(GLES2Interface* gl, gfx::Size size) - : texture_(gl), framebuffer_(gl), size_(size) { - content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, texture_); - gl->TexImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA, - size.width(), - size.height(), - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - NULL); - content::ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder( - gl, framebuffer_); - gl->FramebufferTexture2D( - GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0); - } - - GLuint texture() const { return texture_.id(); } - GLuint framebuffer() const { return framebuffer_.id(); } - gfx::Size size() const { return size_; } - - private: - content::ScopedTexture texture_; - content::ScopedFramebuffer framebuffer_; - gfx::Size size_; - - DISALLOW_COPY_AND_ASSIGN(TextureFrameBufferPair); -}; - -// Helper class for holding a scaler, a texture for the output of that -// scaler and an associated frame buffer. This is inteded to be used -// when the output of a scaler is to be sent to a readback. -class ScalerHolder { - public: - ScalerHolder(GLES2Interface* gl, content::GLHelper::ScalerInterface* scaler) - : texture_and_framebuffer_(gl, scaler->DstSize()), scaler_(scaler) {} - - void Scale(GLuint src_texture) { - scaler_->Scale(src_texture, texture_and_framebuffer_.texture()); - } - - content::GLHelper::ScalerInterface* scaler() const { return scaler_.get(); } - TextureFrameBufferPair* texture_and_framebuffer() { - return &texture_and_framebuffer_; - } - GLuint texture() const { return texture_and_framebuffer_.texture(); } - - private: - TextureFrameBufferPair texture_and_framebuffer_; - scoped_ptr<content::GLHelper::ScalerInterface> scaler_; - - DISALLOW_COPY_AND_ASSIGN(ScalerHolder); -}; - -} // namespace - -namespace content { -typedef GLHelperReadbackSupport::FormatSupport FormatSupport; - -// Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates -// the data needed for it. -class GLHelper::CopyTextureToImpl - : public base::SupportsWeakPtr<GLHelper::CopyTextureToImpl> { - public: - CopyTextureToImpl(GLES2Interface* gl, - gpu::ContextSupport* context_support, - GLHelper* helper) - : gl_(gl), - context_support_(context_support), - helper_(helper), - flush_(gl), - max_draw_buffers_(0) { - const GLubyte* extensions = gl_->GetString(GL_EXTENSIONS); - if (!extensions) - return; - std::string extensions_string = - " " + std::string(reinterpret_cast<const char*>(extensions)) + " "; - if (extensions_string.find(" GL_EXT_draw_buffers ") != std::string::npos) { - gl_->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max_draw_buffers_); - } - } - ~CopyTextureToImpl() { CancelRequests(); } - - GLuint ConsumeMailboxToTexture(const gpu::Mailbox& mailbox, - const gpu::SyncToken& sync_token) { - return helper_->ConsumeMailboxToTexture(mailbox, sync_token); - } - - void CropScaleReadbackAndCleanTexture( - GLuint src_texture, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - unsigned char* out, - const SkColorType out_color_type, - const base::Callback<void(bool)>& callback, - GLHelper::ScalerQuality quality); - - void ReadbackTextureSync(GLuint texture, - const gfx::Rect& src_rect, - unsigned char* out, - SkColorType format); - - void ReadbackTextureAsync(GLuint texture, - const gfx::Size& dst_size, - unsigned char* out, - SkColorType color_type, - const base::Callback<void(bool)>& callback); - - // Reads back bytes from the currently bound frame buffer. - // Note that dst_size is specified in bytes, not pixels. - void ReadbackAsync( - const gfx::Size& dst_size, - int32_t bytes_per_row, // generally dst_size.width() * 4 - int32_t row_stride_bytes, // generally dst_size.width() * 4 - unsigned char* out, - GLenum format, - GLenum type, - size_t bytes_per_pixel, - const base::Callback<void(bool)>& callback); - - void ReadbackPlane(TextureFrameBufferPair* source, - const scoped_refptr<media::VideoFrame>& target, - int plane, - int size_shift, - const gfx::Rect& paste_rect, - ReadbackSwizzle swizzle, - const base::Callback<void(bool)>& callback); - - GLuint CopyAndScaleTexture(GLuint texture, - const gfx::Size& src_size, - const gfx::Size& dst_size, - bool vertically_flip_texture, - GLHelper::ScalerQuality quality); - - ReadbackYUVInterface* CreateReadbackPipelineYUV( - GLHelper::ScalerQuality quality, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool flip_vertically, - bool use_mrt); - - // Returns the maximum number of draw buffers available, - // 0 if GL_EXT_draw_buffers is not available. - GLint MaxDrawBuffers() const { return max_draw_buffers_; } - - FormatSupport GetReadbackConfig(SkColorType color_type, - bool can_swizzle, - GLenum* format, - GLenum* type, - size_t* bytes_per_pixel); - - private: - // A single request to CropScaleReadbackAndCleanTexture. - // The main thread can cancel the request, before it's handled by the helper - // thread, by resetting the texture and pixels fields. Alternatively, the - // thread marks that it handles the request by resetting the pixels field - // (meaning it guarantees that the callback with be called). - // In either case, the callback must be called exactly once, and the texture - // must be deleted by the main thread gl. - struct Request { - Request(const gfx::Size& size_, - int32_t bytes_per_row_, - int32_t row_stride_bytes_, - unsigned char* pixels_, - const base::Callback<void(bool)>& callback_) - : done(false), - size(size_), - bytes_per_row(bytes_per_row_), - row_stride_bytes(row_stride_bytes_), - pixels(pixels_), - callback(callback_), - buffer(0), - query(0) {} - - bool done; - bool result; - gfx::Size size; - int bytes_per_row; - int row_stride_bytes; - unsigned char* pixels; - base::Callback<void(bool)> callback; - GLuint buffer; - GLuint query; - }; - - // We must take care to call the callbacks last, as they may - // end up destroying the gl_helper and make *this invalid. - // We stick the finished requests in a stack object that calls - // the callbacks when it goes out of scope. - class FinishRequestHelper { - public: - FinishRequestHelper() {} - ~FinishRequestHelper() { - while (!requests_.empty()) { - Request* request = requests_.front(); - requests_.pop(); - request->callback.Run(request->result); - delete request; - } - } - void Add(Request* r) { - requests_.push(r); - } - private: - std::queue<Request*> requests_; - DISALLOW_COPY_AND_ASSIGN(FinishRequestHelper); - }; - - // A readback pipeline that also converts the data to YUV before - // reading it back. - class ReadbackYUVImpl : public ReadbackYUVInterface { - public: - ReadbackYUVImpl(GLES2Interface* gl, - CopyTextureToImpl* copy_impl, - GLHelperScaling* scaler_impl, - GLHelper::ScalerQuality quality, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool flip_vertically, - ReadbackSwizzle swizzle); - - void ReadbackYUV(const gpu::Mailbox& mailbox, - const gpu::SyncToken& sync_token, - const scoped_refptr<media::VideoFrame>& target, - const gfx::Point& paste_location, - const base::Callback<void(bool)>& callback) override; - - ScalerInterface* scaler() override { return scaler_.scaler(); } - - private: - GLES2Interface* gl_; - CopyTextureToImpl* copy_impl_; - gfx::Size dst_size_; - ReadbackSwizzle swizzle_; - ScalerHolder scaler_; - ScalerHolder y_; - ScalerHolder u_; - ScalerHolder v_; - - DISALLOW_COPY_AND_ASSIGN(ReadbackYUVImpl); - }; - - // A readback pipeline that also converts the data to YUV before - // reading it back. This one uses Multiple Render Targets, which - // may not be supported on all platforms. - class ReadbackYUV_MRT : public ReadbackYUVInterface { - public: - ReadbackYUV_MRT(GLES2Interface* gl, - CopyTextureToImpl* copy_impl, - GLHelperScaling* scaler_impl, - GLHelper::ScalerQuality quality, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool flip_vertically, - ReadbackSwizzle swizzle); - - void ReadbackYUV(const gpu::Mailbox& mailbox, - const gpu::SyncToken& sync_token, - const scoped_refptr<media::VideoFrame>& target, - const gfx::Point& paste_location, - const base::Callback<void(bool)>& callback) override; - - ScalerInterface* scaler() override { return scaler_.scaler(); } - - private: - GLES2Interface* gl_; - CopyTextureToImpl* copy_impl_; - gfx::Size dst_size_; - GLHelper::ScalerQuality quality_; - ReadbackSwizzle swizzle_; - ScalerHolder scaler_; - scoped_ptr<content::GLHelperScaling::ShaderInterface> pass1_shader_; - scoped_ptr<content::GLHelperScaling::ShaderInterface> pass2_shader_; - TextureFrameBufferPair y_; - ScopedTexture uv_; - TextureFrameBufferPair u_; - TextureFrameBufferPair v_; - - DISALLOW_COPY_AND_ASSIGN(ReadbackYUV_MRT); - }; - - // Copies the block of pixels specified with |src_subrect| from |src_texture|, - // scales it to |dst_size|, writes it into a texture, and returns its ID. - // |src_size| is the size of |src_texture|. - GLuint ScaleTexture(GLuint src_texture, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool vertically_flip_texture, - bool swizzle, - SkColorType color_type, - GLHelper::ScalerQuality quality); - - // Converts each four consecutive pixels of the source texture into one pixel - // in the result texture with each pixel channel representing the grayscale - // color of one of the four original pixels: - // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X1X2X3X4 - // The resulting texture is still an RGBA texture (which is ~4 times narrower - // than the original). If rendered directly, it wouldn't show anything useful, - // but the data in it can be used to construct a grayscale image. - // |encoded_texture_size| is the exact size of the resulting RGBA texture. It - // is equal to src_size.width()/4 rounded upwards. Some channels in the last - // pixel ((-src_size.width()) % 4) to be exact) are padding and don't contain - // useful data. - // If swizzle is set to true, the transformed pixels are reordered: - // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X3X2X1X4. - GLuint EncodeTextureAsGrayscale(GLuint src_texture, - const gfx::Size& src_size, - gfx::Size* const encoded_texture_size, - bool vertically_flip_texture, - bool swizzle); - - static void nullcallback(bool success) {} - void ReadbackDone(Request *request, int bytes_per_pixel); - void FinishRequest(Request* request, - bool result, - FinishRequestHelper* helper); - void CancelRequests(); - - static const float kRGBtoYColorWeights[]; - static const float kRGBtoUColorWeights[]; - static const float kRGBtoVColorWeights[]; - static const float kRGBtoGrayscaleColorWeights[]; - - GLES2Interface* gl_; - gpu::ContextSupport* context_support_; - GLHelper* helper_; - - // A scoped flush that will ensure all resource deletions are flushed when - // this object is destroyed. Must be declared before other Scoped* fields. - ScopedFlush flush_; - - std::queue<Request*> request_queue_; - GLint max_draw_buffers_; -}; - -GLHelper::ScalerInterface* GLHelper::CreateScaler(ScalerQuality quality, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool vertically_flip_texture, - bool swizzle) { - InitScalerImpl(); - return scaler_impl_->CreateScaler(quality, - src_size, - src_subrect, - dst_size, - vertically_flip_texture, - swizzle); -} - -GLuint GLHelper::CopyTextureToImpl::ScaleTexture( - GLuint src_texture, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool vertically_flip_texture, - bool swizzle, - SkColorType color_type, - GLHelper::ScalerQuality quality) { - GLuint dst_texture = 0u; - gl_->GenTextures(1, &dst_texture); - { - GLenum format = GL_RGBA, type = GL_UNSIGNED_BYTE; - ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture); - - // Use GL_RGBA for destination/temporary texture unless we're working with - // 16-bit data - if (color_type == kRGB_565_SkColorType) { - format = GL_RGB; - type = GL_UNSIGNED_SHORT_5_6_5; - } - - gl_->TexImage2D(GL_TEXTURE_2D, - 0, - format, - dst_size.width(), - dst_size.height(), - 0, - format, - type, - NULL); - } - scoped_ptr<ScalerInterface> scaler( - helper_->CreateScaler(quality, - src_size, - src_subrect, - dst_size, - vertically_flip_texture, - swizzle)); - scaler->Scale(src_texture, dst_texture); - return dst_texture; -} - -GLuint GLHelper::CopyTextureToImpl::EncodeTextureAsGrayscale( - GLuint src_texture, - const gfx::Size& src_size, - gfx::Size* const encoded_texture_size, - bool vertically_flip_texture, - bool swizzle) { - GLuint dst_texture = 0u; - gl_->GenTextures(1, &dst_texture); - // The size of the encoded texture. - *encoded_texture_size = - gfx::Size((src_size.width() + 3) / 4, src_size.height()); - { - ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture); - gl_->TexImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA, - encoded_texture_size->width(), - encoded_texture_size->height(), - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - NULL); - } - - helper_->InitScalerImpl(); - scoped_ptr<ScalerInterface> grayscale_scaler( - helper_->scaler_impl_.get()->CreatePlanarScaler( - src_size, - gfx::Rect(0, 0, (src_size.width() + 3) & ~3, src_size.height()), - *encoded_texture_size, - vertically_flip_texture, - swizzle, - kRGBtoGrayscaleColorWeights)); - grayscale_scaler->Scale(src_texture, dst_texture); - return dst_texture; -} - -void GLHelper::CopyTextureToImpl::ReadbackAsync( - const gfx::Size& dst_size, - int32_t bytes_per_row, - int32_t row_stride_bytes, - unsigned char* out, - GLenum format, - GLenum type, - size_t bytes_per_pixel, - const base::Callback<void(bool)>& callback) { - TRACE_EVENT0("gpu.capture", "GLHelper::CopyTextureToImpl::ReadbackAsync"); - Request* request = - new Request(dst_size, bytes_per_row, row_stride_bytes, out, callback); - request_queue_.push(request); - request->buffer = 0u; - - gl_->GenBuffers(1, &request->buffer); - gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer); - gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, - bytes_per_pixel * dst_size.GetArea(), - NULL, - GL_STREAM_READ); - - request->query = 0u; - gl_->GenQueriesEXT(1, &request->query); - gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, request->query); - gl_->ReadPixels(0, - 0, - dst_size.width(), - dst_size.height(), - format, - type, - NULL); - gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM); - gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0); - context_support_->SignalQuery( - request->query, - base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(), - request, bytes_per_pixel)); -} - -void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture( - GLuint src_texture, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - unsigned char* out, - const SkColorType out_color_type, - const base::Callback<void(bool)>& callback, - GLHelper::ScalerQuality quality) { - GLenum format, type; - size_t bytes_per_pixel; - SkColorType readback_color_type = out_color_type; - // Single-component textures are not supported by all GPUs, so we implement - // kAlpha_8_SkColorType support here via a special encoding (see below) using - // a 32-bit texture to represent an 8-bit image. - // Thus we use generic 32-bit readback in this case. - if (out_color_type == kAlpha_8_SkColorType) { - readback_color_type = kRGBA_8888_SkColorType; - } - - FormatSupport supported = GetReadbackConfig( - readback_color_type, true, &format, &type, &bytes_per_pixel); - - if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) { - callback.Run(false); - return; - } - - GLuint texture = src_texture; - - // Scale texture if needed - // Optimization: SCALER_QUALITY_FAST is just a single bilinear pass, which we - // can do just as well in EncodeTextureAsGrayscale, which we will do if - // out_color_type is kAlpha_8_SkColorType, so let's skip the scaling step - // in that case. - bool scale_texture = out_color_type != kAlpha_8_SkColorType || - quality != GLHelper::SCALER_QUALITY_FAST; - if (scale_texture) { - // Don't swizzle during the scale step for kAlpha_8_SkColorType. - // We will swizzle in the encode step below if needed. - bool scale_swizzle = out_color_type == kAlpha_8_SkColorType - ? false - : supported == GLHelperReadbackSupport::SWIZZLE; - texture = - ScaleTexture(src_texture, - src_size, - src_subrect, - dst_size, - true, - scale_swizzle, - out_color_type == kAlpha_8_SkColorType ? kN32_SkColorType - : out_color_type, - quality); - DCHECK(texture); - } - - gfx::Size readback_texture_size = dst_size; - // Encode texture to grayscale if needed. - if (out_color_type == kAlpha_8_SkColorType) { - // Do the vertical flip here if we haven't already done it when we scaled - // the texture. - bool encode_as_grayscale_vertical_flip = !scale_texture; - // EncodeTextureAsGrayscale by default creates a texture which should be - // read back as RGBA, so need to swizzle if the readback format is BGRA. - bool encode_as_grayscale_swizzle = format == GL_BGRA_EXT; - GLuint tmp_texture = - EncodeTextureAsGrayscale(texture, - dst_size, - &readback_texture_size, - encode_as_grayscale_vertical_flip, - encode_as_grayscale_swizzle); - // If the scaled texture was created - delete it - if (scale_texture) - gl_->DeleteTextures(1, &texture); - texture = tmp_texture; - DCHECK(texture); - } - - // Readback the pixels of the resulting texture - ScopedFramebuffer dst_framebuffer(gl_); - ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, - dst_framebuffer); - ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); - gl_->FramebufferTexture2D(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - texture, - 0); - - int32_t bytes_per_row = out_color_type == kAlpha_8_SkColorType - ? dst_size.width() - : dst_size.width() * bytes_per_pixel; - - ReadbackAsync(readback_texture_size, - bytes_per_row, - bytes_per_row, - out, - format, - type, - bytes_per_pixel, - callback); - gl_->DeleteTextures(1, &texture); -} - -void GLHelper::CopyTextureToImpl::ReadbackTextureSync( - GLuint texture, - const gfx::Rect& src_rect, - unsigned char* out, - SkColorType color_type) { - GLenum format, type; - size_t bytes_per_pixel; - FormatSupport supported = - GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel); - if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) { - return; - } - - ScopedFramebuffer dst_framebuffer(gl_); - ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, - dst_framebuffer); - ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); - gl_->FramebufferTexture2D( - GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); - gl_->ReadPixels(src_rect.x(), - src_rect.y(), - src_rect.width(), - src_rect.height(), - format, - type, - out); -} - -void GLHelper::CopyTextureToImpl::ReadbackTextureAsync( - GLuint texture, - const gfx::Size& dst_size, - unsigned char* out, - SkColorType color_type, - const base::Callback<void(bool)>& callback) { - GLenum format, type; - size_t bytes_per_pixel; - FormatSupport supported = - GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel); - if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) { - callback.Run(false); - return; - } - - ScopedFramebuffer dst_framebuffer(gl_); - ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, - dst_framebuffer); - ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); - gl_->FramebufferTexture2D(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - texture, - 0); - ReadbackAsync(dst_size, - dst_size.width() * bytes_per_pixel, - dst_size.width() * bytes_per_pixel, - out, - format, - type, - bytes_per_pixel, - callback); -} - -GLuint GLHelper::CopyTextureToImpl::CopyAndScaleTexture( - GLuint src_texture, - const gfx::Size& src_size, - const gfx::Size& dst_size, - bool vertically_flip_texture, - GLHelper::ScalerQuality quality) { - return ScaleTexture(src_texture, - src_size, - gfx::Rect(src_size), - dst_size, - vertically_flip_texture, - false, - kRGBA_8888_SkColorType, // GL_RGBA - quality); -} - -void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request, - int bytes_per_pixel) { - TRACE_EVENT0("gpu.capture", - "GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete"); - finished_request->done = true; - - FinishRequestHelper finish_request_helper; - - // We process transfer requests in the order they were received, regardless - // of the order we get the callbacks in. - while (!request_queue_.empty()) { - Request* request = request_queue_.front(); - if (!request->done) { - break; - } - - bool result = false; - if (request->buffer != 0) { - gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer); - unsigned char* data = static_cast<unsigned char*>(gl_->MapBufferCHROMIUM( - GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY)); - if (data) { - result = true; - if (request->bytes_per_row == request->size.width() * bytes_per_pixel && - request->bytes_per_row == request->row_stride_bytes) { - memcpy(request->pixels, data, - request->size.GetArea() * bytes_per_pixel); - } else { - unsigned char* out = request->pixels; - for (int y = 0; y < request->size.height(); y++) { - memcpy(out, data, request->bytes_per_row); - out += request->row_stride_bytes; - data += request->size.width() * bytes_per_pixel; - } - } - gl_->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM); - } - gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0); - } - FinishRequest(request, result, &finish_request_helper); - } -} - -void GLHelper::CopyTextureToImpl::FinishRequest( - Request* request, - bool result, - FinishRequestHelper* finish_request_helper) { - TRACE_EVENT0("gpu.capture", "GLHelper::CopyTextureToImpl::FinishRequest"); - DCHECK(request_queue_.front() == request); - request_queue_.pop(); - request->result = result; - ScopedFlush flush(gl_); - if (request->query != 0) { - gl_->DeleteQueriesEXT(1, &request->query); - request->query = 0; - } - if (request->buffer != 0) { - gl_->DeleteBuffers(1, &request->buffer); - request->buffer = 0; - } - finish_request_helper->Add(request); -} - -void GLHelper::CopyTextureToImpl::CancelRequests() { - FinishRequestHelper finish_request_helper; - while (!request_queue_.empty()) { - Request* request = request_queue_.front(); - FinishRequest(request, false, &finish_request_helper); - } -} - -FormatSupport GLHelper::CopyTextureToImpl::GetReadbackConfig( - SkColorType color_type, - bool can_swizzle, - GLenum* format, - GLenum* type, - size_t* bytes_per_pixel) { - return helper_->readback_support_->GetReadbackConfig( - color_type, can_swizzle, format, type, bytes_per_pixel); -} - -GLHelper::GLHelper(GLES2Interface* gl, gpu::ContextSupport* context_support) - : gl_(gl), - context_support_(context_support), - readback_support_(new GLHelperReadbackSupport(gl)) {} - -GLHelper::~GLHelper() {} - -void GLHelper::CropScaleReadbackAndCleanTexture( - GLuint src_texture, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - unsigned char* out, - const SkColorType out_color_type, - const base::Callback<void(bool)>& callback, - GLHelper::ScalerQuality quality) { - InitCopyTextToImpl(); - copy_texture_to_impl_->CropScaleReadbackAndCleanTexture(src_texture, - src_size, - src_subrect, - dst_size, - out, - out_color_type, - callback, - quality); -} - -void GLHelper::CropScaleReadbackAndCleanMailbox( - const gpu::Mailbox& src_mailbox, - const gpu::SyncToken& sync_token, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - unsigned char* out, - const SkColorType out_color_type, - const base::Callback<void(bool)>& callback, - GLHelper::ScalerQuality quality) { - GLuint mailbox_texture = ConsumeMailboxToTexture(src_mailbox, sync_token); - CropScaleReadbackAndCleanTexture(mailbox_texture, - src_size, - src_subrect, - dst_size, - out, - out_color_type, - callback, - quality); - gl_->DeleteTextures(1, &mailbox_texture); -} - -void GLHelper::ReadbackTextureSync(GLuint texture, - const gfx::Rect& src_rect, - unsigned char* out, - SkColorType format) { - InitCopyTextToImpl(); - copy_texture_to_impl_->ReadbackTextureSync(texture, src_rect, out, format); -} - -void GLHelper::ReadbackTextureAsync( - GLuint texture, - const gfx::Size& dst_size, - unsigned char* out, - SkColorType color_type, - const base::Callback<void(bool)>& callback) { - InitCopyTextToImpl(); - copy_texture_to_impl_->ReadbackTextureAsync(texture, - dst_size, - out, - color_type, - callback); -} - -GLuint GLHelper::CopyTexture(GLuint texture, const gfx::Size& size) { - InitCopyTextToImpl(); - return copy_texture_to_impl_->CopyAndScaleTexture( - texture, size, size, false, GLHelper::SCALER_QUALITY_FAST); -} - -GLuint GLHelper::CopyAndScaleTexture(GLuint texture, - const gfx::Size& src_size, - const gfx::Size& dst_size, - bool vertically_flip_texture, - ScalerQuality quality) { - InitCopyTextToImpl(); - return copy_texture_to_impl_->CopyAndScaleTexture( - texture, src_size, dst_size, vertically_flip_texture, quality); -} - -GLuint GLHelper::CompileShaderFromSource(const GLchar* source, GLenum type) { - GLuint shader = gl_->CreateShader(type); - GLint length = strlen(source); - gl_->ShaderSource(shader, 1, &source, &length); - gl_->CompileShader(shader); - GLint compile_status = 0; - gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &compile_status); - if (!compile_status) { - GLint log_length = 0; - gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length); - if (log_length) { - scoped_ptr<GLchar[]> log(new GLchar[log_length]); - GLsizei returned_log_length = 0; - gl_->GetShaderInfoLog( - shader, log_length, &returned_log_length, log.get()); - LOG(ERROR) << std::string(log.get(), returned_log_length); - } - gl_->DeleteShader(shader); - return 0; - } - return shader; -} - -void GLHelper::InitCopyTextToImpl() { - // Lazily initialize |copy_texture_to_impl_| - if (!copy_texture_to_impl_) - copy_texture_to_impl_.reset( - new CopyTextureToImpl(gl_, context_support_, this)); -} - -void GLHelper::InitScalerImpl() { - // Lazily initialize |scaler_impl_| - if (!scaler_impl_) - scaler_impl_.reset(new GLHelperScaling(gl_, this)); -} - -GLint GLHelper::MaxDrawBuffers() { - InitCopyTextToImpl(); - return copy_texture_to_impl_->MaxDrawBuffers(); -} - -void GLHelper::CopySubBufferDamage(GLenum target, - GLuint texture, - GLuint previous_texture, - const SkRegion& new_damage, - const SkRegion& old_damage) { - SkRegion region(old_damage); - if (region.op(new_damage, SkRegion::kDifference_Op)) { - ScopedFramebuffer dst_framebuffer(gl_); - ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, - dst_framebuffer); - gl_->BindTexture(target, texture); - gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, - previous_texture, 0); - for (SkRegion::Iterator it(region); !it.done(); it.next()) { - const SkIRect& rect = it.rect(); - gl_->CopyTexSubImage2D(target, 0, rect.x(), rect.y(), rect.x(), rect.y(), - rect.width(), rect.height()); - } - gl_->BindTexture(target, 0); - gl_->Flush(); - } -} - -GLuint GLHelper::CreateTexture() { - GLuint texture = 0u; - gl_->GenTextures(1, &texture); - content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); - gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - return texture; -} - -void GLHelper::DeleteTexture(GLuint texture_id) { - gl_->DeleteTextures(1, &texture_id); -} - -void GLHelper::GenerateSyncToken(gpu::SyncToken* sync_token) { - const uint64_t fence_sync = gl_->InsertFenceSyncCHROMIUM(); - gl_->ShallowFlushCHROMIUM(); - gl_->GenSyncTokenCHROMIUM(fence_sync, sync_token->GetData()); -} - -void GLHelper::WaitSyncToken(const gpu::SyncToken& sync_token) { - gl_->WaitSyncTokenCHROMIUM(sync_token.GetConstData()); -} - -gpu::MailboxHolder GLHelper::ProduceMailboxHolderFromTexture( - GLuint texture_id) { - gpu::Mailbox mailbox; - gl_->GenMailboxCHROMIUM(mailbox.name); - gl_->ProduceTextureDirectCHROMIUM(texture_id, GL_TEXTURE_2D, mailbox.name); - - gpu::SyncToken sync_token; - GenerateSyncToken(&sync_token); - - return gpu::MailboxHolder(mailbox, sync_token, GL_TEXTURE_2D); -} - -GLuint GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox& mailbox, - const gpu::SyncToken& sync_token) { - if (mailbox.IsZero()) - return 0; - if (sync_token.HasData()) - WaitSyncToken(sync_token); - GLuint texture = - gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); - return texture; -} - -void GLHelper::ResizeTexture(GLuint texture, const gfx::Size& size) { - content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); - gl_->TexImage2D(GL_TEXTURE_2D, - 0, - GL_RGB, - size.width(), - size.height(), - 0, - GL_RGB, - GL_UNSIGNED_BYTE, - NULL); -} - -void GLHelper::CopyTextureSubImage(GLuint texture, const gfx::Rect& rect) { - content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); - gl_->CopyTexSubImage2D(GL_TEXTURE_2D, - 0, - rect.x(), - rect.y(), - rect.x(), - rect.y(), - rect.width(), - rect.height()); -} - -void GLHelper::CopyTextureFullImage(GLuint texture, const gfx::Size& size) { - content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); - gl_->CopyTexImage2D( - GL_TEXTURE_2D, 0, GL_RGB, 0, 0, size.width(), size.height(), 0); -} - -void GLHelper::Flush() { - gl_->Flush(); -} - -void GLHelper::InsertOrderingBarrier() { - gl_->OrderingBarrierCHROMIUM(); -} - -void GLHelper::CopyTextureToImpl::ReadbackPlane( - TextureFrameBufferPair* source, - const scoped_refptr<media::VideoFrame>& target, - int plane, - int size_shift, - const gfx::Rect& paste_rect, - ReadbackSwizzle swizzle, - const base::Callback<void(bool)>& callback) { - gl_->BindFramebuffer(GL_FRAMEBUFFER, source->framebuffer()); - const size_t offset = target->stride(plane) * (paste_rect.y() >> size_shift) + - (paste_rect.x() >> size_shift); - ReadbackAsync(source->size(), - paste_rect.width() >> size_shift, - target->stride(plane), - target->data(plane) + offset, - (swizzle == kSwizzleBGRA) ? GL_BGRA_EXT : GL_RGBA, - GL_UNSIGNED_BYTE, - 4, - callback); -} - -const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights[] = { - 0.257f, 0.504f, 0.098f, 0.0625f}; -const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = { - -0.148f, -0.291f, 0.439f, 0.5f}; -const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = { - 0.439f, -0.368f, -0.071f, 0.5f}; -const float GLHelper::CopyTextureToImpl::kRGBtoGrayscaleColorWeights[] = { - 0.213f, 0.715f, 0.072f, 0.0f}; - -// YUV readback constructors. Initiates the main scaler pipeline and -// one planar scaler for each of the Y, U and V planes. -GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl( - GLES2Interface* gl, - CopyTextureToImpl* copy_impl, - GLHelperScaling* scaler_impl, - GLHelper::ScalerQuality quality, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool flip_vertically, - ReadbackSwizzle swizzle) - : gl_(gl), - copy_impl_(copy_impl), - dst_size_(dst_size), - swizzle_(swizzle), - scaler_(gl, - scaler_impl->CreateScaler(quality, - src_size, - src_subrect, - dst_size, - flip_vertically, - false)), - y_(gl, - scaler_impl->CreatePlanarScaler( - dst_size, - gfx::Rect(0, - 0, - (dst_size.width() + 3) & ~3, - dst_size.height()), - gfx::Size((dst_size.width() + 3) / 4, dst_size.height()), - false, - (swizzle == kSwizzleBGRA), - kRGBtoYColorWeights)), - u_(gl, - scaler_impl->CreatePlanarScaler( - dst_size, - gfx::Rect(0, - 0, - (dst_size.width() + 7) & ~7, - (dst_size.height() + 1) & ~1), - gfx::Size((dst_size.width() + 7) / 8, - (dst_size.height() + 1) / 2), - false, - (swizzle == kSwizzleBGRA), - kRGBtoUColorWeights)), - v_(gl, - scaler_impl->CreatePlanarScaler( - dst_size, - gfx::Rect(0, - 0, - (dst_size.width() + 7) & ~7, - (dst_size.height() + 1) & ~1), - gfx::Size((dst_size.width() + 7) / 8, - (dst_size.height() + 1) / 2), - false, - (swizzle == kSwizzleBGRA), - kRGBtoVColorWeights)) { - DCHECK(!(dst_size.width() & 1)); - DCHECK(!(dst_size.height() & 1)); -} - -static void CallbackKeepingVideoFrameAlive( - scoped_refptr<media::VideoFrame> video_frame, - const base::Callback<void(bool)>& callback, - bool success) { - callback.Run(success); -} - -void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV( - const gpu::Mailbox& mailbox, - const gpu::SyncToken& sync_token, - const scoped_refptr<media::VideoFrame>& target, - const gfx::Point& paste_location, - const base::Callback<void(bool)>& callback) { - DCHECK(!(paste_location.x() & 1)); - DCHECK(!(paste_location.y() & 1)); - - GLuint mailbox_texture = - copy_impl_->ConsumeMailboxToTexture(mailbox, sync_token); - - // Scale texture to right size. - scaler_.Scale(mailbox_texture); - gl_->DeleteTextures(1, &mailbox_texture); - - // Convert the scaled texture in to Y, U and V planes. - y_.Scale(scaler_.texture()); - u_.Scale(scaler_.texture()); - v_.Scale(scaler_.texture()); - - const gfx::Rect paste_rect(paste_location, dst_size_); - if (!target->visible_rect().Contains(paste_rect)) { - LOG(DFATAL) << "Paste rect not inside VideoFrame's visible rect!"; - callback.Run(false); - return; - } - - // Read back planes, one at a time. Keep the video frame alive while doing the - // readback. - copy_impl_->ReadbackPlane(y_.texture_and_framebuffer(), - target, - media::VideoFrame::kYPlane, - 0, - paste_rect, - swizzle_, - base::Bind(&nullcallback)); - copy_impl_->ReadbackPlane(u_.texture_and_framebuffer(), - target, - media::VideoFrame::kUPlane, - 1, - paste_rect, - swizzle_, - base::Bind(&nullcallback)); - copy_impl_->ReadbackPlane( - v_.texture_and_framebuffer(), - target, - media::VideoFrame::kVPlane, - 1, - paste_rect, - swizzle_, - base::Bind(&CallbackKeepingVideoFrameAlive, target, callback)); - gl_->BindFramebuffer(GL_FRAMEBUFFER, 0); - media::LetterboxYUV(target.get(), paste_rect); -} - -// YUV readback constructors. Initiates the main scaler pipeline and -// one planar scaler for each of the Y, U and V planes. -GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT( - GLES2Interface* gl, - CopyTextureToImpl* copy_impl, - GLHelperScaling* scaler_impl, - GLHelper::ScalerQuality quality, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool flip_vertically, - ReadbackSwizzle swizzle) - : gl_(gl), - copy_impl_(copy_impl), - dst_size_(dst_size), - quality_(quality), - swizzle_(swizzle), - scaler_(gl, - scaler_impl->CreateScaler(quality, - src_size, - src_subrect, - dst_size, - false, - false)), - pass1_shader_(scaler_impl->CreateYuvMrtShader( - dst_size, - gfx::Rect(0, 0, (dst_size.width() + 3) & ~3, dst_size.height()), - gfx::Size((dst_size.width() + 3) / 4, dst_size.height()), - flip_vertically, - (swizzle == kSwizzleBGRA), - GLHelperScaling::SHADER_YUV_MRT_PASS1)), - pass2_shader_(scaler_impl->CreateYuvMrtShader( - gfx::Size((dst_size.width() + 3) / 4, dst_size.height()), - gfx::Rect(0, - 0, - (dst_size.width() + 7) / 8 * 2, - dst_size.height()), - gfx::Size((dst_size.width() + 7) / 8, - (dst_size.height() + 1) / 2), - false, - (swizzle == kSwizzleBGRA), - GLHelperScaling::SHADER_YUV_MRT_PASS2)), - y_(gl, gfx::Size((dst_size.width() + 3) / 4, dst_size.height())), - uv_(gl), - u_(gl, - gfx::Size((dst_size.width() + 7) / 8, - (dst_size.height() + 1) / 2)), - v_(gl, - gfx::Size((dst_size.width() + 7) / 8, - (dst_size.height() + 1) / 2)) { - DCHECK(!(dst_size.width() & 1)); - DCHECK(!(dst_size.height() & 1)); - - content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, uv_); - gl->TexImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA, - (dst_size.width() + 3) / 4, - dst_size.height(), - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - NULL); -} - -void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV( - const gpu::Mailbox& mailbox, - const gpu::SyncToken& sync_token, - const scoped_refptr<media::VideoFrame>& target, - const gfx::Point& paste_location, - const base::Callback<void(bool)>& callback) { - DCHECK(!(paste_location.x() & 1)); - DCHECK(!(paste_location.y() & 1)); - - GLuint mailbox_texture = - copy_impl_->ConsumeMailboxToTexture(mailbox, sync_token); - - GLuint texture; - if (quality_ == GLHelper::SCALER_QUALITY_FAST) { - // Optimization: SCALER_QUALITY_FAST is just a single bilinear - // pass, which pass1_shader_ can do just as well, so let's skip - // the actual scaling in that case. - texture = mailbox_texture; - } else { - // Scale texture to right size. - scaler_.Scale(mailbox_texture); - texture = scaler_.texture(); - } - - std::vector<GLuint> outputs(2); - // Convert the scaled texture in to Y, U and V planes. - outputs[0] = y_.texture(); - outputs[1] = uv_; - pass1_shader_->Execute(texture, outputs); - - gl_->DeleteTextures(1, &mailbox_texture); - - outputs[0] = u_.texture(); - outputs[1] = v_.texture(); - pass2_shader_->Execute(uv_, outputs); - - const gfx::Rect paste_rect(paste_location, dst_size_); - if (!target->visible_rect().Contains(paste_rect)) { - LOG(DFATAL) << "Paste rect not inside VideoFrame's visible rect!"; - callback.Run(false); - return; - } - - // Read back planes, one at a time. - copy_impl_->ReadbackPlane(&y_, - target, - media::VideoFrame::kYPlane, - 0, - paste_rect, - swizzle_, - base::Bind(&nullcallback)); - copy_impl_->ReadbackPlane(&u_, - target, - media::VideoFrame::kUPlane, - 1, - paste_rect, - swizzle_, - base::Bind(&nullcallback)); - copy_impl_->ReadbackPlane( - &v_, - target, - media::VideoFrame::kVPlane, - 1, - paste_rect, - swizzle_, - base::Bind(&CallbackKeepingVideoFrameAlive, target, callback)); - gl_->BindFramebuffer(GL_FRAMEBUFFER, 0); - media::LetterboxYUV(target.get(), paste_rect); -} - -bool GLHelper::IsReadbackConfigSupported(SkColorType color_type) { - DCHECK(readback_support_.get()); - GLenum format, type; - size_t bytes_per_pixel; - FormatSupport support = readback_support_->GetReadbackConfig( - color_type, false, &format, &type, &bytes_per_pixel); - - return (support == GLHelperReadbackSupport::SUPPORTED); -} - -ReadbackYUVInterface* GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV( - GLHelper::ScalerQuality quality, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool flip_vertically, - bool use_mrt) { - helper_->InitScalerImpl(); - // Just query if the best readback configuration needs a swizzle In - // ReadbackPlane() we will choose GL_RGBA/GL_BGRA_EXT based on swizzle - GLenum format, type; - size_t bytes_per_pixel; - FormatSupport supported = GetReadbackConfig( - kRGBA_8888_SkColorType, true, &format, &type, &bytes_per_pixel); - DCHECK((format == GL_RGBA || format == GL_BGRA_EXT) && - type == GL_UNSIGNED_BYTE); - - ReadbackSwizzle swizzle = kSwizzleNone; - if (supported == GLHelperReadbackSupport::SWIZZLE) - swizzle = kSwizzleBGRA; - - if (max_draw_buffers_ >= 2 && use_mrt) { - return new ReadbackYUV_MRT(gl_, - this, - helper_->scaler_impl_.get(), - quality, - src_size, - src_subrect, - dst_size, - flip_vertically, - swizzle); - } - return new ReadbackYUVImpl(gl_, - this, - helper_->scaler_impl_.get(), - quality, - src_size, - src_subrect, - dst_size, - flip_vertically, - swizzle); -} - -ReadbackYUVInterface* GLHelper::CreateReadbackPipelineYUV( - ScalerQuality quality, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool flip_vertically, - bool use_mrt) { - InitCopyTextToImpl(); - return copy_texture_to_impl_->CreateReadbackPipelineYUV(quality, - src_size, - src_subrect, - dst_size, - flip_vertically, - use_mrt); -} - -} // namespace content diff --git a/chromium/content/common/gpu/client/gl_helper.h b/chromium/content/common/gpu/client/gl_helper.h deleted file mode 100644 index 2be3f5ae210..00000000000 --- a/chromium/content/common/gpu/client/gl_helper.h +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_GPU_CLIENT_GL_HELPER_H_ -#define CONTENT_COMMON_GPU_CLIENT_GL_HELPER_H_ - -#include "base/atomicops.h" -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "content/common/content_export.h" -#include "gpu/command_buffer/client/gles2_interface.h" -#include "gpu/command_buffer/common/mailbox_holder.h" -#include "third_party/skia/include/core/SkBitmap.h" - -namespace gfx { -class Point; -class Rect; -class Size; -} - -namespace gpu { -class ContextSupport; -struct Mailbox; -} - -namespace media { -class VideoFrame; -}; - -class SkRegion; - -namespace content { - -class GLHelperScaling; - -class ScopedGLuint { - public: - typedef void (gpu::gles2::GLES2Interface::*GenFunc)(GLsizei n, GLuint* ids); - typedef void (gpu::gles2::GLES2Interface::*DeleteFunc)(GLsizei n, - const GLuint* ids); - ScopedGLuint(gpu::gles2::GLES2Interface* gl, - GenFunc gen_func, - DeleteFunc delete_func) - : gl_(gl), id_(0u), delete_func_(delete_func) { - (gl_->*gen_func)(1, &id_); - } - - operator GLuint() const { return id_; } - - GLuint id() const { return id_; } - - ~ScopedGLuint() { - if (id_ != 0) { - (gl_->*delete_func_)(1, &id_); - } - } - - private: - gpu::gles2::GLES2Interface* gl_; - GLuint id_; - DeleteFunc delete_func_; - - DISALLOW_COPY_AND_ASSIGN(ScopedGLuint); -}; - -class ScopedBuffer : public ScopedGLuint { - public: - explicit ScopedBuffer(gpu::gles2::GLES2Interface* gl) - : ScopedGLuint(gl, - &gpu::gles2::GLES2Interface::GenBuffers, - &gpu::gles2::GLES2Interface::DeleteBuffers) {} -}; - -class ScopedFramebuffer : public ScopedGLuint { - public: - explicit ScopedFramebuffer(gpu::gles2::GLES2Interface* gl) - : ScopedGLuint(gl, - &gpu::gles2::GLES2Interface::GenFramebuffers, - &gpu::gles2::GLES2Interface::DeleteFramebuffers) {} -}; - -class ScopedTexture : public ScopedGLuint { - public: - explicit ScopedTexture(gpu::gles2::GLES2Interface* gl) - : ScopedGLuint(gl, - &gpu::gles2::GLES2Interface::GenTextures, - &gpu::gles2::GLES2Interface::DeleteTextures) {} -}; - -template <GLenum Target> -class ScopedBinder { - public: - typedef void (gpu::gles2::GLES2Interface::*BindFunc)(GLenum target, - GLuint id); - ScopedBinder(gpu::gles2::GLES2Interface* gl, GLuint id, BindFunc bind_func) - : gl_(gl), bind_func_(bind_func) { - (gl_->*bind_func_)(Target, id); - } - - virtual ~ScopedBinder() { (gl_->*bind_func_)(Target, 0); } - - private: - gpu::gles2::GLES2Interface* gl_; - BindFunc bind_func_; - - DISALLOW_COPY_AND_ASSIGN(ScopedBinder); -}; - -template <GLenum Target> -class ScopedBufferBinder : ScopedBinder<Target> { - public: - ScopedBufferBinder(gpu::gles2::GLES2Interface* gl, GLuint id) - : ScopedBinder<Target>(gl, id, &gpu::gles2::GLES2Interface::BindBuffer) {} -}; - -template <GLenum Target> -class ScopedFramebufferBinder : ScopedBinder<Target> { - public: - ScopedFramebufferBinder(gpu::gles2::GLES2Interface* gl, GLuint id) - : ScopedBinder<Target>(gl, - id, - &gpu::gles2::GLES2Interface::BindFramebuffer) {} -}; - -template <GLenum Target> -class ScopedTextureBinder : ScopedBinder<Target> { - public: - ScopedTextureBinder(gpu::gles2::GLES2Interface* gl, GLuint id) - : ScopedBinder<Target>(gl, id, &gpu::gles2::GLES2Interface::BindTexture) { - } -}; - -class ReadbackYUVInterface; -class GLHelperReadbackSupport; - -// Provides higher level operations on top of the gpu::gles2::GLES2Interface -// interfaces. -class CONTENT_EXPORT GLHelper { - public: - GLHelper(gpu::gles2::GLES2Interface* gl, - gpu::ContextSupport* context_support); - ~GLHelper(); - - enum ScalerQuality { - // Bilinear single pass, fastest possible. - SCALER_QUALITY_FAST = 1, - - // Bilinear upscale + N * 50% bilinear downscales. - // This is still fast enough for most purposes and - // Image quality is nearly as good as the BEST option. - SCALER_QUALITY_GOOD = 2, - - // Bicubic upscale + N * 50% bicubic downscales. - // Produces very good quality scaled images, but it's - // 2-8x slower than the "GOOD" quality, so it's not always - // worth it. - SCALER_QUALITY_BEST = 3, - }; - - // Copies the block of pixels specified with |src_subrect| from |src_texture|, - // scales it to |dst_size|, and writes it into |out|. - // |src_size| is the size of |src_texture|. The result is in |out_color_type| - // format and is potentially flipped vertically to make it a correct image - // representation. |callback| is invoked with the copy result when the copy - // operation has completed. - // Note that the src_texture will have the min/mag filter set to GL_LINEAR - // and wrap_s/t set to CLAMP_TO_EDGE in this call. - void CropScaleReadbackAndCleanTexture( - GLuint src_texture, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - unsigned char* out, - const SkColorType out_color_type, - const base::Callback<void(bool)>& callback, - GLHelper::ScalerQuality quality); - - // Copies the block of pixels specified with |src_subrect| from |src_mailbox|, - // scales it to |dst_size|, and writes it into |out|. - // |src_size| is the size of |src_mailbox|. The result is in |out_color_type| - // format and is potentially flipped vertically to make it a correct image - // representation. |callback| is invoked with the copy result when the copy - // operation has completed. - // Note that the texture bound to src_mailbox will have the min/mag filter set - // to GL_LINEAR and wrap_s/t set to CLAMP_TO_EDGE in this call. src_mailbox is - // assumed to be GL_TEXTURE_2D. - void CropScaleReadbackAndCleanMailbox( - const gpu::Mailbox& src_mailbox, - const gpu::SyncToken& sync_token, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - unsigned char* out, - const SkColorType out_color_type, - const base::Callback<void(bool)>& callback, - GLHelper::ScalerQuality quality); - - // Copies the texture data out of |texture| into |out|. |size| is the - // size of the texture. No post processing is applied to the pixels. The - // texture is assumed to have a format of GL_RGBA with a pixel type of - // GL_UNSIGNED_BYTE. This is a blocking call that calls glReadPixels on the - // current OpenGL context. - void ReadbackTextureSync(GLuint texture, - const gfx::Rect& src_rect, - unsigned char* out, - SkColorType format); - - void ReadbackTextureAsync(GLuint texture, - const gfx::Size& dst_size, - unsigned char* out, - SkColorType color_type, - const base::Callback<void(bool)>& callback); - - // Creates a copy of the specified texture. |size| is the size of the texture. - // Note that the src_texture will have the min/mag filter set to GL_LINEAR - // and wrap_s/t set to CLAMP_TO_EDGE in this call. - GLuint CopyTexture(GLuint texture, const gfx::Size& size); - - // Creates a scaled copy of the specified texture. |src_size| is the size of - // the texture and |dst_size| is the size of the resulting copy. - // Note that the src_texture will have the min/mag filter set to GL_LINEAR - // and wrap_s/t set to CLAMP_TO_EDGE in this call. - GLuint CopyAndScaleTexture(GLuint texture, - const gfx::Size& src_size, - const gfx::Size& dst_size, - bool vertically_flip_texture, - ScalerQuality quality); - - // Returns the shader compiled from the source. - GLuint CompileShaderFromSource(const GLchar* source, GLenum type); - - // Copies all pixels from |previous_texture| into |texture| that are - // inside the region covered by |old_damage| but not part of |new_damage|. - void CopySubBufferDamage(GLenum target, - GLuint texture, - GLuint previous_texture, - const SkRegion& new_damage, - const SkRegion& old_damage); - - // Simply creates a texture. - GLuint CreateTexture(); - // Deletes a texture. - void DeleteTexture(GLuint texture_id); - - // Inserts a fence sync, flushes, and generates a sync token. - void GenerateSyncToken(gpu::SyncToken* sync_token); - - // Wait for the sync token before executing further GL commands. - void WaitSyncToken(const gpu::SyncToken& sync_token); - - // Creates a mailbox holder that is attached to the given texture id, with a - // sync point to wait on before using the mailbox. Returns a holder with an - // empty mailbox on failure. - // Note the texture is assumed to be GL_TEXTURE_2D. - gpu::MailboxHolder ProduceMailboxHolderFromTexture(GLuint texture_id); - - // Creates a texture and consumes a mailbox into it. Returns 0 on failure. - // Note the mailbox is assumed to be GL_TEXTURE_2D. - GLuint ConsumeMailboxToTexture(const gpu::Mailbox& mailbox, - const gpu::SyncToken& sync_token); - - // Resizes the texture's size to |size|. - void ResizeTexture(GLuint texture, const gfx::Size& size); - - // Copies the framebuffer data given in |rect| to |texture|. - void CopyTextureSubImage(GLuint texture, const gfx::Rect& rect); - - // Copies the all framebuffer data to |texture|. |size| specifies the - // size of the framebuffer. - void CopyTextureFullImage(GLuint texture, const gfx::Size& size); - - // Flushes GL commands. - void Flush(); - - // Force commands in the current command buffer to be executed before commands - // in other command buffers from the same process (ie channel to the GPU - // process). - void InsertOrderingBarrier(); - - // A scaler will cache all intermediate textures and programs - // needed to scale from a specified size to a destination size. - // If the source or destination sizes changes, you must create - // a new scaler. - class CONTENT_EXPORT ScalerInterface { - public: - ScalerInterface() {} - virtual ~ScalerInterface() {} - - // Note that the src_texture will have the min/mag filter set to GL_LINEAR - // and wrap_s/t set to CLAMP_TO_EDGE in this call. - virtual void Scale(GLuint source_texture, GLuint dest_texture) = 0; - virtual const gfx::Size& SrcSize() = 0; - virtual const gfx::Rect& SrcSubrect() = 0; - virtual const gfx::Size& DstSize() = 0; - }; - - // Note that the quality may be adjusted down if texture - // allocations fail or hardware doesn't support the requtested - // quality. Note that ScalerQuality enum is arranged in - // numerical order for simplicity. - ScalerInterface* CreateScaler(ScalerQuality quality, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool vertically_flip_texture, - bool swizzle); - - // Create a readback pipeline that will scale a subsection of the source - // texture, then convert it to YUV422 planar form and then read back that. - // This reduces the amount of memory read from GPU to CPU memory by a factor - // 2.6, which can be quite handy since readbacks have very limited speed - // on some platforms. All values in |dst_size| must be a multiple of two. If - // |use_mrt| is true, the pipeline will try to optimize the YUV conversion - // using the multi-render-target extension. |use_mrt| should only be set to - // false for testing. - ReadbackYUVInterface* CreateReadbackPipelineYUV(ScalerQuality quality, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool flip_vertically, - bool use_mrt); - - // Returns the maximum number of draw buffers available, - // 0 if GL_EXT_draw_buffers is not available. - GLint MaxDrawBuffers(); - - // Checks whether the readbback is supported for texture with the - // matching config. This doesnt check for cross format readbacks. - bool IsReadbackConfigSupported(SkColorType texture_format); - - protected: - class CopyTextureToImpl; - - // Creates |copy_texture_to_impl_| if NULL. - void InitCopyTextToImpl(); - // Creates |scaler_impl_| if NULL. - void InitScalerImpl(); - - enum ReadbackSwizzle { - kSwizzleNone = 0, - kSwizzleBGRA - }; - - gpu::gles2::GLES2Interface* gl_; - gpu::ContextSupport* context_support_; - scoped_ptr<CopyTextureToImpl> copy_texture_to_impl_; - scoped_ptr<GLHelperScaling> scaler_impl_; - scoped_ptr<GLHelperReadbackSupport> readback_support_; - - DISALLOW_COPY_AND_ASSIGN(GLHelper); -}; - -// Similar to a ScalerInterface, a yuv readback pipeline will -// cache a scaler and all intermediate textures and frame buffers -// needed to scale, crop, letterbox and read back a texture from -// the GPU into CPU-accessible RAM. A single readback pipeline -// can handle multiple outstanding readbacks at the same time, but -// if the source or destination sizes change, you'll need to create -// a new readback pipeline. -class CONTENT_EXPORT ReadbackYUVInterface { - public: - ReadbackYUVInterface() {} - virtual ~ReadbackYUVInterface() {} - - // Note that |target| must use YV12 format. |paste_location| specifies where - // the captured pixels that are read back will be placed in the video frame. - // The region defined by the |paste_location| and the |dst_size| specified in - // the call to CreateReadbackPipelineYUV() must be fully contained within - // |target->visible_rect()|. - virtual void ReadbackYUV(const gpu::Mailbox& mailbox, - const gpu::SyncToken& sync_token, - const scoped_refptr<media::VideoFrame>& target, - const gfx::Point& paste_location, - const base::Callback<void(bool)>& callback) = 0; - virtual GLHelper::ScalerInterface* scaler() = 0; -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_CLIENT_GL_HELPER_H_ diff --git a/chromium/content/common/gpu/client/gl_helper_benchmark.cc b/chromium/content/common/gpu/client/gl_helper_benchmark.cc deleted file mode 100644 index 9e751b37852..00000000000 --- a/chromium/content/common/gpu/client/gl_helper_benchmark.cc +++ /dev/null @@ -1,310 +0,0 @@ -// Copyright (c) 2012 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. - -// This file looks like a unit test, but it contains benchmarks and test -// utilities intended for manual evaluation of the scalers in -// gl_helper*. These tests produce output in the form of files and printouts, -// but cannot really "fail". There is no point in making these tests part -// of any test automation run. - -#include <stddef.h> -#include <stdio.h> -#include <cmath> -#include <string> -#include <vector> - -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#include <GLES2/gl2extchromium.h> - -#include "base/at_exit.h" -#include "base/command_line.h" -#include "base/files/file_util.h" -#include "base/macros.h" -#include "base/strings/stringprintf.h" -#include "base/time/time.h" -#include "build/build_config.h" -#include "content/common/gpu/client/gl_helper.h" -#include "content/common/gpu/client/gl_helper_scaling.h" -#include "content/public/test/unittest_test_suite.h" -#include "content/test/content_test_suite.h" -#include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkTypes.h" -#include "ui/gfx/codec/png_codec.h" -#include "ui/gl/gl_surface.h" - -#if defined(OS_MACOSX) -#include "base/mac/scoped_nsautorelease_pool.h" -#endif - -namespace content { - -using blink::WebGLId; -using blink::WebGraphicsContext3D; - -content::GLHelper::ScalerQuality kQualities[] = { - content::GLHelper::SCALER_QUALITY_BEST, - content::GLHelper::SCALER_QUALITY_GOOD, - content::GLHelper::SCALER_QUALITY_FAST, -}; - -const char *kQualityNames[] = { - "best", - "good", - "fast", -}; - -class GLHelperTest : public testing::Test { - protected: - void SetUp() override { - WebGraphicsContext3D::Attributes attributes; - bool lose_context_when_out_of_memory = false; - context_ = gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl:: - CreateOffscreenContext(attributes, lose_context_when_out_of_memory); - context_->InitializeOnCurrentThread(); - - helper_.reset( - new content::GLHelper(context_->GetGLInterface(), - context_->GetContextSupport())); - helper_scaling_.reset(new content::GLHelperScaling( - context_->GetGLInterface(), - helper_.get())); - } - - void TearDown() override { - helper_scaling_.reset(NULL); - helper_.reset(NULL); - context_.reset(NULL); - } - - - void LoadPngFileToSkBitmap(const base::FilePath& filename, - SkBitmap* bitmap) { - std::string compressed; - base::ReadFileToString(base::MakeAbsoluteFilePath(filename), &compressed); - ASSERT_TRUE(compressed.size()); - ASSERT_TRUE(gfx::PNGCodec::Decode( - reinterpret_cast<const unsigned char*>(compressed.data()), - compressed.size(), bitmap)); - } - - // Save the image to a png file. Used to create the initial test files. - void SaveToFile(SkBitmap* bitmap, const base::FilePath& filename) { - std::vector<unsigned char> compressed; - ASSERT_TRUE(gfx::PNGCodec::Encode( - static_cast<unsigned char*>(bitmap->getPixels()), - gfx::PNGCodec::FORMAT_BGRA, - gfx::Size(bitmap->width(), bitmap->height()), - static_cast<int>(bitmap->rowBytes()), - true, - std::vector<gfx::PNGCodec::Comment>(), - &compressed)); - ASSERT_TRUE(compressed.size()); - FILE* f = base::OpenFile(filename, "wb"); - ASSERT_TRUE(f); - ASSERT_EQ(fwrite(&*compressed.begin(), 1, compressed.size(), f), - compressed.size()); - base::CloseFile(f); - } - - scoped_ptr<gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl> - context_; - scoped_ptr<content::GLHelper> helper_; - scoped_ptr<content::GLHelperScaling> helper_scaling_; - std::deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_; -}; - - -TEST_F(GLHelperTest, ScaleBenchmark) { - int output_sizes[] = { 1920, 1080, - 1249, 720, // Output size on pixel - 256, 144 }; - int input_sizes[] = { 3200, 2040, - 2560, 1476, // Pixel tab size - 1920, 1080, - 1280, 720, - 800, 480, - 256, 144 }; - - for (size_t q = 0; q < arraysize(kQualities); q++) { - for (size_t outsize = 0; - outsize < arraysize(output_sizes); - outsize += 2) { - for (size_t insize = 0; - insize < arraysize(input_sizes); - insize += 2) { - WebGLId src_texture = context_->createTexture(); - WebGLId dst_texture = context_->createTexture(); - WebGLId framebuffer = context_->createFramebuffer(); - const gfx::Size src_size(input_sizes[insize], - input_sizes[insize + 1]); - const gfx::Size dst_size(output_sizes[outsize], - output_sizes[outsize + 1]); - SkBitmap input; - input.allocN32Pixels(src_size.width(), src_size.height()); - - SkBitmap output_pixels; - output_pixels.allocN32Pixels(dst_size.width(), dst_size.height()); - - context_->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); - context_->bindTexture(GL_TEXTURE_2D, dst_texture); - context_->texImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA, - dst_size.width(), - dst_size.height(), - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - 0); - context_->bindTexture(GL_TEXTURE_2D, src_texture); - context_->texImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA, - src_size.width(), - src_size.height(), - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - input.getPixels()); - - gfx::Rect src_subrect(0, 0, - src_size.width(), src_size.height()); - scoped_ptr<content::GLHelper::ScalerInterface> scaler( - helper_->CreateScaler(kQualities[q], - src_size, - src_subrect, - dst_size, - false, - false)); - // Scale once beforehand before we start measuring. - scaler->Scale(src_texture, dst_texture); - context_->finish(); - - base::TimeTicks start_time = base::TimeTicks::Now(); - int iterations = 0; - base::TimeTicks end_time; - while (true) { - for (int i = 0; i < 50; i++) { - iterations++; - scaler->Scale(src_texture, dst_texture); - context_->flush(); - } - context_->finish(); - end_time = base::TimeTicks::Now(); - if (iterations > 2000) { - break; - } - if ((end_time - start_time).InMillisecondsF() > 1000) { - break; - } - } - context_->deleteTexture(dst_texture); - context_->deleteTexture(src_texture); - context_->deleteFramebuffer(framebuffer); - - std::string name; - name = base::StringPrintf("scale_%dx%d_to_%dx%d_%s", - src_size.width(), - src_size.height(), - dst_size.width(), - dst_size.height(), - kQualityNames[q]); - - float ms = (end_time - start_time).InMillisecondsF() / iterations; - printf("*RESULT gpu_scale_time: %s=%.2f ms\n", name.c_str(), ms); - } - } - } -} - -// This is more of a test utility than a test. -// Put an PNG image called "testimage.png" in your -// current directory, then run this test. It will -// create testoutput_Q_P.png, where Q is the scaling -// mode and P is the scaling percentage taken from -// the table below. -TEST_F(GLHelperTest, DISABLED_ScaleTestImage) { - int percents[] = { - 230, - 180, - 150, - 110, - 90, - 70, - 50, - 49, - 40, - 20, - 10, - }; - - SkBitmap input; - LoadPngFileToSkBitmap(base::FilePath( - FILE_PATH_LITERAL("testimage.png")), &input); - - WebGLId framebuffer = context_->createFramebuffer(); - WebGLId src_texture = context_->createTexture(); - const gfx::Size src_size(input.width(), input.height()); - context_->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); - context_->bindTexture(GL_TEXTURE_2D, src_texture); - context_->texImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA, - src_size.width(), - src_size.height(), - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - input.getPixels()); - - for (size_t q = 0; q < arraysize(kQualities); q++) { - for (size_t p = 0; p < arraysize(percents); p++) { - const gfx::Size dst_size(input.width() * percents[p] / 100, - input.height() * percents[p] / 100); - WebGLId dst_texture = helper_->CopyAndScaleTexture( - src_texture, - src_size, - dst_size, - false, - kQualities[q]); - - SkBitmap output_pixels; - output_pixels.allocN32Pixels(dst_size.width(), dst_size.height()); - - helper_->ReadbackTextureSync( - dst_texture, - gfx::Rect(0, 0, - dst_size.width(), - dst_size.height()), - static_cast<unsigned char *>(output_pixels.getPixels()), - kN32_SkColorType); - context_->deleteTexture(dst_texture); - std::string filename = base::StringPrintf("testoutput_%s_%d.ppm", - kQualityNames[q], - percents[p]); - VLOG(0) << "Writing " << filename; - SaveToFile(&output_pixels, base::FilePath::FromUTF8Unsafe(filename)); - } - } - context_->deleteTexture(src_texture); - context_->deleteFramebuffer(framebuffer); -} - -} // namespace - -// These tests needs to run against a proper GL environment, so we -// need to set it up before we can run the tests. -int main(int argc, char** argv) { - base::CommandLine::Init(argc, argv); - base::TestSuite* suite = new content::ContentTestSuite(argc, argv); -#if defined(OS_MACOSX) - base::mac::ScopedNSAutoreleasePool pool; -#endif - gfx::GLSurface::InitializeOneOff(); - - return content::UnitTestTestSuite(suite).Run(); -} diff --git a/chromium/content/common/gpu/client/gl_helper_readback_support.cc b/chromium/content/common/gpu/client/gl_helper_readback_support.cc deleted file mode 100644 index e773ca90782..00000000000 --- a/chromium/content/common/gpu/client/gl_helper_readback_support.cc +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2014 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 "content/common/gpu/client/gl_helper_readback_support.h" -#include "base/logging.h" -#include "gpu/GLES2/gl2extchromium.h" -#include "third_party/skia/include/core/SkImageInfo.h" - -namespace content { - -GLHelperReadbackSupport::GLHelperReadbackSupport(gpu::gles2::GLES2Interface* gl) - : gl_(gl) { - InitializeReadbackSupport(); -} - -GLHelperReadbackSupport::~GLHelperReadbackSupport() {} - -void GLHelperReadbackSupport::InitializeReadbackSupport() { - // We are concerned about 16, 32-bit formats only. The below are the most - // used 16, 32-bit formats. In future if any new format support is needed - // that should be added here. Initialize the array with - // GLHelperReadbackSupport::NOT_SUPPORTED as we dont know the supported - // formats yet. - for (int i = 0; i <= kLastEnum_SkColorType; ++i) { - format_support_table_[i] = GLHelperReadbackSupport::NOT_SUPPORTED; - } - // TODO(sikugu): kAlpha_8_SkColorType support check is failing on mesa. - // See crbug.com/415667. - CheckForReadbackSupport(kRGB_565_SkColorType); - CheckForReadbackSupport(kARGB_4444_SkColorType); - CheckForReadbackSupport(kRGBA_8888_SkColorType); - CheckForReadbackSupport(kBGRA_8888_SkColorType); - // Further any formats, support should be checked here. -} - -void GLHelperReadbackSupport::CheckForReadbackSupport( - SkColorType texture_format) { - bool supports_format = false; - switch (texture_format) { - case kRGB_565_SkColorType: - supports_format = SupportsFormat(GL_RGB, GL_UNSIGNED_SHORT_5_6_5); - break; - case kRGBA_8888_SkColorType: - // This is the baseline, assume always true. - supports_format = true; - break; - case kBGRA_8888_SkColorType: - supports_format = SupportsFormat(GL_BGRA_EXT, GL_UNSIGNED_BYTE); - break; - case kARGB_4444_SkColorType: - supports_format = false; - break; - default: - NOTREACHED(); - supports_format = false; - break; - } - DCHECK((int)texture_format <= (int)kLastEnum_SkColorType); - format_support_table_[texture_format] = - supports_format ? GLHelperReadbackSupport::SUPPORTED - : GLHelperReadbackSupport::NOT_SUPPORTED; -} - -void GLHelperReadbackSupport::GetAdditionalFormat(GLenum format, - GLenum type, - GLenum* format_out, - GLenum* type_out) { - for (unsigned int i = 0; i < format_cache_.size(); i++) { - if (format_cache_[i].format == format && format_cache_[i].type == type) { - *format_out = format_cache_[i].read_format; - *type_out = format_cache_[i].read_type; - return; - } - } - - const int kTestSize = 64; - content::ScopedTexture dst_texture(gl_); - ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture); - gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - gl_->TexImage2D( - GL_TEXTURE_2D, 0, format, kTestSize, kTestSize, 0, format, type, NULL); - ScopedFramebuffer dst_framebuffer(gl_); - ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, - dst_framebuffer); - gl_->FramebufferTexture2D( - GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_texture, 0); - GLint format_tmp = 0, type_tmp = 0; - gl_->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &format_tmp); - gl_->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &type_tmp); - *format_out = format_tmp; - *type_out = type_tmp; - - struct FormatCacheEntry entry = { format, type, *format_out, *type_out }; - format_cache_.push_back(entry); -} - -bool GLHelperReadbackSupport::SupportsFormat(GLenum format, GLenum type) { - // GLES2.0 Specification says this pairing is always supported - // with additional format from GL_IMPLEMENTATION_COLOR_READ_FORMAT/TYPE - if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) - return true; - - if (format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE) { - const GLubyte* tmp = gl_->GetString(GL_EXTENSIONS); - if (tmp) { - std::string extensions = - " " + std::string(reinterpret_cast<const char*>(tmp)) + " "; - if (extensions.find(" GL_EXT_read_format_bgra ") != std::string::npos) { - return true; - } - } - } - - bool supports_format = false; - GLenum ext_format = 0, ext_type = 0; - GetAdditionalFormat(format, type, &ext_format, &ext_type); - if ((ext_format == format) && (ext_type == type)) { - supports_format = true; - } - return supports_format; -} - -GLHelperReadbackSupport::FormatSupport -GLHelperReadbackSupport::GetReadbackConfig(SkColorType color_type, - bool can_swizzle, - GLenum* format, - GLenum* type, - size_t* bytes_per_pixel) { - DCHECK(format && type && bytes_per_pixel); - *bytes_per_pixel = 4; - *type = GL_UNSIGNED_BYTE; - GLenum new_format = 0, new_type = 0; - switch (color_type) { - case kRGB_565_SkColorType: - if (format_support_table_[color_type] == - GLHelperReadbackSupport::SUPPORTED) { - *format = GL_RGB; - *type = GL_UNSIGNED_SHORT_5_6_5; - *bytes_per_pixel = 2; - return GLHelperReadbackSupport::SUPPORTED; - } - break; - case kRGBA_8888_SkColorType: - *format = GL_RGBA; - if (can_swizzle) { - // If GL_BGRA_EXT is advertised as the readback format through - // GL_IMPLEMENTATION_COLOR_READ_FORMAT then assume it is preferred by - // the implementation for performance. - GetAdditionalFormat(*format, *type, &new_format, &new_type); - - if (new_format == GL_BGRA_EXT && new_type == GL_UNSIGNED_BYTE) { - *format = GL_BGRA_EXT; - return GLHelperReadbackSupport::SWIZZLE; - } - } - return GLHelperReadbackSupport::SUPPORTED; - case kBGRA_8888_SkColorType: - *format = GL_BGRA_EXT; - if (format_support_table_[color_type] == - GLHelperReadbackSupport::SUPPORTED) - return GLHelperReadbackSupport::SUPPORTED; - - if (can_swizzle) { - *format = GL_RGBA; - return GLHelperReadbackSupport::SWIZZLE; - } - - break; - case kARGB_4444_SkColorType: - return GLHelperReadbackSupport::NOT_SUPPORTED; - default: - NOTREACHED(); - break; - } - - return GLHelperReadbackSupport::NOT_SUPPORTED; -} - -} // namespace content diff --git a/chromium/content/common/gpu/client/gl_helper_readback_support.h b/chromium/content/common/gpu/client/gl_helper_readback_support.h deleted file mode 100644 index f9329e9912c..00000000000 --- a/chromium/content/common/gpu/client/gl_helper_readback_support.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2014 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 CONTENT_COMMON_GPU_CLIENT_GL_HELPER_READBACK_SUPPORT_H_ -#define CONTENT_COMMON_GPU_CLIENT_GL_HELPER_READBACK_SUPPORT_H_ - -#include <stddef.h> - -#include <vector> - -#include "content/common/gpu/client/gl_helper.h" - -namespace content { - -class CONTENT_EXPORT GLHelperReadbackSupport { - public: - enum FormatSupport { SUPPORTED, SWIZZLE, NOT_SUPPORTED }; - - GLHelperReadbackSupport(gpu::gles2::GLES2Interface* gl); - - ~GLHelperReadbackSupport(); - - // For a given color type retrieve whether readback is supported and if so - // how it should be performed. The |format|, |type| and |bytes_per_pixel| are - // the values that should be used with glReadPixels to facilitate the - // readback. If |can_swizzle| is true then this method will return SWIZZLE if - // the data needs to be swizzled before using the returned |format| otherwise - // the method will return SUPPORTED to indicate that readback is permitted of - // this color othewise NOT_SUPPORTED will be returned. This method always - // overwrites the out values irrespective of the return value. - FormatSupport GetReadbackConfig(SkColorType color_type, - bool can_swizzle, - GLenum* format, - GLenum* type, - size_t* bytes_per_pixel); - // Provides the additional readback format/type pairing for a render target - // of a given format/type pairing - void GetAdditionalFormat(GLenum format, GLenum type, GLenum *format_out, - GLenum *type_out); - private: - struct FormatCacheEntry { - GLenum format; - GLenum type; - GLenum read_format; - GLenum read_type; - }; - - // This populates the format_support_table with the list of supported - // formats. - void InitializeReadbackSupport(); - - // This api is called once per format and it is done in the - // InitializeReadbackSupport. We should not use this any where - // except the InitializeReadbackSupport.Calling this at other places - // can distrub the state of normal gl operations. - void CheckForReadbackSupport(SkColorType texture_format); - - // Helper functions for checking the supported texture formats. - // Avoid using this API in between texture operations, as this does some - // teture opertions (bind, attach) internally. - bool SupportsFormat(GLenum format, GLenum type); - - FormatSupport format_support_table_[kLastEnum_SkColorType + 1]; - - gpu::gles2::GLES2Interface* gl_; - std::vector<struct FormatCacheEntry> format_cache_; -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_CLIENT_GL_HELPER_READBACK_SUPPORT_H_ diff --git a/chromium/content/common/gpu/client/gl_helper_scaling.cc b/chromium/content/common/gpu/client/gl_helper_scaling.cc deleted file mode 100644 index f4cd6b3eb52..00000000000 --- a/chromium/content/common/gpu/client/gl_helper_scaling.cc +++ /dev/null @@ -1,934 +0,0 @@ -// Copyright (c) 2012 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 "content/common/gpu/client/gl_helper_scaling.h" - -#include <stddef.h> - -#include <deque> -#include <string> -#include <vector> - -#include "base/bind.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "base/time/time.h" -#include "base/trace_event/trace_event.h" -#include "gpu/command_buffer/client/gles2_interface.h" -#include "third_party/skia/include/core/SkRegion.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/size.h" - -using gpu::gles2::GLES2Interface; - -namespace content { - -GLHelperScaling::GLHelperScaling(GLES2Interface* gl, GLHelper* helper) - : gl_(gl), helper_(helper), vertex_attributes_buffer_(gl_) { - InitBuffer(); -} - -GLHelperScaling::~GLHelperScaling() {} - -// Used to keep track of a generated shader program. The program -// is passed in as text through Setup and is used by calling -// UseProgram() with the right parameters. Note that |gl_| -// and |helper_| are assumed to live longer than this program. -class ShaderProgram : public base::RefCounted<ShaderProgram> { - public: - ShaderProgram(GLES2Interface* gl, GLHelper* helper) - : gl_(gl), - helper_(helper), - program_(gl_->CreateProgram()), - position_location_(-1), - texcoord_location_(-1), - src_subrect_location_(-1), - src_pixelsize_location_(-1), - dst_pixelsize_location_(-1), - scaling_vector_location_(-1), - color_weights_location_(-1) {} - - // Compile shader program. - void Setup(const GLchar* vertex_shader_text, - const GLchar* fragment_shader_text); - - // UseProgram must be called with GL_TEXTURE_2D bound to the - // source texture and GL_ARRAY_BUFFER bound to a vertex - // attribute buffer. - void UseProgram(const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool scale_x, - bool flip_y, - GLfloat color_weights[4]); - - bool Initialized() const { return position_location_ != -1; } - - private: - friend class base::RefCounted<ShaderProgram>; - ~ShaderProgram() { gl_->DeleteProgram(program_); } - - GLES2Interface* gl_; - GLHelper* helper_; - - // A program for copying a source texture into a destination texture. - GLuint program_; - - // The location of the position in the program. - GLint position_location_; - // The location of the texture coordinate in the program. - GLint texcoord_location_; - // The location of the source texture in the program. - GLint texture_location_; - // The location of the texture coordinate of - // the sub-rectangle in the program. - GLint src_subrect_location_; - // Location of size of source image in pixels. - GLint src_pixelsize_location_; - // Location of size of destination image in pixels. - GLint dst_pixelsize_location_; - // Location of vector for scaling direction. - GLint scaling_vector_location_; - // Location of color weights. - GLint color_weights_location_; - - DISALLOW_COPY_AND_ASSIGN(ShaderProgram); -}; - -// Implementation of a single stage in a scaler pipeline. If the pipeline has -// multiple stages, it calls Scale() on the subscaler, then further scales the -// output. Caches textures and framebuffers to avoid allocating/deleting -// them once per frame, which can be expensive on some drivers. -class ScalerImpl : public GLHelper::ScalerInterface, - public GLHelperScaling::ShaderInterface { - public: - // |gl| and |copy_impl| are expected to live longer than this object. - // |src_size| is the size of the input texture in pixels. - // |dst_size| is the size of the output texutre in pixels. - // |src_subrect| is the portion of the src to copy to the output texture. - // If |scale_x| is true, we are scaling along the X axis, otherwise Y. - // If we are scaling in both X and Y, |scale_x| is ignored. - // If |vertically_flip_texture| is true, output will be upside-down. - // If |swizzle| is true, RGBA will be transformed into BGRA. - // |color_weights| are only used together with SHADER_PLANAR to specify - // how to convert RGB colors into a single value. - ScalerImpl(GLES2Interface* gl, - GLHelperScaling* scaler_helper, - const GLHelperScaling::ScalerStage& scaler_stage, - ScalerImpl* subscaler, - const float* color_weights) - : gl_(gl), - scaler_helper_(scaler_helper), - spec_(scaler_stage), - intermediate_texture_(0), - dst_framebuffer_(gl), - subscaler_(subscaler) { - if (color_weights) { - color_weights_[0] = color_weights[0]; - color_weights_[1] = color_weights[1]; - color_weights_[2] = color_weights[2]; - color_weights_[3] = color_weights[3]; - } else { - color_weights_[0] = 0.0; - color_weights_[1] = 0.0; - color_weights_[2] = 0.0; - color_weights_[3] = 0.0; - } - shader_program_ = - scaler_helper_->GetShaderProgram(spec_.shader, spec_.swizzle); - - if (subscaler_) { - intermediate_texture_ = 0u; - gl_->GenTextures(1, &intermediate_texture_); - ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, - intermediate_texture_); - gl_->TexImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA, - spec_.src_size.width(), - spec_.src_size.height(), - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - NULL); - } - } - - ~ScalerImpl() override { - if (intermediate_texture_) { - gl_->DeleteTextures(1, &intermediate_texture_); - } - } - - // GLHelperShader::ShaderInterface implementation. - void Execute(GLuint source_texture, - const std::vector<GLuint>& dest_textures) override { - if (subscaler_) { - subscaler_->Scale(source_texture, intermediate_texture_); - source_texture = intermediate_texture_; - } - - ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder( - gl_, dst_framebuffer_); - DCHECK_GT(dest_textures.size(), 0U); - scoped_ptr<GLenum[]> buffers(new GLenum[dest_textures.size()]); - for (size_t t = 0; t < dest_textures.size(); t++) { - ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dest_textures[t]); - gl_->FramebufferTexture2D(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0 + t, - GL_TEXTURE_2D, - dest_textures[t], - 0); - buffers[t] = GL_COLOR_ATTACHMENT0 + t; - } - ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, source_texture); - - gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - ScopedBufferBinder<GL_ARRAY_BUFFER> buffer_binder( - gl_, scaler_helper_->vertex_attributes_buffer_); - shader_program_->UseProgram(spec_.src_size, - spec_.src_subrect, - spec_.dst_size, - spec_.scale_x, - spec_.vertically_flip_texture, - color_weights_); - gl_->Viewport(0, 0, spec_.dst_size.width(), spec_.dst_size.height()); - - if (dest_textures.size() > 1) { - DCHECK_LE(static_cast<int>(dest_textures.size()), - scaler_helper_->helper_->MaxDrawBuffers()); - gl_->DrawBuffersEXT(dest_textures.size(), buffers.get()); - } - // Conduct texture mapping by drawing a quad composed of two triangles. - gl_->DrawArrays(GL_TRIANGLE_STRIP, 0, 4); - if (dest_textures.size() > 1) { - // Set the draw buffers back to not confuse others. - gl_->DrawBuffersEXT(1, &buffers[0]); - } - } - - // GLHelper::ScalerInterface implementation. - void Scale(GLuint source_texture, GLuint dest_texture) override { - std::vector<GLuint> tmp(1); - tmp[0] = dest_texture; - Execute(source_texture, tmp); - } - - const gfx::Size& SrcSize() override { - if (subscaler_) { - return subscaler_->SrcSize(); - } - return spec_.src_size; - } - const gfx::Rect& SrcSubrect() override { - if (subscaler_) { - return subscaler_->SrcSubrect(); - } - return spec_.src_subrect; - } - const gfx::Size& DstSize() override { return spec_.dst_size; } - - private: - GLES2Interface* gl_; - GLHelperScaling* scaler_helper_; - GLHelperScaling::ScalerStage spec_; - GLfloat color_weights_[4]; - GLuint intermediate_texture_; - scoped_refptr<ShaderProgram> shader_program_; - ScopedFramebuffer dst_framebuffer_; - scoped_ptr<ScalerImpl> subscaler_; -}; - -GLHelperScaling::ScalerStage::ScalerStage(ShaderType shader_, - gfx::Size src_size_, - gfx::Rect src_subrect_, - gfx::Size dst_size_, - bool scale_x_, - bool vertically_flip_texture_, - bool swizzle_) - : shader(shader_), - src_size(src_size_), - src_subrect(src_subrect_), - dst_size(dst_size_), - scale_x(scale_x_), - vertically_flip_texture(vertically_flip_texture_), - swizzle(swizzle_) {} - -// The important inputs for this function is |x_ops| and -// |y_ops|. They represent scaling operations to be done -// on an imag of size |src_size|. If |quality| is SCALER_QUALITY_BEST, -// then we will interpret these scale operations literally and we'll -// create one scaler stage for each ScaleOp. However, if |quality| -// is SCALER_QUALITY_GOOD, then we can do a whole bunch of optimizations -// by combining two or more ScaleOps in to a single scaler stage. -// Normally we process ScaleOps from |y_ops| first and |x_ops| after -// all |y_ops| are processed, but sometimes we can combine one or more -// operation from both queues essentially for free. This is the reason -// why |x_ops| and |y_ops| aren't just one single queue. -void GLHelperScaling::ConvertScalerOpsToScalerStages( - GLHelper::ScalerQuality quality, - gfx::Size src_size, - gfx::Rect src_subrect, - const gfx::Size& dst_size, - bool vertically_flip_texture, - bool swizzle, - std::deque<GLHelperScaling::ScaleOp>* x_ops, - std::deque<GLHelperScaling::ScaleOp>* y_ops, - std::vector<ScalerStage>* scaler_stages) { - while (!x_ops->empty() || !y_ops->empty()) { - gfx::Size intermediate_size = src_subrect.size(); - std::deque<ScaleOp>* current_queue = NULL; - - if (!y_ops->empty()) { - current_queue = y_ops; - } else { - current_queue = x_ops; - } - - ShaderType current_shader = SHADER_BILINEAR; - switch (current_queue->front().scale_factor) { - case 0: - if (quality == GLHelper::SCALER_QUALITY_BEST) { - current_shader = SHADER_BICUBIC_UPSCALE; - } - break; - case 2: - if (quality == GLHelper::SCALER_QUALITY_BEST) { - current_shader = SHADER_BICUBIC_HALF_1D; - } - break; - case 3: - DCHECK(quality != GLHelper::SCALER_QUALITY_BEST); - current_shader = SHADER_BILINEAR3; - break; - default: - NOTREACHED(); - } - bool scale_x = current_queue->front().scale_x; - current_queue->front().UpdateSize(&intermediate_size); - current_queue->pop_front(); - - // Optimization: Sometimes we can combine 2-4 scaling operations into - // one operation. - if (quality == GLHelper::SCALER_QUALITY_GOOD) { - if (!current_queue->empty() && current_shader == SHADER_BILINEAR) { - // Combine two steps in the same dimension. - current_queue->front().UpdateSize(&intermediate_size); - current_queue->pop_front(); - current_shader = SHADER_BILINEAR2; - if (!current_queue->empty()) { - // Combine three steps in the same dimension. - current_queue->front().UpdateSize(&intermediate_size); - current_queue->pop_front(); - current_shader = SHADER_BILINEAR4; - } - } - // Check if we can combine some steps in the other dimension as well. - // Since all shaders currently use GL_LINEAR, we can easily scale up - // or scale down by exactly 2x at the same time as we do another - // operation. Currently, the following mergers are supported: - // * 1 bilinear Y-pass with 1 bilinear X-pass (up or down) - // * 2 bilinear Y-passes with 2 bilinear X-passes - // * 1 bilinear Y-pass with N bilinear X-pass - // * N bilinear Y-passes with 1 bilinear X-pass (down only) - // Measurements indicate that generalizing this for 3x3 and 4x4 - // makes it slower on some platforms, such as the Pixel. - if (!scale_x && x_ops->size() > 0 && x_ops->front().scale_factor <= 2) { - int x_passes = 0; - if (current_shader == SHADER_BILINEAR2 && x_ops->size() >= 2) { - // 2y + 2x passes - x_passes = 2; - current_shader = SHADER_BILINEAR2X2; - } else if (current_shader == SHADER_BILINEAR) { - // 1y + Nx passes - scale_x = true; - switch (x_ops->size()) { - case 0: - NOTREACHED(); - case 1: - if (x_ops->front().scale_factor == 3) { - current_shader = SHADER_BILINEAR3; - } - x_passes = 1; - break; - case 2: - x_passes = 2; - current_shader = SHADER_BILINEAR2; - break; - default: - x_passes = 3; - current_shader = SHADER_BILINEAR4; - break; - } - } else if (x_ops->front().scale_factor == 2) { - // Ny + 1x-downscale - x_passes = 1; - } - - for (int i = 0; i < x_passes; i++) { - x_ops->front().UpdateSize(&intermediate_size); - x_ops->pop_front(); - } - } - } - - scaler_stages->push_back(ScalerStage(current_shader, - src_size, - src_subrect, - intermediate_size, - scale_x, - vertically_flip_texture, - swizzle)); - src_size = intermediate_size; - src_subrect = gfx::Rect(intermediate_size); - vertically_flip_texture = false; - swizzle = false; - } -} - -void GLHelperScaling::ComputeScalerStages( - GLHelper::ScalerQuality quality, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool vertically_flip_texture, - bool swizzle, - std::vector<ScalerStage>* scaler_stages) { - if (quality == GLHelper::SCALER_QUALITY_FAST || - src_subrect.size() == dst_size) { - scaler_stages->push_back(ScalerStage(SHADER_BILINEAR, - src_size, - src_subrect, - dst_size, - false, - vertically_flip_texture, - swizzle)); - return; - } - - std::deque<GLHelperScaling::ScaleOp> x_ops, y_ops; - GLHelperScaling::ScaleOp::AddOps(src_subrect.width(), - dst_size.width(), - true, - quality == GLHelper::SCALER_QUALITY_GOOD, - &x_ops); - GLHelperScaling::ScaleOp::AddOps(src_subrect.height(), - dst_size.height(), - false, - quality == GLHelper::SCALER_QUALITY_GOOD, - &y_ops); - - ConvertScalerOpsToScalerStages(quality, - src_size, - src_subrect, - dst_size, - vertically_flip_texture, - swizzle, - &x_ops, - &y_ops, - scaler_stages); -} - -GLHelper::ScalerInterface* GLHelperScaling::CreateScaler( - GLHelper::ScalerQuality quality, - gfx::Size src_size, - gfx::Rect src_subrect, - const gfx::Size& dst_size, - bool vertically_flip_texture, - bool swizzle) { - std::vector<ScalerStage> scaler_stages; - ComputeScalerStages(quality, - src_size, - src_subrect, - dst_size, - vertically_flip_texture, - swizzle, - &scaler_stages); - - ScalerImpl* ret = NULL; - for (unsigned int i = 0; i < scaler_stages.size(); i++) { - ret = new ScalerImpl(gl_, this, scaler_stages[i], ret, NULL); - } - return ret; -} - -GLHelper::ScalerInterface* GLHelperScaling::CreatePlanarScaler( - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool vertically_flip_texture, - bool swizzle, - const float color_weights[4]) { - ScalerStage stage(SHADER_PLANAR, - src_size, - src_subrect, - dst_size, - true, - vertically_flip_texture, - swizzle); - return new ScalerImpl(gl_, this, stage, NULL, color_weights); -} - -GLHelperScaling::ShaderInterface* GLHelperScaling::CreateYuvMrtShader( - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool vertically_flip_texture, - bool swizzle, - ShaderType shader) { - DCHECK(shader == SHADER_YUV_MRT_PASS1 || shader == SHADER_YUV_MRT_PASS2); - ScalerStage stage(shader, - src_size, - src_subrect, - dst_size, - true, - vertically_flip_texture, - swizzle); - return new ScalerImpl(gl_, this, stage, NULL, NULL); -} - -const GLfloat GLHelperScaling::kVertexAttributes[] = { - -1.0f, -1.0f, 0.0f, 0.0f, // vertex 0 - 1.0f, -1.0f, 1.0f, 0.0f, // vertex 1 - -1.0f, 1.0f, 0.0f, 1.0f, // vertex 2 - 1.0f, 1.0f, 1.0f, 1.0f, }; // vertex 3 - -void GLHelperScaling::InitBuffer() { - ScopedBufferBinder<GL_ARRAY_BUFFER> buffer_binder(gl_, - vertex_attributes_buffer_); - gl_->BufferData(GL_ARRAY_BUFFER, - sizeof(kVertexAttributes), - kVertexAttributes, - GL_STATIC_DRAW); -} - -scoped_refptr<ShaderProgram> GLHelperScaling::GetShaderProgram(ShaderType type, - bool swizzle) { - ShaderProgramKeyType key(type, swizzle); - scoped_refptr<ShaderProgram>& cache_entry(shader_programs_[key]); - if (!cache_entry.get()) { - cache_entry = new ShaderProgram(gl_, helper_); - std::basic_string<GLchar> vertex_program; - std::basic_string<GLchar> fragment_program; - std::basic_string<GLchar> vertex_header; - std::basic_string<GLchar> fragment_directives; - std::basic_string<GLchar> fragment_header; - std::basic_string<GLchar> shared_variables; - - vertex_header.append( - "precision highp float;\n" - "attribute vec2 a_position;\n" - "attribute vec2 a_texcoord;\n" - "uniform vec4 src_subrect;\n"); - - fragment_header.append( - "precision mediump float;\n" - "uniform sampler2D s_texture;\n"); - - vertex_program.append( - " gl_Position = vec4(a_position, 0.0, 1.0);\n" - " vec2 texcoord = src_subrect.xy + a_texcoord * src_subrect.zw;\n"); - - switch (type) { - case SHADER_BILINEAR: - shared_variables.append("varying vec2 v_texcoord;\n"); - vertex_program.append(" v_texcoord = texcoord;\n"); - fragment_program.append( - " gl_FragColor = texture2D(s_texture, v_texcoord);\n"); - break; - - case SHADER_BILINEAR2: - // This is equivialent to two passes of the BILINEAR shader above. - // It can be used to scale an image down 1.0x-2.0x in either dimension, - // or exactly 4x. - shared_variables.append( - "varying vec4 v_texcoords;\n"); // 2 texcoords packed in one quad - vertex_header.append( - "uniform vec2 scaling_vector;\n" - "uniform vec2 dst_pixelsize;\n"); - vertex_program.append( - " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" - " step /= 4.0;\n" - " v_texcoords.xy = texcoord + step;\n" - " v_texcoords.zw = texcoord - step;\n"); - - fragment_program.append( - " gl_FragColor = (texture2D(s_texture, v_texcoords.xy) +\n" - " texture2D(s_texture, v_texcoords.zw)) / 2.0;\n"); - break; - - case SHADER_BILINEAR3: - // This is kind of like doing 1.5 passes of the BILINEAR shader. - // It can be used to scale an image down 1.5x-3.0x, or exactly 6x. - shared_variables.append( - "varying vec4 v_texcoords1;\n" // 2 texcoords packed in one quad - "varying vec2 v_texcoords2;\n"); - vertex_header.append( - "uniform vec2 scaling_vector;\n" - "uniform vec2 dst_pixelsize;\n"); - vertex_program.append( - " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" - " step /= 3.0;\n" - " v_texcoords1.xy = texcoord + step;\n" - " v_texcoords1.zw = texcoord;\n" - " v_texcoords2 = texcoord - step;\n"); - fragment_program.append( - " gl_FragColor = (texture2D(s_texture, v_texcoords1.xy) +\n" - " texture2D(s_texture, v_texcoords1.zw) +\n" - " texture2D(s_texture, v_texcoords2)) / 3.0;\n"); - break; - - case SHADER_BILINEAR4: - // This is equivialent to three passes of the BILINEAR shader above, - // It can be used to scale an image down 2.0x-4.0x or exactly 8x. - shared_variables.append("varying vec4 v_texcoords[2];\n"); - vertex_header.append( - "uniform vec2 scaling_vector;\n" - "uniform vec2 dst_pixelsize;\n"); - vertex_program.append( - " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" - " step /= 8.0;\n" - " v_texcoords[0].xy = texcoord - step * 3.0;\n" - " v_texcoords[0].zw = texcoord - step;\n" - " v_texcoords[1].xy = texcoord + step;\n" - " v_texcoords[1].zw = texcoord + step * 3.0;\n"); - fragment_program.append( - " gl_FragColor = (\n" - " texture2D(s_texture, v_texcoords[0].xy) +\n" - " texture2D(s_texture, v_texcoords[0].zw) +\n" - " texture2D(s_texture, v_texcoords[1].xy) +\n" - " texture2D(s_texture, v_texcoords[1].zw)) / 4.0;\n"); - break; - - case SHADER_BILINEAR2X2: - // This is equivialent to four passes of the BILINEAR shader above. - // Two in each dimension. It can be used to scale an image down - // 1.0x-2.0x in both X and Y directions. Or, it could be used to - // scale an image down by exactly 4x in both dimensions. - shared_variables.append("varying vec4 v_texcoords[2];\n"); - vertex_header.append("uniform vec2 dst_pixelsize;\n"); - vertex_program.append( - " vec2 step = src_subrect.zw / 4.0 / dst_pixelsize;\n" - " v_texcoords[0].xy = texcoord + vec2(step.x, step.y);\n" - " v_texcoords[0].zw = texcoord + vec2(step.x, -step.y);\n" - " v_texcoords[1].xy = texcoord + vec2(-step.x, step.y);\n" - " v_texcoords[1].zw = texcoord + vec2(-step.x, -step.y);\n"); - fragment_program.append( - " gl_FragColor = (\n" - " texture2D(s_texture, v_texcoords[0].xy) +\n" - " texture2D(s_texture, v_texcoords[0].zw) +\n" - " texture2D(s_texture, v_texcoords[1].xy) +\n" - " texture2D(s_texture, v_texcoords[1].zw)) / 4.0;\n"); - break; - - case SHADER_BICUBIC_HALF_1D: - // This scales down texture by exactly half in one dimension. - // directions in one pass. We use bilinear lookup to reduce - // the number of texture reads from 8 to 4 - shared_variables.append( - "const float CenterDist = 99.0 / 140.0;\n" - "const float LobeDist = 11.0 / 4.0;\n" - "const float CenterWeight = 35.0 / 64.0;\n" - "const float LobeWeight = -3.0 / 64.0;\n" - "varying vec4 v_texcoords[2];\n"); - vertex_header.append( - "uniform vec2 scaling_vector;\n" - "uniform vec2 src_pixelsize;\n"); - vertex_program.append( - " vec2 step = src_subrect.zw * scaling_vector / src_pixelsize;\n" - " v_texcoords[0].xy = texcoord - LobeDist * step;\n" - " v_texcoords[0].zw = texcoord - CenterDist * step;\n" - " v_texcoords[1].xy = texcoord + CenterDist * step;\n" - " v_texcoords[1].zw = texcoord + LobeDist * step;\n"); - fragment_program.append( - " gl_FragColor = \n" - // Lobe pixels - " (texture2D(s_texture, v_texcoords[0].xy) +\n" - " texture2D(s_texture, v_texcoords[1].zw)) *\n" - " LobeWeight +\n" - // Center pixels - " (texture2D(s_texture, v_texcoords[0].zw) +\n" - " texture2D(s_texture, v_texcoords[1].xy)) *\n" - " CenterWeight;\n"); - break; - - case SHADER_BICUBIC_UPSCALE: - // When scaling up, we need 4 texture reads, but we can - // save some instructions because will know in which range of - // the bicubic function each call call to the bicubic function - // will be in. - // Also, when sampling the bicubic function like this, the sum - // is always exactly one, so we can skip normalization as well. - shared_variables.append("varying vec2 v_texcoord;\n"); - vertex_program.append(" v_texcoord = texcoord;\n"); - fragment_header.append( - "uniform vec2 src_pixelsize;\n" - "uniform vec2 scaling_vector;\n" - "const float a = -0.5;\n" - // This function is equivialent to calling the bicubic - // function with x-1, x, 1-x and 2-x - // (assuming 0 <= x < 1) - "vec4 filt4(float x) {\n" - " return vec4(x * x * x, x * x, x, 1) *\n" - " mat4( a, -2.0 * a, a, 0.0,\n" - " a + 2.0, -a - 3.0, 0.0, 1.0,\n" - " -a - 2.0, 3.0 + 2.0 * a, -a, 0.0,\n" - " -a, a, 0.0, 0.0);\n" - "}\n" - "mat4 pixels_x(vec2 pos, vec2 step) {\n" - " return mat4(\n" - " texture2D(s_texture, pos - step),\n" - " texture2D(s_texture, pos),\n" - " texture2D(s_texture, pos + step),\n" - " texture2D(s_texture, pos + step * 2.0));\n" - "}\n"); - fragment_program.append( - " vec2 pixel_pos = v_texcoord * src_pixelsize - \n" - " scaling_vector / 2.0;\n" - " float frac = fract(dot(pixel_pos, scaling_vector));\n" - " vec2 base = (floor(pixel_pos) + vec2(0.5)) / src_pixelsize;\n" - " vec2 step = scaling_vector / src_pixelsize;\n" - " gl_FragColor = pixels_x(base, step) * filt4(frac);\n"); - break; - - case SHADER_PLANAR: - // Converts four RGBA pixels into one pixel. Each RGBA - // pixel will be dot-multiplied with the color weights and - // then placed into a component of the output. This is used to - // convert RGBA textures into Y, U and V textures. We do this - // because single-component textures are not renderable on all - // architectures. - shared_variables.append("varying vec4 v_texcoords[2];\n"); - vertex_header.append( - "uniform vec2 scaling_vector;\n" - "uniform vec2 dst_pixelsize;\n"); - vertex_program.append( - " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" - " step /= 4.0;\n" - " v_texcoords[0].xy = texcoord - step * 1.5;\n" - " v_texcoords[0].zw = texcoord - step * 0.5;\n" - " v_texcoords[1].xy = texcoord + step * 0.5;\n" - " v_texcoords[1].zw = texcoord + step * 1.5;\n"); - fragment_header.append("uniform vec4 color_weights;\n"); - fragment_program.append( - " gl_FragColor = color_weights * mat4(\n" - " vec4(texture2D(s_texture, v_texcoords[0].xy).rgb, 1.0),\n" - " vec4(texture2D(s_texture, v_texcoords[0].zw).rgb, 1.0),\n" - " vec4(texture2D(s_texture, v_texcoords[1].xy).rgb, 1.0),\n" - " vec4(texture2D(s_texture, v_texcoords[1].zw).rgb, 1.0));\n"); - break; - - case SHADER_YUV_MRT_PASS1: - // RGB24 to YV12 in two passes; writing two 8888 targets each pass. - // - // YV12 is full-resolution luma and half-resolution blue/red chroma. - // - // (original) - // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX - // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX - // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX - // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX - // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX - // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX - // | - // | (y plane) (temporary) - // | YYYY YYYY UUVV UUVV - // +--> { YYYY YYYY + UUVV UUVV } - // YYYY YYYY UUVV UUVV - // First YYYY YYYY UUVV UUVV - // pass YYYY YYYY UUVV UUVV - // YYYY YYYY UUVV UUVV - // | - // | (u plane) (v plane) - // Second | UUUU VVVV - // pass +--> { UUUU + VVVV } - // UUUU VVVV - // - shared_variables.append("varying vec4 v_texcoords[2];\n"); - vertex_header.append( - "uniform vec2 scaling_vector;\n" - "uniform vec2 dst_pixelsize;\n"); - vertex_program.append( - " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" - " step /= 4.0;\n" - " v_texcoords[0].xy = texcoord - step * 1.5;\n" - " v_texcoords[0].zw = texcoord - step * 0.5;\n" - " v_texcoords[1].xy = texcoord + step * 0.5;\n" - " v_texcoords[1].zw = texcoord + step * 1.5;\n"); - fragment_directives.append("#extension GL_EXT_draw_buffers : enable\n"); - fragment_header.append( - "const vec3 kRGBtoY = vec3(0.257, 0.504, 0.098);\n" - "const float kYBias = 0.0625;\n" - // Divide U and V by two to compensate for averaging below. - "const vec3 kRGBtoU = vec3(-0.148, -0.291, 0.439) / 2.0;\n" - "const vec3 kRGBtoV = vec3(0.439, -0.368, -0.071) / 2.0;\n" - "const float kUVBias = 0.5;\n"); - fragment_program.append( - " vec3 pixel1 = texture2D(s_texture, v_texcoords[0].xy).rgb;\n" - " vec3 pixel2 = texture2D(s_texture, v_texcoords[0].zw).rgb;\n" - " vec3 pixel3 = texture2D(s_texture, v_texcoords[1].xy).rgb;\n" - " vec3 pixel4 = texture2D(s_texture, v_texcoords[1].zw).rgb;\n" - " vec3 pixel12 = pixel1 + pixel2;\n" - " vec3 pixel34 = pixel3 + pixel4;\n" - " gl_FragData[0] = vec4(dot(pixel1, kRGBtoY),\n" - " dot(pixel2, kRGBtoY),\n" - " dot(pixel3, kRGBtoY),\n" - " dot(pixel4, kRGBtoY)) + kYBias;\n" - " gl_FragData[1] = vec4(dot(pixel12, kRGBtoU),\n" - " dot(pixel34, kRGBtoU),\n" - " dot(pixel12, kRGBtoV),\n" - " dot(pixel34, kRGBtoV)) + kUVBias;\n"); - break; - - case SHADER_YUV_MRT_PASS2: - // We're just sampling two pixels and unswizzling them. There's - // no need to do vertical scaling with math, since bilinear - // interpolation in the sampler takes care of that. - shared_variables.append("varying vec4 v_texcoords;\n"); - vertex_header.append( - "uniform vec2 scaling_vector;\n" - "uniform vec2 dst_pixelsize;\n"); - vertex_program.append( - " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" - " step /= 2.0;\n" - " v_texcoords.xy = texcoord - step * 0.5;\n" - " v_texcoords.zw = texcoord + step * 0.5;\n"); - fragment_directives.append("#extension GL_EXT_draw_buffers : enable\n"); - fragment_program.append( - " vec4 lo_uuvv = texture2D(s_texture, v_texcoords.xy);\n" - " vec4 hi_uuvv = texture2D(s_texture, v_texcoords.zw);\n" - " gl_FragData[0] = vec4(lo_uuvv.rg, hi_uuvv.rg);\n" - " gl_FragData[1] = vec4(lo_uuvv.ba, hi_uuvv.ba);\n"); - break; - } - if (swizzle) { - switch(type) { - case SHADER_YUV_MRT_PASS1: - fragment_program.append(" gl_FragData[0] = gl_FragData[0].bgra;\n"); - break; - case SHADER_YUV_MRT_PASS2: - fragment_program.append(" gl_FragData[0] = gl_FragData[0].bgra;\n"); - fragment_program.append(" gl_FragData[1] = gl_FragData[1].bgra;\n"); - break; - default: - fragment_program.append(" gl_FragColor = gl_FragColor.bgra;\n"); - break; - } - } - - vertex_program = vertex_header + shared_variables + "void main() {\n" + - vertex_program + "}\n"; - - fragment_program = fragment_directives + fragment_header + - shared_variables + "void main() {\n" + fragment_program + - "}\n"; - - cache_entry->Setup(vertex_program.c_str(), fragment_program.c_str()); - } - return cache_entry; -} - -void ShaderProgram::Setup(const GLchar* vertex_shader_text, - const GLchar* fragment_shader_text) { - // Shaders to map the source texture to |dst_texture_|. - GLuint vertex_shader = - helper_->CompileShaderFromSource(vertex_shader_text, GL_VERTEX_SHADER); - if (vertex_shader == 0) - return; - - gl_->AttachShader(program_, vertex_shader); - gl_->DeleteShader(vertex_shader); - - GLuint fragment_shader = helper_->CompileShaderFromSource( - fragment_shader_text, GL_FRAGMENT_SHADER); - if (fragment_shader == 0) - return; - gl_->AttachShader(program_, fragment_shader); - gl_->DeleteShader(fragment_shader); - - gl_->LinkProgram(program_); - - GLint link_status = 0; - gl_->GetProgramiv(program_, GL_LINK_STATUS, &link_status); - if (!link_status) - return; - - position_location_ = gl_->GetAttribLocation(program_, "a_position"); - texcoord_location_ = gl_->GetAttribLocation(program_, "a_texcoord"); - texture_location_ = gl_->GetUniformLocation(program_, "s_texture"); - src_subrect_location_ = gl_->GetUniformLocation(program_, "src_subrect"); - src_pixelsize_location_ = gl_->GetUniformLocation(program_, "src_pixelsize"); - dst_pixelsize_location_ = gl_->GetUniformLocation(program_, "dst_pixelsize"); - scaling_vector_location_ = - gl_->GetUniformLocation(program_, "scaling_vector"); - color_weights_location_ = gl_->GetUniformLocation(program_, "color_weights"); - // The only reason fetching these attribute locations should fail is - // if the context was spontaneously lost (i.e., because the GPU - // process crashed, perhaps deliberately for testing). - DCHECK(Initialized() || gl_->GetGraphicsResetStatusKHR() != GL_NO_ERROR); -} - -void ShaderProgram::UseProgram(const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool scale_x, - bool flip_y, - GLfloat color_weights[4]) { - gl_->UseProgram(program_); - - // OpenGL defines the last parameter to VertexAttribPointer as type - // "const GLvoid*" even though it is actually an offset into the buffer - // object's data store and not a pointer to the client's address space. - const void* offsets[2] = { - 0, reinterpret_cast<const void*>(2 * sizeof(GLfloat)) - }; - - gl_->VertexAttribPointer(position_location_, - 2, - GL_FLOAT, - GL_FALSE, - 4 * sizeof(GLfloat), - offsets[0]); - gl_->EnableVertexAttribArray(position_location_); - - gl_->VertexAttribPointer(texcoord_location_, - 2, - GL_FLOAT, - GL_FALSE, - 4 * sizeof(GLfloat), - offsets[1]); - gl_->EnableVertexAttribArray(texcoord_location_); - - gl_->Uniform1i(texture_location_, 0); - - // Convert |src_subrect| to texture coordinates. - GLfloat src_subrect_texcoord[] = { - static_cast<float>(src_subrect.x()) / src_size.width(), - static_cast<float>(src_subrect.y()) / src_size.height(), - static_cast<float>(src_subrect.width()) / src_size.width(), - static_cast<float>(src_subrect.height()) / src_size.height(), }; - if (flip_y) { - src_subrect_texcoord[1] += src_subrect_texcoord[3]; - src_subrect_texcoord[3] *= -1.0; - } - gl_->Uniform4fv(src_subrect_location_, 1, src_subrect_texcoord); - - gl_->Uniform2f(src_pixelsize_location_, src_size.width(), src_size.height()); - gl_->Uniform2f(dst_pixelsize_location_, - static_cast<float>(dst_size.width()), - static_cast<float>(dst_size.height())); - - gl_->Uniform2f( - scaling_vector_location_, scale_x ? 1.0 : 0.0, scale_x ? 0.0 : 1.0); - gl_->Uniform4fv(color_weights_location_, 1, color_weights); -} - -} // namespace content diff --git a/chromium/content/common/gpu/client/gl_helper_scaling.h b/chromium/content/common/gpu/client/gl_helper_scaling.h deleted file mode 100644 index 6157d8e0d9b..00000000000 --- a/chromium/content/common/gpu/client/gl_helper_scaling.h +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright (c) 2013 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 CONTENT_COMMON_GPU_CLIENT_GL_HELPER_SCALING_H_ -#define CONTENT_COMMON_GPU_CLIENT_GL_HELPER_SCALING_H_ - -#include <deque> -#include <map> -#include <vector> - -#include "base/macros.h" -#include "content/common/gpu/client/gl_helper.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/size.h" - -namespace content { - -class ShaderProgram; -class ScalerImpl; -class GLHelperTest; - -// Implements GPU texture scaling methods. -// Note that you should probably not use this class directly. -// See gl_helper.cc::CreateScaler instead. -class CONTENT_EXPORT GLHelperScaling { - public: - enum ShaderType { - SHADER_BILINEAR, - SHADER_BILINEAR2, - SHADER_BILINEAR3, - SHADER_BILINEAR4, - SHADER_BILINEAR2X2, - SHADER_BICUBIC_UPSCALE, - SHADER_BICUBIC_HALF_1D, - SHADER_PLANAR, - SHADER_YUV_MRT_PASS1, - SHADER_YUV_MRT_PASS2, - }; - - // Similar to ScalerInterface, but can generate multiple outputs. - // Used for YUV conversion in gl_helper.c - class CONTENT_EXPORT ShaderInterface { - public: - ShaderInterface() {} - virtual ~ShaderInterface() {} - // Note that the src_texture will have the min/mag filter set to GL_LINEAR - // and wrap_s/t set to CLAMP_TO_EDGE in this call. - virtual void Execute(GLuint source_texture, - const std::vector<GLuint>& dest_textures) = 0; - }; - - typedef std::pair<ShaderType, bool> ShaderProgramKeyType; - - GLHelperScaling(gpu::gles2::GLES2Interface* gl, - GLHelper* helper); - ~GLHelperScaling(); - void InitBuffer(); - - GLHelper::ScalerInterface* CreateScaler( - GLHelper::ScalerQuality quality, - gfx::Size src_size, - gfx::Rect src_subrect, - const gfx::Size& dst_size, - bool vertically_flip_texture, - bool swizzle); - - GLHelper::ScalerInterface* CreatePlanarScaler( - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool vertically_flip_texture, - bool swizzle, - const float color_weights[4]); - - ShaderInterface* CreateYuvMrtShader( - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool vertically_flip_texture, - bool swizzle, - ShaderType shader); - - private: - // A ScaleOp represents a pass in a scaler pipeline, in one dimension. - // Note that when quality is GOOD, multiple scaler passes will be - // combined into one operation for increased performance. - // Exposed in the header file for testing purposes. - struct ScaleOp { - ScaleOp(int factor, bool x, int size) - : scale_factor(factor), scale_x(x), scale_size(size) { - } - - // Calculate a set of ScaleOp needed to convert an image of size - // |src| into an image of size |dst|. If |scale_x| is true, then - // the calculations are for the X axis of the image, otherwise Y. - // If |allow3| is true, we can use a SHADER_BILINEAR3 to replace - // a scale up and scale down with a 3-tap bilinear scale. - // The calculated ScaleOps are added to |ops|. - static void AddOps(int src, - int dst, - bool scale_x, - bool allow3, - std::deque<ScaleOp>* ops) { - int num_downscales = 0; - if (allow3 && dst * 3 >= src && dst * 2 < src) { - // Technically, this should be a scale up and then a - // scale down, but it makes the optimization code more - // complicated. - ops->push_back(ScaleOp(3, scale_x, dst)); - return; - } - while ((dst << num_downscales) < src) { - num_downscales++; - } - if ((dst << num_downscales) != src) { - ops->push_back(ScaleOp(0, scale_x, dst << num_downscales)); - } - while (num_downscales) { - num_downscales--; - ops->push_back(ScaleOp(2, scale_x, dst << num_downscales)); - } - } - - // Update |size| to its new size. Before calling this function - // |size| should be the size of the input image. After calling it, - // |size| will be the size of the image after this particular - // scaling operation. - void UpdateSize(gfx::Size* subrect) { - if (scale_x) { - subrect->set_width(scale_size); - } else { - subrect->set_height(scale_size); - } - } - - // A scale factor of 0 means upscale - // 2 means 50% scale - // 3 means 33% scale, etc. - int scale_factor; - bool scale_x; // Otherwise y - int scale_size; // Size to scale to. - }; - - // Full specification for a single scaling stage. - struct ScalerStage { - ScalerStage(ShaderType shader_, - gfx::Size src_size_, - gfx::Rect src_subrect_, - gfx::Size dst_size_, - bool scale_x_, - bool vertically_flip_texture_, - bool swizzle_); - ShaderType shader; - gfx::Size src_size; - gfx::Rect src_subrect; - gfx::Size dst_size; - bool scale_x; - bool vertically_flip_texture; - bool swizzle; - }; - - // Compute a vector of scaler stages for a particular - // set of input/output parameters. - void ComputeScalerStages(GLHelper::ScalerQuality quality, - const gfx::Size& src_size, - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - bool vertically_flip_texture, - bool swizzle, - std::vector<ScalerStage> *scaler_stages); - - // Take two queues of ScaleOp structs and generate a - // vector of scaler stages. This is the second half of - // ComputeScalerStages. - void ConvertScalerOpsToScalerStages( - GLHelper::ScalerQuality quality, - gfx::Size src_size, - gfx::Rect src_subrect, - const gfx::Size& dst_size, - bool vertically_flip_texture, - bool swizzle, - std::deque<GLHelperScaling::ScaleOp>* x_ops, - std::deque<GLHelperScaling::ScaleOp>* y_ops, - std::vector<ScalerStage> *scaler_stages); - - - scoped_refptr<ShaderProgram> GetShaderProgram(ShaderType type, bool swizzle); - - // Interleaved array of 2-dimentional vertex positions (x, y) and - // 2-dimentional texture coordinates (s, t). - static const GLfloat kVertexAttributes[]; - - gpu::gles2::GLES2Interface* gl_; - GLHelper* helper_; - - // The buffer that holds the vertices and the texture coordinates data for - // drawing a quad. - ScopedBuffer vertex_attributes_buffer_; - - std::map<ShaderProgramKeyType, - scoped_refptr<ShaderProgram> > shader_programs_; - - friend class ShaderProgram; - friend class ScalerImpl; - friend class GLHelperTest; - DISALLOW_COPY_AND_ASSIGN(GLHelperScaling); -}; - - -} // namespace content - -#endif // CONTENT_COMMON_GPU_CLIENT_GL_HELPER_SCALING_H_ diff --git a/chromium/content/common/gpu/client/gl_helper_unittest.cc b/chromium/content/common/gpu/client/gl_helper_unittest.cc deleted file mode 100644 index 57022351c51..00000000000 --- a/chromium/content/common/gpu/client/gl_helper_unittest.cc +++ /dev/null @@ -1,2016 +0,0 @@ -// Copyright 2014 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 <stddef.h> -#include <stdint.h> -#include <stdio.h> -#include <string.h> -#include <cmath> -#include <string> -#include <vector> - -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#include <GLES2/gl2extchromium.h> - -#include "base/at_exit.h" -#include "base/bind.h" -#include "base/command_line.h" -#include "base/files/file_util.h" -#include "base/json/json_reader.h" -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/strings/stringprintf.h" -#include "base/synchronization/waitable_event.h" -#include "base/test/launcher/unit_test_launcher.h" -#include "base/test/test_suite.h" -#include "base/time/time.h" -#include "base/trace_event/trace_event.h" -#include "build/build_config.h" -#include "content/common/gpu/client/gl_helper.h" -#include "content/common/gpu/client/gl_helper_readback_support.h" -#include "content/common/gpu/client/gl_helper_scaling.h" -#include "content/public/test/unittest_test_suite.h" -#include "content/test/content_test_suite.h" -#include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h" -#include "media/base/video_frame.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkTypes.h" -#include "ui/gl/gl_implementation.h" - -#if defined(OS_MACOSX) -#include "base/mac/scoped_nsautorelease_pool.h" -#endif - -namespace content { - -using blink::WebGLId; -using blink::WebGraphicsContext3D; -using gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl; - -content::GLHelper::ScalerQuality kQualities[] = { - content::GLHelper::SCALER_QUALITY_BEST, - content::GLHelper::SCALER_QUALITY_GOOD, - content::GLHelper::SCALER_QUALITY_FAST, }; - -const char* kQualityNames[] = {"best", "good", "fast", }; - -class GLHelperTest : public testing::Test { - protected: - void SetUp() override { - WebGraphicsContext3D::Attributes attributes; - bool lose_context_when_out_of_memory = false; - context_ = - WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext( - attributes, lose_context_when_out_of_memory); - context_->InitializeOnCurrentThread(); - context_support_ = context_->GetContextSupport(); - helper_.reset( - new content::GLHelper(context_->GetGLInterface(), context_support_)); - helper_scaling_.reset(new content::GLHelperScaling( - context_->GetGLInterface(), helper_.get())); - } - - void TearDown() override { - helper_scaling_.reset(NULL); - helper_.reset(NULL); - context_.reset(NULL); - } - - void StartTracing(const std::string& filter) { - base::trace_event::TraceLog::GetInstance()->SetEnabled( - base::trace_event::TraceConfig(filter, - base::trace_event::RECORD_UNTIL_FULL), - base::trace_event::TraceLog::RECORDING_MODE); - } - - static void TraceDataCB( - const base::Callback<void()>& callback, - std::string* output, - const scoped_refptr<base::RefCountedString>& json_events_str, - bool has_more_events) { - if (output->size() > 1 && !json_events_str->data().empty()) { - output->append(","); - } - output->append(json_events_str->data()); - if (!has_more_events) { - callback.Run(); - } - } - - // End tracing, return tracing data in a simple map - // of event name->counts. - void EndTracing(std::map<std::string, int>* event_counts) { - std::string json_data = "["; - base::trace_event::TraceLog::GetInstance()->SetDisabled(); - base::RunLoop run_loop; - base::trace_event::TraceLog::GetInstance()->Flush( - base::Bind(&GLHelperTest::TraceDataCB, - run_loop.QuitClosure(), - base::Unretained(&json_data))); - run_loop.Run(); - json_data.append("]"); - - std::string error_msg; - scoped_ptr<base::Value> trace_data = - base::JSONReader::ReadAndReturnError(json_data, 0, NULL, &error_msg); - CHECK(trace_data) - << "JSON parsing failed (" << error_msg << ") JSON data:" << std::endl - << json_data; - - base::ListValue* list; - CHECK(trace_data->GetAsList(&list)); - for (size_t i = 0; i < list->GetSize(); i++) { - base::Value* item = NULL; - if (list->Get(i, &item)) { - base::DictionaryValue* dict; - CHECK(item->GetAsDictionary(&dict)); - std::string name; - CHECK(dict->GetString("name", &name)); - std::string trace_type; - CHECK(dict->GetString("ph", &trace_type)); - // Count all except END traces, as they come in BEGIN/END pairs. - if (trace_type != "E" && trace_type != "e") - (*event_counts)[name]++; - VLOG(1) << "trace name: " << name; - } - } - } - - // Bicubic filter kernel function. - static float Bicubic(float x) { - const float a = -0.5; - x = std::abs(x); - float x2 = x * x; - float x3 = x2 * x; - if (x <= 1) { - return (a + 2) * x3 - (a + 3) * x2 + 1; - } else if (x < 2) { - return a * x3 - 5 * a * x2 + 8 * a * x - 4 * a; - } else { - return 0.0f; - } - } - - // Look up a single channel value. Works for 4-channel and single channel - // bitmaps. Clamp x/y. - int Channel(SkBitmap* pixels, int x, int y, int c) { - if (pixels->bytesPerPixel() == 4) { - uint32_t* data = - pixels->getAddr32(std::max(0, std::min(x, pixels->width() - 1)), - std::max(0, std::min(y, pixels->height() - 1))); - return (*data) >> (c * 8) & 0xff; - } else { - DCHECK_EQ(pixels->bytesPerPixel(), 1); - DCHECK_EQ(c, 0); - return *pixels->getAddr8(std::max(0, std::min(x, pixels->width() - 1)), - std::max(0, std::min(y, pixels->height() - 1))); - } - } - - // Set a single channel value. Works for 4-channel and single channel - // bitmaps. Clamp x/y. - void SetChannel(SkBitmap* pixels, int x, int y, int c, int v) { - DCHECK_GE(x, 0); - DCHECK_GE(y, 0); - DCHECK_LT(x, pixels->width()); - DCHECK_LT(y, pixels->height()); - if (pixels->bytesPerPixel() == 4) { - uint32_t* data = pixels->getAddr32(x, y); - v = std::max(0, std::min(v, 255)); - *data = (*data & ~(0xffu << (c * 8))) | (v << (c * 8)); - } else { - DCHECK_EQ(pixels->bytesPerPixel(), 1); - DCHECK_EQ(c, 0); - uint8_t* data = pixels->getAddr8(x, y); - v = std::max(0, std::min(v, 255)); - *data = v; - } - } - - // Print all the R, G, B or A values from an SkBitmap in a - // human-readable format. - void PrintChannel(SkBitmap* pixels, int c) { - for (int y = 0; y < pixels->height(); y++) { - std::string formatted; - for (int x = 0; x < pixels->width(); x++) { - formatted.append(base::StringPrintf("%3d, ", Channel(pixels, x, y, c))); - } - LOG(ERROR) << formatted; - } - } - - // Print out the individual steps of a scaler pipeline. - std::string PrintStages( - const std::vector<GLHelperScaling::ScalerStage>& scaler_stages) { - std::string ret; - for (size_t i = 0; i < scaler_stages.size(); i++) { - ret.append(base::StringPrintf("%dx%d -> %dx%d ", - scaler_stages[i].src_size.width(), - scaler_stages[i].src_size.height(), - scaler_stages[i].dst_size.width(), - scaler_stages[i].dst_size.height())); - bool xy_matters = false; - switch (scaler_stages[i].shader) { - case GLHelperScaling::SHADER_BILINEAR: - ret.append("bilinear"); - break; - case GLHelperScaling::SHADER_BILINEAR2: - ret.append("bilinear2"); - xy_matters = true; - break; - case GLHelperScaling::SHADER_BILINEAR3: - ret.append("bilinear3"); - xy_matters = true; - break; - case GLHelperScaling::SHADER_BILINEAR4: - ret.append("bilinear4"); - xy_matters = true; - break; - case GLHelperScaling::SHADER_BILINEAR2X2: - ret.append("bilinear2x2"); - break; - case GLHelperScaling::SHADER_BICUBIC_UPSCALE: - ret.append("bicubic upscale"); - xy_matters = true; - break; - case GLHelperScaling::SHADER_BICUBIC_HALF_1D: - ret.append("bicubic 1/2"); - xy_matters = true; - break; - case GLHelperScaling::SHADER_PLANAR: - ret.append("planar"); - break; - case GLHelperScaling::SHADER_YUV_MRT_PASS1: - ret.append("rgb2yuv pass 1"); - break; - case GLHelperScaling::SHADER_YUV_MRT_PASS2: - ret.append("rgb2yuv pass 2"); - break; - } - - if (xy_matters) { - if (scaler_stages[i].scale_x) { - ret.append(" X"); - } else { - ret.append(" Y"); - } - } - ret.append("\n"); - } - return ret; - } - - bool CheckScale(double scale, int samples, bool already_scaled) { - // 1:1 is valid if there is one sample. - if (samples == 1 && scale == 1.0) { - return true; - } - // Is it an exact down-scale (50%, 25%, etc.?) - if (scale == 2.0 * samples) { - return true; - } - // Upscales, only valid if we haven't already scaled in this dimension. - if (!already_scaled) { - // Is it a valid bilinear upscale? - if (samples == 1 && scale <= 1.0) { - return true; - } - // Multi-sample upscale-downscale combination? - if (scale > samples / 2.0 && scale < samples) { - return true; - } - } - return false; - } - - // Make sure that the stages of the scaler pipeline are sane. - void ValidateScalerStages( - content::GLHelper::ScalerQuality quality, - const std::vector<GLHelperScaling::ScalerStage>& scaler_stages, - const gfx::Size& dst_size, - const std::string& message) { - bool previous_error = HasFailure(); - // First, check that the input size for each stage is equal to - // the output size of the previous stage. - for (size_t i = 1; i < scaler_stages.size(); i++) { - EXPECT_EQ(scaler_stages[i - 1].dst_size.width(), - scaler_stages[i].src_size.width()); - EXPECT_EQ(scaler_stages[i - 1].dst_size.height(), - scaler_stages[i].src_size.height()); - EXPECT_EQ(scaler_stages[i].src_subrect.x(), 0); - EXPECT_EQ(scaler_stages[i].src_subrect.y(), 0); - EXPECT_EQ(scaler_stages[i].src_subrect.width(), - scaler_stages[i].src_size.width()); - EXPECT_EQ(scaler_stages[i].src_subrect.height(), - scaler_stages[i].src_size.height()); - } - - // Check the output size matches the destination of the last stage - EXPECT_EQ(scaler_stages[scaler_stages.size() - 1].dst_size.width(), - dst_size.width()); - EXPECT_EQ(scaler_stages[scaler_stages.size() - 1].dst_size.height(), - dst_size.height()); - - // Used to verify that up-scales are not attempted after some - // other scale. - bool scaled_x = false; - bool scaled_y = false; - - for (size_t i = 0; i < scaler_stages.size(); i++) { - // Note: 2.0 means scaling down by 50% - double x_scale = - static_cast<double>(scaler_stages[i].src_subrect.width()) / - static_cast<double>(scaler_stages[i].dst_size.width()); - double y_scale = - static_cast<double>(scaler_stages[i].src_subrect.height()) / - static_cast<double>(scaler_stages[i].dst_size.height()); - - int x_samples = 0; - int y_samples = 0; - - // Codify valid scale operations. - switch (scaler_stages[i].shader) { - case GLHelperScaling::SHADER_PLANAR: - case GLHelperScaling::SHADER_YUV_MRT_PASS1: - case GLHelperScaling::SHADER_YUV_MRT_PASS2: - EXPECT_TRUE(false) << "Invalid shader."; - break; - - case GLHelperScaling::SHADER_BILINEAR: - if (quality != content::GLHelper::SCALER_QUALITY_FAST) { - x_samples = 1; - y_samples = 1; - } - break; - case GLHelperScaling::SHADER_BILINEAR2: - x_samples = 2; - y_samples = 1; - break; - case GLHelperScaling::SHADER_BILINEAR3: - x_samples = 3; - y_samples = 1; - break; - case GLHelperScaling::SHADER_BILINEAR4: - x_samples = 4; - y_samples = 1; - break; - case GLHelperScaling::SHADER_BILINEAR2X2: - x_samples = 2; - y_samples = 2; - break; - case GLHelperScaling::SHADER_BICUBIC_UPSCALE: - if (scaler_stages[i].scale_x) { - EXPECT_LT(x_scale, 1.0); - EXPECT_EQ(y_scale, 1.0); - } else { - EXPECT_EQ(x_scale, 1.0); - EXPECT_LT(y_scale, 1.0); - } - break; - case GLHelperScaling::SHADER_BICUBIC_HALF_1D: - if (scaler_stages[i].scale_x) { - EXPECT_EQ(x_scale, 2.0); - EXPECT_EQ(y_scale, 1.0); - } else { - EXPECT_EQ(x_scale, 1.0); - EXPECT_EQ(y_scale, 2.0); - } - break; - } - - if (!scaler_stages[i].scale_x) { - std::swap(x_samples, y_samples); - } - - if (x_samples) { - EXPECT_TRUE(CheckScale(x_scale, x_samples, scaled_x)) - << "x_scale = " << x_scale; - } - if (y_samples) { - EXPECT_TRUE(CheckScale(y_scale, y_samples, scaled_y)) - << "y_scale = " << y_scale; - } - - if (x_scale != 1.0) { - scaled_x = true; - } - if (y_scale != 1.0) { - scaled_y = true; - } - } - - if (HasFailure() && !previous_error) { - LOG(ERROR) << "Invalid scaler stages: " << message; - LOG(ERROR) << "Scaler stages:"; - LOG(ERROR) << PrintStages(scaler_stages); - } - } - - // Compares two bitmaps taking color types into account. Checks whether each - // component of each pixel is no more than |maxdiff| apart. If bitmaps are not - // similar enough, prints out |truth|, |other|, |source|, |scaler_stages| - // and |message|. - void Compare(SkBitmap* truth, - SkBitmap* other, - int maxdiff, - SkBitmap* source, - const std::vector<GLHelperScaling::ScalerStage>& scaler_stages, - std::string message) { - EXPECT_EQ(truth->width(), other->width()); - EXPECT_EQ(truth->height(), other->height()); - bool swizzle = (truth->colorType() == kRGBA_8888_SkColorType && - other->colorType() == kBGRA_8888_SkColorType) || - (truth->colorType() == kBGRA_8888_SkColorType && - other->colorType() == kRGBA_8888_SkColorType); - EXPECT_TRUE(swizzle || truth->colorType() == other->colorType()); - int bpp = truth->bytesPerPixel(); - for (int x = 0; x < truth->width(); x++) { - for (int y = 0; y < truth->height(); y++) { - for (int c = 0; c < bpp; c++) { - int a = Channel(truth, x, y, c); - // swizzle when comparing if needed - int b = swizzle && (c == 0 || c == 2) - ? Channel(other, x, y, (c + 2) & 2) - : Channel(other, x, y, c); - EXPECT_NEAR(a, b, maxdiff) << " x=" << x << " y=" << y << " c=" << c - << " " << message; - if (std::abs(a - b) > maxdiff) { - LOG(ERROR) << "-------expected--------"; - for (int i = 0; i < bpp; i++) { - LOG(ERROR) << "Channel " << i << ":"; - PrintChannel(truth, i); - } - LOG(ERROR) << "-------actual--------"; - for (int i = 0; i < bpp; i++) { - LOG(ERROR) << "Channel " << i << ":"; - PrintChannel(other, i); - } - if (source) { - LOG(ERROR) << "-------original--------"; - for (int i = 0; i < source->bytesPerPixel(); i++) { - LOG(ERROR) << "Channel " << i << ":"; - PrintChannel(source, i); - } - } - LOG(ERROR) << "-----Scaler stages------"; - LOG(ERROR) << PrintStages(scaler_stages); - return; - } - } - } - } - } - - // Get a single R, G, B or A value as a float. - float ChannelAsFloat(SkBitmap* pixels, int x, int y, int c) { - return Channel(pixels, x, y, c) / 255.0; - } - - // Works like a GL_LINEAR lookup on an SkBitmap. - float Bilinear(SkBitmap* pixels, float x, float y, int c) { - x -= 0.5; - y -= 0.5; - int base_x = static_cast<int>(floorf(x)); - int base_y = static_cast<int>(floorf(y)); - x -= base_x; - y -= base_y; - return (ChannelAsFloat(pixels, base_x, base_y, c) * (1 - x) * (1 - y) + - ChannelAsFloat(pixels, base_x + 1, base_y, c) * x * (1 - y) + - ChannelAsFloat(pixels, base_x, base_y + 1, c) * (1 - x) * y + - ChannelAsFloat(pixels, base_x + 1, base_y + 1, c) * x * y); - } - - // Encodes an RGBA bitmap to grayscale. - // Reference implementation for - // GLHelper::CopyToTextureImpl::EncodeTextureAsGrayscale. - void EncodeToGrayscaleSlow(SkBitmap* input, SkBitmap* output) { - const float kRGBtoGrayscaleColorWeights[3] = {0.213f, 0.715f, 0.072f}; - CHECK_EQ(kAlpha_8_SkColorType, output->colorType()); - CHECK_EQ(input->width(), output->width()); - CHECK_EQ(input->height(), output->height()); - CHECK_EQ(input->colorType(), kRGBA_8888_SkColorType); - - for (int dst_y = 0; dst_y < output->height(); dst_y++) { - for (int dst_x = 0; dst_x < output->width(); dst_x++) { - float c0 = ChannelAsFloat(input, dst_x, dst_y, 0); - float c1 = ChannelAsFloat(input, dst_x, dst_y, 1); - float c2 = ChannelAsFloat(input, dst_x, dst_y, 2); - float value = c0 * kRGBtoGrayscaleColorWeights[0] + - c1 * kRGBtoGrayscaleColorWeights[1] + - c2 * kRGBtoGrayscaleColorWeights[2]; - SetChannel( - output, dst_x, dst_y, 0, static_cast<int>(value * 255.0f + 0.5f)); - } - } - } - - // Very slow bicubic / bilinear scaler for reference. - void ScaleSlow(SkBitmap* input, - SkBitmap* output, - content::GLHelper::ScalerQuality quality) { - float xscale = static_cast<float>(input->width()) / output->width(); - float yscale = static_cast<float>(input->height()) / output->height(); - float clamped_xscale = xscale < 1.0 ? 1.0 : 1.0 / xscale; - float clamped_yscale = yscale < 1.0 ? 1.0 : 1.0 / yscale; - for (int dst_y = 0; dst_y < output->height(); dst_y++) { - for (int dst_x = 0; dst_x < output->width(); dst_x++) { - for (int channel = 0; channel < 4; channel++) { - float dst_x_in_src = (dst_x + 0.5f) * xscale; - float dst_y_in_src = (dst_y + 0.5f) * yscale; - - float value = 0.0f; - float sum = 0.0f; - switch (quality) { - case content::GLHelper::SCALER_QUALITY_BEST: - for (int src_y = -10; src_y < input->height() + 10; ++src_y) { - float coeff_y = - Bicubic((src_y + 0.5f - dst_y_in_src) * clamped_yscale); - if (coeff_y == 0.0f) { - continue; - } - for (int src_x = -10; src_x < input->width() + 10; ++src_x) { - float coeff = - coeff_y * - Bicubic((src_x + 0.5f - dst_x_in_src) * clamped_xscale); - if (coeff == 0.0f) { - continue; - } - sum += coeff; - float c = ChannelAsFloat(input, src_x, src_y, channel); - value += c * coeff; - } - } - break; - - case content::GLHelper::SCALER_QUALITY_GOOD: { - int xshift = 0, yshift = 0; - while ((output->width() << xshift) < input->width()) { - xshift++; - } - while ((output->height() << yshift) < input->height()) { - yshift++; - } - int xmag = 1 << xshift; - int ymag = 1 << yshift; - if (xmag == 4 && output->width() * 3 >= input->width()) { - xmag = 3; - } - if (ymag == 4 && output->height() * 3 >= input->height()) { - ymag = 3; - } - for (int x = 0; x < xmag; x++) { - for (int y = 0; y < ymag; y++) { - value += Bilinear(input, - (dst_x * xmag + x + 0.5) * xscale / xmag, - (dst_y * ymag + y + 0.5) * yscale / ymag, - channel); - sum += 1.0; - } - } - break; - } - - case content::GLHelper::SCALER_QUALITY_FAST: - value = Bilinear(input, dst_x_in_src, dst_y_in_src, channel); - sum = 1.0; - } - value /= sum; - SetChannel(output, - dst_x, - dst_y, - channel, - static_cast<int>(value * 255.0f + 0.5f)); - } - } - } - } - - void FlipSKBitmap(SkBitmap* bitmap) { - int bpp = bitmap->bytesPerPixel(); - DCHECK(bpp == 4 || bpp == 1); - int top_line = 0; - int bottom_line = bitmap->height() - 1; - while (top_line < bottom_line) { - for (int x = 0; x < bitmap->width(); x++) { - bpp == 4 ? std::swap(*bitmap->getAddr32(x, top_line), - *bitmap->getAddr32(x, bottom_line)) - : std::swap(*bitmap->getAddr8(x, top_line), - *bitmap->getAddr8(x, bottom_line)); - } - top_line++; - bottom_line--; - } - } - - // Swaps red and blue channels in each pixel in a 32-bit bitmap. - void SwizzleSKBitmap(SkBitmap* bitmap) { - int bpp = bitmap->bytesPerPixel(); - DCHECK(bpp == 4); - for (int y = 0; y < bitmap->height(); y++) { - for (int x = 0; x < bitmap->width(); x++) { - // Swap channels 0 and 2 (red and blue) - int c0 = Channel(bitmap, x, y, 0); - int c2 = Channel(bitmap, x, y, 2); - SetChannel(bitmap, x, y, 2, c0); - SetChannel(bitmap, x, y, 0, c2); - } - } - } - - // gl_helper scales recursively, so we'll need to do that - // in the reference implementation too. - void ScaleSlowRecursive(SkBitmap* input, - SkBitmap* output, - content::GLHelper::ScalerQuality quality) { - if (quality == content::GLHelper::SCALER_QUALITY_FAST || - quality == content::GLHelper::SCALER_QUALITY_GOOD) { - ScaleSlow(input, output, quality); - return; - } - - float xscale = static_cast<float>(output->width()) / input->width(); - - // This corresponds to all the operations we can do directly. - float yscale = static_cast<float>(output->height()) / input->height(); - if ((xscale == 1.0f && yscale == 1.0f) || - (xscale == 0.5f && yscale == 1.0f) || - (xscale == 1.0f && yscale == 0.5f) || - (xscale >= 1.0f && yscale == 1.0f) || - (xscale == 1.0f && yscale >= 1.0f)) { - ScaleSlow(input, output, quality); - return; - } - - // Now we break the problem down into smaller pieces, using the - // operations available. - int xtmp = input->width(); - int ytmp = input->height(); - - if (output->height() != input->height()) { - ytmp = output->height(); - while (ytmp < input->height() && ytmp * 2 != input->height()) { - ytmp += ytmp; - } - } else { - xtmp = output->width(); - while (xtmp < input->width() && xtmp * 2 != input->width()) { - xtmp += xtmp; - } - } - - SkBitmap tmp; - tmp.allocN32Pixels(xtmp, ytmp); - - ScaleSlowRecursive(input, &tmp, quality); - ScaleSlowRecursive(&tmp, output, quality); - } - - // Creates an RGBA SkBitmap - scoped_ptr<SkBitmap> CreateTestBitmap(int width, - int height, - int test_pattern) { - scoped_ptr<SkBitmap> bitmap(new SkBitmap); - bitmap->allocPixels(SkImageInfo::Make( - width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType)); - - for (int x = 0; x < width; ++x) { - for (int y = 0; y < height; ++y) { - switch (test_pattern) { - case 0: // Smooth test pattern - SetChannel(bitmap.get(), x, y, 0, x * 10); - SetChannel(bitmap.get(), x, y, 0, y == 0 ? x * 50 : x * 10); - SetChannel(bitmap.get(), x, y, 1, y * 10); - SetChannel(bitmap.get(), x, y, 2, (x + y) * 10); - SetChannel(bitmap.get(), x, y, 3, 255); - break; - case 1: // Small blocks - SetChannel(bitmap.get(), x, y, 0, x & 1 ? 255 : 0); - SetChannel(bitmap.get(), x, y, 1, y & 1 ? 255 : 0); - SetChannel(bitmap.get(), x, y, 2, (x + y) & 1 ? 255 : 0); - SetChannel(bitmap.get(), x, y, 3, 255); - break; - case 2: // Medium blocks - SetChannel(bitmap.get(), x, y, 0, 10 + x / 2 * 50); - SetChannel(bitmap.get(), x, y, 1, 10 + y / 3 * 50); - SetChannel(bitmap.get(), x, y, 2, (x + y) / 5 * 50 + 5); - SetChannel(bitmap.get(), x, y, 3, 255); - break; - } - } - } - return bitmap; - } - - // Binds texture and framebuffer and loads the bitmap pixels into the texture. - void BindTextureAndFrameBuffer(WebGLId texture, - WebGLId framebuffer, - SkBitmap* bitmap, - int width, - int height) { - context_->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); - context_->bindTexture(GL_TEXTURE_2D, texture); - context_->texImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA, - width, - height, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - bitmap->getPixels()); - } - - // Create a test image, transform it using - // GLHelper::CropScaleReadbackAndCleanTexture and a reference implementation - // and compare the results. - void TestCropScaleReadbackAndCleanTexture(int xsize, - int ysize, - int scaled_xsize, - int scaled_ysize, - int test_pattern, - SkColorType out_color_type, - bool swizzle, - size_t quality_index) { - DCHECK(out_color_type == kAlpha_8_SkColorType || - out_color_type == kRGBA_8888_SkColorType || - out_color_type == kBGRA_8888_SkColorType); - WebGLId src_texture = context_->createTexture(); - WebGLId framebuffer = context_->createFramebuffer(); - scoped_ptr<SkBitmap> input_pixels = - CreateTestBitmap(xsize, ysize, test_pattern); - BindTextureAndFrameBuffer( - src_texture, framebuffer, input_pixels.get(), xsize, ysize); - - std::string message = base::StringPrintf( - "input size: %dx%d " - "output size: %dx%d " - "pattern: %d , quality: %s, " - "out_color_type: %d", - xsize, - ysize, - scaled_xsize, - scaled_ysize, - test_pattern, - kQualityNames[quality_index], - out_color_type); - - // Transform the bitmap using GLHelper::CropScaleReadbackAndCleanTexture. - SkBitmap output_pixels; - output_pixels.allocPixels(SkImageInfo::Make( - scaled_xsize, scaled_ysize, out_color_type, kPremul_SkAlphaType)); - base::RunLoop run_loop; - gfx::Size encoded_texture_size; - helper_->CropScaleReadbackAndCleanTexture( - src_texture, - gfx::Size(xsize, ysize), - gfx::Rect(xsize, ysize), - gfx::Size(scaled_xsize, scaled_ysize), - static_cast<unsigned char*>(output_pixels.getPixels()), - out_color_type, - base::Bind(&callcallback, run_loop.QuitClosure()), - kQualities[quality_index]); - run_loop.Run(); - // CropScaleReadbackAndCleanTexture flips the pixels. Flip them back. - FlipSKBitmap(&output_pixels); - - // If the bitmap shouldn't have changed - compare against input. - if (xsize == scaled_xsize && ysize == scaled_ysize && - out_color_type != kAlpha_8_SkColorType) { - const std::vector<GLHelperScaling::ScalerStage> dummy_stages; - Compare(input_pixels.get(), - &output_pixels, - 0, - NULL, - dummy_stages, - message + " comparing against input"); - return; - } - - // Now transform the bitmap using the reference implementation. - SkBitmap scaled_pixels; - scaled_pixels.allocPixels(SkImageInfo::Make(scaled_xsize, - scaled_ysize, - kRGBA_8888_SkColorType, - kPremul_SkAlphaType)); - SkBitmap truth_pixels; - // Step 1: Scale - ScaleSlowRecursive( - input_pixels.get(), &scaled_pixels, kQualities[quality_index]); - // Step 2: Encode to grayscale if needed. - if (out_color_type == kAlpha_8_SkColorType) { - truth_pixels.allocPixels(SkImageInfo::Make( - scaled_xsize, scaled_ysize, out_color_type, kPremul_SkAlphaType)); - EncodeToGrayscaleSlow(&scaled_pixels, &truth_pixels); - } else { - truth_pixels = scaled_pixels; - } - - // Now compare the results. - SkAutoLockPixels lock_input(truth_pixels); - const std::vector<GLHelperScaling::ScalerStage> dummy_stages; - Compare(&truth_pixels, - &output_pixels, - 2, - input_pixels.get(), - dummy_stages, - message + " comparing against transformed/scaled"); - - context_->deleteTexture(src_texture); - context_->deleteFramebuffer(framebuffer); - } - - // Scaling test: Create a test image, scale it using GLHelperScaling - // and a reference implementation and compare the results. - void TestScale(int xsize, - int ysize, - int scaled_xsize, - int scaled_ysize, - int test_pattern, - size_t quality_index, - bool flip) { - WebGLId src_texture = context_->createTexture(); - WebGLId framebuffer = context_->createFramebuffer(); - scoped_ptr<SkBitmap> input_pixels = - CreateTestBitmap(xsize, ysize, test_pattern); - BindTextureAndFrameBuffer( - src_texture, framebuffer, input_pixels.get(), xsize, ysize); - - std::string message = base::StringPrintf( - "input size: %dx%d " - "output size: %dx%d " - "pattern: %d quality: %s", - xsize, - ysize, - scaled_xsize, - scaled_ysize, - test_pattern, - kQualityNames[quality_index]); - - std::vector<GLHelperScaling::ScalerStage> stages; - helper_scaling_->ComputeScalerStages(kQualities[quality_index], - gfx::Size(xsize, ysize), - gfx::Rect(0, 0, xsize, ysize), - gfx::Size(scaled_xsize, scaled_ysize), - flip, - false, - &stages); - ValidateScalerStages(kQualities[quality_index], - stages, - gfx::Size(scaled_xsize, scaled_ysize), - message); - - WebGLId dst_texture = - helper_->CopyAndScaleTexture(src_texture, - gfx::Size(xsize, ysize), - gfx::Size(scaled_xsize, scaled_ysize), - flip, - kQualities[quality_index]); - - SkBitmap output_pixels; - output_pixels.allocPixels(SkImageInfo::Make(scaled_xsize, - scaled_ysize, - kRGBA_8888_SkColorType, - kPremul_SkAlphaType)); - - helper_->ReadbackTextureSync( - dst_texture, - gfx::Rect(0, 0, scaled_xsize, scaled_ysize), - static_cast<unsigned char*>(output_pixels.getPixels()), - kRGBA_8888_SkColorType); - if (flip) { - // Flip the pixels back. - FlipSKBitmap(&output_pixels); - } - - // If the bitmap shouldn't have changed - compare against input. - if (xsize == scaled_xsize && ysize == scaled_ysize) { - Compare(input_pixels.get(), - &output_pixels, - 0, - NULL, - stages, - message + " comparing against input"); - return; - } - - // Now scale the bitmap using the reference implementation. - SkBitmap truth_pixels; - truth_pixels.allocPixels(SkImageInfo::Make(scaled_xsize, - scaled_ysize, - kRGBA_8888_SkColorType, - kPremul_SkAlphaType)); - ScaleSlowRecursive( - input_pixels.get(), &truth_pixels, kQualities[quality_index]); - Compare(&truth_pixels, - &output_pixels, - 2, - input_pixels.get(), - stages, - message + " comparing against scaled"); - - context_->deleteTexture(src_texture); - context_->deleteTexture(dst_texture); - context_->deleteFramebuffer(framebuffer); - } - - // Create a scaling pipeline and check that it is made up of - // valid scaling operations. - void TestScalerPipeline(size_t quality, - int xsize, - int ysize, - int dst_xsize, - int dst_ysize) { - std::vector<GLHelperScaling::ScalerStage> stages; - helper_scaling_->ComputeScalerStages(kQualities[quality], - gfx::Size(xsize, ysize), - gfx::Rect(0, 0, xsize, ysize), - gfx::Size(dst_xsize, dst_ysize), - false, - false, - &stages); - ValidateScalerStages(kQualities[quality], - stages, - gfx::Size(dst_xsize, dst_ysize), - base::StringPrintf( - "input size: %dx%d " - "output size: %dx%d " - "quality: %s", - xsize, - ysize, - dst_xsize, - dst_ysize, - kQualityNames[quality])); - } - - // Create a scaling pipeline and make sure that the steps - // are exactly the steps we expect. - void CheckPipeline(content::GLHelper::ScalerQuality quality, - int xsize, - int ysize, - int dst_xsize, - int dst_ysize, - const std::string& description) { - std::vector<GLHelperScaling::ScalerStage> stages; - helper_scaling_->ComputeScalerStages(quality, - gfx::Size(xsize, ysize), - gfx::Rect(0, 0, xsize, ysize), - gfx::Size(dst_xsize, dst_ysize), - false, - false, - &stages); - ValidateScalerStages(content::GLHelper::SCALER_QUALITY_GOOD, - stages, - gfx::Size(dst_xsize, dst_ysize), - ""); - EXPECT_EQ(PrintStages(stages), description); - } - - // Note: Left/Right means Top/Bottom when used for Y dimension. - enum Margin { - MarginLeft, - MarginMiddle, - MarginRight, - MarginInvalid, - }; - - static Margin NextMargin(Margin m) { - switch (m) { - case MarginLeft: - return MarginMiddle; - case MarginMiddle: - return MarginRight; - case MarginRight: - return MarginInvalid; - default: - return MarginInvalid; - } - } - - int compute_margin(int insize, int outsize, Margin m) { - int available = outsize - insize; - switch (m) { - default: - EXPECT_TRUE(false) << "This should not happen."; - return 0; - case MarginLeft: - return 0; - case MarginMiddle: - return (available / 2) & ~1; - case MarginRight: - return available; - } - } - - // Convert 0.0 - 1.0 to 0 - 255 - int float_to_byte(float v) { - int ret = static_cast<int>(floorf(v * 255.0f + 0.5f)); - if (ret < 0) { - return 0; - } - if (ret > 255) { - return 255; - } - return ret; - } - - static void callcallback(const base::Callback<void()>& callback, - bool result) { - callback.Run(); - } - - void PrintPlane(unsigned char* plane, int xsize, int stride, int ysize) { - for (int y = 0; y < ysize; y++) { - std::string formatted; - for (int x = 0; x < xsize; x++) { - formatted.append(base::StringPrintf("%3d, ", plane[y * stride + x])); - } - LOG(ERROR) << formatted << " (" << (plane + y * stride) << ")"; - } - } - - // Compare two planes make sure that each component of each pixel - // is no more than |maxdiff| apart. - void ComparePlane(unsigned char* truth, - int truth_stride, - unsigned char* other, - int other_stride, - int maxdiff, - int xsize, - int ysize, - SkBitmap* source, - std::string message) { - for (int x = 0; x < xsize; x++) { - for (int y = 0; y < ysize; y++) { - int a = other[y * other_stride + x]; - int b = truth[y * truth_stride + x]; - EXPECT_NEAR(a, b, maxdiff) << " x=" << x << " y=" << y << " " - << message; - if (std::abs(a - b) > maxdiff) { - LOG(ERROR) << "-------expected--------"; - PrintPlane(truth, xsize, truth_stride, ysize); - LOG(ERROR) << "-------actual--------"; - PrintPlane(other, xsize, other_stride, ysize); - if (source) { - LOG(ERROR) << "-------before yuv conversion: red--------"; - PrintChannel(source, 0); - LOG(ERROR) << "-------before yuv conversion: green------"; - PrintChannel(source, 1); - LOG(ERROR) << "-------before yuv conversion: blue-------"; - PrintChannel(source, 2); - } - return; - } - } - } - } - - void DrawGridToBitmap(int w, int h, - SkColor background_color, - SkColor grid_color, - int grid_pitch, - int grid_width, - SkBitmap& bmp) { - ASSERT_GT(grid_pitch, 0); - ASSERT_GT(grid_width, 0); - ASSERT_NE(background_color, grid_color); - - for (int y = 0; y < h; ++y) { - bool y_on_grid = ((y % grid_pitch) < grid_width); - - for (int x = 0; x < w; ++x) { - bool on_grid = (y_on_grid || ((x % grid_pitch) < grid_width)); - - if (bmp.colorType() == kRGBA_8888_SkColorType || - bmp.colorType() == kBGRA_8888_SkColorType) { - *bmp.getAddr32(x, y) = (on_grid ? grid_color : background_color); - } else if (bmp.colorType() == kRGB_565_SkColorType) { - *bmp.getAddr16(x, y) = (on_grid ? grid_color : background_color); - } - } - } - } - - void DrawCheckerToBitmap(int w, int h, - SkColor color1, SkColor color2, - int rect_w, int rect_h, - SkBitmap& bmp) { - ASSERT_GT(rect_w, 0); - ASSERT_GT(rect_h, 0); - ASSERT_NE(color1, color2); - - for (int y = 0; y < h; ++y) { - bool y_bit = (((y / rect_h) & 0x1) == 0); - - for (int x = 0; x < w; ++x) { - bool x_bit = (((x / rect_w) & 0x1) == 0); - - bool use_color2 = (x_bit != y_bit); // xor - if (bmp.colorType() == kRGBA_8888_SkColorType || - bmp.colorType() == kBGRA_8888_SkColorType) { - *bmp.getAddr32(x, y) = (use_color2 ? color2 : color1); - } else if (bmp.colorType() == kRGB_565_SkColorType) { - *bmp.getAddr16(x, y) = (use_color2 ? color2 : color1); - } - } - } - } - - bool ColorComponentsClose(SkColor component1, - SkColor component2, - SkColorType color_type) { - int c1 = static_cast<int>(component1); - int c2 = static_cast<int>(component2); - bool result = false; - switch (color_type) { - case kRGBA_8888_SkColorType: - case kBGRA_8888_SkColorType: - result = (std::abs(c1 - c2) == 0); - break; - case kRGB_565_SkColorType: - result = (std::abs(c1 - c2) <= 7); - break; - default: - break; - } - return result; - } - - bool ColorsClose(SkColor color1, SkColor color2, SkColorType color_type) { - bool red = ColorComponentsClose(SkColorGetR(color1), - SkColorGetR(color2), color_type); - bool green = ColorComponentsClose(SkColorGetG(color1), - SkColorGetG(color2), color_type); - bool blue = ColorComponentsClose(SkColorGetB(color1), - SkColorGetB(color2), color_type); - bool alpha = ColorComponentsClose(SkColorGetA(color1), - SkColorGetA(color2), color_type); - if (color_type == kRGB_565_SkColorType) { - return red && blue && green; - } - return red && blue && green && alpha; - } - - bool IsEqual(const SkBitmap& bmp1, const SkBitmap& bmp2) { - if (bmp1.isNull() && bmp2.isNull()) - return true; - if (bmp1.width() != bmp2.width() || - bmp1.height() != bmp2.height()) { - LOG(ERROR) << "Bitmap geometry check failure"; - return false; - } - if (bmp1.colorType() != bmp2.colorType()) - return false; - - SkAutoLockPixels lock1(bmp1); - SkAutoLockPixels lock2(bmp2); - if (!bmp1.getPixels() || !bmp2.getPixels()) { - LOG(ERROR) << "Empty Bitmap!"; - return false; - } - for (int y = 0; y < bmp1.height(); ++y) { - for (int x = 0; x < bmp1.width(); ++x) { - if (!ColorsClose(bmp1.getColor(x,y), - bmp2.getColor(x,y), - bmp1.colorType())) { - LOG(ERROR) << "Bitmap color comparision failure"; - return false; - } - } - } - return true; - } - - void BindAndAttachTextureWithPixels(GLuint src_texture, - SkColorType color_type, - const gfx::Size& src_size, - const SkBitmap& input_pixels) { - context_->bindTexture(GL_TEXTURE_2D, src_texture); - GLenum format = 0; - switch (color_type) { - case kBGRA_8888_SkColorType: - format = GL_BGRA_EXT; - break; - case kRGBA_8888_SkColorType: - format = GL_RGBA; - break; - case kRGB_565_SkColorType: - format = GL_RGB; - break; - default: - NOTREACHED(); - } - GLenum type = (color_type == kRGB_565_SkColorType) ? - GL_UNSIGNED_SHORT_5_6_5 : GL_UNSIGNED_BYTE; - context_->texImage2D(GL_TEXTURE_2D, - 0, - format, - src_size.width(), - src_size.height(), - 0, - format, - type, - input_pixels.getPixels()); - } - - void ReadBackTexture(GLuint src_texture, - const gfx::Size& src_size, - unsigned char* pixels, - SkColorType color_type, - bool async) { - if (async) { - base::RunLoop run_loop; - helper_->ReadbackTextureAsync(src_texture, - src_size, - pixels, - color_type, - base::Bind(&callcallback, - run_loop.QuitClosure())); - run_loop.Run(); - } else { - helper_->ReadbackTextureSync(src_texture, - gfx::Rect(src_size), - pixels, - color_type); - } - } - // Test basic format readback. - bool TestTextureFormatReadback(const gfx::Size& src_size, - SkColorType color_type, - bool async) { - SkImageInfo info = - SkImageInfo::Make(src_size.width(), - src_size.height(), - color_type, - kPremul_SkAlphaType); - if (!helper_->IsReadbackConfigSupported(color_type)) { - LOG(INFO) << "Skipping test format not supported" << color_type; - return true; - } - WebGLId src_texture = context_->createTexture(); - SkBitmap input_pixels; - input_pixels.allocPixels(info); - // Test Pattern-1, Fill with Plain color pattern. - // Erase the input bitmap with red color. - input_pixels.eraseColor(SK_ColorRED); - BindAndAttachTextureWithPixels(src_texture, - color_type, - src_size, - input_pixels); - SkBitmap output_pixels; - output_pixels.allocPixels(info); - // Initialize the output bitmap with Green color. - // When the readback is over output bitmap should have the red color. - output_pixels.eraseColor(SK_ColorGREEN); - uint8_t* pixels = static_cast<uint8_t*>(output_pixels.getPixels()); - ReadBackTexture(src_texture, src_size, pixels, color_type, async); - bool result = IsEqual(input_pixels, output_pixels); - if (!result) { - LOG(ERROR) << "Bitmap comparision failure Pattern-1"; - return false; - } - const int rect_w = 10, rect_h = 4, src_grid_pitch = 10, src_grid_width = 4; - const SkColor color1 = SK_ColorRED, color2 = SK_ColorBLUE; - // Test Pattern-2, Fill with Grid Pattern. - DrawGridToBitmap(src_size.width(), src_size.height(), - color2, color1, - src_grid_pitch, src_grid_width, - input_pixels); - BindAndAttachTextureWithPixels(src_texture, - color_type, - src_size, - input_pixels); - ReadBackTexture(src_texture, src_size, pixels, color_type, async); - result = IsEqual(input_pixels, output_pixels); - if (!result) { - LOG(ERROR) << "Bitmap comparision failure Pattern-2"; - return false; - } - // Test Pattern-3, Fill with CheckerBoard Pattern. - DrawCheckerToBitmap(src_size.width(), - src_size.height(), - color1, - color2, rect_w, rect_h, input_pixels); - BindAndAttachTextureWithPixels(src_texture, - color_type, - src_size, - input_pixels); - ReadBackTexture(src_texture, src_size, pixels, color_type, async); - result = IsEqual(input_pixels, output_pixels); - if (!result) { - LOG(ERROR) << "Bitmap comparision failure Pattern-3"; - return false; - } - context_->deleteTexture(src_texture); - if (HasFailure()) { - return false; - } - return true; - } - - // YUV readback test. Create a test pattern, convert to YUV - // with reference implementation and compare to what gl_helper - // returns. - void TestYUVReadback(int xsize, - int ysize, - int output_xsize, - int output_ysize, - int xmargin, - int ymargin, - int test_pattern, - bool flip, - bool use_mrt, - content::GLHelper::ScalerQuality quality) { - WebGLId src_texture = context_->createTexture(); - SkBitmap input_pixels; - input_pixels.allocN32Pixels(xsize, ysize); - - for (int x = 0; x < xsize; ++x) { - for (int y = 0; y < ysize; ++y) { - switch (test_pattern) { - case 0: // Smooth test pattern - SetChannel(&input_pixels, x, y, 0, x * 10); - SetChannel(&input_pixels, x, y, 1, y * 10); - SetChannel(&input_pixels, x, y, 2, (x + y) * 10); - SetChannel(&input_pixels, x, y, 3, 255); - break; - case 1: // Small blocks - SetChannel(&input_pixels, x, y, 0, x & 1 ? 255 : 0); - SetChannel(&input_pixels, x, y, 1, y & 1 ? 255 : 0); - SetChannel(&input_pixels, x, y, 2, (x + y) & 1 ? 255 : 0); - SetChannel(&input_pixels, x, y, 3, 255); - break; - case 2: // Medium blocks - SetChannel(&input_pixels, x, y, 0, 10 + x / 2 * 50); - SetChannel(&input_pixels, x, y, 1, 10 + y / 3 * 50); - SetChannel(&input_pixels, x, y, 2, (x + y) / 5 * 50 + 5); - SetChannel(&input_pixels, x, y, 3, 255); - break; - } - } - } - - context_->bindTexture(GL_TEXTURE_2D, src_texture); - context_->texImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA, - xsize, - ysize, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - input_pixels.getPixels()); - - gpu::Mailbox mailbox; - context_->genMailboxCHROMIUM(mailbox.name); - EXPECT_FALSE(mailbox.IsZero()); - context_->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); - const blink::WGC3Duint64 fence_sync = context_->insertFenceSyncCHROMIUM(); - context_->shallowFlushCHROMIUM(); - - gpu::SyncToken sync_token; - ASSERT_TRUE(context_->genSyncTokenCHROMIUM(fence_sync, - sync_token.GetData())); - - std::string message = base::StringPrintf( - "input size: %dx%d " - "output size: %dx%d " - "margin: %dx%d " - "pattern: %d %s %s", - xsize, - ysize, - output_xsize, - output_ysize, - xmargin, - ymargin, - test_pattern, - flip ? "flip" : "noflip", - flip ? "mrt" : "nomrt"); - scoped_ptr<ReadbackYUVInterface> yuv_reader( - helper_->CreateReadbackPipelineYUV( - quality, - gfx::Size(xsize, ysize), - gfx::Rect(0, 0, xsize, ysize), - gfx::Size(xsize, ysize), - flip, - use_mrt)); - - scoped_refptr<media::VideoFrame> output_frame = - media::VideoFrame::CreateFrame( - media::PIXEL_FORMAT_YV12, - // The coded size of the output frame is rounded up to the next - // 16-byte boundary. This tests that the readback is being - // positioned inside the frame's visible region, and not dependent - // on its coded size. - gfx::Size((output_xsize + 15) & ~15, (output_ysize + 15) & ~15), - gfx::Rect(0, 0, output_xsize, output_ysize), - gfx::Size(output_xsize, output_ysize), - base::TimeDelta::FromSeconds(0)); - scoped_refptr<media::VideoFrame> truth_frame = - media::VideoFrame::CreateFrame( - media::PIXEL_FORMAT_YV12, gfx::Size(output_xsize, output_ysize), - gfx::Rect(0, 0, output_xsize, output_ysize), - gfx::Size(output_xsize, output_ysize), - base::TimeDelta::FromSeconds(0)); - - base::RunLoop run_loop; - yuv_reader->ReadbackYUV(mailbox, sync_token, output_frame.get(), - gfx::Point(xmargin, ymargin), - base::Bind(&callcallback, run_loop.QuitClosure())); - run_loop.Run(); - - if (flip) { - FlipSKBitmap(&input_pixels); - } - - unsigned char* Y = truth_frame->visible_data(media::VideoFrame::kYPlane); - unsigned char* U = truth_frame->visible_data(media::VideoFrame::kUPlane); - unsigned char* V = truth_frame->visible_data(media::VideoFrame::kVPlane); - int32_t y_stride = truth_frame->stride(media::VideoFrame::kYPlane); - int32_t u_stride = truth_frame->stride(media::VideoFrame::kUPlane); - int32_t v_stride = truth_frame->stride(media::VideoFrame::kVPlane); - memset(Y, 0x00, y_stride * output_ysize); - memset(U, 0x80, u_stride * output_ysize / 2); - memset(V, 0x80, v_stride * output_ysize / 2); - - const float kRGBtoYColorWeights[] = {0.257f, 0.504f, 0.098f, 0.0625f}; - const float kRGBtoUColorWeights[] = {-0.148f, -0.291f, 0.439f, 0.5f}; - const float kRGBtoVColorWeights[] = {0.439f, -0.368f, -0.071f, 0.5f}; - - for (int y = 0; y < ysize; y++) { - for (int x = 0; x < xsize; x++) { - Y[(y + ymargin) * y_stride + x + xmargin] = float_to_byte( - ChannelAsFloat(&input_pixels, x, y, 0) * kRGBtoYColorWeights[0] + - ChannelAsFloat(&input_pixels, x, y, 1) * kRGBtoYColorWeights[1] + - ChannelAsFloat(&input_pixels, x, y, 2) * kRGBtoYColorWeights[2] + - kRGBtoYColorWeights[3]); - } - } - - for (int y = 0; y < ysize / 2; y++) { - for (int x = 0; x < xsize / 2; x++) { - U[(y + ymargin / 2) * u_stride + x + xmargin / 2] = - float_to_byte(Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 0) * - kRGBtoUColorWeights[0] + - Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 1) * - kRGBtoUColorWeights[1] + - Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 2) * - kRGBtoUColorWeights[2] + - kRGBtoUColorWeights[3]); - V[(y + ymargin / 2) * v_stride + x + xmargin / 2] = - float_to_byte(Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 0) * - kRGBtoVColorWeights[0] + - Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 1) * - kRGBtoVColorWeights[1] + - Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 2) * - kRGBtoVColorWeights[2] + - kRGBtoVColorWeights[3]); - } - } - - ComparePlane(Y, - y_stride, - output_frame->visible_data(media::VideoFrame::kYPlane), - output_frame->stride(media::VideoFrame::kYPlane), - 2, - output_xsize, - output_ysize, - &input_pixels, - message + " Y plane"); - ComparePlane(U, - u_stride, - output_frame->visible_data(media::VideoFrame::kUPlane), - output_frame->stride(media::VideoFrame::kUPlane), - 2, - output_xsize / 2, - output_ysize / 2, - &input_pixels, - message + " U plane"); - ComparePlane(V, - v_stride, - output_frame->visible_data(media::VideoFrame::kVPlane), - output_frame->stride(media::VideoFrame::kVPlane), - 2, - output_xsize / 2, - output_ysize / 2, - &input_pixels, - message + " V plane"); - - context_->deleteTexture(src_texture); - } - - void TestAddOps(int src, int dst, bool scale_x, bool allow3) { - std::deque<GLHelperScaling::ScaleOp> ops; - GLHelperScaling::ScaleOp::AddOps(src, dst, scale_x, allow3, &ops); - // Scale factor 3 is a special case. - // It is currently only allowed by itself. - if (allow3 && dst * 3 >= src && dst * 2 < src) { - EXPECT_EQ(ops[0].scale_factor, 3); - EXPECT_EQ(ops.size(), 1U); - EXPECT_EQ(ops[0].scale_x, scale_x); - EXPECT_EQ(ops[0].scale_size, dst); - return; - } - - for (size_t i = 0; i < ops.size(); i++) { - EXPECT_EQ(ops[i].scale_x, scale_x); - if (i == 0) { - // Only the first op is allowed to be a scale up. - // (Scaling up *after* scaling down would make it fuzzy.) - EXPECT_TRUE(ops[0].scale_factor == 0 || ops[0].scale_factor == 2); - } else { - // All other operations must be 50% downscales. - EXPECT_EQ(ops[i].scale_factor, 2); - } - } - // Check that the scale factors make sense and add up. - int tmp = dst; - for (int i = static_cast<int>(ops.size() - 1); i >= 0; i--) { - EXPECT_EQ(tmp, ops[i].scale_size); - if (ops[i].scale_factor == 0) { - EXPECT_EQ(i, 0); - EXPECT_GT(tmp, src); - tmp = src; - } else { - tmp *= ops[i].scale_factor; - } - } - EXPECT_EQ(tmp, src); - } - - void CheckPipeline2(int xsize, - int ysize, - int dst_xsize, - int dst_ysize, - const std::string& description) { - std::vector<GLHelperScaling::ScalerStage> stages; - helper_scaling_->ConvertScalerOpsToScalerStages( - content::GLHelper::SCALER_QUALITY_GOOD, - gfx::Size(xsize, ysize), - gfx::Rect(0, 0, xsize, ysize), - gfx::Size(dst_xsize, dst_ysize), - false, - false, - &x_ops_, - &y_ops_, - &stages); - EXPECT_EQ(x_ops_.size(), 0U); - EXPECT_EQ(y_ops_.size(), 0U); - ValidateScalerStages(content::GLHelper::SCALER_QUALITY_GOOD, - stages, - gfx::Size(dst_xsize, dst_ysize), - ""); - EXPECT_EQ(PrintStages(stages), description); - } - - void CheckOptimizationsTest() { - // Basic upscale. X and Y should be combined into one pass. - x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 2000)); - y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 2000)); - CheckPipeline2(1024, 768, 2000, 2000, "1024x768 -> 2000x2000 bilinear\n"); - - // X scaled 1/2, Y upscaled, should still be one pass. - x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 512)); - y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 2000)); - CheckPipeline2(1024, 768, 512, 2000, "1024x768 -> 512x2000 bilinear\n"); - - // X upscaled, Y scaled 1/2, one bilinear pass - x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 2000)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 384)); - CheckPipeline2(1024, 768, 2000, 384, "1024x768 -> 2000x384 bilinear\n"); - - // X scaled 1/2, Y scaled 1/2, one bilinear pass - x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 512)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 384)); - CheckPipeline2(1024, 768, 512, 384, "1024x768 -> 512x384 bilinear\n"); - - // X scaled 1/2, Y scaled to 60%, one bilinear2 pass. - x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 50)); - y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60)); - CheckPipeline2(100, 100, 50, 60, "100x100 -> 50x60 bilinear2 Y\n"); - - // X scaled to 60%, Y scaled 1/2, one bilinear2 pass. - x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120)); - x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 50)); - CheckPipeline2(100, 100, 60, 50, "100x100 -> 60x50 bilinear2 X\n"); - - // X scaled to 60%, Y scaled 60%, one bilinear2x2 pass. - x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120)); - x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60)); - y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60)); - CheckPipeline2(100, 100, 60, 60, "100x100 -> 60x60 bilinear2x2\n"); - - // X scaled to 40%, Y scaled 40%, two bilinear3 passes. - x_ops_.push_back(GLHelperScaling::ScaleOp(3, true, 40)); - y_ops_.push_back(GLHelperScaling::ScaleOp(3, false, 40)); - CheckPipeline2(100, - 100, - 40, - 40, - "100x100 -> 100x40 bilinear3 Y\n" - "100x40 -> 40x40 bilinear3 X\n"); - - // X scaled to 60%, Y scaled 40% - x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120)); - x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60)); - y_ops_.push_back(GLHelperScaling::ScaleOp(3, false, 40)); - CheckPipeline2(100, - 100, - 60, - 40, - "100x100 -> 100x40 bilinear3 Y\n" - "100x40 -> 60x40 bilinear2 X\n"); - - // X scaled to 40%, Y scaled 60% - x_ops_.push_back(GLHelperScaling::ScaleOp(3, true, 40)); - y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60)); - CheckPipeline2(100, - 100, - 40, - 60, - "100x100 -> 100x60 bilinear2 Y\n" - "100x60 -> 40x60 bilinear3 X\n"); - - // X scaled to 30%, Y scaled 30% - x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120)); - x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60)); - x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 30)); - y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 30)); - CheckPipeline2(100, - 100, - 30, - 30, - "100x100 -> 100x30 bilinear4 Y\n" - "100x30 -> 30x30 bilinear4 X\n"); - - // X scaled to 50%, Y scaled 30% - x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 50)); - y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 30)); - CheckPipeline2(100, 100, 50, 30, "100x100 -> 50x30 bilinear4 Y\n"); - - // X scaled to 150%, Y scaled 30% - // Note that we avoid combinding X and Y passes - // as that would probably be LESS efficient here. - x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 150)); - y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 30)); - CheckPipeline2(100, - 100, - 150, - 30, - "100x100 -> 100x30 bilinear4 Y\n" - "100x30 -> 150x30 bilinear\n"); - - // X scaled to 1%, Y scaled 1% - x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 128)); - x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 64)); - x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 32)); - x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 16)); - x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 8)); - x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 4)); - x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 2)); - x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 1)); - y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 128)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 64)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 32)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 16)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 8)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 4)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 2)); - y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 1)); - CheckPipeline2(100, - 100, - 1, - 1, - "100x100 -> 100x32 bilinear4 Y\n" - "100x32 -> 100x4 bilinear4 Y\n" - "100x4 -> 64x1 bilinear2x2\n" - "64x1 -> 8x1 bilinear4 X\n" - "8x1 -> 1x1 bilinear4 X\n"); - } - - scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context_; - gpu::ContextSupport* context_support_; - scoped_ptr<content::GLHelper> helper_; - scoped_ptr<content::GLHelperScaling> helper_scaling_; - std::deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_; -}; - -class GLHelperPixelTest : public GLHelperTest { - private: - gfx::DisableNullDrawGLBindings enable_pixel_output_; -}; - -TEST_F(GLHelperTest, RGBASyncReadbackTest) { - const int kTestSize = 64; - bool result = TestTextureFormatReadback(gfx::Size(kTestSize,kTestSize), - kRGBA_8888_SkColorType, - false); - EXPECT_EQ(result, true); -} - - -TEST_F(GLHelperTest, BGRASyncReadbackTest) { - const int kTestSize = 64; - bool result = TestTextureFormatReadback(gfx::Size(kTestSize,kTestSize), - kBGRA_8888_SkColorType, - false); - EXPECT_EQ(result, true); -} - -TEST_F(GLHelperTest, RGB565SyncReadbackTest) { - const int kTestSize = 64; - bool result = TestTextureFormatReadback(gfx::Size(kTestSize,kTestSize), - kRGB_565_SkColorType, - false); - EXPECT_EQ(result, true); -} - -TEST_F(GLHelperTest, RGBAASyncReadbackTest) { - const int kTestSize = 64; - bool result = TestTextureFormatReadback(gfx::Size(kTestSize,kTestSize), - kRGBA_8888_SkColorType, - true); - EXPECT_EQ(result, true); -} - -TEST_F(GLHelperTest, BGRAASyncReadbackTest) { - const int kTestSize = 64; - bool result = TestTextureFormatReadback(gfx::Size(kTestSize,kTestSize), - kBGRA_8888_SkColorType, - true); - EXPECT_EQ(result, true); -} - -TEST_F(GLHelperTest, RGB565ASyncReadbackTest) { - const int kTestSize = 64; - bool result = TestTextureFormatReadback(gfx::Size(kTestSize,kTestSize), - kRGB_565_SkColorType, - true); - EXPECT_EQ(result, true); -} - -TEST_F(GLHelperPixelTest, YUVReadbackOptTest) { - // This test uses the gpu.service/gpu_decoder tracing events to detect how - // many scaling passes are actually performed by the YUV readback pipeline. - StartTracing(TRACE_DISABLED_BY_DEFAULT("gpu.service") "," - TRACE_DISABLED_BY_DEFAULT("gpu_decoder")); - - TestYUVReadback(800, - 400, - 800, - 400, - 0, - 0, - 1, - false, - true, - content::GLHelper::SCALER_QUALITY_FAST); - - std::map<std::string, int> event_counts; - EndTracing(&event_counts); - int draw_buffer_calls = event_counts["kDrawBuffersEXTImmediate"]; - int draw_arrays_calls = event_counts["kDrawArrays"]; - VLOG(1) << "Draw buffer calls: " << draw_buffer_calls; - VLOG(1) << "DrawArrays calls: " << draw_arrays_calls; - - if (draw_buffer_calls) { - // When using MRT, the YUV readback code should only - // execute two draw arrays, and scaling should be integrated - // into those two calls since we are using the FAST scalign - // quality. - EXPECT_EQ(2, draw_arrays_calls); - } else { - // When not using MRT, there are three passes for the YUV, - // and one for the scaling. - EXPECT_EQ(4, draw_arrays_calls); - } -} - -class GLHelperPixelYuvReadback : - public GLHelperPixelTest, - public ::testing::WithParamInterface< - std::tr1::tuple<bool, bool, unsigned int, unsigned int>> {}; - -int kYUVReadBackSizes[] = {2, 4, 14}; - -TEST_P(GLHelperPixelYuvReadback, Test) { - bool flip = std::tr1::get<0>(GetParam()); - bool use_mrt = std::tr1::get<1>(GetParam()); - unsigned int x = std::tr1::get<2>(GetParam()); - unsigned int y = std::tr1::get<3>(GetParam()); - - for (unsigned int ox = x; ox < arraysize(kYUVReadBackSizes); ox++) { - for (unsigned int oy = y; oy < arraysize(kYUVReadBackSizes); oy++) { - // If output is a subsection of the destination frame, (letterbox) - // then try different variations of where the subsection goes. - for (Margin xm = x < ox ? MarginLeft : MarginRight; - xm <= MarginRight; - xm = NextMargin(xm)) { - for (Margin ym = y < oy ? MarginLeft : MarginRight; - ym <= MarginRight; - ym = NextMargin(ym)) { - for (int pattern = 0; pattern < 3; pattern++) { - TestYUVReadback(kYUVReadBackSizes[x], - kYUVReadBackSizes[y], - kYUVReadBackSizes[ox], - kYUVReadBackSizes[oy], - compute_margin(kYUVReadBackSizes[x], - kYUVReadBackSizes[ox], xm), - compute_margin(kYUVReadBackSizes[y], - kYUVReadBackSizes[oy], ym), - pattern, - flip, - use_mrt, - content::GLHelper::SCALER_QUALITY_GOOD); - if (HasFailure()) { - return; - } - } - } - } - } - } -} - -// First argument is intentionally empty. -INSTANTIATE_TEST_CASE_P( - , - GLHelperPixelYuvReadback, - ::testing::Combine( - ::testing::Bool(), - ::testing::Bool(), - ::testing::Range<unsigned int>(0, arraysize(kYUVReadBackSizes)), - ::testing::Range<unsigned int>(0, arraysize(kYUVReadBackSizes)))); - - -// Per pixel tests, all sizes are small so that we can print -// out the generated bitmaps. -TEST_F(GLHelperPixelTest, ScaleTest) { - int sizes[] = {3, 6, 16}; - for (int flip = 0; flip <= 1; flip++) { - for (size_t q_index = 0; q_index < arraysize(kQualities); q_index++) { - for (int x = 0; x < 3; x++) { - for (int y = 0; y < 3; y++) { - for (int dst_x = 0; dst_x < 3; dst_x++) { - for (int dst_y = 0; dst_y < 3; dst_y++) { - for (int pattern = 0; pattern < 3; pattern++) { - TestScale(sizes[x], - sizes[y], - sizes[dst_x], - sizes[dst_y], - pattern, - q_index, - flip == 1); - if (HasFailure()) { - return; - } - } - } - } - } - } - } - } -} - -// Per pixel tests, all sizes are small so that we can print -// out the generated bitmaps. -TEST_F(GLHelperPixelTest, CropScaleReadbackAndCleanTextureTest) { - const int kSizes[] = {3, 6, 16}; - const SkColorType kColorTypes[] = { - kAlpha_8_SkColorType, kRGBA_8888_SkColorType, kBGRA_8888_SkColorType}; - for (size_t color_type = 0; color_type < arraysize(kColorTypes); - color_type++) { - // Test BEST and FAST qualities, skip GOOD - for (size_t q_index = 0; q_index < arraysize(kQualities); q_index += 2) { - for (size_t x = 0; x < arraysize(kSizes); x++) { - for (size_t y = 0; y < arraysize(kSizes); y++) { - for (size_t dst_x = 0; dst_x < arraysize(kSizes); dst_x++) { - for (size_t dst_y = 0; dst_y < arraysize(kSizes); dst_y++) { - for (int pattern = 0; pattern < 3; pattern++) { - TestCropScaleReadbackAndCleanTexture(kSizes[x], - kSizes[y], - kSizes[dst_x], - kSizes[dst_y], - pattern, - kColorTypes[color_type], - false, - q_index); - if (HasFailure()) - return; - } - } - } - } - } - } - } -} - -// Validate that all scaling generates valid pipelines. -TEST_F(GLHelperTest, ValidateScalerPipelines) { - int sizes[] = {7, 99, 128, 256, 512, 719, 720, 721, 1920, 2011, 3217, 4096}; - for (size_t q = 0; q < arraysize(kQualities); q++) { - for (size_t x = 0; x < arraysize(sizes); x++) { - for (size_t y = 0; y < arraysize(sizes); y++) { - for (size_t dst_x = 0; dst_x < arraysize(sizes); dst_x++) { - for (size_t dst_y = 0; dst_y < arraysize(sizes); dst_y++) { - TestScalerPipeline( - q, sizes[x], sizes[y], sizes[dst_x], sizes[dst_y]); - if (HasFailure()) { - return; - } - } - } - } - } - } -} - -// Make sure we don't create overly complicated pipelines -// for a few common use cases. -TEST_F(GLHelperTest, CheckSpecificPipelines) { - // Upscale should be single pass. - CheckPipeline(content::GLHelper::SCALER_QUALITY_GOOD, - 1024, - 700, - 1280, - 720, - "1024x700 -> 1280x720 bilinear\n"); - // Slight downscale should use BILINEAR2X2. - CheckPipeline(content::GLHelper::SCALER_QUALITY_GOOD, - 1280, - 720, - 1024, - 700, - "1280x720 -> 1024x700 bilinear2x2\n"); - // Most common tab capture pipeline on the Pixel. - // Should be using two BILINEAR3 passes. - CheckPipeline(content::GLHelper::SCALER_QUALITY_GOOD, - 2560, - 1476, - 1249, - 720, - "2560x1476 -> 2560x720 bilinear3 Y\n" - "2560x720 -> 1249x720 bilinear3 X\n"); -} - -TEST_F(GLHelperTest, ScalerOpTest) { - for (int allow3 = 0; allow3 <= 1; allow3++) { - for (int dst = 1; dst < 2049; dst += 1 + (dst >> 3)) { - for (int src = 1; src < 2049; src++) { - TestAddOps(src, dst, allow3 == 1, (src & 1) == 1); - if (HasFailure()) { - LOG(ERROR) << "Failed for src=" << src << " dst=" << dst - << " allow3=" << allow3; - return; - } - } - } - } -} - -TEST_F(GLHelperTest, CheckOptimizations) { - // Test in baseclass since it is friends with GLHelperScaling - CheckOptimizationsTest(); -} - -} // namespace content - -namespace { - -int RunHelper(base::TestSuite* test_suite) { - content::UnitTestTestSuite runner(test_suite); - base::MessageLoopForIO message_loop; - return runner.Run(); -} - -} // namespace - -// These tests needs to run against a proper GL environment, so we -// need to set it up before we can run the tests. -int main(int argc, char** argv) { - base::CommandLine::Init(argc, argv); - base::TestSuite* suite = new content::ContentTestSuite(argc, argv); -#if defined(OS_MACOSX) - base::mac::ScopedNSAutoreleasePool pool; -#endif - - return base::LaunchUnitTestsSerially( - argc, - argv, - base::Bind(&RunHelper, base::Unretained(suite))); -} diff --git a/chromium/content/common/gpu/client/gpu_channel_host.cc b/chromium/content/common/gpu/client/gpu_channel_host.cc deleted file mode 100644 index 25328f45399..00000000000 --- a/chromium/content/common/gpu/client/gpu_channel_host.cc +++ /dev/null @@ -1,552 +0,0 @@ -// Copyright (c) 2012 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 "content/common/gpu/client/gpu_channel_host.h" - -#include <algorithm> -#include <utility> - -#include "base/atomic_sequence_num.h" -#include "base/bind.h" -#include "base/location.h" -#include "base/posix/eintr_wrapper.h" -#include "base/single_thread_task_runner.h" -#include "base/thread_task_runner_handle.h" -#include "base/threading/thread_restrictions.h" -#include "base/trace_event/trace_event.h" -#include "build/build_config.h" -#include "content/common/gpu/client/command_buffer_proxy_impl.h" -#include "content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h" -#include "content/common/gpu/gpu_messages.h" -#include "ipc/ipc_sync_message_filter.h" -#include "url/gurl.h" - -#if defined(OS_WIN) || defined(OS_MACOSX) -#include "content/public/common/sandbox_init.h" -#endif - -using base::AutoLock; - -namespace content { -namespace { - -// Global atomic to generate unique transfer buffer IDs. -base::StaticAtomicSequenceNumber g_next_transfer_buffer_id; - -} // namespace - -GpuChannelHost::StreamFlushInfo::StreamFlushInfo() - : next_stream_flush_id(1), - flushed_stream_flush_id(0), - verified_stream_flush_id(0), - flush_pending(false), - route_id(MSG_ROUTING_NONE), - put_offset(0), - flush_count(0), - flush_id(0) {} - -GpuChannelHost::StreamFlushInfo::~StreamFlushInfo() {} - -// static -scoped_refptr<GpuChannelHost> GpuChannelHost::Create( - GpuChannelHostFactory* factory, - int channel_id, - const gpu::GPUInfo& gpu_info, - const IPC::ChannelHandle& channel_handle, - base::WaitableEvent* shutdown_event, - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager) { - DCHECK(factory->IsMainThread()); - scoped_refptr<GpuChannelHost> host = - new GpuChannelHost(factory, channel_id, gpu_info, - gpu_memory_buffer_manager); - host->Connect(channel_handle, shutdown_event); - return host; -} - -GpuChannelHost::GpuChannelHost( - GpuChannelHostFactory* factory, - int channel_id, - const gpu::GPUInfo& gpu_info, - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager) - : factory_(factory), - channel_id_(channel_id), - gpu_info_(gpu_info), - gpu_memory_buffer_manager_(gpu_memory_buffer_manager) { - next_image_id_.GetNext(); - next_route_id_.GetNext(); - next_stream_id_.GetNext(); -} - -void GpuChannelHost::Connect(const IPC::ChannelHandle& channel_handle, - base::WaitableEvent* shutdown_event) { - DCHECK(factory_->IsMainThread()); - // Open a channel to the GPU process. We pass NULL as the main listener here - // since we need to filter everything to route it to the right thread. - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner = - factory_->GetIOThreadTaskRunner(); - channel_ = - IPC::SyncChannel::Create(channel_handle, IPC::Channel::MODE_CLIENT, NULL, - io_task_runner.get(), true, shutdown_event); - - sync_filter_ = channel_->CreateSyncMessageFilter(); - - channel_filter_ = new MessageFilter(); - - // Install the filter last, because we intercept all leftover - // messages. - channel_->AddFilter(channel_filter_.get()); -} - -bool GpuChannelHost::Send(IPC::Message* msg) { - // Callee takes ownership of message, regardless of whether Send is - // successful. See IPC::Sender. - scoped_ptr<IPC::Message> message(msg); - // The GPU process never sends synchronous IPCs so clear the unblock flag to - // preserve order. - message->set_unblock(false); - - // Currently we need to choose between two different mechanisms for sending. - // On the main thread we use the regular channel Send() method, on another - // thread we use SyncMessageFilter. We also have to be careful interpreting - // IsMainThread() since it might return false during shutdown, - // impl we are actually calling from the main thread (discard message then). - // - // TODO: Can we just always use sync_filter_ since we setup the channel - // without a main listener? - if (factory_->IsMainThread()) { - // channel_ is only modified on the main thread, so we don't need to take a - // lock here. - if (!channel_) { - DVLOG(1) << "GpuChannelHost::Send failed: Channel already destroyed"; - return false; - } - // http://crbug.com/125264 - base::ThreadRestrictions::ScopedAllowWait allow_wait; - bool result = channel_->Send(message.release()); - if (!result) - DVLOG(1) << "GpuChannelHost::Send failed: Channel::Send failed"; - return result; - } - - bool result = sync_filter_->Send(message.release()); - return result; -} - -uint32_t GpuChannelHost::OrderingBarrier( - int32_t route_id, - int32_t stream_id, - int32_t put_offset, - uint32_t flush_count, - const std::vector<ui::LatencyInfo>& latency_info, - bool put_offset_changed, - bool do_flush) { - AutoLock lock(context_lock_); - StreamFlushInfo& flush_info = stream_flush_info_[stream_id]; - if (flush_info.flush_pending && flush_info.route_id != route_id) - InternalFlush(&flush_info); - - if (put_offset_changed) { - const uint32_t flush_id = flush_info.next_stream_flush_id++; - flush_info.flush_pending = true; - flush_info.route_id = route_id; - flush_info.put_offset = put_offset; - flush_info.flush_count = flush_count; - flush_info.flush_id = flush_id; - flush_info.latency_info.insert(flush_info.latency_info.end(), - latency_info.begin(), latency_info.end()); - - if (do_flush) - InternalFlush(&flush_info); - - return flush_id; - } - return 0; -} - -void GpuChannelHost::FlushPendingStream(int32_t stream_id) { - AutoLock lock(context_lock_); - auto flush_info_iter = stream_flush_info_.find(stream_id); - if (flush_info_iter == stream_flush_info_.end()) - return; - - StreamFlushInfo& flush_info = flush_info_iter->second; - if (flush_info.flush_pending) - InternalFlush(&flush_info); -} - -void GpuChannelHost::InternalFlush(StreamFlushInfo* flush_info) { - context_lock_.AssertAcquired(); - DCHECK(flush_info); - DCHECK(flush_info->flush_pending); - DCHECK_LT(flush_info->flushed_stream_flush_id, flush_info->flush_id); - Send(new GpuCommandBufferMsg_AsyncFlush( - flush_info->route_id, flush_info->put_offset, flush_info->flush_count, - flush_info->latency_info)); - flush_info->latency_info.clear(); - flush_info->flush_pending = false; - - flush_info->flushed_stream_flush_id = flush_info->flush_id; -} - -scoped_ptr<CommandBufferProxyImpl> GpuChannelHost::CreateViewCommandBuffer( - int32_t surface_id, - CommandBufferProxyImpl* share_group, - int32_t stream_id, - GpuStreamPriority stream_priority, - const std::vector<int32_t>& attribs, - const GURL& active_url, - gfx::GpuPreference gpu_preference) { - DCHECK(!share_group || (stream_id == share_group->stream_id())); - TRACE_EVENT1("gpu", - "GpuChannelHost::CreateViewCommandBuffer", - "surface_id", - surface_id); - - GPUCreateCommandBufferConfig init_params; - init_params.share_group_id = - share_group ? share_group->route_id() : MSG_ROUTING_NONE; - init_params.stream_id = stream_id; - init_params.stream_priority = stream_priority; - init_params.attribs = attribs; - init_params.active_url = active_url; - init_params.gpu_preference = gpu_preference; - - int32_t route_id = GenerateRouteID(); - - CreateCommandBufferResult result = factory_->CreateViewCommandBuffer( - surface_id, init_params, route_id); - if (result != CREATE_COMMAND_BUFFER_SUCCEEDED) { - LOG(ERROR) << "GpuChannelHost::CreateViewCommandBuffer failed."; - - if (result == CREATE_COMMAND_BUFFER_FAILED_AND_CHANNEL_LOST) { - // The GPU channel needs to be considered lost. The caller will - // then set up a new connection, and the GPU channel and any - // view command buffers will all be associated with the same GPU - // process. - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner = - factory_->GetIOThreadTaskRunner(); - io_task_runner->PostTask( - FROM_HERE, base::Bind(&GpuChannelHost::MessageFilter::OnChannelError, - channel_filter_.get())); - } - - return NULL; - } - - scoped_ptr<CommandBufferProxyImpl> command_buffer = - make_scoped_ptr(new CommandBufferProxyImpl(this, route_id, stream_id)); - AddRoute(route_id, command_buffer->AsWeakPtr()); - - return command_buffer; -} - -scoped_ptr<CommandBufferProxyImpl> GpuChannelHost::CreateOffscreenCommandBuffer( - const gfx::Size& size, - CommandBufferProxyImpl* share_group, - int32_t stream_id, - GpuStreamPriority stream_priority, - const std::vector<int32_t>& attribs, - const GURL& active_url, - gfx::GpuPreference gpu_preference) { - DCHECK(!share_group || (stream_id == share_group->stream_id())); - TRACE_EVENT0("gpu", "GpuChannelHost::CreateOffscreenCommandBuffer"); - - GPUCreateCommandBufferConfig init_params; - init_params.share_group_id = - share_group ? share_group->route_id() : MSG_ROUTING_NONE; - init_params.stream_id = stream_id; - init_params.stream_priority = stream_priority; - init_params.attribs = attribs; - init_params.active_url = active_url; - init_params.gpu_preference = gpu_preference; - - int32_t route_id = GenerateRouteID(); - - bool succeeded = false; - if (!Send(new GpuChannelMsg_CreateOffscreenCommandBuffer( - size, init_params, route_id, &succeeded))) { - LOG(ERROR) << "Failed to send GpuChannelMsg_CreateOffscreenCommandBuffer."; - return NULL; - } - - if (!succeeded) { - LOG(ERROR) - << "GpuChannelMsg_CreateOffscreenCommandBuffer returned failure."; - return NULL; - } - - scoped_ptr<CommandBufferProxyImpl> command_buffer = - make_scoped_ptr(new CommandBufferProxyImpl(this, route_id, stream_id)); - AddRoute(route_id, command_buffer->AsWeakPtr()); - - return command_buffer; -} - -scoped_ptr<media::JpegDecodeAccelerator> GpuChannelHost::CreateJpegDecoder( - media::JpegDecodeAccelerator::Client* client) { - TRACE_EVENT0("gpu", "GpuChannelHost::CreateJpegDecoder"); - - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner = - factory_->GetIOThreadTaskRunner(); - int32_t route_id = GenerateRouteID(); - scoped_ptr<GpuJpegDecodeAcceleratorHost> decoder( - new GpuJpegDecodeAcceleratorHost(this, route_id, io_task_runner)); - if (!decoder->Initialize(client)) { - return nullptr; - } - - // The reply message of jpeg decoder should run on IO thread. - io_task_runner->PostTask(FROM_HERE, - base::Bind(&GpuChannelHost::MessageFilter::AddRoute, - channel_filter_.get(), route_id, - decoder->GetReceiver(), io_task_runner)); - - return std::move(decoder); -} - -void GpuChannelHost::DestroyCommandBuffer( - CommandBufferProxyImpl* command_buffer) { - TRACE_EVENT0("gpu", "GpuChannelHost::DestroyCommandBuffer"); - - int32_t route_id = command_buffer->route_id(); - int32_t stream_id = command_buffer->stream_id(); - Send(new GpuChannelMsg_DestroyCommandBuffer(route_id)); - RemoveRoute(route_id); - - AutoLock lock(context_lock_); - StreamFlushInfo& flush_info = stream_flush_info_[stream_id]; - if (flush_info.flush_pending && flush_info.route_id == route_id) - flush_info.flush_pending = false; -} - -void GpuChannelHost::DestroyChannel() { - DCHECK(factory_->IsMainThread()); - AutoLock lock(context_lock_); - channel_.reset(); -} - -void GpuChannelHost::AddRoute( - int route_id, base::WeakPtr<IPC::Listener> listener) { - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner = - factory_->GetIOThreadTaskRunner(); - io_task_runner->PostTask(FROM_HERE, - base::Bind(&GpuChannelHost::MessageFilter::AddRoute, - channel_filter_.get(), route_id, listener, - base::ThreadTaskRunnerHandle::Get())); -} - -void GpuChannelHost::RemoveRoute(int route_id) { - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner = - factory_->GetIOThreadTaskRunner(); - io_task_runner->PostTask( - FROM_HERE, base::Bind(&GpuChannelHost::MessageFilter::RemoveRoute, - channel_filter_.get(), route_id)); -} - -base::SharedMemoryHandle GpuChannelHost::ShareToGpuProcess( - base::SharedMemoryHandle source_handle) { - if (IsLost()) - return base::SharedMemory::NULLHandle(); - -#if defined(OS_WIN) || defined(OS_MACOSX) - // Windows and Mac need to explicitly duplicate the handle out to another - // process. - base::SharedMemoryHandle target_handle; - base::ProcessId peer_pid; - { - AutoLock lock(context_lock_); - if (!channel_) - return base::SharedMemory::NULLHandle(); - peer_pid = channel_->GetPeerPID(); - } - bool success = BrokerDuplicateSharedMemoryHandle(source_handle, peer_pid, - &target_handle); - if (!success) - return base::SharedMemory::NULLHandle(); - - return target_handle; -#else - return base::SharedMemory::DuplicateHandle(source_handle); -#endif // defined(OS_WIN) || defined(OS_MACOSX) -} - -int32_t GpuChannelHost::ReserveTransferBufferId() { - // 0 is a reserved value. - return g_next_transfer_buffer_id.GetNext() + 1; -} - -gfx::GpuMemoryBufferHandle GpuChannelHost::ShareGpuMemoryBufferToGpuProcess( - const gfx::GpuMemoryBufferHandle& source_handle, - bool* requires_sync_point) { - switch (source_handle.type) { - case gfx::SHARED_MEMORY_BUFFER: { - gfx::GpuMemoryBufferHandle handle; - handle.type = gfx::SHARED_MEMORY_BUFFER; - handle.handle = ShareToGpuProcess(source_handle.handle); - handle.offset = source_handle.offset; - handle.stride = source_handle.stride; - *requires_sync_point = false; - return handle; - } - case gfx::IO_SURFACE_BUFFER: - case gfx::SURFACE_TEXTURE_BUFFER: - case gfx::OZONE_NATIVE_PIXMAP: - *requires_sync_point = true; - return source_handle; - default: - NOTREACHED(); - return gfx::GpuMemoryBufferHandle(); - } -} - -int32_t GpuChannelHost::ReserveImageId() { - return next_image_id_.GetNext(); -} - -int32_t GpuChannelHost::GenerateRouteID() { - return next_route_id_.GetNext(); -} - -int32_t GpuChannelHost::GenerateStreamID() { - const int32_t stream_id = next_stream_id_.GetNext(); - DCHECK_NE(0, stream_id); - DCHECK_NE(kDefaultStreamId, stream_id); - return stream_id; -} - -uint32_t GpuChannelHost::ValidateFlushIDReachedServer(int32_t stream_id, - bool force_validate) { - // Store what flush ids we will be validating for all streams. - base::hash_map<int32_t, uint32_t> validate_flushes; - uint32_t flushed_stream_flush_id = 0; - uint32_t verified_stream_flush_id = 0; - { - AutoLock lock(context_lock_); - for (const auto& iter : stream_flush_info_) { - const int32_t iter_stream_id = iter.first; - const StreamFlushInfo& flush_info = iter.second; - if (iter_stream_id == stream_id) { - flushed_stream_flush_id = flush_info.flushed_stream_flush_id; - verified_stream_flush_id = flush_info.verified_stream_flush_id; - } - - if (flush_info.flushed_stream_flush_id > - flush_info.verified_stream_flush_id) { - validate_flushes.insert( - std::make_pair(iter_stream_id, flush_info.flushed_stream_flush_id)); - } - } - } - - if (!force_validate && flushed_stream_flush_id == verified_stream_flush_id) { - // Current stream has no unverified flushes. - return verified_stream_flush_id; - } - - if (Send(new GpuChannelMsg_Nop())) { - // Update verified flush id for all streams. - uint32_t highest_flush_id = 0; - AutoLock lock(context_lock_); - for (const auto& iter : validate_flushes) { - const int32_t validated_stream_id = iter.first; - const uint32_t validated_flush_id = iter.second; - StreamFlushInfo& flush_info = stream_flush_info_[validated_stream_id]; - if (flush_info.verified_stream_flush_id < validated_flush_id) { - flush_info.verified_stream_flush_id = validated_flush_id; - } - - if (validated_stream_id == stream_id) - highest_flush_id = flush_info.verified_stream_flush_id; - } - - return highest_flush_id; - } - - return 0; -} - -uint32_t GpuChannelHost::GetHighestValidatedFlushID(int32_t stream_id) { - AutoLock lock(context_lock_); - StreamFlushInfo& flush_info = stream_flush_info_[stream_id]; - return flush_info.verified_stream_flush_id; -} - -GpuChannelHost::~GpuChannelHost() { -#if DCHECK_IS_ON() - AutoLock lock(context_lock_); - DCHECK(!channel_) - << "GpuChannelHost::DestroyChannel must be called before destruction."; -#endif -} - -GpuChannelHost::MessageFilter::ListenerInfo::ListenerInfo() {} - -GpuChannelHost::MessageFilter::ListenerInfo::~ListenerInfo() {} - -GpuChannelHost::MessageFilter::MessageFilter() - : lost_(false) { -} - -GpuChannelHost::MessageFilter::~MessageFilter() {} - -void GpuChannelHost::MessageFilter::AddRoute( - int32_t route_id, - base::WeakPtr<IPC::Listener> listener, - scoped_refptr<base::SingleThreadTaskRunner> task_runner) { - DCHECK(listeners_.find(route_id) == listeners_.end()); - DCHECK(task_runner); - ListenerInfo info; - info.listener = listener; - info.task_runner = task_runner; - listeners_[route_id] = info; -} - -void GpuChannelHost::MessageFilter::RemoveRoute(int32_t route_id) { - listeners_.erase(route_id); -} - -bool GpuChannelHost::MessageFilter::OnMessageReceived( - const IPC::Message& message) { - // Never handle sync message replies or we will deadlock here. - if (message.is_reply()) - return false; - - auto it = listeners_.find(message.routing_id()); - if (it == listeners_.end()) - return false; - - const ListenerInfo& info = it->second; - info.task_runner->PostTask( - FROM_HERE, - base::Bind(base::IgnoreResult(&IPC::Listener::OnMessageReceived), - info.listener, message)); - return true; -} - -void GpuChannelHost::MessageFilter::OnChannelError() { - // Set the lost state before signalling the proxies. That way, if they - // themselves post a task to recreate the context, they will not try to re-use - // this channel host. - { - AutoLock lock(lock_); - lost_ = true; - } - - // Inform all the proxies that an error has occurred. This will be reported - // via OpenGL as a lost context. - for (const auto& kv : listeners_) { - const ListenerInfo& info = kv.second; - info.task_runner->PostTask( - FROM_HERE, base::Bind(&IPC::Listener::OnChannelError, info.listener)); - } - - listeners_.clear(); -} - -bool GpuChannelHost::MessageFilter::IsLost() const { - AutoLock lock(lock_); - return lost_; -} - -} // namespace content diff --git a/chromium/content/common/gpu/client/gpu_channel_host.h b/chromium/content/common/gpu/client/gpu_channel_host.h deleted file mode 100644 index bf7b3894c21..00000000000 --- a/chromium/content/common/gpu/client/gpu_channel_host.h +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_GPU_CLIENT_GPU_CHANNEL_HOST_H_ -#define CONTENT_COMMON_GPU_CLIENT_GPU_CHANNEL_HOST_H_ - -#include <stddef.h> -#include <stdint.h> - -#include <string> -#include <vector> - -#include "base/atomic_sequence_num.h" -#include "base/containers/scoped_ptr_hash_map.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "base/process/process.h" -#include "base/synchronization/lock.h" -#include "content/common/content_export.h" -#include "content/common/gpu/gpu_process_launch_causes.h" -#include "content/common/gpu/gpu_result_codes.h" -#include "content/common/gpu/gpu_stream_priority.h" -#include "content/common/message_router.h" -#include "gpu/config/gpu_info.h" -#include "ipc/ipc_channel_handle.h" -#include "ipc/ipc_sync_channel.h" -#include "ipc/message_filter.h" -#include "media/video/jpeg_decode_accelerator.h" -#include "ui/events/latency_info.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/gpu_memory_buffer.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gl/gpu_preference.h" - -class GURL; -class TransportTextureService; -struct GPUCreateCommandBufferConfig; - -namespace base { -class MessageLoop; -class WaitableEvent; -} - -namespace IPC { -class SyncMessageFilter; -} - -namespace media { -class JpegDecodeAccelerator; -class VideoDecodeAccelerator; -class VideoEncodeAccelerator; -} - -namespace gpu { -class GpuMemoryBufferManager; -} - -namespace content { -class CommandBufferProxyImpl; -class GpuChannelHost; - -class CONTENT_EXPORT GpuChannelHostFactory { - public: - virtual ~GpuChannelHostFactory() {} - - virtual bool IsMainThread() = 0; - virtual scoped_refptr<base::SingleThreadTaskRunner> - GetIOThreadTaskRunner() = 0; - virtual scoped_ptr<base::SharedMemory> AllocateSharedMemory(size_t size) = 0; - virtual CreateCommandBufferResult CreateViewCommandBuffer( - int32_t surface_id, - const GPUCreateCommandBufferConfig& init_params, - int32_t route_id) = 0; -}; - -// Encapsulates an IPC channel between the client and one GPU process. -// On the GPU process side there's a corresponding GpuChannel. -// Every method can be called on any thread with a message loop, except for the -// IO thread. -class GpuChannelHost : public IPC::Sender, - public base::RefCountedThreadSafe<GpuChannelHost> { - public: - // Must be called on the main thread (as defined by the factory). - static scoped_refptr<GpuChannelHost> Create( - GpuChannelHostFactory* factory, - int channel_id, - const gpu::GPUInfo& gpu_info, - const IPC::ChannelHandle& channel_handle, - base::WaitableEvent* shutdown_event, - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager); - - static const int32_t kDefaultStreamId = -1; - static const GpuStreamPriority kDefaultStreamPriority = - GpuStreamPriority::NORMAL; - - bool IsLost() const { - DCHECK(channel_filter_.get()); - return channel_filter_->IsLost(); - } - - int channel_id() const { return channel_id_; } - - // The GPU stats reported by the GPU process. - const gpu::GPUInfo& gpu_info() const { return gpu_info_; } - - // IPC::Sender implementation: - bool Send(IPC::Message* msg) override; - - // Set an ordering barrier. AsyncFlushes any pending barriers on other - // routes. Combines multiple OrderingBarriers into a single AsyncFlush. - // Returns the flush ID for the stream or 0 if put offset was not changed. - uint32_t OrderingBarrier(int32_t route_id, - int32_t stream_id, - int32_t put_offset, - uint32_t flush_count, - const std::vector<ui::LatencyInfo>& latency_info, - bool put_offset_changed, - bool do_flush); - - void FlushPendingStream(int32_t stream_id); - - // Create and connect to a command buffer in the GPU process. - scoped_ptr<CommandBufferProxyImpl> CreateViewCommandBuffer( - int32_t surface_id, - CommandBufferProxyImpl* share_group, - int32_t stream_id, - GpuStreamPriority stream_priority, - const std::vector<int32_t>& attribs, - const GURL& active_url, - gfx::GpuPreference gpu_preference); - - // Create and connect to a command buffer in the GPU process. - scoped_ptr<CommandBufferProxyImpl> CreateOffscreenCommandBuffer( - const gfx::Size& size, - CommandBufferProxyImpl* share_group, - int32_t stream_id, - GpuStreamPriority stream_priority, - const std::vector<int32_t>& attribs, - const GURL& active_url, - gfx::GpuPreference gpu_preference); - - // Creates a JPEG decoder in the GPU process. - scoped_ptr<media::JpegDecodeAccelerator> CreateJpegDecoder( - media::JpegDecodeAccelerator::Client* client); - - // Destroy a command buffer created by this channel. - void DestroyCommandBuffer(CommandBufferProxyImpl* command_buffer); - - // Destroy this channel. Must be called on the main thread, before - // destruction. - void DestroyChannel(); - - // Add a route for the current message loop. - void AddRoute(int route_id, base::WeakPtr<IPC::Listener> listener); - void RemoveRoute(int route_id); - - GpuChannelHostFactory* factory() const { return factory_; } - - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager() const { - return gpu_memory_buffer_manager_; - } - - // Returns a handle to the shared memory that can be sent via IPC to the - // GPU process. The caller is responsible for ensuring it is closed. Returns - // an invalid handle on failure. - base::SharedMemoryHandle ShareToGpuProcess( - base::SharedMemoryHandle source_handle); - - // Reserve one unused transfer buffer ID. - int32_t ReserveTransferBufferId(); - - // Returns a GPU memory buffer handle to the buffer that can be sent via - // IPC to the GPU process. The caller is responsible for ensuring it is - // closed. Returns an invalid handle on failure. - gfx::GpuMemoryBufferHandle ShareGpuMemoryBufferToGpuProcess( - const gfx::GpuMemoryBufferHandle& source_handle, - bool* requires_sync_point); - - // Reserve one unused image ID. - int32_t ReserveImageId(); - - // Generate a route ID guaranteed to be unique for this channel. - int32_t GenerateRouteID(); - - // Generate a stream ID guaranteed to be unique for this channel. - int32_t GenerateStreamID(); - - // Sends a synchronous nop to the server which validate that all previous IPC - // messages have been received. Once the synchronous nop has been sent to the - // server all previous flushes will all be marked as validated, including - // flushes for other streams on the same channel. Once a validation has been - // sent, it will return the highest validated flush id for the stream. - // If the validation fails (which can only happen upon context lost), the - // highest validated flush id will not change. If no flush ID were ever - // validated then it will return 0 (Note the lowest valid flush ID is 1). - uint32_t ValidateFlushIDReachedServer(int32_t stream_id, bool force_validate); - - // Returns the highest validated flush ID for a given stream. - uint32_t GetHighestValidatedFlushID(int32_t stream_id); - - private: - friend class base::RefCountedThreadSafe<GpuChannelHost>; - - // A filter used internally to route incoming messages from the IO thread - // to the correct message loop. It also maintains some shared state between - // all the contexts. - class MessageFilter : public IPC::MessageFilter { - public: - MessageFilter(); - - // Called on the IO thread. - void AddRoute(int32_t route_id, - base::WeakPtr<IPC::Listener> listener, - scoped_refptr<base::SingleThreadTaskRunner> task_runner); - // Called on the IO thread. - void RemoveRoute(int32_t route_id); - - // IPC::MessageFilter implementation - // (called on the IO thread): - bool OnMessageReceived(const IPC::Message& msg) override; - void OnChannelError() override; - - // The following methods can be called on any thread. - - // Whether the channel is lost. - bool IsLost() const; - - private: - struct ListenerInfo { - ListenerInfo(); - ~ListenerInfo(); - - base::WeakPtr<IPC::Listener> listener; - scoped_refptr<base::SingleThreadTaskRunner> task_runner; - }; - - ~MessageFilter() override; - - // Threading notes: |listeners_| is only accessed on the IO thread. Every - // other field is protected by |lock_|. - base::hash_map<int32_t, ListenerInfo> listeners_; - - // Protects all fields below this one. - mutable base::Lock lock_; - - // Whether the channel has been lost. - bool lost_; - }; - - struct StreamFlushInfo { - StreamFlushInfo(); - ~StreamFlushInfo(); - - // These are global per stream. - uint32_t next_stream_flush_id; - uint32_t flushed_stream_flush_id; - uint32_t verified_stream_flush_id; - - // These are local per context. - bool flush_pending; - int32_t route_id; - int32_t put_offset; - uint32_t flush_count; - uint32_t flush_id; - std::vector<ui::LatencyInfo> latency_info; - }; - - GpuChannelHost(GpuChannelHostFactory* factory, - int channel_id, - const gpu::GPUInfo& gpu_info, - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager); - ~GpuChannelHost() override; - void Connect(const IPC::ChannelHandle& channel_handle, - base::WaitableEvent* shutdown_event); - bool InternalSend(IPC::Message* msg); - void InternalFlush(StreamFlushInfo* flush_info); - - // Threading notes: all fields are constant during the lifetime of |this| - // except: - // - |next_image_id_|, atomic type - // - |next_route_id_|, atomic type - // - |next_stream_id_|, atomic type - // - |channel_| and |stream_flush_info_|, protected by |context_lock_| - GpuChannelHostFactory* const factory_; - - const int channel_id_; - const gpu::GPUInfo gpu_info_; - - scoped_refptr<MessageFilter> channel_filter_; - - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_; - - // A filter for sending messages from thread other than the main thread. - scoped_refptr<IPC::SyncMessageFilter> sync_filter_; - - // Image IDs are allocated in sequence. - base::AtomicSequenceNumber next_image_id_; - - // Route IDs are allocated in sequence. - base::AtomicSequenceNumber next_route_id_; - - // Stream IDs are allocated in sequence. - base::AtomicSequenceNumber next_stream_id_; - - // Protects channel_ and stream_flush_info_. - mutable base::Lock context_lock_; - scoped_ptr<IPC::SyncChannel> channel_; - base::hash_map<int32_t, StreamFlushInfo> stream_flush_info_; - - DISALLOW_COPY_AND_ASSIGN(GpuChannelHost); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_CLIENT_GPU_CHANNEL_HOST_H_ diff --git a/chromium/content/common/gpu/client/gpu_context_tests.h b/chromium/content/common/gpu/client/gpu_context_tests.h index 8810789d076..9687c4a057e 100644 --- a/chromium/content/common/gpu/client/gpu_context_tests.h +++ b/chromium/content/common/gpu/client/gpu_context_tests.h @@ -10,6 +10,7 @@ #include "base/run_loop.h" #include "gpu/GLES2/gl2extchromium.h" #include "gpu/command_buffer/client/context_support.h" +#include "gpu/command_buffer/client/gles2_interface.h" #include "gpu/command_buffer/common/sync_token.h" namespace { @@ -30,32 +31,39 @@ class SignalTest : public ContextTestBase { } // These tests should time out if the callback doesn't get called. - void TestSignalQuery(blink::WebGLId query) { + void TestSignalQuery(GLuint query) { base::RunLoop run_loop; context_support_->SignalQuery( - query, - base::Bind( - &RunOnlyOnce, run_loop.QuitClosure(), base::Owned(new int(0)))); + query, base::Bind(&RunOnlyOnce, run_loop.QuitClosure(), + base::Owned(new int(0)))); run_loop.Run(); } }; CONTEXT_TEST_F(SignalTest, BasicSignalSyncTokenTest) { - if (!context_) +#if defined(OS_WIN) + // The IPC version of ContextTestBase::SetUpOnMainThread does not succeed on + // some platforms. + if (!gl_) return; +#endif - const blink::WGC3Duint64 fence_sync = context_->insertFenceSyncCHROMIUM(); - context_->shallowFlushCHROMIUM(); + const GLuint64 fence_sync = gl_->InsertFenceSyncCHROMIUM(); + gl_->ShallowFlushCHROMIUM(); gpu::SyncToken sync_token; - ASSERT_TRUE(context_->genSyncTokenCHROMIUM(fence_sync, sync_token.GetData())); + gl_->GenSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); TestSignalSyncToken(sync_token); }; CONTEXT_TEST_F(SignalTest, EmptySignalSyncTokenTest) { - if (!context_) +#if defined(OS_WIN) + // The IPC version of ContextTestBase::SetUpOnMainThread does not succeed on + // some platforms. + if (!gl_) return; +#endif // Signalling something that doesn't exist should run the callback // immediately. @@ -64,42 +72,59 @@ CONTEXT_TEST_F(SignalTest, EmptySignalSyncTokenTest) { }; CONTEXT_TEST_F(SignalTest, InvalidSignalSyncTokenTest) { - if (!context_) +#if defined(OS_WIN) + // The IPC version of ContextTestBase::SetUpOnMainThread does not succeed on + // some platforms. + if (!gl_) return; +#endif // Signalling something that doesn't exist should run the callback // immediately. - gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, - 0, - 1297824234, + gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0, + gpu::CommandBufferId::FromUnsafeValue(1297824234), 9123743439); TestSignalSyncToken(sync_token); }; CONTEXT_TEST_F(SignalTest, BasicSignalQueryTest) { - if (!context_) +#if defined(OS_WIN) + // The IPC version of ContextTestBase::SetUpOnMainThread does not succeed on + // some platforms. + if (!gl_) return; +#endif - unsigned query = context_->createQueryEXT(); - context_->beginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, query); - context_->finish(); - context_->endQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM); + unsigned query; + gl_->GenQueriesEXT(1, &query); + gl_->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, query); + gl_->Finish(); + gl_->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM); TestSignalQuery(query); - context_->deleteQueryEXT(query); + gl_->DeleteQueriesEXT(1, &query); }; CONTEXT_TEST_F(SignalTest, SignalQueryUnboundTest) { - if (!context_) +#if defined(OS_WIN) + // The IPC version of ContextTestBase::SetUpOnMainThread does not succeed on + // some platforms. + if (!gl_) return; +#endif - blink::WebGLId query = context_->createQueryEXT(); + GLuint query; + gl_->GenQueriesEXT(1, &query); TestSignalQuery(query); - context_->deleteQueryEXT(query); + gl_->DeleteQueriesEXT(1, &query); }; CONTEXT_TEST_F(SignalTest, InvalidSignalQueryUnboundTest) { - if (!context_) +#if defined(OS_WIN) + // The IPC version of ContextTestBase::SetUpOnMainThread does not succeed on + // some platforms. + if (!gl_) return; +#endif // Signalling something that doesn't exist should run the callback // immediately. @@ -110,5 +135,4 @@ CONTEXT_TEST_F(SignalTest, InvalidSignalQueryUnboundTest) { TestSignalQuery(928729082); TestSignalQuery(928729081); }; - }; diff --git a/chromium/content/common/gpu/client/gpu_in_process_context_tests.cc b/chromium/content/common/gpu/client/gpu_in_process_context_tests.cc index 6e740572211..c8f0d3f293f 100644 --- a/chromium/content/common/gpu/client/gpu_in_process_context_tests.cc +++ b/chromium/content/common/gpu/client/gpu_in_process_context_tests.cc @@ -7,32 +7,50 @@ #include <string> #include <vector> -#include "content/public/test/unittest_test_suite.h" -#include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h" +#include "gpu/command_buffer/client/gl_in_process_context.h" +#include "gpu/command_buffer/client/gles2_implementation.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gl/gl_surface.h" namespace { -using gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl; - class ContextTestBase : public testing::Test { public: void SetUp() override { - blink::WebGraphicsContext3D::Attributes attributes; - bool lose_context_when_out_of_memory = false; - typedef WebGraphicsContext3DInProcessCommandBufferImpl WGC3DIPCBI; - context_ = WGC3DIPCBI::CreateOffscreenContext( - attributes, lose_context_when_out_of_memory); - context_->InitializeOnCurrentThread(); - context_support_ = context_->GetContextSupport(); + gpu::gles2::ContextCreationAttribHelper attributes; + attributes.alpha_size = 8; + attributes.depth_size = 24; + attributes.red_size = 8; + attributes.green_size = 8; + attributes.blue_size = 8; + attributes.stencil_size = 8; + attributes.samples = 4; + attributes.sample_buffers = 1; + attributes.bind_generates_resource = false; + + context_.reset(gpu::GLInProcessContext::Create( + nullptr, /* service */ + nullptr, /* surface */ + true, /* offscreen */ + gfx::kNullAcceleratedWidget, /* window */ + gfx::Size(1, 1), /* size */ + nullptr, /* share_context */ + attributes, gfx::PreferDiscreteGpu, + ::gpu::GLInProcessContextSharedMemoryLimits(), + nullptr, /* gpu_memory_buffer_manager */ + nullptr /* image_factory */)); + gl_ = context_->GetImplementation(); + context_support_ = context_->GetImplementation(); } void TearDown() override { context_.reset(NULL); } protected: - scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context_; + gpu::gles2::GLES2Interface* gl_; gpu::ContextSupport* context_support_; + + private: + scoped_ptr<gpu::GLInProcessContext> context_; }; } // namespace diff --git a/chromium/content/common/gpu/client/gpu_jpeg_decode_accelerator_host.cc b/chromium/content/common/gpu/client/gpu_jpeg_decode_accelerator_host.cc deleted file mode 100644 index eac971b43b7..00000000000 --- a/chromium/content/common/gpu/client/gpu_jpeg_decode_accelerator_host.cc +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2015 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 "content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h" - -#include <stddef.h> - -#include "base/bind.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/shared_memory_handle.h" -#include "base/memory/weak_ptr.h" -#include "base/synchronization/waitable_event.h" -#include "build/build_config.h" -#include "content/common/gpu/client/gpu_channel_host.h" -#include "content/common/gpu/gpu_messages.h" -#include "ipc/ipc_listener.h" -#include "ipc/ipc_message_macros.h" -#include "ipc/ipc_message_utils.h" - -namespace content { - -// Class to receive AcceleratedJpegDecoderHostMsg_DecodeAck IPC message on IO -// thread. This does very similar what MessageFilter usually does. It is not -// MessageFilter because GpuChannelHost doesn't support AddFilter. -class GpuJpegDecodeAcceleratorHost::Receiver : public IPC::Listener, - public base::NonThreadSafe { - public: - Receiver(Client* client, - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) - : client_(client), - io_task_runner_(io_task_runner), - weak_factory_for_io_(this) { - DCHECK(CalledOnValidThread()); - } - - ~Receiver() override { DCHECK(CalledOnValidThread()); } - - void InvalidateWeakPtr(base::WaitableEvent* event) { - DCHECK(io_task_runner_->BelongsToCurrentThread()); - weak_factory_for_io_.InvalidateWeakPtrs(); - event->Signal(); - } - - // IPC::Listener implementation. - void OnChannelError() override { - DCHECK(io_task_runner_->BelongsToCurrentThread()); - - OnDecodeAck(kInvalidBitstreamBufferId, PLATFORM_FAILURE); - } - - bool OnMessageReceived(const IPC::Message& msg) override { - DCHECK(io_task_runner_->BelongsToCurrentThread()); - - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(GpuJpegDecodeAcceleratorHost::Receiver, msg) - IPC_MESSAGE_HANDLER(AcceleratedJpegDecoderHostMsg_DecodeAck, OnDecodeAck) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - DCHECK(handled); - return handled; - } - - base::WeakPtr<IPC::Listener> AsWeakPtrForIO() { - return weak_factory_for_io_.GetWeakPtr(); - } - - private: - void OnDecodeAck(int32_t bitstream_buffer_id, Error error) { - DCHECK(io_task_runner_->BelongsToCurrentThread()); - - if (!client_) - return; - - if (error == media::JpegDecodeAccelerator::NO_ERRORS) { - client_->VideoFrameReady(bitstream_buffer_id); - } else { - // Only NotifyError once. - // Client::NotifyError() may trigger deletion of |this| (on another - // thread), so calling it needs to be the last thing done on this stack! - media::JpegDecodeAccelerator::Client* client = nullptr; - std::swap(client, client_); - client->NotifyError(bitstream_buffer_id, error); - } - } - - Client* client_; - - // GPU IO task runner. - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; - - // Weak pointers will be invalidated on IO thread. - base::WeakPtrFactory<Receiver> weak_factory_for_io_; - - DISALLOW_COPY_AND_ASSIGN(Receiver); -}; - -GpuJpegDecodeAcceleratorHost::GpuJpegDecodeAcceleratorHost( - GpuChannelHost* channel, - int32_t route_id, - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) - : channel_(channel), - decoder_route_id_(route_id), - io_task_runner_(io_task_runner) { - DCHECK(channel_); - DCHECK_NE(decoder_route_id_, MSG_ROUTING_NONE); -} - -GpuJpegDecodeAcceleratorHost::~GpuJpegDecodeAcceleratorHost() { - DCHECK(CalledOnValidThread()); - Send(new AcceleratedJpegDecoderMsg_Destroy(decoder_route_id_)); - - if (receiver_) { - channel_->RemoveRoute(decoder_route_id_); - - // Invalidate weak ptr of |receiver_|. After that, no more messages will be - // routed to |receiver_| on IO thread. - base::WaitableEvent event(false, false); - io_task_runner_->PostTask(FROM_HERE, - base::Bind(&Receiver::InvalidateWeakPtr, - base::Unretained(receiver_.get()), - base::Unretained(&event))); - event.Wait(); - } -} - -bool GpuJpegDecodeAcceleratorHost::Initialize( - media::JpegDecodeAccelerator::Client* client) { - DCHECK(CalledOnValidThread()); - - bool succeeded = false; - // This cannot be on IO thread because the msg is synchronous. - Send(new GpuMsg_CreateJpegDecoder(decoder_route_id_, &succeeded)); - - if (!succeeded) { - DLOG(ERROR) << "Send(GpuMsg_CreateJpegDecoder()) failed"; - return false; - } - - receiver_.reset(new Receiver(client, io_task_runner_)); - - return true; -} - -void GpuJpegDecodeAcceleratorHost::Decode( - const media::BitstreamBuffer& bitstream_buffer, - const scoped_refptr<media::VideoFrame>& video_frame) { - DCHECK(CalledOnValidThread()); - - DCHECK( - base::SharedMemory::IsHandleValid(video_frame->shared_memory_handle())); - - base::SharedMemoryHandle input_handle = - channel_->ShareToGpuProcess(bitstream_buffer.handle()); - if (!base::SharedMemory::IsHandleValid(input_handle)) { - DLOG(ERROR) << "Failed to duplicate handle of BitstreamBuffer"; - return; - } - base::SharedMemoryHandle output_handle = - channel_->ShareToGpuProcess(video_frame->shared_memory_handle()); - if (!base::SharedMemory::IsHandleValid(output_handle)) { - DLOG(ERROR) << "Failed to duplicate handle of VideoFrame"; -#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS)) - if (input_handle.auto_close) { - // Defer closing task to the ScopedFD. - base::ScopedFD(input_handle.fd); - } -#else - // TODO(kcwu) fix the handle leak after crbug.com/493414 resolved. -#endif - return; - } - - size_t output_buffer_size = media::VideoFrame::AllocationSize( - video_frame->format(), video_frame->coded_size()); - - AcceleratedJpegDecoderMsg_Decode_Params decode_params; - decode_params.coded_size = video_frame->coded_size(); - decode_params.input_buffer_id = bitstream_buffer.id(); - decode_params.input_buffer_handle = input_handle; - decode_params.input_buffer_size = bitstream_buffer.size(); - decode_params.output_video_frame_handle = output_handle; - decode_params.output_buffer_size = output_buffer_size; - Send(new AcceleratedJpegDecoderMsg_Decode(decoder_route_id_, decode_params)); -} - -bool GpuJpegDecodeAcceleratorHost::IsSupported() { - return channel_->gpu_info().jpeg_decode_accelerator_supported; -} - -void GpuJpegDecodeAcceleratorHost::Send(IPC::Message* message) { - DCHECK(CalledOnValidThread()); - - if (!channel_->Send(message)) { - DLOG(ERROR) << "Send(" << message->type() << ") failed"; - } -} - -base::WeakPtr<IPC::Listener> GpuJpegDecodeAcceleratorHost::GetReceiver() { - return receiver_->AsWeakPtrForIO(); -} - -} // namespace content diff --git a/chromium/content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h b/chromium/content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h deleted file mode 100644 index 53465f3aee7..00000000000 --- a/chromium/content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2015 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 CONTENT_COMMON_GPU_CLIENT_GPU_JPEG_DECODE_ACCELERATOR_HOST_H_ -#define CONTENT_COMMON_GPU_CLIENT_GPU_JPEG_DECODE_ACCELERATOR_HOST_H_ - -#include <stdint.h> - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/non_thread_safe.h" -#include "media/video/jpeg_decode_accelerator.h" - -namespace base { -class SingleThreadTaskRunner; -} - -namespace IPC { -class Listener; -class Message; -} - -namespace content { -class GpuChannelHost; - -// This class is used to talk to JpegDecodeAccelerator in the GPU process -// through IPC messages. -class GpuJpegDecodeAcceleratorHost : public media::JpegDecodeAccelerator, - public base::NonThreadSafe { - public: - // VideoCaptureGpuJpegDecoder owns |this| and |channel|. And - // VideoCaptureGpuJpegDecoder delete |this| before |channel|. So |this| is - // guaranteed not to outlive |channel|. - GpuJpegDecodeAcceleratorHost( - GpuChannelHost* channel, - int32_t route_id, - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner); - ~GpuJpegDecodeAcceleratorHost() override; - - // media::JpegDecodeAccelerator implementation. - // |client| is called on the IO thread, but is never called into after the - // GpuJpegDecodeAcceleratorHost is destroyed. - bool Initialize(media::JpegDecodeAccelerator::Client* client) override; - void Decode(const media::BitstreamBuffer& bitstream_buffer, - const scoped_refptr<media::VideoFrame>& video_frame) override; - bool IsSupported() override; - - base::WeakPtr<IPC::Listener> GetReceiver(); - - private: - class Receiver; - - void Send(IPC::Message* message); - - // Unowned reference to the GpuChannelHost to send IPC messages to the GPU - // process. - GpuChannelHost* channel_; - - // Route ID for the associated decoder in the GPU process. - int32_t decoder_route_id_; - - // GPU IO task runner. - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; - - scoped_ptr<Receiver> receiver_; - - DISALLOW_COPY_AND_ASSIGN(GpuJpegDecodeAcceleratorHost); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_CLIENT_GPU_JPEG_DECODE_ACCELERATOR_HOST_H_ diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl.cc deleted file mode 100644 index 5c6571aaf66..00000000000 --- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl.cc +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2013 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 "content/common/gpu/client/gpu_memory_buffer_impl.h" - -#include "base/logging.h" -#include "build/build_config.h" -#include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h" - -#if defined(OS_MACOSX) -#include "content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h" -#endif - -#if defined(OS_ANDROID) -#include "content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.h" -#endif - -#if defined(USE_OZONE) -#include "content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_pixmap.h" -#endif - -namespace content { - -GpuMemoryBufferImpl::GpuMemoryBufferImpl(gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - const DestructionCallback& callback) - : id_(id), - size_(size), - format_(format), - callback_(callback), - mapped_(false) {} - -GpuMemoryBufferImpl::~GpuMemoryBufferImpl() { - DCHECK(!mapped_); - callback_.Run(destruction_sync_token_); -} - -// static -scoped_ptr<GpuMemoryBufferImpl> GpuMemoryBufferImpl::CreateFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - const DestructionCallback& callback) { - switch (handle.type) { - case gfx::SHARED_MEMORY_BUFFER: - return GpuMemoryBufferImplSharedMemory::CreateFromHandle( - handle, size, format, usage, callback); -#if defined(OS_MACOSX) - case gfx::IO_SURFACE_BUFFER: - return GpuMemoryBufferImplIOSurface::CreateFromHandle( - handle, size, format, usage, callback); -#endif -#if defined(OS_ANDROID) - case gfx::SURFACE_TEXTURE_BUFFER: - return GpuMemoryBufferImplSurfaceTexture::CreateFromHandle( - handle, size, format, usage, callback); -#endif -#if defined(USE_OZONE) - case gfx::OZONE_NATIVE_PIXMAP: - return GpuMemoryBufferImplOzoneNativePixmap::CreateFromHandle( - handle, size, format, usage, callback); -#endif - default: - NOTREACHED(); - return nullptr; - } -} - -// static -GpuMemoryBufferImpl* GpuMemoryBufferImpl::FromClientBuffer( - ClientBuffer buffer) { - return reinterpret_cast<GpuMemoryBufferImpl*>(buffer); -} - -gfx::Size GpuMemoryBufferImpl::GetSize() const { - return size_; -} - -gfx::BufferFormat GpuMemoryBufferImpl::GetFormat() const { - return format_; -} - -gfx::GpuMemoryBufferId GpuMemoryBufferImpl::GetId() const { - return id_; -} - -ClientBuffer GpuMemoryBufferImpl::AsClientBuffer() { - return reinterpret_cast<ClientBuffer>(this); -} - -} // namespace content diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl.h b/chromium/content/common/gpu/client/gpu_memory_buffer_impl.h deleted file mode 100644 index 954a87535fd..00000000000 --- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2013 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 CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_H_ -#define CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_H_ - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "content/common/content_export.h" -#include "gpu/command_buffer/common/sync_token.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/gpu_memory_buffer.h" - -namespace content { - -// Provides common implementation of a GPU memory buffer. -class CONTENT_EXPORT GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer { - public: - typedef base::Callback<void(const gpu::SyncToken& sync)> DestructionCallback; - - ~GpuMemoryBufferImpl() override; - - // Creates an instance from the given |handle|. |size| and |internalformat| - // should match what was used to allocate the |handle|. |callback| is - // called when instance is deleted, which is not necessarily on the same - // thread as this function was called on and instance was created on. - static scoped_ptr<GpuMemoryBufferImpl> CreateFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - const DestructionCallback& callback); - - // Type-checking upcast routine. Returns an NULL on failure. - static GpuMemoryBufferImpl* FromClientBuffer(ClientBuffer buffer); - - // Overridden from gfx::GpuMemoryBuffer: - gfx::Size GetSize() const override; - gfx::BufferFormat GetFormat() const override; - gfx::GpuMemoryBufferId GetId() const override; - ClientBuffer AsClientBuffer() override; - - void set_destruction_sync_token(const gpu::SyncToken& sync_token) { - destruction_sync_token_ = sync_token; - } - - protected: - GpuMemoryBufferImpl(gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - const DestructionCallback& callback); - - const gfx::GpuMemoryBufferId id_; - const gfx::Size size_; - const gfx::BufferFormat format_; - const DestructionCallback callback_; - bool mapped_; - gpu::SyncToken destruction_sync_token_; - - private: - DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferImpl); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_H_ diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.cc deleted file mode 100644 index b6038cf72da..00000000000 --- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.cc +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2013 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 "content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h" - -#include "base/logging.h" -#include "content/common/gpu/gpu_memory_buffer_factory_io_surface.h" -#include "ui/gfx/buffer_format_util.h" -#include "ui/gfx/mac/io_surface.h" - -namespace content { -namespace { - -uint32_t LockFlags(gfx::BufferUsage usage) { - switch (usage) { - case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE: - return kIOSurfaceLockAvoidSync; - case gfx::BufferUsage::GPU_READ: - case gfx::BufferUsage::SCANOUT: - case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT: - return 0; - } - NOTREACHED(); - return 0; -} - -void NoOp() { -} - -} // namespace - -GpuMemoryBufferImplIOSurface::GpuMemoryBufferImplIOSurface( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - const DestructionCallback& callback, - IOSurfaceRef io_surface, - uint32_t lock_flags) - : GpuMemoryBufferImpl(id, size, format, callback), - io_surface_(io_surface), - lock_flags_(lock_flags) {} - -GpuMemoryBufferImplIOSurface::~GpuMemoryBufferImplIOSurface() { -} - -// static -scoped_ptr<GpuMemoryBufferImplIOSurface> -GpuMemoryBufferImplIOSurface::CreateFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - const DestructionCallback& callback) { - base::ScopedCFTypeRef<IOSurfaceRef> io_surface( - IOSurfaceLookupFromMachPort(handle.mach_port.get())); - if (!io_surface) - return nullptr; - - return make_scoped_ptr( - new GpuMemoryBufferImplIOSurface(handle.id, size, format, callback, - io_surface.release(), LockFlags(usage))); -} - -// static -bool GpuMemoryBufferImplIOSurface::IsConfigurationSupported( - gfx::BufferFormat format, - gfx::BufferUsage usage) { - return GpuMemoryBufferFactoryIOSurface:: - IsGpuMemoryBufferConfigurationSupported(format, usage); -} - -// static -base::Closure GpuMemoryBufferImplIOSurface::AllocateForTesting( - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - gfx::GpuMemoryBufferHandle* handle) { - base::ScopedCFTypeRef<IOSurfaceRef> io_surface( - gfx::CreateIOSurface(size, format)); - DCHECK(io_surface); - gfx::GpuMemoryBufferId kBufferId(1); - handle->type = gfx::IO_SURFACE_BUFFER; - handle->id = kBufferId; - handle->mach_port.reset(IOSurfaceCreateMachPort(io_surface)); - return base::Bind(&NoOp); -} - -bool GpuMemoryBufferImplIOSurface::Map() { - DCHECK(!mapped_); - IOReturn status = IOSurfaceLock(io_surface_, lock_flags_, NULL); - DCHECK_NE(status, kIOReturnCannotLock); - mapped_ = true; - return true; -} - -void* GpuMemoryBufferImplIOSurface::memory(size_t plane) { - DCHECK(mapped_); - DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format_)); - return IOSurfaceGetBaseAddressOfPlane(io_surface_, plane); -} - -void GpuMemoryBufferImplIOSurface::Unmap() { - DCHECK(mapped_); - IOSurfaceUnlock(io_surface_, lock_flags_, NULL); - mapped_ = false; -} - -bool GpuMemoryBufferImplIOSurface::IsInUseByMacOSWindowServer() const { - return IOSurfaceIsInUse(io_surface_); -} - -int GpuMemoryBufferImplIOSurface::stride(size_t plane) const { - DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format_)); - return IOSurfaceGetBytesPerRowOfPlane(io_surface_, plane); -} - -gfx::GpuMemoryBufferHandle GpuMemoryBufferImplIOSurface::GetHandle() const { - gfx::GpuMemoryBufferHandle handle; - handle.type = gfx::IO_SURFACE_BUFFER; - handle.id = id_; - return handle; -} - -} // namespace content diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h deleted file mode 100644 index 8883cc1a3e2..00000000000 --- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2013 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 CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_IO_SURFACE_H_ -#define CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_IO_SURFACE_H_ - -#include <IOSurface/IOSurface.h> -#include <stddef.h> -#include <stdint.h> - -#include "base/mac/scoped_cftyperef.h" -#include "base/macros.h" -#include "content/common/content_export.h" -#include "content/common/gpu/client/gpu_memory_buffer_impl.h" - -namespace content { - -// Implementation of GPU memory buffer based on IO surfaces. -class CONTENT_EXPORT GpuMemoryBufferImplIOSurface : public GpuMemoryBufferImpl { - public: - ~GpuMemoryBufferImplIOSurface() override; - - static scoped_ptr<GpuMemoryBufferImplIOSurface> CreateFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - const DestructionCallback& callback); - - static bool IsConfigurationSupported(gfx::BufferFormat format, - gfx::BufferUsage usage); - - static base::Closure AllocateForTesting(const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - gfx::GpuMemoryBufferHandle* handle); - - // Overridden from gfx::GpuMemoryBuffer: - bool Map() override; - void* memory(size_t plane) override; - void Unmap() override; - bool IsInUseByMacOSWindowServer() const override; - int stride(size_t plane) const override; - gfx::GpuMemoryBufferHandle GetHandle() const override; - - private: - GpuMemoryBufferImplIOSurface(gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - const DestructionCallback& callback, - IOSurfaceRef io_surface, - uint32_t lock_flags); - - base::ScopedCFTypeRef<IOSurfaceRef> io_surface_; - uint32_t lock_flags_; - - DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferImplIOSurface); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_IO_SURFACE_H_ diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface_unittest.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface_unittest.cc deleted file mode 100644 index 83edce6c3e7..00000000000 --- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_io_surface_unittest.cc +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 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 "content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h" -#include "content/test/gpu_memory_buffer_impl_test_template.h" - -namespace content { -namespace { - -INSTANTIATE_TYPED_TEST_CASE_P(GpuMemoryBufferImplIOSurface, - GpuMemoryBufferImplTest, - GpuMemoryBufferImplIOSurface); - -} // namespace -} // namespace content diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_pixmap.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_pixmap.cc deleted file mode 100644 index c0303555ad9..00000000000 --- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_pixmap.cc +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2014 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 "content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_pixmap.h" - -#include <utility> - -#include "content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.h" -#include "ui/gfx/buffer_format_util.h" -#include "ui/ozone/public/client_native_pixmap_factory.h" -#include "ui/ozone/public/native_pixmap.h" -#include "ui/ozone/public/ozone_platform.h" -#include "ui/ozone/public/surface_factory_ozone.h" - -namespace content { -namespace { - -void FreeNativePixmapForTesting(scoped_refptr<ui::NativePixmap> native_pixmap) { - // Nothing to do here. |native_pixmap| will be freed when this function - // returns and reference count drops to 0. -} - -} // namespace - -GpuMemoryBufferImplOzoneNativePixmap::GpuMemoryBufferImplOzoneNativePixmap( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - const DestructionCallback& callback, - scoped_ptr<ui::ClientNativePixmap> pixmap) - : GpuMemoryBufferImpl(id, size, format, callback), - pixmap_(std::move(pixmap)) {} - -GpuMemoryBufferImplOzoneNativePixmap::~GpuMemoryBufferImplOzoneNativePixmap() {} - -// static -scoped_ptr<GpuMemoryBufferImplOzoneNativePixmap> -GpuMemoryBufferImplOzoneNativePixmap::CreateFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - const DestructionCallback& callback) { - scoped_ptr<ui::ClientNativePixmap> native_pixmap = - ui::ClientNativePixmapFactory::GetInstance()->ImportFromHandle( - handle.native_pixmap_handle, size, usage); - DCHECK(native_pixmap); - return make_scoped_ptr(new GpuMemoryBufferImplOzoneNativePixmap( - handle.id, size, format, callback, std::move(native_pixmap))); -} - -// static -bool GpuMemoryBufferImplOzoneNativePixmap::IsConfigurationSupported( - gfx::BufferFormat format, - gfx::BufferUsage usage) { - return GpuMemoryBufferFactoryOzoneNativePixmap:: - IsGpuMemoryBufferConfigurationSupported(format, usage); -} - -// static -base::Closure GpuMemoryBufferImplOzoneNativePixmap::AllocateForTesting( - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - gfx::GpuMemoryBufferHandle* handle) { - DCHECK(IsConfigurationSupported(format, usage)); - scoped_refptr<ui::NativePixmap> pixmap = - ui::OzonePlatform::GetInstance() - ->GetSurfaceFactoryOzone() - ->CreateNativePixmap(gfx::kNullPluginWindow, size, format, usage); - handle->type = gfx::OZONE_NATIVE_PIXMAP; - handle->native_pixmap_handle = pixmap->ExportHandle(); - return base::Bind(&FreeNativePixmapForTesting, pixmap); -} - -bool GpuMemoryBufferImplOzoneNativePixmap::Map() { - DCHECK(!mapped_); - if (!pixmap_->Map()) - return false; - mapped_ = true; - return mapped_; -} - -void* GpuMemoryBufferImplOzoneNativePixmap::memory(size_t plane) { - DCHECK(mapped_); - DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format_)); - return pixmap_->Map(); -} - -void GpuMemoryBufferImplOzoneNativePixmap::Unmap() { - DCHECK(mapped_); - pixmap_->Unmap(); - mapped_ = false; -} - -int GpuMemoryBufferImplOzoneNativePixmap::stride(size_t plane) const { - DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format_)); - int stride; - pixmap_->GetStride(&stride); - return stride; -} - -gfx::GpuMemoryBufferHandle GpuMemoryBufferImplOzoneNativePixmap::GetHandle() - const { - gfx::GpuMemoryBufferHandle handle; - handle.type = gfx::OZONE_NATIVE_PIXMAP; - handle.id = id_; - return handle; -} - -} // namespace content diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_pixmap.h b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_pixmap.h deleted file mode 100644 index aa073e111e3..00000000000 --- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_pixmap.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2014 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 CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_OZONE_NATIVE_PIXMAP_H_ -#define CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_OZONE_NATIVE_PIXMAP_H_ - -#include <stddef.h> - -#include "base/macros.h" -#include "content/common/content_export.h" -#include "content/common/gpu/client/gpu_memory_buffer_impl.h" - -namespace ui { -class ClientNativePixmap; -} - -namespace content { - -// Implementation of GPU memory buffer based on Ozone native pixmap. -class CONTENT_EXPORT GpuMemoryBufferImplOzoneNativePixmap - : public GpuMemoryBufferImpl { - public: - ~GpuMemoryBufferImplOzoneNativePixmap() override; - - static scoped_ptr<GpuMemoryBufferImplOzoneNativePixmap> CreateFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - const DestructionCallback& callback); - - static bool IsConfigurationSupported(gfx::BufferFormat format, - gfx::BufferUsage usage); - - static base::Closure AllocateForTesting(const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - gfx::GpuMemoryBufferHandle* handle); - - // Overridden from gfx::GpuMemoryBuffer: - bool Map() override; - void* memory(size_t plane) override; - void Unmap() override; - int stride(size_t plane) const override; - gfx::GpuMemoryBufferHandle GetHandle() const override; - - private: - GpuMemoryBufferImplOzoneNativePixmap( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - const DestructionCallback& callback, - scoped_ptr<ui::ClientNativePixmap> native_pixmap); - - scoped_ptr<ui::ClientNativePixmap> pixmap_; - - DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferImplOzoneNativePixmap); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_OZONE_NATIVE_PIXMAP_H_ diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_pixmap_unittest.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_pixmap_unittest.cc deleted file mode 100644 index 08295c5186e..00000000000 --- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_pixmap_unittest.cc +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 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 "content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_pixmap.h" -#include "content/test/gpu_memory_buffer_impl_test_template.h" - -namespace content { -namespace { - -INSTANTIATE_TYPED_TEST_CASE_P(GpuMemoryBufferImplOzoneNativePixmap, - GpuMemoryBufferImplTest, - GpuMemoryBufferImplOzoneNativePixmap); - -} // namespace -} // namespace content diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc deleted file mode 100644 index 83781ae8553..00000000000 --- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 2014 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 "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h" - -#include <stdint.h> -#include <utility> - -#include "base/bind.h" -#include "base/numerics/safe_math.h" -#include "base/process/memory.h" -#include "ui/gfx/buffer_format_util.h" -#include "ui/gl/gl_bindings.h" - -namespace content { -namespace { - -void Noop() {} - -} // namespace - -GpuMemoryBufferImplSharedMemory::GpuMemoryBufferImplSharedMemory( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - const DestructionCallback& callback, - scoped_ptr<base::SharedMemory> shared_memory, - size_t offset, - int stride) - : GpuMemoryBufferImpl(id, size, format, callback), - shared_memory_(std::move(shared_memory)), - offset_(offset), - stride_(stride) { - DCHECK(IsSizeValidForFormat(size, format)); -} - -GpuMemoryBufferImplSharedMemory::~GpuMemoryBufferImplSharedMemory() { -} - -// static -scoped_ptr<GpuMemoryBufferImplSharedMemory> -GpuMemoryBufferImplSharedMemory::Create(gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - const DestructionCallback& callback) { - size_t buffer_size = 0u; - if (!gfx::BufferSizeForBufferFormatChecked(size, format, &buffer_size)) - return nullptr; - - scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); - if (!shared_memory->CreateAndMapAnonymous(buffer_size)) - return nullptr; - - return make_scoped_ptr(new GpuMemoryBufferImplSharedMemory( - id, size, format, callback, std::move(shared_memory), 0, - gfx::RowSizeForBufferFormat(size.width(), format, 0))); -} - -// static -gfx::GpuMemoryBufferHandle -GpuMemoryBufferImplSharedMemory::AllocateForChildProcess( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - base::ProcessHandle child_process) { - size_t buffer_size = 0u; - if (!gfx::BufferSizeForBufferFormatChecked(size, format, &buffer_size)) - return gfx::GpuMemoryBufferHandle(); - - base::SharedMemory shared_memory; - if (!shared_memory.CreateAnonymous(buffer_size)) - return gfx::GpuMemoryBufferHandle(); - - gfx::GpuMemoryBufferHandle handle; - handle.type = gfx::SHARED_MEMORY_BUFFER; - handle.id = id; - handle.offset = 0; - handle.stride = static_cast<int32_t>( - gfx::RowSizeForBufferFormat(size.width(), format, 0)); - shared_memory.GiveToProcess(child_process, &handle.handle); - return handle; -} - -// static -scoped_ptr<GpuMemoryBufferImplSharedMemory> -GpuMemoryBufferImplSharedMemory::CreateFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - const DestructionCallback& callback) { - DCHECK(base::SharedMemory::IsHandleValid(handle.handle)); - - return make_scoped_ptr(new GpuMemoryBufferImplSharedMemory( - handle.id, size, format, callback, - make_scoped_ptr(new base::SharedMemory(handle.handle, false)), - handle.offset, handle.stride)); -} - -// static -bool GpuMemoryBufferImplSharedMemory::IsUsageSupported(gfx::BufferUsage usage) { - switch (usage) { - case gfx::BufferUsage::GPU_READ: - case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE: - case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT: - return true; - case gfx::BufferUsage::SCANOUT: - return false; - } - NOTREACHED(); - return false; -} - -// static -bool GpuMemoryBufferImplSharedMemory::IsConfigurationSupported( - gfx::BufferFormat format, - gfx::BufferUsage usage) { - return IsUsageSupported(usage); -} - -// static -bool GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat( - const gfx::Size& size, - gfx::BufferFormat format) { - switch (format) { - case gfx::BufferFormat::ATC: - case gfx::BufferFormat::ATCIA: - case gfx::BufferFormat::DXT1: - case gfx::BufferFormat::DXT5: - case gfx::BufferFormat::ETC1: - // Compressed images must have a width and height that's evenly divisible - // by the block size. - return size.width() % 4 == 0 && size.height() % 4 == 0; - case gfx::BufferFormat::R_8: - case gfx::BufferFormat::RGBA_4444: - case gfx::BufferFormat::RGBA_8888: - case gfx::BufferFormat::RGBX_8888: - case gfx::BufferFormat::BGRA_8888: - case gfx::BufferFormat::BGRX_8888: - return true; - case gfx::BufferFormat::YUV_420: - case gfx::BufferFormat::YUV_420_BIPLANAR: { - size_t num_planes = gfx::NumberOfPlanesForBufferFormat(format); - for (size_t i = 0; i < num_planes; ++i) { - size_t factor = gfx::SubsamplingFactorForBufferFormat(format, i); - if (size.width() % factor || size.height() % factor) - return false; - } - return true; - } - case gfx::BufferFormat::UYVY_422: - return size.width() % 2 == 0; - } - - NOTREACHED(); - return false; -} - -// static -base::Closure GpuMemoryBufferImplSharedMemory::AllocateForTesting( - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - gfx::GpuMemoryBufferHandle* handle) { - base::SharedMemory shared_memory; - bool rv = shared_memory.CreateAnonymous( - gfx::BufferSizeForBufferFormat(size, format)); - DCHECK(rv); - handle->type = gfx::SHARED_MEMORY_BUFFER; - handle->offset = 0; - handle->stride = static_cast<int32_t>( - gfx::RowSizeForBufferFormat(size.width(), format, 0)); - handle->handle = base::SharedMemory::DuplicateHandle(shared_memory.handle()); - return base::Bind(&Noop); -} - -bool GpuMemoryBufferImplSharedMemory::Map() { - DCHECK(!mapped_); - - // Map the buffer first time Map() is called then keep it mapped for the - // lifetime of the buffer. This avoids mapping the buffer unless necessary. - if (!shared_memory_->memory()) { - DCHECK_EQ(static_cast<size_t>(stride_), - gfx::RowSizeForBufferFormat(size_.width(), format_, 0)); - size_t buffer_size = gfx::BufferSizeForBufferFormat(size_, format_); - // Note: offset_ != 0 is not common use-case. To keep it simple we - // map offset + buffer_size here but this can be avoided using MapAt(). - size_t map_size = offset_ + buffer_size; - if (!shared_memory_->Map(map_size)) - base::TerminateBecauseOutOfMemory(map_size); - } - mapped_ = true; - return true; -} - -void* GpuMemoryBufferImplSharedMemory::memory(size_t plane) { - DCHECK(mapped_); - DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format_)); - return reinterpret_cast<uint8_t*>(shared_memory_->memory()) + offset_ + - gfx::BufferOffsetForBufferFormat(size_, format_, plane); -} - -void GpuMemoryBufferImplSharedMemory::Unmap() { - DCHECK(mapped_); - mapped_ = false; -} - -int GpuMemoryBufferImplSharedMemory::stride(size_t plane) const { - DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format_)); - return gfx::RowSizeForBufferFormat(size_.width(), format_, plane); -} - -gfx::GpuMemoryBufferHandle GpuMemoryBufferImplSharedMemory::GetHandle() const { - gfx::GpuMemoryBufferHandle handle; - handle.type = gfx::SHARED_MEMORY_BUFFER; - handle.id = id_; - handle.offset = offset_; - handle.stride = stride_; - handle.handle = shared_memory_->handle(); - return handle; -} - -} // namespace content diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h deleted file mode 100644 index 9416cbb31e1..00000000000 --- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2014 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 CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_SHARED_MEMORY_H_ -#define CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_SHARED_MEMORY_H_ - -#include <stddef.h> - -#include "base/macros.h" -#include "content/common/content_export.h" -#include "content/common/gpu/client/gpu_memory_buffer_impl.h" - -namespace content { - -// Implementation of GPU memory buffer based on shared memory. -class CONTENT_EXPORT GpuMemoryBufferImplSharedMemory - : public GpuMemoryBufferImpl { - public: - ~GpuMemoryBufferImplSharedMemory() override; - - static scoped_ptr<GpuMemoryBufferImplSharedMemory> Create( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - const DestructionCallback& callback); - - static gfx::GpuMemoryBufferHandle AllocateForChildProcess( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - base::ProcessHandle child_process); - - static scoped_ptr<GpuMemoryBufferImplSharedMemory> CreateFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - const DestructionCallback& callback); - - static bool IsUsageSupported(gfx::BufferUsage usage); - static bool IsConfigurationSupported(gfx::BufferFormat format, - gfx::BufferUsage usage); - static bool IsSizeValidForFormat(const gfx::Size& size, - gfx::BufferFormat format); - - static base::Closure AllocateForTesting(const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - gfx::GpuMemoryBufferHandle* handle); - - // Overridden from gfx::GpuMemoryBuffer: - bool Map() override; - void* memory(size_t plane) override; - void Unmap() override; - int stride(size_t plane) const override; - gfx::GpuMemoryBufferHandle GetHandle() const override; - - private: - GpuMemoryBufferImplSharedMemory(gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - const DestructionCallback& callback, - scoped_ptr<base::SharedMemory> shared_memory, - size_t offset, - int stride); - - scoped_ptr<base::SharedMemory> shared_memory_; - size_t offset_; - int stride_; - - DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferImplSharedMemory); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_SHARED_MEMORY_H_ diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory_unittest.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory_unittest.cc deleted file mode 100644 index 251e16c4a3a..00000000000 --- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory_unittest.cc +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2015 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 "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h" -#include "content/test/gpu_memory_buffer_impl_test_template.h" - -namespace content { -namespace { - -INSTANTIATE_TYPED_TEST_CASE_P(GpuMemoryBufferImplSharedMemory, - GpuMemoryBufferImplTest, - GpuMemoryBufferImplSharedMemory); - -void BufferDestroyed(bool* destroyed, const gpu::SyncToken& sync_token) { - *destroyed = true; -} - -TEST(GpuMemoryBufferImplSharedMemoryTest, Create) { - const gfx::GpuMemoryBufferId kBufferId(1); - - gfx::Size buffer_size(8, 8); - - for (auto format : gfx::GetBufferFormatsForTesting()) { - bool destroyed = false; - scoped_ptr<GpuMemoryBufferImplSharedMemory> buffer( - GpuMemoryBufferImplSharedMemory::Create( - kBufferId, buffer_size, format, - base::Bind(&BufferDestroyed, base::Unretained(&destroyed)))); - ASSERT_TRUE(buffer); - EXPECT_EQ(buffer->GetFormat(), format); - - // Check if destruction callback is executed when deleting the buffer. - buffer.reset(); - ASSERT_TRUE(destroyed); - } -} - -} // namespace -} // namespace content diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.cc deleted file mode 100644 index 64de624c155..00000000000 --- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.cc +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2014 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 "content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.h" - -#include "base/logging.h" -#include "base/trace_event/trace_event.h" -#include "content/common/android/surface_texture_manager.h" -#include "content/common/gpu/gpu_memory_buffer_factory_surface_texture.h" -#include "ui/gfx/buffer_format_util.h" -#include "ui/gl/android/surface_texture.h" -#include "ui/gl/gl_bindings.h" - -namespace content { -namespace { - -int WindowFormat(gfx::BufferFormat format) { - switch (format) { - case gfx::BufferFormat::RGBA_8888: - return WINDOW_FORMAT_RGBA_8888; - case gfx::BufferFormat::ATC: - case gfx::BufferFormat::ATCIA: - case gfx::BufferFormat::DXT1: - case gfx::BufferFormat::DXT5: - case gfx::BufferFormat::ETC1: - case gfx::BufferFormat::R_8: - case gfx::BufferFormat::RGBA_4444: - case gfx::BufferFormat::RGBX_8888: - case gfx::BufferFormat::BGRX_8888: - case gfx::BufferFormat::BGRA_8888: - case gfx::BufferFormat::YUV_420: - case gfx::BufferFormat::YUV_420_BIPLANAR: - case gfx::BufferFormat::UYVY_422: - NOTREACHED(); - return 0; - } - - NOTREACHED(); - return 0; -} - -void FreeSurfaceTextureForTesting( - scoped_refptr<gfx::SurfaceTexture> surface_texture, - gfx::GpuMemoryBufferId id) { - SurfaceTextureManager::GetInstance()->UnregisterSurfaceTexture(id.id, 0); -} - -} // namespace - -GpuMemoryBufferImplSurfaceTexture::GpuMemoryBufferImplSurfaceTexture( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - const DestructionCallback& callback, - ANativeWindow* native_window) - : GpuMemoryBufferImpl(id, size, format, callback), - native_window_(native_window) {} - -GpuMemoryBufferImplSurfaceTexture::~GpuMemoryBufferImplSurfaceTexture() { - ANativeWindow_release(native_window_); -} - -// static -scoped_ptr<GpuMemoryBufferImplSurfaceTexture> -GpuMemoryBufferImplSurfaceTexture::CreateFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - const DestructionCallback& callback) { - ANativeWindow* native_window = - SurfaceTextureManager::GetInstance() - ->AcquireNativeWidgetForSurfaceTexture(handle.id.id); - if (!native_window) - return nullptr; - - ANativeWindow_setBuffersGeometry( - native_window, size.width(), size.height(), WindowFormat(format)); - - return make_scoped_ptr(new GpuMemoryBufferImplSurfaceTexture( - handle.id, size, format, callback, native_window)); -} - -// static -bool GpuMemoryBufferImplSurfaceTexture::IsConfigurationSupported( - gfx::BufferFormat format, - gfx::BufferUsage usage) { - return GpuMemoryBufferFactorySurfaceTexture:: - IsGpuMemoryBufferConfigurationSupported(format, usage); -} - -// static -base::Closure GpuMemoryBufferImplSurfaceTexture::AllocateForTesting( - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - gfx::GpuMemoryBufferHandle* handle) { - scoped_refptr<gfx::SurfaceTexture> surface_texture = - gfx::SurfaceTexture::Create(0); - DCHECK(surface_texture); - const gfx::GpuMemoryBufferId kBufferId(1); - SurfaceTextureManager::GetInstance()->RegisterSurfaceTexture( - kBufferId.id, 0, surface_texture.get()); - handle->type = gfx::SURFACE_TEXTURE_BUFFER; - handle->id = kBufferId; - return base::Bind(&FreeSurfaceTextureForTesting, surface_texture, kBufferId); -} - -bool GpuMemoryBufferImplSurfaceTexture::Map() { - TRACE_EVENT0("gpu", "GpuMemoryBufferImplSurfaceTexture::Map"); - DCHECK(!mapped_); - DCHECK(native_window_); - if (ANativeWindow_lock(native_window_, &buffer_, NULL)) { - DPLOG(ERROR) << "ANativeWindow_lock failed"; - return false; - } - DCHECK_LE(size_.width(), buffer_.stride); - mapped_ = true; - return true; -} - -void* GpuMemoryBufferImplSurfaceTexture::memory(size_t plane) { - TRACE_EVENT0("gpu", "GpuMemoryBufferImplSurfaceTexture::memory"); - DCHECK(mapped_); - DCHECK_EQ(0u, plane); - return buffer_.bits; -} - -void GpuMemoryBufferImplSurfaceTexture::Unmap() { - TRACE_EVENT0("gpu", "GpuMemoryBufferImplSurfaceTexture::Unmap"); - DCHECK(mapped_); - ANativeWindow_unlockAndPost(native_window_); - mapped_ = false; -} - -int GpuMemoryBufferImplSurfaceTexture::stride(size_t plane) const { - DCHECK(mapped_); - DCHECK_EQ(0u, plane); - return gfx::RowSizeForBufferFormat(buffer_.stride, format_, 0); -} - -gfx::GpuMemoryBufferHandle -GpuMemoryBufferImplSurfaceTexture::GetHandle() const { - gfx::GpuMemoryBufferHandle handle; - handle.type = gfx::SURFACE_TEXTURE_BUFFER; - handle.id = id_; - return handle; -} - -} // namespace content diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.h b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.h deleted file mode 100644 index 1613c63134b..00000000000 --- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2014 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 CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_SURFACE_TEXTURE_H_ -#define CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_SURFACE_TEXTURE_H_ - -#include <android/native_window.h> -#include <stddef.h> - -#include "base/macros.h" -#include "content/common/content_export.h" -#include "content/common/gpu/client/gpu_memory_buffer_impl.h" - -namespace content { - -// Implementation of GPU memory buffer based on SurfaceTextures. -class CONTENT_EXPORT GpuMemoryBufferImplSurfaceTexture - : public GpuMemoryBufferImpl { - public: - ~GpuMemoryBufferImplSurfaceTexture() override; - - static scoped_ptr<GpuMemoryBufferImplSurfaceTexture> CreateFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - const DestructionCallback& callback); - - static bool IsConfigurationSupported(gfx::BufferFormat format, - gfx::BufferUsage usage); - - static base::Closure AllocateForTesting(const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - gfx::GpuMemoryBufferHandle* handle); - - // Overridden from gfx::GpuMemoryBuffer: - bool Map() override; - void* memory(size_t plane) override; - void Unmap() override; - int stride(size_t plane) const override; - gfx::GpuMemoryBufferHandle GetHandle() const override; - - private: - GpuMemoryBufferImplSurfaceTexture(gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - const DestructionCallback& callback, - ANativeWindow* native_window); - - ANativeWindow* native_window_; - ANativeWindow_Buffer buffer_; - - DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferImplSurfaceTexture); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_SURFACE_TEXTURE_H_ diff --git a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture_unittest.cc b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture_unittest.cc index 1cd513df3ac..a3edc70bd8b 100644 --- a/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture_unittest.cc +++ b/chromium/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture_unittest.cc @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.h" -#include "content/test/gpu_memory_buffer_impl_test_template.h" +#include "gpu/ipc/client/gpu_memory_buffer_impl_surface_texture.h" +#include "gpu/ipc/client/gpu_memory_buffer_impl_test_template.h" -namespace content { +namespace gpu { namespace { INSTANTIATE_TYPED_TEST_CASE_P(GpuMemoryBufferImplSurfaceTexture, @@ -13,4 +13,4 @@ INSTANTIATE_TYPED_TEST_CASE_P(GpuMemoryBufferImplSurfaceTexture, GpuMemoryBufferImplSurfaceTexture); } // namespace -} // namespace content +} // namespace gpu diff --git a/chromium/content/common/gpu/client/gpu_video_decode_accelerator_host.cc b/chromium/content/common/gpu/client/gpu_video_decode_accelerator_host.cc deleted file mode 100644 index 19a336b9ca3..00000000000 --- a/chromium/content/common/gpu/client/gpu_video_decode_accelerator_host.cc +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright (c) 2012 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 "content/common/gpu/client/gpu_video_decode_accelerator_host.h" - -#include "base/bind.h" -#include "base/logging.h" -#include "base/message_loop/message_loop.h" -#include "build/build_config.h" -#include "content/common/gpu/client/gpu_channel_host.h" -#include "content/common/gpu/gpu_messages.h" -#include "content/common/view_messages.h" -#include "ipc/ipc_message_macros.h" -#include "ipc/ipc_message_utils.h" - -#if defined(OS_WIN) -#include "content/public/common/sandbox_init.h" -#endif // OS_WIN - -using media::VideoDecodeAccelerator; -namespace content { - -GpuVideoDecodeAcceleratorHost::GpuVideoDecodeAcceleratorHost( - GpuChannelHost* channel, - CommandBufferProxyImpl* impl) - : channel_(channel), - decoder_route_id_(MSG_ROUTING_NONE), - client_(NULL), - impl_(impl), - weak_this_factory_(this) { - DCHECK(channel_); - DCHECK(impl_); - impl_->AddDeletionObserver(this); -} - -GpuVideoDecodeAcceleratorHost::~GpuVideoDecodeAcceleratorHost() { - DCHECK(CalledOnValidThread()); - - if (channel_ && decoder_route_id_ != MSG_ROUTING_NONE) - channel_->RemoveRoute(decoder_route_id_); - if (impl_) - impl_->RemoveDeletionObserver(this); -} - -bool GpuVideoDecodeAcceleratorHost::OnMessageReceived(const IPC::Message& msg) { - DCHECK(CalledOnValidThread()); - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAcceleratorHost, msg) - IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_CdmAttached, - OnCdmAttached) - IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed, - OnBitstreamBufferProcessed) - IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers, - OnProvidePictureBuffer) - IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_PictureReady, - OnPictureReady) - IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_FlushDone, - OnFlushDone) - IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ResetDone, - OnResetDone) - IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ErrorNotification, - OnNotifyError) - IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_DismissPictureBuffer, - OnDismissPictureBuffer) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - DCHECK(handled); - // See OnNotifyError for why |this| mustn't be used after OnNotifyError might - // have been called above. - return handled; -} - -void GpuVideoDecodeAcceleratorHost::OnChannelError() { - DCHECK(CalledOnValidThread()); - if (channel_) { - if (decoder_route_id_ != MSG_ROUTING_NONE) - channel_->RemoveRoute(decoder_route_id_); - channel_ = NULL; - } - DLOG(ERROR) << "OnChannelError()"; - PostNotifyError(PLATFORM_FAILURE); -} - -bool GpuVideoDecodeAcceleratorHost::Initialize(const Config& config, - Client* client) { - DCHECK(CalledOnValidThread()); - client_ = client; - - if (!impl_) - return false; - - int32_t route_id = channel_->GenerateRouteID(); - channel_->AddRoute(route_id, weak_this_factory_.GetWeakPtr()); - - bool succeeded = false; - Send(new GpuCommandBufferMsg_CreateVideoDecoder(impl_->route_id(), config, - route_id, &succeeded)); - - if (!succeeded) { - DLOG(ERROR) << "Send(GpuCommandBufferMsg_CreateVideoDecoder()) failed"; - PostNotifyError(PLATFORM_FAILURE); - channel_->RemoveRoute(route_id); - return false; - } - decoder_route_id_ = route_id; - return true; -} - -void GpuVideoDecodeAcceleratorHost::SetCdm(int cdm_id) { - DCHECK(CalledOnValidThread()); - if (!channel_) - return; - Send(new AcceleratedVideoDecoderMsg_SetCdm(decoder_route_id_, cdm_id)); -} - -void GpuVideoDecodeAcceleratorHost::Decode( - const media::BitstreamBuffer& bitstream_buffer) { - DCHECK(CalledOnValidThread()); - if (!channel_) - return; - - base::SharedMemoryHandle handle = channel_->ShareToGpuProcess( - bitstream_buffer.handle()); - if (!base::SharedMemory::IsHandleValid(handle)) { - NOTREACHED() << "Failed to duplicate buffer handler"; - return; - } - - AcceleratedVideoDecoderMsg_Decode_Params params; - params.bitstream_buffer_id = bitstream_buffer.id(); - params.buffer_handle = handle; - params.size = bitstream_buffer.size(); - params.presentation_timestamp = bitstream_buffer.presentation_timestamp(); - params.key_id = bitstream_buffer.key_id(); - params.iv = bitstream_buffer.iv(); - params.subsamples = bitstream_buffer.subsamples(); - - Send(new AcceleratedVideoDecoderMsg_Decode(decoder_route_id_, params)); -} - -void GpuVideoDecodeAcceleratorHost::AssignPictureBuffers( - const std::vector<media::PictureBuffer>& buffers) { - DCHECK(CalledOnValidThread()); - if (!channel_) - return; - // Rearrange data for IPC command. - std::vector<int32_t> buffer_ids; - std::vector<uint32_t> texture_ids; - for (uint32_t i = 0; i < buffers.size(); i++) { - const media::PictureBuffer& buffer = buffers[i]; - if (buffer.size() != picture_buffer_dimensions_) { - DLOG(ERROR) << "buffer.size() invalid: expected " - << picture_buffer_dimensions_.ToString() - << ", got " << buffer.size().ToString(); - PostNotifyError(INVALID_ARGUMENT); - return; - } - texture_ids.push_back(buffer.texture_id()); - buffer_ids.push_back(buffer.id()); - } - Send(new AcceleratedVideoDecoderMsg_AssignPictureBuffers( - decoder_route_id_, buffer_ids, texture_ids)); -} - -void GpuVideoDecodeAcceleratorHost::ReusePictureBuffer( - int32_t picture_buffer_id) { - DCHECK(CalledOnValidThread()); - if (!channel_) - return; - Send(new AcceleratedVideoDecoderMsg_ReusePictureBuffer( - decoder_route_id_, picture_buffer_id)); -} - -void GpuVideoDecodeAcceleratorHost::Flush() { - DCHECK(CalledOnValidThread()); - if (!channel_) - return; - Send(new AcceleratedVideoDecoderMsg_Flush(decoder_route_id_)); -} - -void GpuVideoDecodeAcceleratorHost::Reset() { - DCHECK(CalledOnValidThread()); - if (!channel_) - return; - Send(new AcceleratedVideoDecoderMsg_Reset(decoder_route_id_)); -} - -void GpuVideoDecodeAcceleratorHost::Destroy() { - DCHECK(CalledOnValidThread()); - if (channel_) - Send(new AcceleratedVideoDecoderMsg_Destroy(decoder_route_id_)); - client_ = NULL; - delete this; -} - -void GpuVideoDecodeAcceleratorHost::OnWillDeleteImpl() { - DCHECK(CalledOnValidThread()); - impl_ = NULL; - - // The CommandBufferProxyImpl is going away; error out this VDA. - OnChannelError(); -} - -void GpuVideoDecodeAcceleratorHost::PostNotifyError(Error error) { - DCHECK(CalledOnValidThread()); - DVLOG(2) << "PostNotifyError(): error=" << error; - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&GpuVideoDecodeAcceleratorHost::OnNotifyError, - weak_this_factory_.GetWeakPtr(), error)); -} - -void GpuVideoDecodeAcceleratorHost::Send(IPC::Message* message) { - DCHECK(CalledOnValidThread()); - uint32_t message_type = message->type(); - if (!channel_->Send(message)) { - DLOG(ERROR) << "Send(" << message_type << ") failed"; - PostNotifyError(PLATFORM_FAILURE); - } -} - -void GpuVideoDecodeAcceleratorHost::OnCdmAttached(bool success) { - DCHECK(CalledOnValidThread()); - if (client_) - client_->NotifyCdmAttached(success); -} - -void GpuVideoDecodeAcceleratorHost::OnBitstreamBufferProcessed( - int32_t bitstream_buffer_id) { - DCHECK(CalledOnValidThread()); - if (client_) - client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id); -} - -void GpuVideoDecodeAcceleratorHost::OnProvidePictureBuffer( - uint32_t num_requested_buffers, - const gfx::Size& dimensions, - uint32_t texture_target) { - DCHECK(CalledOnValidThread()); - picture_buffer_dimensions_ = dimensions; - if (client_) { - client_->ProvidePictureBuffers( - num_requested_buffers, dimensions, texture_target); - } -} - -void GpuVideoDecodeAcceleratorHost::OnDismissPictureBuffer( - int32_t picture_buffer_id) { - DCHECK(CalledOnValidThread()); - if (client_) - client_->DismissPictureBuffer(picture_buffer_id); -} - -void GpuVideoDecodeAcceleratorHost::OnPictureReady( - int32_t picture_buffer_id, - int32_t bitstream_buffer_id, - const gfx::Rect& visible_rect, - bool allow_overlay) { - DCHECK(CalledOnValidThread()); - if (!client_) - return; - media::Picture picture(picture_buffer_id, bitstream_buffer_id, visible_rect, - allow_overlay); - client_->PictureReady(picture); -} - -void GpuVideoDecodeAcceleratorHost::OnFlushDone() { - DCHECK(CalledOnValidThread()); - if (client_) - client_->NotifyFlushDone(); -} - -void GpuVideoDecodeAcceleratorHost::OnResetDone() { - DCHECK(CalledOnValidThread()); - if (client_) - client_->NotifyResetDone(); -} - -void GpuVideoDecodeAcceleratorHost::OnNotifyError(uint32_t error) { - DCHECK(CalledOnValidThread()); - if (!client_) - return; - weak_this_factory_.InvalidateWeakPtrs(); - - // Client::NotifyError() may Destroy() |this|, so calling it needs to be the - // last thing done on this stack! - media::VideoDecodeAccelerator::Client* client = NULL; - std::swap(client, client_); - client->NotifyError(static_cast<media::VideoDecodeAccelerator::Error>(error)); -} - -} // namespace content diff --git a/chromium/content/common/gpu/client/gpu_video_decode_accelerator_host.h b/chromium/content/common/gpu/client/gpu_video_decode_accelerator_host.h deleted file mode 100644 index 5e4ba9df1f6..00000000000 --- a/chromium/content/common/gpu/client/gpu_video_decode_accelerator_host.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_GPU_CLIENT_GPU_VIDEO_DECODE_ACCELERATOR_HOST_H_ -#define CONTENT_COMMON_GPU_CLIENT_GPU_VIDEO_DECODE_ACCELERATOR_HOST_H_ - -#include <stdint.h> - -#include <vector> - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/non_thread_safe.h" -#include "content/common/gpu/client/command_buffer_proxy_impl.h" -#include "ipc/ipc_listener.h" -#include "media/video/video_decode_accelerator.h" -#include "ui/gfx/geometry/size.h" - -namespace content { -class GpuChannelHost; - -// This class is used to talk to VideoDecodeAccelerator in the Gpu process -// through IPC messages. -class GpuVideoDecodeAcceleratorHost - : public IPC::Listener, - public media::VideoDecodeAccelerator, - public CommandBufferProxyImpl::DeletionObserver, - public base::NonThreadSafe { - public: - // |this| is guaranteed not to outlive |channel| and |impl|. (See comments - // for |channel_| and |impl_|.) - GpuVideoDecodeAcceleratorHost(GpuChannelHost* channel, - CommandBufferProxyImpl* impl); - - // IPC::Listener implementation. - void OnChannelError() override; - bool OnMessageReceived(const IPC::Message& message) override; - - // media::VideoDecodeAccelerator implementation. - bool Initialize(const Config& config, Client* client) override; - void SetCdm(int cdm_id) override; - void Decode(const media::BitstreamBuffer& bitstream_buffer) override; - void AssignPictureBuffers( - const std::vector<media::PictureBuffer>& buffers) override; - void ReusePictureBuffer(int32_t picture_buffer_id) override; - void Flush() override; - void Reset() override; - void Destroy() override; - - // CommandBufferProxyImpl::DeletionObserver implemetnation. - void OnWillDeleteImpl() override; - - private: - // Only Destroy() should be deleting |this|. - ~GpuVideoDecodeAcceleratorHost() override; - - // Notify |client_| of an error. Posts a task to avoid re-entrancy. - void PostNotifyError(Error); - - void Send(IPC::Message* message); - - // IPC handlers, proxying media::VideoDecodeAccelerator::Client for the GPU - // process. Should not be called directly. - void OnCdmAttached(bool success); - void OnBitstreamBufferProcessed(int32_t bitstream_buffer_id); - void OnProvidePictureBuffer(uint32_t num_requested_buffers, - const gfx::Size& dimensions, - uint32_t texture_target); - void OnDismissPictureBuffer(int32_t picture_buffer_id); - void OnPictureReady(int32_t picture_buffer_id, - int32_t bitstream_buffer_id, - const gfx::Rect& visible_rect, - bool allow_overlay); - void OnFlushDone(); - void OnResetDone(); - void OnNotifyError(uint32_t error); - - // Unowned reference to the GpuChannelHost to send IPC messages to the GPU - // process. |channel_| outlives |impl_|, so the reference is always valid as - // long as it is not NULL. - GpuChannelHost* channel_; - - // Route ID for the associated decoder in the GPU process. - int32_t decoder_route_id_; - - // The client that will receive callbacks from the decoder. - Client* client_; - - // Unowned reference to the CommandBufferProxyImpl that created us. |this| - // registers as a DeletionObserver of |impl_|, the so reference is always - // valid as long as it is not NULL. - CommandBufferProxyImpl* impl_; - - // Requested dimensions of the buffer, from ProvidePictureBuffers(). - gfx::Size picture_buffer_dimensions_; - - // WeakPtr factory for posting tasks back to itself. - base::WeakPtrFactory<GpuVideoDecodeAcceleratorHost> weak_this_factory_; - - DISALLOW_COPY_AND_ASSIGN(GpuVideoDecodeAcceleratorHost); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_CLIENT_GPU_VIDEO_DECODE_ACCELERATOR_HOST_H_ diff --git a/chromium/content/common/gpu/client/gpu_video_encode_accelerator_host.cc b/chromium/content/common/gpu/client/gpu_video_encode_accelerator_host.cc deleted file mode 100644 index 9002490e1dd..00000000000 --- a/chromium/content/common/gpu/client/gpu_video_encode_accelerator_host.cc +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright 2013 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 "content/common/gpu/client/gpu_video_encode_accelerator_host.h" - -#include "base/location.h" -#include "base/logging.h" -#include "content/common/gpu/client/gpu_channel_host.h" -#include "content/common/gpu/gpu_messages.h" -#include "content/common/gpu/media/gpu_video_accelerator_util.h" -#include "media/base/video_frame.h" -#include "media/video/video_encode_accelerator.h" -#include "ui/gfx/gpu_memory_buffer.h" - -namespace content { - -GpuVideoEncodeAcceleratorHost::GpuVideoEncodeAcceleratorHost( - GpuChannelHost* channel, - CommandBufferProxyImpl* impl) - : channel_(channel), - encoder_route_id_(MSG_ROUTING_NONE), - client_(NULL), - impl_(impl), - next_frame_id_(0), - weak_this_factory_(this) { - DCHECK(channel_); - DCHECK(impl_); - impl_->AddDeletionObserver(this); -} - -GpuVideoEncodeAcceleratorHost::~GpuVideoEncodeAcceleratorHost() { - DCHECK(CalledOnValidThread()); - if (channel_ && encoder_route_id_ != MSG_ROUTING_NONE) - channel_->RemoveRoute(encoder_route_id_); - if (impl_) - impl_->RemoveDeletionObserver(this); -} - -bool GpuVideoEncodeAcceleratorHost::OnMessageReceived( - const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAcceleratorHost, message) - IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers, - OnRequireBitstreamBuffers) - IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyInputDone, - OnNotifyInputDone) - IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_BitstreamBufferReady, - OnBitstreamBufferReady) - IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyError, - OnNotifyError) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - DCHECK(handled); - // See OnNotifyError for why |this| mustn't be used after OnNotifyError might - // have been called above. - return handled; -} - -void GpuVideoEncodeAcceleratorHost::OnChannelError() { - DCHECK(CalledOnValidThread()); - if (channel_) { - if (encoder_route_id_ != MSG_ROUTING_NONE) - channel_->RemoveRoute(encoder_route_id_); - channel_ = NULL; - } - PostNotifyError(FROM_HERE, kPlatformFailureError, "OnChannelError()"); -} - -media::VideoEncodeAccelerator::SupportedProfiles -GpuVideoEncodeAcceleratorHost::GetSupportedProfiles() { - DCHECK(CalledOnValidThread()); - if (!channel_) - return media::VideoEncodeAccelerator::SupportedProfiles(); - return GpuVideoAcceleratorUtil::ConvertGpuToMediaEncodeProfiles( - channel_->gpu_info().video_encode_accelerator_supported_profiles); -} - -bool GpuVideoEncodeAcceleratorHost::Initialize( - media::VideoPixelFormat input_format, - const gfx::Size& input_visible_size, - media::VideoCodecProfile output_profile, - uint32_t initial_bitrate, - Client* client) { - DCHECK(CalledOnValidThread()); - client_ = client; - if (!impl_) { - DLOG(ERROR) << "impl_ destroyed"; - return false; - } - - int32_t route_id = channel_->GenerateRouteID(); - channel_->AddRoute(route_id, weak_this_factory_.GetWeakPtr()); - - bool succeeded = false; - Send(new GpuCommandBufferMsg_CreateVideoEncoder( - impl_->route_id(), input_format, input_visible_size, output_profile, - initial_bitrate, route_id, &succeeded)); - if (!succeeded) { - DLOG(ERROR) << "Send(GpuCommandBufferMsg_CreateVideoEncoder()) failed"; - channel_->RemoveRoute(route_id); - return false; - } - encoder_route_id_ = route_id; - return true; -} - -void GpuVideoEncodeAcceleratorHost::Encode( - const scoped_refptr<media::VideoFrame>& frame, - bool force_keyframe) { - DCHECK(CalledOnValidThread()); - DCHECK_EQ(media::PIXEL_FORMAT_I420, frame->format()); - if (!channel_) - return; - - switch (frame->storage_type()) { - case media::VideoFrame::STORAGE_SHMEM: - EncodeSharedMemoryFrame(frame, force_keyframe); - break; - case media::VideoFrame::STORAGE_GPU_MEMORY_BUFFERS: - EncodeGpuMemoryBufferFrame(frame, force_keyframe); - break; - default: - PostNotifyError(FROM_HERE, kPlatformFailureError, - "Encode(): cannot encode frame with invalid handles"); - return; - } - - frame_map_[next_frame_id_] = frame; - - // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. - next_frame_id_ = (next_frame_id_ + 1) & 0x3FFFFFFF; -} - -void GpuVideoEncodeAcceleratorHost::UseOutputBitstreamBuffer( - const media::BitstreamBuffer& buffer) { - DCHECK(CalledOnValidThread()); - if (!channel_) - return; - - base::SharedMemoryHandle handle = - channel_->ShareToGpuProcess(buffer.handle()); - if (!base::SharedMemory::IsHandleValid(handle)) { - PostNotifyError( - FROM_HERE, kPlatformFailureError, - base::StringPrintf("UseOutputBitstreamBuffer(): failed to duplicate " - "buffer handle for GPU process: buffer.id()=%d", - buffer.id())); - return; - } - Send(new AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer( - encoder_route_id_, buffer.id(), handle, buffer.size())); -} - -void GpuVideoEncodeAcceleratorHost::RequestEncodingParametersChange( - uint32_t bitrate, - uint32_t framerate) { - DCHECK(CalledOnValidThread()); - if (!channel_) - return; - - Send(new AcceleratedVideoEncoderMsg_RequestEncodingParametersChange( - encoder_route_id_, bitrate, framerate)); -} - -void GpuVideoEncodeAcceleratorHost::Destroy() { - DCHECK(CalledOnValidThread()); - if (channel_) - Send(new AcceleratedVideoEncoderMsg_Destroy(encoder_route_id_)); - client_ = NULL; - delete this; -} - -void GpuVideoEncodeAcceleratorHost::OnWillDeleteImpl() { - DCHECK(CalledOnValidThread()); - impl_ = NULL; - - // The CommandBufferProxyImpl is going away; error out this VEA. - OnChannelError(); -} - -void GpuVideoEncodeAcceleratorHost::EncodeGpuMemoryBufferFrame( - const scoped_refptr<media::VideoFrame>& frame, - bool force_keyframe){ - DCHECK_EQ(media::VideoFrame::NumPlanes(media::PIXEL_FORMAT_I420), - frame->gpu_memory_buffer_handles().size()); - AcceleratedVideoEncoderMsg_Encode_Params2 params; - params.frame_id = next_frame_id_; - params.timestamp = frame->timestamp(); - bool requires_sync_point = false; - for (const auto& handle : frame->gpu_memory_buffer_handles()) { - gfx::GpuMemoryBufferHandle new_handle = - channel_->ShareGpuMemoryBufferToGpuProcess(handle, - &requires_sync_point); - if (new_handle.is_null()) { - PostNotifyError(FROM_HERE, kPlatformFailureError, - "EncodeGpuMemoryBufferFrame(): failed to share gpu " - "memory buffer handle for gpu process"); - return; - } - params.gpu_memory_buffer_handles.push_back(new_handle); - } - params.size = frame->coded_size(); - params.force_keyframe = force_keyframe; - - Send(new AcceleratedVideoEncoderMsg_Encode2(encoder_route_id_, params)); -} - -void GpuVideoEncodeAcceleratorHost::EncodeSharedMemoryFrame( - const scoped_refptr<media::VideoFrame>& frame, - bool force_keyframe){ - if (!base::SharedMemory::IsHandleValid(frame->shared_memory_handle())) { - PostNotifyError(FROM_HERE, kPlatformFailureError, - "EncodeSharedMemory(): cannot encode frame with invalid " - "shared memory handle"); - return; - } - - AcceleratedVideoEncoderMsg_Encode_Params params; - params.frame_id = next_frame_id_; - params.timestamp = frame->timestamp(); - params.buffer_handle = - channel_->ShareToGpuProcess(frame->shared_memory_handle()); - if (!base::SharedMemory::IsHandleValid(params.buffer_handle)) { - PostNotifyError(FROM_HERE, kPlatformFailureError, - "Encode(): failed to duplicate shared memory buffer handle " - "for GPU process"); - return; - } - params.buffer_offset = - base::checked_cast<uint32_t>(frame->shared_memory_offset()); - params.buffer_size = - media::VideoFrame::AllocationSize(frame->format(), frame->coded_size()); - params.force_keyframe = force_keyframe; - - Send(new AcceleratedVideoEncoderMsg_Encode(encoder_route_id_, params)); -} - -void GpuVideoEncodeAcceleratorHost::PostNotifyError( - const tracked_objects::Location& location, Error error, - const std::string& message) { - DCHECK(CalledOnValidThread()); - DLOG(ERROR) << "Error from " << location.function_name() - << "(" << location.file_name() << ":" - << location.line_number() << ") " - << message << " (error = " << error << ")"; - // Post the error notification back to this thread, to avoid re-entrancy. - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&GpuVideoEncodeAcceleratorHost::OnNotifyError, - weak_this_factory_.GetWeakPtr(), error)); -} - -void GpuVideoEncodeAcceleratorHost::Send(IPC::Message* message) { - DCHECK(CalledOnValidThread()); - uint32_t message_type = message->type(); - if (!channel_->Send(message)) { - PostNotifyError(FROM_HERE, kPlatformFailureError, - base::StringPrintf("Send(%d) failed", message_type)); - } -} - -void GpuVideoEncodeAcceleratorHost::OnRequireBitstreamBuffers( - uint32_t input_count, - const gfx::Size& input_coded_size, - uint32_t output_buffer_size) { - DCHECK(CalledOnValidThread()); - DVLOG(2) << "OnRequireBitstreamBuffers(): input_count=" << input_count - << ", input_coded_size=" << input_coded_size.ToString() - << ", output_buffer_size=" << output_buffer_size; - if (client_) { - client_->RequireBitstreamBuffers( - input_count, input_coded_size, output_buffer_size); - } -} - -void GpuVideoEncodeAcceleratorHost::OnNotifyInputDone(int32_t frame_id) { - DCHECK(CalledOnValidThread()); - DVLOG(3) << "OnNotifyInputDone(): frame_id=" << frame_id; - // Fun-fact: std::hash_map is not spec'd to be re-entrant; since freeing a - // frame can trigger a further encode to be kicked off and thus an .insert() - // back into the map, we separate the frame's dtor running from the .erase() - // running by holding on to the frame temporarily. This isn't "just - // theoretical" - Android's std::hash_map crashes if we don't do this. - scoped_refptr<media::VideoFrame> frame = frame_map_[frame_id]; - if (!frame_map_.erase(frame_id)) { - DLOG(ERROR) << "OnNotifyInputDone(): " - "invalid frame_id=" << frame_id; - // See OnNotifyError for why this needs to be the last thing in this - // function. - OnNotifyError(kPlatformFailureError); - return; - } - frame = NULL; // Not necessary but nice to be explicit; see fun-fact above. -} - -void GpuVideoEncodeAcceleratorHost::OnBitstreamBufferReady( - int32_t bitstream_buffer_id, - uint32_t payload_size, - bool key_frame) { - DCHECK(CalledOnValidThread()); - DVLOG(3) << "OnBitstreamBufferReady(): " - "bitstream_buffer_id=" << bitstream_buffer_id - << ", payload_size=" << payload_size - << ", key_frame=" << key_frame; - if (client_) - client_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame); -} - -void GpuVideoEncodeAcceleratorHost::OnNotifyError(Error error) { - DCHECK(CalledOnValidThread()); - DVLOG(2) << "OnNotifyError(): error=" << error; - if (!client_) - return; - weak_this_factory_.InvalidateWeakPtrs(); - - // Client::NotifyError() may Destroy() |this|, so calling it needs to be the - // last thing done on this stack! - media::VideoEncodeAccelerator::Client* client = NULL; - std::swap(client_, client); - client->NotifyError(error); -} - -} // namespace content diff --git a/chromium/content/common/gpu/client/gpu_video_encode_accelerator_host.h b/chromium/content/common/gpu/client/gpu_video_encode_accelerator_host.h deleted file mode 100644 index 38995938259..00000000000 --- a/chromium/content/common/gpu/client/gpu_video_encode_accelerator_host.h +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2013 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 CONTENT_COMMON_GPU_CLIENT_GPU_VIDEO_ENCODE_ACCELERATOR_HOST_H_ -#define CONTENT_COMMON_GPU_CLIENT_GPU_VIDEO_ENCODE_ACCELERATOR_HOST_H_ - -#include <stdint.h> - -#include <vector> - -#include "base/containers/hash_tables.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/non_thread_safe.h" -#include "content/common/gpu/client/command_buffer_proxy_impl.h" -#include "gpu/config/gpu_info.h" -#include "ipc/ipc_listener.h" -#include "media/video/video_encode_accelerator.h" - -namespace gfx { -struct GpuMemoryBufferHandle; -class Size; -} // namespace gfx - -namespace media { -class VideoFrame; -} // namespace media - -namespace tracked_objects { -class Location; -} // namespace tracked_objects - -namespace content { -class GpuChannelHost; - -// This class is the renderer-side host for the VideoEncodeAccelerator in the -// GPU process, coordinated over IPC. -class GpuVideoEncodeAcceleratorHost - : public IPC::Listener, - public media::VideoEncodeAccelerator, - public CommandBufferProxyImpl::DeletionObserver, - public base::NonThreadSafe { - public: - // |this| is guaranteed not to outlive |channel| and |impl|. (See comments - // for |channel_| and |impl_|.) - GpuVideoEncodeAcceleratorHost(GpuChannelHost* channel, - CommandBufferProxyImpl* impl); - - // IPC::Listener implementation. - bool OnMessageReceived(const IPC::Message& message) override; - void OnChannelError() override; - - // media::VideoEncodeAccelerator implementation. - SupportedProfiles GetSupportedProfiles() override; - bool Initialize(media::VideoPixelFormat input_format, - const gfx::Size& input_visible_size, - media::VideoCodecProfile output_profile, - uint32_t initial_bitrate, - Client* client) override; - void Encode(const scoped_refptr<media::VideoFrame>& frame, - bool force_keyframe) override; - void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer) override; - void RequestEncodingParametersChange(uint32_t bitrate, - uint32_t framerate_num) override; - void Destroy() override; - - // CommandBufferProxyImpl::DeletionObserver implementation. - void OnWillDeleteImpl() override; - - private: - // Only Destroy() should be deleting |this|. - ~GpuVideoEncodeAcceleratorHost() override; - - // Encode specific video frame types. - void EncodeGpuMemoryBufferFrame(const scoped_refptr<media::VideoFrame>& frame, - bool force_keyframe); - void EncodeSharedMemoryFrame(const scoped_refptr<media::VideoFrame>& frame, - bool force_keyframe); - - // Notify |client_| of an error. Posts a task to avoid re-entrancy. - void PostNotifyError(const tracked_objects::Location& location, - Error error, const std::string& message); - - void Send(IPC::Message* message); - - // IPC handlers, proxying media::VideoEncodeAccelerator::Client for the GPU - // process. Should not be called directly. - void OnRequireBitstreamBuffers(uint32_t input_count, - const gfx::Size& input_coded_size, - uint32_t output_buffer_size); - void OnNotifyInputDone(int32_t frame_id); - void OnBitstreamBufferReady(int32_t bitstream_buffer_id, - uint32_t payload_size, - bool key_frame); - void OnNotifyError(Error error); - - // Unowned reference to the GpuChannelHost to send IPC messages to the GPU - // process. |channel_| outlives |impl_|, so the reference is always valid as - // long as it is not NULL. - GpuChannelHost* channel_; - - // Route ID for the associated encoder in the GPU process. - int32_t encoder_route_id_; - - // The client that will receive callbacks from the encoder. - Client* client_; - - // Unowned reference to the CommandBufferProxyImpl that created us. |this| - // registers as a DeletionObserver of |impl_|, so the reference is always - // valid as long as it is not NULL. - CommandBufferProxyImpl* impl_; - - // media::VideoFrames sent to the encoder. - // base::IDMap not used here, since that takes pointers, not scoped_refptr. - typedef base::hash_map<int32_t, scoped_refptr<media::VideoFrame>> FrameMap; - FrameMap frame_map_; - - // ID serial number for the next frame to send to the GPU process. - int32_t next_frame_id_; - - // WeakPtr factory for posting tasks back to itself. - base::WeakPtrFactory<GpuVideoEncodeAcceleratorHost> weak_this_factory_; - - DISALLOW_COPY_AND_ASSIGN(GpuVideoEncodeAcceleratorHost); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_CLIENT_GPU_VIDEO_ENCODE_ACCELERATOR_HOST_H_ diff --git a/chromium/content/common/gpu/client/grcontext_for_gles2_interface.cc b/chromium/content/common/gpu/client/grcontext_for_gles2_interface.cc new file mode 100644 index 00000000000..cebdfd7745c --- /dev/null +++ b/chromium/content/common/gpu/client/grcontext_for_gles2_interface.cc @@ -0,0 +1,62 @@ +// Copyright (c) 2013 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 "content/common/gpu/client/grcontext_for_gles2_interface.h" + +#include <stddef.h> +#include <string.h> +#include <utility> + +#include "base/lazy_instance.h" +#include "base/macros.h" +#include "base/trace_event/trace_event.h" +#include "gpu/command_buffer/client/gles2_interface.h" +#include "gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h" +#include "third_party/skia/include/gpu/GrContext.h" +#include "third_party/skia/include/gpu/gl/GrGLInterface.h" + +namespace content { + +GrContextForGLES2Interface::GrContextForGLES2Interface( + gpu::gles2::GLES2Interface* gl) { + sk_sp<GrGLInterface> interface( + skia_bindings::CreateGLES2InterfaceBindings(gl)); + gr_context_ = + sk_sp<GrContext>(GrContext::Create(kOpenGL_GrBackend, + // GrContext takes ownership of |interface|. + reinterpret_cast<GrBackendContext>(interface.get()))); + if (gr_context_) { + // The limit of the number of GPU resources we hold in the GrContext's + // GPU cache. + static const int kMaxGaneshResourceCacheCount = 2048; + // The limit of the bytes allocated toward GPU resources in the GrContext's + // GPU cache. + static const size_t kMaxGaneshResourceCacheBytes = 96 * 1024 * 1024; + + gr_context_->setResourceCacheLimits(kMaxGaneshResourceCacheCount, + kMaxGaneshResourceCacheBytes); + } +} + +GrContextForGLES2Interface::~GrContextForGLES2Interface() { + // At this point the GLES2Interface is going to be destroyed, so have + // the GrContext clean up and not try to use it anymore. + if (gr_context_) + gr_context_->releaseResourcesAndAbandonContext(); +} + +void GrContextForGLES2Interface::OnLostContext() { + if (gr_context_) + gr_context_->abandonContext(); +} + +void GrContextForGLES2Interface::FreeGpuResources() { + if (gr_context_) { + TRACE_EVENT_INSTANT0("gpu", "GrContext::freeGpuResources", + TRACE_EVENT_SCOPE_THREAD); + gr_context_->freeGpuResources(); + } +} + +} // namespace content diff --git a/chromium/content/common/gpu/client/grcontext_for_gles2_interface.h b/chromium/content/common/gpu/client/grcontext_for_gles2_interface.h new file mode 100644 index 00000000000..354092a9592 --- /dev/null +++ b/chromium/content/common/gpu/client/grcontext_for_gles2_interface.h @@ -0,0 +1,42 @@ +// Copyright (c) 2013 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 CONTENT_COMMON_GPU_CLIENT_GRCONTEXT_FOR_GLES2_INTERFACE_H_ +#define CONTENT_COMMON_GPU_CLIENT_GRCONTEXT_FOR_GLES2_INTERFACE_H_ + +#include "base/macros.h" +#include "third_party/skia/include/core/SkRefCnt.h" + +class GrContext; + +namespace gpu { +namespace gles2 { +class GLES2Interface; +} +} + +namespace content { + +// This class binds an offscreen GrContext to an offscreen context3d. The +// context3d is used by the GrContext so must be valid as long as this class +// is alive. +class GrContextForGLES2Interface { + public: + explicit GrContextForGLES2Interface(gpu::gles2::GLES2Interface* gl); + virtual ~GrContextForGLES2Interface(); + + GrContext* get() { return gr_context_.get(); } + + void OnLostContext(); + void FreeGpuResources(); + + private: + sk_sp<class GrContext> gr_context_; + + DISALLOW_COPY_AND_ASSIGN(GrContextForGLES2Interface); +}; + +} // namespace content + +#endif // CONTENT_COMMON_GPU_CLIENT_GRCONTEXT_FOR_GLES2_INTERFACE_H_ diff --git a/chromium/content/common/gpu/client/grcontext_for_webgraphicscontext3d.cc b/chromium/content/common/gpu/client/grcontext_for_webgraphicscontext3d.cc deleted file mode 100644 index 5cd4944db68..00000000000 --- a/chromium/content/common/gpu/client/grcontext_for_webgraphicscontext3d.cc +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2013 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 "content/common/gpu/client/grcontext_for_webgraphicscontext3d.h" - -#include <stddef.h> -#include <string.h> -#include <utility> - -#include "base/lazy_instance.h" -#include "base/macros.h" -#include "base/trace_event/trace_event.h" -#include "gpu/blink/webgraphicscontext3d_impl.h" -#include "gpu/command_buffer/client/gles2_lib.h" -#include "gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h" -#include "third_party/skia/include/gpu/GrContext.h" - -using gpu_blink::WebGraphicsContext3DImpl; - -namespace content { - -namespace { - -// Singleton used to initialize and terminate the gles2 library. -class GLES2Initializer { - public: - GLES2Initializer() { gles2::Initialize(); } - - ~GLES2Initializer() { gles2::Terminate(); } - - private: - DISALLOW_COPY_AND_ASSIGN(GLES2Initializer); -}; - -base::LazyInstance<GLES2Initializer> g_gles2_initializer = - LAZY_INSTANCE_INITIALIZER; - -void BindWebGraphicsContext3DGLContextCallback(const GrGLInterface* interface) { - gles2::SetGLContext(static_cast<const GrGLInterfaceForWebGraphicsContext3D*>( - interface)->WebContext3D()->GetGLInterface()); -} - -} // namespace anonymous - -GrContextForWebGraphicsContext3D::GrContextForWebGraphicsContext3D( - skia::RefPtr<GrGLInterfaceForWebGraphicsContext3D> gr_interface) { - if (!gr_interface || !gr_interface->WebContext3D()) - return; - - // Ensure the gles2 library is initialized first in a thread safe way. - g_gles2_initializer.Get(); - gles2::SetGLContext(gr_interface->WebContext3D()->GetGLInterface()); - - skia_bindings::InitCommandBufferSkiaGLBinding(gr_interface.get()); - - gr_interface->fCallback = BindWebGraphicsContext3DGLContextCallback; - - gr_context_ = skia::AdoptRef(GrContext::Create( - kOpenGL_GrBackend, - reinterpret_cast<GrBackendContext>(gr_interface.get()))); - if (gr_context_) { - // The limit of the number of GPU resources we hold in the GrContext's - // GPU cache. - static const int kMaxGaneshResourceCacheCount = 2048; - // The limit of the bytes allocated toward GPU resources in the GrContext's - // GPU cache. - static const size_t kMaxGaneshResourceCacheBytes = 96 * 1024 * 1024; - - gr_context_->setResourceCacheLimits(kMaxGaneshResourceCacheCount, - kMaxGaneshResourceCacheBytes); - } -} - -GrContextForWebGraphicsContext3D::~GrContextForWebGraphicsContext3D() { -} - -void GrContextForWebGraphicsContext3D::OnLostContext() { - if (gr_context_) - gr_context_->abandonContext(); -} - -void GrContextForWebGraphicsContext3D::FreeGpuResources() { - if (gr_context_) { - TRACE_EVENT_INSTANT0("gpu", "GrContext::freeGpuResources", \ - TRACE_EVENT_SCOPE_THREAD); - gr_context_->freeGpuResources(); - } -} - -GrGLInterfaceForWebGraphicsContext3D::GrGLInterfaceForWebGraphicsContext3D( - scoped_ptr<gpu_blink::WebGraphicsContext3DImpl> context3d) - : context3d_(std::move(context3d)) {} - -void GrGLInterfaceForWebGraphicsContext3D::BindToCurrentThread() { - context_thread_checker_.DetachFromThread(); -} - -GrGLInterfaceForWebGraphicsContext3D::~GrGLInterfaceForWebGraphicsContext3D() { - DCHECK(context_thread_checker_.CalledOnValidThread()); -#if !defined(NDEBUG) - // Set all the function pointers to zero, in order to crash if function - // pointers are used after free. - memset(&fFunctions, 0, sizeof(GrGLInterface::Functions)); -#endif -} - -} // namespace content diff --git a/chromium/content/common/gpu/client/grcontext_for_webgraphicscontext3d.h b/chromium/content/common/gpu/client/grcontext_for_webgraphicscontext3d.h deleted file mode 100644 index 7597f906a58..00000000000 --- a/chromium/content/common/gpu/client/grcontext_for_webgraphicscontext3d.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2013 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 CONTENT_COMMON_GPU_CLIENT_GRCONTEXT_FOR_WEBGRAPHICSCONTEXT3D_H_ -#define CONTENT_COMMON_GPU_CLIENT_GRCONTEXT_FOR_WEBGRAPHICSCONTEXT3D_H_ - -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "base/threading/thread_checker.h" -#include "skia/ext/refptr.h" -#include "third_party/skia/include/gpu/gl/GrGLInterface.h" - -class GrContext; - -namespace gpu_blink { -class WebGraphicsContext3DImpl; -} - -namespace content { - -// Wrap WebGraphicsContext3DImpl into a GrGLInterface object, which allows -// the WebGraphicsContext3DImpl to be jointly refcounted (indirectly) -// by the GrContext and the context provider. This makes it legal for the -// GrContext to be invoked when it outlives the context provider that created -// it. By doing this we no longer have to worry about use after free errors -// caused a lack of consideration for object destruction order. -class GrGLInterfaceForWebGraphicsContext3D final : public GrGLInterface { - public: - GrGLInterfaceForWebGraphicsContext3D( - scoped_ptr<gpu_blink::WebGraphicsContext3DImpl> context3d); - ~GrGLInterfaceForWebGraphicsContext3D() final; - - void BindToCurrentThread(); - - gpu_blink::WebGraphicsContext3DImpl* WebContext3D() const { - return context3d_.get(); - } - private: - base::ThreadChecker context_thread_checker_; - scoped_ptr<gpu_blink::WebGraphicsContext3DImpl> context3d_; -}; - -// This class binds an offscreen GrContext to an offscreen context3d. The -// context3d is used by the GrContext so must be valid as long as this class -// is alive. -class GrContextForWebGraphicsContext3D { - public: - explicit GrContextForWebGraphicsContext3D( - skia::RefPtr<GrGLInterfaceForWebGraphicsContext3D> context3d); - virtual ~GrContextForWebGraphicsContext3D(); - - GrContext* get() { return gr_context_.get(); } - - void OnLostContext(); - void FreeGpuResources(); - - private: - skia::RefPtr<class GrContext> gr_context_; - - DISALLOW_COPY_AND_ASSIGN(GrContextForWebGraphicsContext3D); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_CLIENT_GRCONTEXT_FOR_WEBGRAPHICSCONTEXT3D_H_ diff --git a/chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc b/chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc index f7783397057..708a3da8ee0 100644 --- a/chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc +++ b/chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc @@ -23,22 +23,19 @@ #include "base/metrics/histogram.h" #include "base/profiler/scoped_tracker.h" #include "base/trace_event/trace_event.h" -#include "content/common/gpu/client/gpu_channel_host.h" -#include "content/public/common/content_constants.h" -#include "content/public/common/content_switches.h" #include "gpu/GLES2/gl2extchromium.h" #include "gpu/command_buffer/client/gles2_cmd_helper.h" #include "gpu/command_buffer/client/gles2_implementation.h" #include "gpu/command_buffer/client/gles2_trace_implementation.h" +#include "gpu/command_buffer/client/gpu_switches.h" #include "gpu/command_buffer/client/transfer_buffer.h" #include "gpu/command_buffer/common/constants.h" #include "gpu/command_buffer/common/gpu_memory_allocation.h" #include "gpu/command_buffer/common/mailbox.h" +#include "gpu/ipc/client/gpu_channel_host.h" #include "gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h" #include "third_party/skia/include/core/SkTypes.h" -using blink::WGC3Denum; - namespace content { namespace { @@ -46,14 +43,15 @@ namespace { static base::LazyInstance<base::Lock>::Leaky g_default_share_groups_lock = LAZY_INSTANCE_INITIALIZER; -typedef std::map<GpuChannelHost*, - scoped_refptr<WebGraphicsContext3DCommandBufferImpl::ShareGroup> > +typedef std::map< + gpu::GpuChannelHost*, + scoped_refptr<WebGraphicsContext3DCommandBufferImpl::ShareGroup>> ShareGroupMap; static base::LazyInstance<ShareGroupMap> g_default_share_groups = LAZY_INSTANCE_INITIALIZER; scoped_refptr<WebGraphicsContext3DCommandBufferImpl::ShareGroup> - GetDefaultShareGroupForHost(GpuChannelHost* host) { +GetDefaultShareGroupForHost(gpu::GpuChannelHost* host) { base::AutoLock lock(g_default_share_groups_lock.Get()); ShareGroupMap& share_groups = g_default_share_groups.Get(); @@ -84,34 +82,38 @@ WebGraphicsContext3DCommandBufferImpl::ShareGroup::~ShareGroup() { } WebGraphicsContext3DCommandBufferImpl::WebGraphicsContext3DCommandBufferImpl( - int surface_id, + gpu::SurfaceHandle surface_handle, const GURL& active_url, - GpuChannelHost* host, - const Attributes& attributes, - bool lose_context_when_out_of_memory, + gpu::GpuChannelHost* host, + const gpu::gles2::ContextCreationAttribHelper& attributes, + gfx::GpuPreference gpu_preference, + bool share_resources, + bool automatic_flushes, const SharedMemoryLimits& limits, WebGraphicsContext3DCommandBufferImpl* share_context) - : lose_context_when_out_of_memory_(lose_context_when_out_of_memory), + : automatic_flushes_(automatic_flushes), attributes_(attributes), - visible_(false), host_(host), - surface_id_(surface_id), + surface_handle_(surface_handle), active_url_(active_url), - context_type_(CONTEXT_TYPE_UNKNOWN), - gpu_preference_(attributes.preferDiscreteGPU ? gfx::PreferDiscreteGpu - : gfx::PreferIntegratedGpu), + gpu_preference_(gpu_preference), mem_limits_(limits), weak_ptr_factory_(this) { - if (attributes_.webGL) - context_type_ = OFFSCREEN_CONTEXT_FOR_WEBGL; + switch (attributes.context_type) { + case gpu::gles2::CONTEXT_TYPE_OPENGLES2: + case gpu::gles2::CONTEXT_TYPE_OPENGLES3: + context_type_ = CONTEXT_TYPE_UNKNOWN; + case gpu::gles2::CONTEXT_TYPE_WEBGL1: + case gpu::gles2::CONTEXT_TYPE_WEBGL2: + context_type_ = OFFSCREEN_CONTEXT_FOR_WEBGL; + } if (share_context) { - DCHECK(!attributes_.shareResources); + DCHECK(!share_resources); share_group_ = share_context->share_group_; + } else if (share_resources) { + share_group_ = GetDefaultShareGroupForHost(host); } else { - share_group_ = attributes_.shareResources - ? GetDefaultShareGroupForHost(host) - : scoped_refptr<WebGraphicsContext3DCommandBufferImpl::ShareGroup>( - new ShareGroup()); + share_group_ = make_scoped_refptr(new ShareGroup); } } @@ -138,7 +140,7 @@ bool WebGraphicsContext3DCommandBufferImpl::MaybeInitializeGL() { FROM_HERE_WITH_EXPLICIT_FUNCTION( "125248 WebGraphicsContext3DCommandBufferImpl::MaybeInitializeGL")); - if (!CreateContext(surface_id_ != 0)) { + if (!CreateContext()) { Destroy(); initialize_failed_ = true; @@ -157,44 +159,31 @@ bool WebGraphicsContext3DCommandBufferImpl::MaybeInitializeGL() { real_gl_->TraceBeginCHROMIUM("WebGraphicsContext3D", "CommandBufferContext"); - visible_ = true; initialized_ = true; return true; } bool WebGraphicsContext3DCommandBufferImpl::InitializeCommandBuffer( - bool onscreen, WebGraphicsContext3DCommandBufferImpl* share_context) { + WebGraphicsContext3DCommandBufferImpl* share_context) { if (!host_.get()) return false; - CommandBufferProxyImpl* share_group_command_buffer = NULL; + gpu::CommandBufferProxyImpl* share_group_command_buffer = NULL; if (share_context) { share_group_command_buffer = share_context->GetCommandBufferProxy(); } - ::gpu::gles2::ContextCreationAttribHelper attribs_for_gles2; - ConvertAttributes(attributes_, &attribs_for_gles2); - attribs_for_gles2.lose_context_when_out_of_memory = - lose_context_when_out_of_memory_; - DCHECK(attribs_for_gles2.buffer_preserved); - std::vector<int32_t> attribs; - attribs_for_gles2.Serialize(&attribs); + DCHECK(attributes_.buffer_preserved); + std::vector<int32_t> serialized_attributes; + attributes_.Serialize(&serialized_attributes); // Create a proxy to a command buffer in the GPU process. - if (onscreen) { - command_buffer_ = - host_->CreateViewCommandBuffer(surface_id_, share_group_command_buffer, - GpuChannelHost::kDefaultStreamId, - GpuChannelHost::kDefaultStreamPriority, - attribs, active_url_, gpu_preference_); - } else { - command_buffer_ = host_->CreateOffscreenCommandBuffer( - gfx::Size(1, 1), share_group_command_buffer, - GpuChannelHost::kDefaultStreamId, - GpuChannelHost::kDefaultStreamPriority, attribs, active_url_, - gpu_preference_); - } + command_buffer_ = host_->CreateCommandBuffer( + surface_handle_, gfx::Size(), share_group_command_buffer, + gpu::GpuChannelHost::kDefaultStreamId, + gpu::GpuChannelHost::kDefaultStreamPriority, serialized_attributes, + active_url_, gpu_preference_); if (!command_buffer_) { DLOG(ERROR) << "GpuChannelHost failed to create command buffer."; @@ -213,7 +202,7 @@ bool WebGraphicsContext3DCommandBufferImpl::InitializeCommandBuffer( return result; } -bool WebGraphicsContext3DCommandBufferImpl::CreateContext(bool onscreen) { +bool WebGraphicsContext3DCommandBufferImpl::CreateContext() { TRACE_EVENT0("gpu", "WebGfxCtx3DCmdBfrImpl::CreateContext"); scoped_refptr<gpu::gles2::ShareGroup> gles2_share_group; @@ -225,7 +214,7 @@ bool WebGraphicsContext3DCommandBufferImpl::CreateContext(bool onscreen) { share_group_lock.reset(new base::AutoLock(share_group_->lock())); share_context = share_group_->GetAnyContextLocked(); - if (!InitializeCommandBuffer(onscreen, share_context)) { + if (!InitializeCommandBuffer(share_context)) { LOG(ERROR) << "Failed to initialize command buffer."; return false; } @@ -243,7 +232,7 @@ bool WebGraphicsContext3DCommandBufferImpl::CreateContext(bool onscreen) { return false; } - if (attributes_.noAutomaticFlushes) + if (!automatic_flushes_) gles2_helper_->SetAutomaticFlushes(false); // Create a transfer buffer used to copy resources between the renderer // process and the GPU process. @@ -251,15 +240,17 @@ bool WebGraphicsContext3DCommandBufferImpl::CreateContext(bool onscreen) { DCHECK(host_.get()); - // Create the object exposing the OpenGL API. - const bool bind_generates_resources = false; + const bool bind_generates_resource = attributes_.bind_generates_resource; + const bool lose_context_when_out_of_memory = + attributes_.lose_context_when_out_of_memory; const bool support_client_side_arrays = false; + // Create the object exposing the OpenGL API. real_gl_.reset(new gpu::gles2::GLES2Implementation( gles2_helper_.get(), gles2_share_group.get(), transfer_buffer_.get(), - bind_generates_resources, lose_context_when_out_of_memory_, + bind_generates_resource, lose_context_when_out_of_memory, support_client_side_arrays, command_buffer_.get())); - setGLInterface(real_gl_.get()); + SetGLInterface(real_gl_.get()); if (!real_gl_->Initialize( mem_limits_.start_transfer_buffer_size, @@ -276,7 +267,7 @@ bool WebGraphicsContext3DCommandBufferImpl::CreateContext(bool onscreen) { if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableGpuClientTracing)) { trace_gl_.reset(new gpu::gles2::GLES2TraceImplementation(GetGLInterface())); - setGLInterface(trace_gl_.get()); + SetGLInterface(trace_gl_.get()); } return true; } @@ -306,7 +297,7 @@ void WebGraphicsContext3DCommandBufferImpl::Destroy() { // issued on this context might not be visible to other contexts in the // share group. gl->Flush(); - setGLInterface(NULL); + SetGLInterface(nullptr); } trace_gl_.reset(); @@ -316,7 +307,7 @@ void WebGraphicsContext3DCommandBufferImpl::Destroy() { real_gl_.reset(); command_buffer_.reset(); - host_ = NULL; + host_ = nullptr; } gpu::ContextSupport* @@ -336,9 +327,11 @@ bool WebGraphicsContext3DCommandBufferImpl::IsCommandBufferContextLost() { // static WebGraphicsContext3DCommandBufferImpl* WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext( - GpuChannelHost* host, - const WebGraphicsContext3D::Attributes& attributes, - bool lose_context_when_out_of_memory, + gpu::GpuChannelHost* host, + const gpu::gles2::ContextCreationAttribHelper& attributes, + gfx::GpuPreference gpu_preference, + bool share_resources, + bool automatic_flushes, const GURL& active_url, const SharedMemoryLimits& limits, WebGraphicsContext3DCommandBufferImpl* share_context) { @@ -349,13 +342,8 @@ WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext( return NULL; return new WebGraphicsContext3DCommandBufferImpl( - 0, - active_url, - host, - attributes, - lose_context_when_out_of_memory, - limits, - share_context); + gpu::kNullSurfaceHandle, active_url, host, attributes, gpu_preference, + share_resources, automatic_flushes, limits, share_context); } void WebGraphicsContext3DCommandBufferImpl::OnContextLost() { diff --git a/chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h b/chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h index b556c1bcdf5..1bbd7202eb6 100644 --- a/chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h +++ b/chromium/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h @@ -18,17 +18,19 @@ #include "base/synchronization/lock.h" #include "content/common/content_export.h" #include "content/common/gpu/client/command_buffer_metrics.h" -#include "content/common/gpu/client/command_buffer_proxy_impl.h" #include "gpu/blink/webgraphicscontext3d_impl.h" +#include "gpu/command_buffer/common/gles2_cmd_utils.h" +#include "gpu/ipc/client/command_buffer_proxy_impl.h" +#include "gpu/ipc/common/surface_handle.h" #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" #include "third_party/WebKit/public/platform/WebString.h" -#include "ui/gfx/native_widget_types.h" #include "ui/gl/gpu_preference.h" #include "url/gurl.h" namespace gpu { class ContextSupport; +class GpuChannelHost; class TransferBuffer; namespace gles2 { @@ -39,7 +41,6 @@ class GLES2Interface; } namespace content { -class GpuChannelHost; const size_t kDefaultCommandBufferSize = 1024 * 1024; const size_t kDefaultStartTransferBufferSize = 1 * 1024 * 1024; @@ -108,17 +109,19 @@ class WebGraphicsContext3DCommandBufferImpl }; WebGraphicsContext3DCommandBufferImpl( - int surface_id, + gpu::SurfaceHandle surface_handle, const GURL& active_url, - GpuChannelHost* host, - const Attributes& attributes, - bool lose_context_when_out_of_memory, + gpu::GpuChannelHost* host, + const gpu::gles2::ContextCreationAttribHelper& attributes, + gfx::GpuPreference gpu_preference, + bool share_resources, + bool automatic_flushes, const SharedMemoryLimits& limits, WebGraphicsContext3DCommandBufferImpl* share_context); ~WebGraphicsContext3DCommandBufferImpl() override; - CommandBufferProxyImpl* GetCommandBufferProxy() { + gpu::CommandBufferProxyImpl* GetCommandBufferProxy() { return command_buffer_.get(); } @@ -135,13 +138,15 @@ class WebGraphicsContext3DCommandBufferImpl // Create & initialize a WebGraphicsContext3DCommandBufferImpl. Return NULL // on any failure. static CONTENT_EXPORT WebGraphicsContext3DCommandBufferImpl* - CreateOffscreenContext( - GpuChannelHost* host, - const WebGraphicsContext3D::Attributes& attributes, - bool lose_context_when_out_of_memory, - const GURL& active_url, - const SharedMemoryLimits& limits, - WebGraphicsContext3DCommandBufferImpl* share_context); + CreateOffscreenContext( + gpu::GpuChannelHost* host, + const gpu::gles2::ContextCreationAttribHelper& attributes, + gfx::GpuPreference gpu_preference, + bool share_resources, + bool automatic_flushes, + const GURL& active_url, + const SharedMemoryLimits& limits, + WebGraphicsContext3DCommandBufferImpl* share_context); size_t GetMappedMemoryLimit() { return mem_limits_.mapped_memory_reclaim_limit; @@ -166,7 +171,7 @@ class WebGraphicsContext3DCommandBufferImpl // thread). bool MaybeInitializeGL(); - bool InitializeCommandBuffer(bool onscreen, + bool InitializeCommandBuffer( WebGraphicsContext3DCommandBufferImpl* share_context); void Destroy(); @@ -178,30 +183,28 @@ class WebGraphicsContext3DCommandBufferImpl // // NOTE: on Mac OS X, this entry point is only used to set up the // accelerated compositor's output. On this platform, we actually pass - // a gfx::PluginWindowHandle in place of the gfx::NativeViewId, + // a gpu::SurfaceHandle in place of the gfx::NativeViewId, // because the facility to allocate a fake PluginWindowHandle is // already in place. We could add more entry points and messages to // allocate both fake PluginWindowHandles and NativeViewIds and map // from fake NativeViewIds to PluginWindowHandles, but this seems like // unnecessary complexity at the moment. - bool CreateContext(bool onscreen); + bool CreateContext(); virtual void OnContextLost(); - bool lose_context_when_out_of_memory_; - blink::WebGraphicsContext3D::Attributes attributes_; - - bool visible_; + bool automatic_flushes_; + gpu::gles2::ContextCreationAttribHelper attributes_; // State needed by MaybeInitializeGL. - scoped_refptr<GpuChannelHost> host_; - int32_t surface_id_; + scoped_refptr<gpu::GpuChannelHost> host_; + gpu::SurfaceHandle surface_handle_; GURL active_url_; CommandBufferContextType context_type_; gfx::GpuPreference gpu_preference_; - scoped_ptr<CommandBufferProxyImpl> command_buffer_; + scoped_ptr<gpu::CommandBufferProxyImpl> command_buffer_; scoped_ptr<gpu::gles2::GLES2CmdHelper> gles2_helper_; scoped_ptr<gpu::TransferBuffer> transfer_buffer_; scoped_ptr<gpu::gles2::GLES2Implementation> real_gl_; diff --git a/chromium/content/common/gpu/gpu_channel.cc b/chromium/content/common/gpu/gpu_channel.cc deleted file mode 100644 index e3f920d96b0..00000000000 --- a/chromium/content/common/gpu/gpu_channel.cc +++ /dev/null @@ -1,1086 +0,0 @@ -// Copyright (c) 2012 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 "content/common/gpu/gpu_channel.h" - -#include <utility> - -#if defined(OS_WIN) -#include <windows.h> -#endif - -#include <algorithm> -#include <deque> -#include <set> -#include <vector> - -#include "base/atomicops.h" -#include "base/bind.h" -#include "base/command_line.h" -#include "base/location.h" -#include "base/numerics/safe_conversions.h" -#include "base/single_thread_task_runner.h" -#include "base/stl_util.h" -#include "base/strings/string_util.h" -#include "base/synchronization/lock.h" -#include "base/thread_task_runner_handle.h" -#include "base/timer/timer.h" -#include "base/trace_event/memory_dump_manager.h" -#include "base/trace_event/process_memory_dump.h" -#include "base/trace_event/trace_event.h" -#include "build/build_config.h" -#include "content/common/gpu/gpu_channel_manager.h" -#include "content/common/gpu/gpu_memory_buffer_factory.h" -#include "content/common/gpu/gpu_messages.h" -#include "content/common/gpu/media/gpu_jpeg_decode_accelerator.h" -#include "content/public/common/content_switches.h" -#include "gpu/command_buffer/common/mailbox.h" -#include "gpu/command_buffer/common/value_state.h" -#include "gpu/command_buffer/service/gpu_scheduler.h" -#include "gpu/command_buffer/service/image_factory.h" -#include "gpu/command_buffer/service/mailbox_manager.h" -#include "gpu/command_buffer/service/sync_point_manager.h" -#include "gpu/command_buffer/service/valuebuffer_manager.h" -#include "ipc/ipc_channel.h" -#include "ipc/message_filter.h" -#include "ui/gl/gl_context.h" -#include "ui/gl/gl_image_shared_memory.h" -#include "ui/gl/gl_surface.h" - -#if defined(OS_POSIX) -#include "ipc/ipc_channel_posix.h" -#endif - -namespace content { -namespace { - -// Number of milliseconds between successive vsync. Many GL commands block -// on vsync, so thresholds for preemption should be multiples of this. -const int64_t kVsyncIntervalMs = 17; - -// Amount of time that we will wait for an IPC to be processed before -// preempting. After a preemption, we must wait this long before triggering -// another preemption. -const int64_t kPreemptWaitTimeMs = 2 * kVsyncIntervalMs; - -// Once we trigger a preemption, the maximum duration that we will wait -// before clearing the preemption. -const int64_t kMaxPreemptTimeMs = kVsyncIntervalMs; - -// Stop the preemption once the time for the longest pending IPC drops -// below this threshold. -const int64_t kStopPreemptThresholdMs = kVsyncIntervalMs; - -} // anonymous namespace - -scoped_refptr<GpuChannelMessageQueue> GpuChannelMessageQueue::Create( - const base::WeakPtr<GpuChannel>& gpu_channel, - base::SingleThreadTaskRunner* task_runner, - gpu::SyncPointManager* sync_point_manager) { - return new GpuChannelMessageQueue(gpu_channel, task_runner, - sync_point_manager); -} - -scoped_refptr<gpu::SyncPointOrderData> -GpuChannelMessageQueue::GetSyncPointOrderData() { - return sync_point_order_data_; -} - -GpuChannelMessageQueue::GpuChannelMessageQueue( - const base::WeakPtr<GpuChannel>& gpu_channel, - base::SingleThreadTaskRunner* task_runner, - gpu::SyncPointManager* sync_point_manager) - : enabled_(true), - sync_point_order_data_(gpu::SyncPointOrderData::Create()), - gpu_channel_(gpu_channel), - task_runner_(task_runner), - sync_point_manager_(sync_point_manager) {} - -GpuChannelMessageQueue::~GpuChannelMessageQueue() { - DCHECK(channel_messages_.empty()); -} - -uint32_t GpuChannelMessageQueue::GetUnprocessedOrderNum() const { - return sync_point_order_data_->unprocessed_order_num(); -} - -uint32_t GpuChannelMessageQueue::GetProcessedOrderNum() const { - return sync_point_order_data_->processed_order_num(); -} - -void GpuChannelMessageQueue::PushBackMessage(const IPC::Message& message) { - base::AutoLock auto_lock(channel_messages_lock_); - if (enabled_) - PushMessageHelper(make_scoped_ptr(new GpuChannelMessage(message))); -} - -bool GpuChannelMessageQueue::GenerateSyncPointMessage( - const IPC::Message& message, - bool retire_sync_point, - uint32_t* sync_point) { - DCHECK_EQ((uint32_t)GpuCommandBufferMsg_InsertSyncPoint::ID, message.type()); - DCHECK(sync_point); - base::AutoLock auto_lock(channel_messages_lock_); - if (enabled_) { - *sync_point = sync_point_manager_->GenerateSyncPoint(); - - scoped_ptr<GpuChannelMessage> msg(new GpuChannelMessage(message)); - msg->retire_sync_point = retire_sync_point; - msg->sync_point = *sync_point; - - PushMessageHelper(std::move(msg)); - return true; - } - return false; -} - -bool GpuChannelMessageQueue::HasQueuedMessages() const { - base::AutoLock auto_lock(channel_messages_lock_); - return !channel_messages_.empty(); -} - -base::TimeTicks GpuChannelMessageQueue::GetNextMessageTimeTick() const { - base::AutoLock auto_lock(channel_messages_lock_); - if (!channel_messages_.empty()) - return channel_messages_.front()->time_received; - return base::TimeTicks(); -} - -GpuChannelMessage* GpuChannelMessageQueue::GetNextMessage() const { - base::AutoLock auto_lock(channel_messages_lock_); - if (!channel_messages_.empty()) { - DCHECK_GT(channel_messages_.front()->order_number, - sync_point_order_data_->processed_order_num()); - DCHECK_LE(channel_messages_.front()->order_number, - sync_point_order_data_->unprocessed_order_num()); - - return channel_messages_.front(); - } - return nullptr; -} - -void GpuChannelMessageQueue::BeginMessageProcessing( - const GpuChannelMessage* msg) { - sync_point_order_data_->BeginProcessingOrderNumber(msg->order_number); -} - -void GpuChannelMessageQueue::PauseMessageProcessing( - const GpuChannelMessage* msg) { - sync_point_order_data_->PauseProcessingOrderNumber(msg->order_number); -} - -bool GpuChannelMessageQueue::MessageProcessed() { - base::AutoLock auto_lock(channel_messages_lock_); - DCHECK(!channel_messages_.empty()); - scoped_ptr<GpuChannelMessage> msg(channel_messages_.front()); - channel_messages_.pop_front(); - sync_point_order_data_->FinishProcessingOrderNumber(msg->order_number); - return !channel_messages_.empty(); -} - -void GpuChannelMessageQueue::DeleteAndDisableMessages() { - { - base::AutoLock auto_lock(channel_messages_lock_); - DCHECK(enabled_); - enabled_ = false; - } - - // We guarantee that the queues will no longer be modified after enabled_ - // is set to false, it is now safe to modify the queue without the lock. - // All public facing modifying functions check enabled_ while all - // private modifying functions DCHECK(enabled_) to enforce this. - while (!channel_messages_.empty()) { - scoped_ptr<GpuChannelMessage> msg(channel_messages_.front()); - channel_messages_.pop_front(); - // This needs to clean up both GpuCommandBufferMsg_InsertSyncPoint and - // GpuCommandBufferMsg_RetireSyncPoint messages, safer to just check - // if we have a sync point number here. - if (msg->sync_point) - sync_point_manager_->RetireSyncPoint(msg->sync_point); - } - - if (sync_point_order_data_) { - sync_point_order_data_->Destroy(); - sync_point_order_data_ = nullptr; - } -} - -void GpuChannelMessageQueue::ScheduleHandleMessage() { - task_runner_->PostTask(FROM_HERE, - base::Bind(&GpuChannel::HandleMessage, gpu_channel_)); -} - -void GpuChannelMessageQueue::PushMessageHelper( - scoped_ptr<GpuChannelMessage> msg) { - channel_messages_lock_.AssertAcquired(); - DCHECK(enabled_); - - msg->order_number = sync_point_order_data_->GenerateUnprocessedOrderNumber( - sync_point_manager_); - msg->time_received = base::TimeTicks::Now(); - - bool had_messages = !channel_messages_.empty(); - channel_messages_.push_back(msg.release()); - if (!had_messages) - ScheduleHandleMessage(); -} - -GpuChannelMessageFilter::GpuChannelMessageFilter( - const base::WeakPtr<GpuChannel>& gpu_channel, - GpuChannelMessageQueue* message_queue, - base::SingleThreadTaskRunner* task_runner, - gpu::PreemptionFlag* preempting_flag, - bool future_sync_points) - : preemption_state_(IDLE), - gpu_channel_(gpu_channel), - message_queue_(message_queue), - sender_(nullptr), - peer_pid_(base::kNullProcessId), - task_runner_(task_runner), - preempting_flag_(preempting_flag), - a_stub_is_descheduled_(false), - future_sync_points_(future_sync_points) {} - -GpuChannelMessageFilter::~GpuChannelMessageFilter() {} - -void GpuChannelMessageFilter::OnFilterAdded(IPC::Sender* sender) { - DCHECK(!sender_); - sender_ = sender; - timer_ = make_scoped_ptr(new base::OneShotTimer); - for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { - filter->OnFilterAdded(sender_); - } -} - -void GpuChannelMessageFilter::OnFilterRemoved() { - DCHECK(sender_); - for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { - filter->OnFilterRemoved(); - } - sender_ = nullptr; - peer_pid_ = base::kNullProcessId; - timer_ = nullptr; -} - -void GpuChannelMessageFilter::OnChannelConnected(int32_t peer_pid) { - DCHECK(peer_pid_ == base::kNullProcessId); - peer_pid_ = peer_pid; - for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { - filter->OnChannelConnected(peer_pid); - } -} - -void GpuChannelMessageFilter::OnChannelError() { - for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { - filter->OnChannelError(); - } -} - -void GpuChannelMessageFilter::OnChannelClosing() { - for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { - filter->OnChannelClosing(); - } -} - -void GpuChannelMessageFilter::AddChannelFilter( - scoped_refptr<IPC::MessageFilter> filter) { - channel_filters_.push_back(filter); - if (sender_) - filter->OnFilterAdded(sender_); - if (peer_pid_ != base::kNullProcessId) - filter->OnChannelConnected(peer_pid_); -} - -void GpuChannelMessageFilter::RemoveChannelFilter( - scoped_refptr<IPC::MessageFilter> filter) { - if (sender_) - filter->OnFilterRemoved(); - channel_filters_.erase( - std::find(channel_filters_.begin(), channel_filters_.end(), filter)); -} - -bool GpuChannelMessageFilter::OnMessageReceived(const IPC::Message& message) { - DCHECK(sender_); - - if (message.should_unblock() || message.is_reply()) { - DLOG(ERROR) << "Unexpected message type"; - return true; - } - - if (message.type() == GpuChannelMsg_Nop::ID) { - IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message); - Send(reply); - return true; - } - - for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { - if (filter->OnMessageReceived(message)) { - return true; - } - } - - bool handled = false; - if ((message.type() == GpuCommandBufferMsg_RetireSyncPoint::ID) && - !future_sync_points_) { - DLOG(ERROR) << "Untrusted client should not send " - "GpuCommandBufferMsg_RetireSyncPoint message"; - return true; - } - - if (message.type() == GpuCommandBufferMsg_InsertSyncPoint::ID) { - base::Tuple<bool> params; - IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message); - if (!GpuCommandBufferMsg_InsertSyncPoint::ReadSendParam(&message, - ¶ms)) { - reply->set_reply_error(); - Send(reply); - return true; - } - bool retire_sync_point = base::get<0>(params); - if (!future_sync_points_ && !retire_sync_point) { - DLOG(ERROR) << "Untrusted contexts can't create future sync points"; - reply->set_reply_error(); - Send(reply); - return true; - } - - // Message queue must handle the entire sync point generation because the - // message queue could be disabled from the main thread during generation. - uint32_t sync_point = 0u; - if (!message_queue_->GenerateSyncPointMessage(message, retire_sync_point, - &sync_point)) { - DLOG(ERROR) << "GpuChannel has been destroyed."; - reply->set_reply_error(); - Send(reply); - return true; - } - - DCHECK_NE(sync_point, 0u); - GpuCommandBufferMsg_InsertSyncPoint::WriteReplyParams(reply, sync_point); - Send(reply); - handled = true; - } - - // Forward all other messages to the GPU Channel. - if (!handled) { - if (message.type() == GpuCommandBufferMsg_WaitForTokenInRange::ID || - message.type() == GpuCommandBufferMsg_WaitForGetOffsetInRange::ID) { - task_runner_->PostTask(FROM_HERE, - base::Bind(&GpuChannel::HandleOutOfOrderMessage, - gpu_channel_, message)); - } else { - message_queue_->PushBackMessage(message); - } - handled = true; - } - - UpdatePreemptionState(); - return handled; -} - -void GpuChannelMessageFilter::OnMessageProcessed() { - UpdatePreemptionState(); -} - -void GpuChannelMessageFilter::UpdateStubSchedulingState( - bool a_stub_is_descheduled) { - a_stub_is_descheduled_ = a_stub_is_descheduled; - UpdatePreemptionState(); -} - -bool GpuChannelMessageFilter::Send(IPC::Message* message) { - return sender_->Send(message); -} - -void GpuChannelMessageFilter::UpdatePreemptionState() { - switch (preemption_state_) { - case IDLE: - if (preempting_flag_.get() && message_queue_->HasQueuedMessages()) - TransitionToWaiting(); - break; - case WAITING: - // A timer will transition us to CHECKING. - DCHECK(timer_->IsRunning()); - break; - case CHECKING: { - base::TimeTicks time_tick = message_queue_->GetNextMessageTimeTick(); - if (!time_tick.is_null()) { - base::TimeDelta time_elapsed = base::TimeTicks::Now() - time_tick; - if (time_elapsed.InMilliseconds() < kPreemptWaitTimeMs) { - // Schedule another check for when the IPC may go long. - timer_->Start(FROM_HERE, - base::TimeDelta::FromMilliseconds(kPreemptWaitTimeMs) - - time_elapsed, - this, &GpuChannelMessageFilter::UpdatePreemptionState); - } else { - if (a_stub_is_descheduled_) - TransitionToWouldPreemptDescheduled(); - else - TransitionToPreempting(); - } - } - } break; - case PREEMPTING: - // A TransitionToIdle() timer should always be running in this state. - DCHECK(timer_->IsRunning()); - if (a_stub_is_descheduled_) - TransitionToWouldPreemptDescheduled(); - else - TransitionToIdleIfCaughtUp(); - break; - case WOULD_PREEMPT_DESCHEDULED: - // A TransitionToIdle() timer should never be running in this state. - DCHECK(!timer_->IsRunning()); - if (!a_stub_is_descheduled_) - TransitionToPreempting(); - else - TransitionToIdleIfCaughtUp(); - break; - default: - NOTREACHED(); - } -} - -void GpuChannelMessageFilter::TransitionToIdleIfCaughtUp() { - DCHECK(preemption_state_ == PREEMPTING || - preemption_state_ == WOULD_PREEMPT_DESCHEDULED); - base::TimeTicks next_tick = message_queue_->GetNextMessageTimeTick(); - if (next_tick.is_null()) { - TransitionToIdle(); - } else { - base::TimeDelta time_elapsed = base::TimeTicks::Now() - next_tick; - if (time_elapsed.InMilliseconds() < kStopPreemptThresholdMs) - TransitionToIdle(); - } -} - -void GpuChannelMessageFilter::TransitionToIdle() { - DCHECK(preemption_state_ == PREEMPTING || - preemption_state_ == WOULD_PREEMPT_DESCHEDULED); - // Stop any outstanding timer set to force us from PREEMPTING to IDLE. - timer_->Stop(); - - preemption_state_ = IDLE; - preempting_flag_->Reset(); - TRACE_COUNTER_ID1("gpu", "GpuChannel::Preempting", this, 0); - - UpdatePreemptionState(); -} - -void GpuChannelMessageFilter::TransitionToWaiting() { - DCHECK_EQ(preemption_state_, IDLE); - DCHECK(!timer_->IsRunning()); - - preemption_state_ = WAITING; - timer_->Start(FROM_HERE, - base::TimeDelta::FromMilliseconds(kPreemptWaitTimeMs), this, - &GpuChannelMessageFilter::TransitionToChecking); -} - -void GpuChannelMessageFilter::TransitionToChecking() { - DCHECK_EQ(preemption_state_, WAITING); - DCHECK(!timer_->IsRunning()); - - preemption_state_ = CHECKING; - max_preemption_time_ = base::TimeDelta::FromMilliseconds(kMaxPreemptTimeMs); - UpdatePreemptionState(); -} - -void GpuChannelMessageFilter::TransitionToPreempting() { - DCHECK(preemption_state_ == CHECKING || - preemption_state_ == WOULD_PREEMPT_DESCHEDULED); - DCHECK(!a_stub_is_descheduled_); - - // Stop any pending state update checks that we may have queued - // while CHECKING. - if (preemption_state_ == CHECKING) - timer_->Stop(); - - preemption_state_ = PREEMPTING; - preempting_flag_->Set(); - TRACE_COUNTER_ID1("gpu", "GpuChannel::Preempting", this, 1); - - timer_->Start(FROM_HERE, max_preemption_time_, this, - &GpuChannelMessageFilter::TransitionToIdle); - - UpdatePreemptionState(); -} - -void GpuChannelMessageFilter::TransitionToWouldPreemptDescheduled() { - DCHECK(preemption_state_ == CHECKING || preemption_state_ == PREEMPTING); - DCHECK(a_stub_is_descheduled_); - - if (preemption_state_ == CHECKING) { - // Stop any pending state update checks that we may have queued - // while CHECKING. - timer_->Stop(); - } else { - // Stop any TransitionToIdle() timers that we may have queued - // while PREEMPTING. - timer_->Stop(); - max_preemption_time_ = timer_->desired_run_time() - base::TimeTicks::Now(); - if (max_preemption_time_ < base::TimeDelta()) { - TransitionToIdle(); - return; - } - } - - preemption_state_ = WOULD_PREEMPT_DESCHEDULED; - preempting_flag_->Reset(); - TRACE_COUNTER_ID1("gpu", "GpuChannel::Preempting", this, 0); - - UpdatePreemptionState(); -} - -GpuChannel::StreamState::StreamState(int32_t id, GpuStreamPriority priority) - : id_(id), priority_(priority) {} - -GpuChannel::StreamState::~StreamState() {} - -void GpuChannel::StreamState::AddRoute(int32_t route_id) { - routes_.insert(route_id); -} -void GpuChannel::StreamState::RemoveRoute(int32_t route_id) { - routes_.erase(route_id); -} - -bool GpuChannel::StreamState::HasRoute(int32_t route_id) const { - return routes_.find(route_id) != routes_.end(); -} - -bool GpuChannel::StreamState::HasRoutes() const { - return !routes_.empty(); -} - -GpuChannel::GpuChannel(GpuChannelManager* gpu_channel_manager, - gpu::SyncPointManager* sync_point_manager, - GpuWatchdog* watchdog, - gfx::GLShareGroup* share_group, - gpu::gles2::MailboxManager* mailbox, - gpu::PreemptionFlag* preempting_flag, - base::SingleThreadTaskRunner* task_runner, - base::SingleThreadTaskRunner* io_task_runner, - int client_id, - uint64_t client_tracing_id, - bool allow_future_sync_points, - bool allow_real_time_streams) - : gpu_channel_manager_(gpu_channel_manager), - sync_point_manager_(sync_point_manager), - channel_id_(IPC::Channel::GenerateVerifiedChannelID("gpu")), - preempting_flag_(preempting_flag), - client_id_(client_id), - client_tracing_id_(client_tracing_id), - task_runner_(task_runner), - io_task_runner_(io_task_runner), - share_group_(share_group), - mailbox_manager_(mailbox), - subscription_ref_set_(new gpu::gles2::SubscriptionRefSet), - pending_valuebuffer_state_(new gpu::ValueStateMap), - watchdog_(watchdog), - num_stubs_descheduled_(0), - allow_future_sync_points_(allow_future_sync_points), - allow_real_time_streams_(allow_real_time_streams), - weak_factory_(this) { - DCHECK(gpu_channel_manager); - DCHECK(client_id); - - message_queue_ = GpuChannelMessageQueue::Create( - weak_factory_.GetWeakPtr(), task_runner, sync_point_manager); - - filter_ = new GpuChannelMessageFilter( - weak_factory_.GetWeakPtr(), message_queue_.get(), task_runner, - preempting_flag, allow_future_sync_points); - - subscription_ref_set_->AddObserver(this); -} - -GpuChannel::~GpuChannel() { - // Clear stubs first because of dependencies. - stubs_.clear(); - - message_queue_->DeleteAndDisableMessages(); - - subscription_ref_set_->RemoveObserver(this); - if (preempting_flag_.get()) - preempting_flag_->Reset(); -} - -IPC::ChannelHandle GpuChannel::Init(base::WaitableEvent* shutdown_event) { - DCHECK(shutdown_event); - DCHECK(!channel_); - - IPC::ChannelHandle channel_handle(channel_id_); - - channel_ = - IPC::SyncChannel::Create(channel_handle, IPC::Channel::MODE_SERVER, this, - io_task_runner_, false, shutdown_event); - -#if defined(OS_POSIX) - // On POSIX, pass the renderer-side FD. Also mark it as auto-close so - // that it gets closed after it has been sent. - base::ScopedFD renderer_fd = channel_->TakeClientFileDescriptor(); - DCHECK(renderer_fd.is_valid()); - channel_handle.socket = base::FileDescriptor(std::move(renderer_fd)); -#endif - - channel_->AddFilter(filter_.get()); - - return channel_handle; -} - -base::ProcessId GpuChannel::GetClientPID() const { - return channel_->GetPeerPID(); -} - -uint32_t GpuChannel::GetProcessedOrderNum() const { - return message_queue_->GetProcessedOrderNum(); -} - -uint32_t GpuChannel::GetUnprocessedOrderNum() const { - return message_queue_->GetUnprocessedOrderNum(); -} - -bool GpuChannel::OnMessageReceived(const IPC::Message& message) { - // All messages should be pushed to channel_messages_ and handled separately. - NOTREACHED(); - return false; -} - -void GpuChannel::OnChannelError() { - gpu_channel_manager_->RemoveChannel(client_id_); -} - -bool GpuChannel::Send(IPC::Message* message) { - // The GPU process must never send a synchronous IPC message to the renderer - // process. This could result in deadlock. - DCHECK(!message->is_sync()); - - DVLOG(1) << "sending message @" << message << " on channel @" << this - << " with type " << message->type(); - - if (!channel_) { - delete message; - return false; - } - - return channel_->Send(message); -} - -void GpuChannel::OnAddSubscription(unsigned int target) { - gpu_channel_manager()->Send( - new GpuHostMsg_AddSubscription(client_id_, target)); -} - -void GpuChannel::OnRemoveSubscription(unsigned int target) { - gpu_channel_manager()->Send( - new GpuHostMsg_RemoveSubscription(client_id_, target)); -} - -void GpuChannel::OnStubSchedulingChanged(GpuCommandBufferStub* stub, - bool scheduled) { - bool a_stub_was_descheduled = num_stubs_descheduled_ > 0; - if (scheduled) { - num_stubs_descheduled_--; - ScheduleHandleMessage(); - } else { - num_stubs_descheduled_++; - } - DCHECK_LE(num_stubs_descheduled_, stubs_.size()); - bool a_stub_is_descheduled = num_stubs_descheduled_ > 0; - - if (a_stub_is_descheduled != a_stub_was_descheduled) { - if (preempting_flag_.get()) { - io_task_runner_->PostTask( - FROM_HERE, - base::Bind(&GpuChannelMessageFilter::UpdateStubSchedulingState, - filter_, a_stub_is_descheduled)); - } - } -} - -CreateCommandBufferResult GpuChannel::CreateViewCommandBuffer( - const gfx::GLSurfaceHandle& window, - const GPUCreateCommandBufferConfig& init_params, - int32_t route_id) { - TRACE_EVENT1("gpu", "GpuChannel::CreateViewCommandBuffer", "route_id", - route_id); - - int32_t share_group_id = init_params.share_group_id; - GpuCommandBufferStub* share_group = stubs_.get(share_group_id); - - if (!share_group && share_group_id != MSG_ROUTING_NONE) - return CREATE_COMMAND_BUFFER_FAILED; - - int32_t stream_id = init_params.stream_id; - GpuStreamPriority stream_priority = init_params.stream_priority; - - if (share_group && stream_id != share_group->stream_id()) - return CREATE_COMMAND_BUFFER_FAILED; - - if (!allow_real_time_streams_ && - stream_priority == GpuStreamPriority::REAL_TIME) - return CREATE_COMMAND_BUFFER_FAILED; - - auto stream_it = streams_.find(stream_id); - if (stream_it != streams_.end() && - stream_priority != GpuStreamPriority::INHERIT && - stream_priority != stream_it->second.priority()) { - return CREATE_COMMAND_BUFFER_FAILED; - } - - bool offscreen = false; - scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub( - this, sync_point_manager_, task_runner_.get(), share_group, window, - mailbox_manager_.get(), preempted_flag_.get(), - subscription_ref_set_.get(), pending_valuebuffer_state_.get(), - gfx::Size(), disallowed_features_, init_params.attribs, - init_params.gpu_preference, stream_id, route_id, offscreen, watchdog_, - init_params.active_url)); - - if (!router_.AddRoute(route_id, stub.get())) { - DLOG(ERROR) << "GpuChannel::CreateViewCommandBuffer(): " - "failed to add route"; - return CREATE_COMMAND_BUFFER_FAILED_AND_CHANNEL_LOST; - } - - if (stream_it != streams_.end()) { - stream_it->second.AddRoute(route_id); - } else { - StreamState stream(stream_id, stream_priority); - stream.AddRoute(route_id); - streams_.insert(std::make_pair(stream_id, stream)); - } - - stubs_.set(route_id, std::move(stub)); - return CREATE_COMMAND_BUFFER_SUCCEEDED; -} - -GpuCommandBufferStub* GpuChannel::LookupCommandBuffer(int32_t route_id) { - return stubs_.get(route_id); -} - -void GpuChannel::LoseAllContexts() { - gpu_channel_manager_->LoseAllContexts(); -} - -void GpuChannel::MarkAllContextsLost() { - for (auto& kv : stubs_) - kv.second->MarkContextLost(); -} - -bool GpuChannel::AddRoute(int32_t route_id, IPC::Listener* listener) { - return router_.AddRoute(route_id, listener); -} - -void GpuChannel::RemoveRoute(int32_t route_id) { - router_.RemoveRoute(route_id); -} - -void GpuChannel::SetPreemptByFlag( - scoped_refptr<gpu::PreemptionFlag> preempted_flag) { - DCHECK(stubs_.empty()); - preempted_flag_ = preempted_flag; -} - -void GpuChannel::OnDestroy() { - TRACE_EVENT0("gpu", "GpuChannel::OnDestroy"); - gpu_channel_manager_->RemoveChannel(client_id_); -} - -bool GpuChannel::OnControlMessageReceived(const IPC::Message& msg) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(GpuChannel, msg) - IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateOffscreenCommandBuffer, - OnCreateOffscreenCommandBuffer) - IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyCommandBuffer, - OnDestroyCommandBuffer) - IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuMsg_CreateJpegDecoder, - OnCreateJpegDecoder) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - DCHECK(handled) << msg.type(); - return handled; -} - -scoped_refptr<gpu::SyncPointOrderData> GpuChannel::GetSyncPointOrderData() { - return message_queue_->GetSyncPointOrderData(); -} - -void GpuChannel::HandleMessage() { - // If we have been preempted by another channel, just post a task to wake up. - if (preempted_flag_ && preempted_flag_->IsSet()) { - ScheduleHandleMessage(); - return; - } - - GpuChannelMessage* m = message_queue_->GetNextMessage(); - - // TODO(sunnyps): This could be a DCHECK maybe? - if (!m) - return; - - const IPC::Message& message = m->message; - message_queue_->BeginMessageProcessing(m); - int32_t routing_id = message.routing_id(); - GpuCommandBufferStub* stub = stubs_.get(routing_id); - - DCHECK(!stub || stub->IsScheduled()); - - DVLOG(1) << "received message @" << &message << " on channel @" << this - << " with type " << message.type(); - - bool handled = false; - - if (routing_id == MSG_ROUTING_CONTROL) { - handled = OnControlMessageReceived(message); - } else if (message.type() == GpuCommandBufferMsg_InsertSyncPoint::ID) { - // TODO(dyen): Temporary handling of old sync points. - // This must ensure that the sync point will be retired. Normally we'll - // find the stub based on the routing ID, and associate the sync point - // with it, but if that fails for any reason (channel or stub already - // deleted, invalid routing id), we need to retire the sync point - // immediately. - if (stub) { - stub->InsertSyncPoint(m->sync_point, m->retire_sync_point); - } else { - sync_point_manager_->RetireSyncPoint(m->sync_point); - } - handled = true; - } else { - handled = router_.RouteMessage(message); - } - - // Respond to sync messages even if router failed to route. - if (!handled && message.is_sync()) { - IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message); - reply->set_reply_error(); - Send(reply); - handled = true; - } - - // A command buffer may be descheduled or preempted but only in the middle of - // a flush. In this case we should not pop the message from the queue. - if (stub && stub->HasUnprocessedCommands()) { - DCHECK_EQ((uint32_t)GpuCommandBufferMsg_AsyncFlush::ID, message.type()); - message_queue_->PauseMessageProcessing(m); - // If the stub is still scheduled then we were preempted and need to - // schedule a wakeup otherwise some other event will wake us up e.g. sync - // point completion. No DCHECK for preemption flag because that can change - // any time. - if (stub->IsScheduled()) - ScheduleHandleMessage(); - return; - } - - if (message_queue_->MessageProcessed()) - ScheduleHandleMessage(); - - if (preempting_flag_) { - io_task_runner_->PostTask( - FROM_HERE, - base::Bind(&GpuChannelMessageFilter::OnMessageProcessed, filter_)); - } -} - -void GpuChannel::ScheduleHandleMessage() { - task_runner_->PostTask(FROM_HERE, base::Bind(&GpuChannel::HandleMessage, - weak_factory_.GetWeakPtr())); -} - -void GpuChannel::HandleOutOfOrderMessage(const IPC::Message& msg) { - switch (msg.type()) { - case GpuCommandBufferMsg_WaitForGetOffsetInRange::ID: - case GpuCommandBufferMsg_WaitForTokenInRange::ID: - router_.RouteMessage(msg); - break; - default: - NOTREACHED(); - } -} - -#if defined(OS_ANDROID) -const GpuCommandBufferStub* GpuChannel::GetOneStub() const { - for (const auto& kv : stubs_) { - const GpuCommandBufferStub* stub = kv.second; - if (stub->decoder() && !stub->decoder()->WasContextLost()) - return stub; - } - return nullptr; -} -#endif - -void GpuChannel::OnCreateOffscreenCommandBuffer( - const gfx::Size& size, - const GPUCreateCommandBufferConfig& init_params, - int32_t route_id, - bool* succeeded) { - TRACE_EVENT1("gpu", "GpuChannel::OnCreateOffscreenCommandBuffer", "route_id", - route_id); - - int32_t share_group_id = init_params.share_group_id; - GpuCommandBufferStub* share_group = stubs_.get(share_group_id); - - if (!share_group && share_group_id != MSG_ROUTING_NONE) { - *succeeded = false; - return; - } - - int32_t stream_id = init_params.stream_id; - GpuStreamPriority stream_priority = init_params.stream_priority; - - if (share_group && stream_id != share_group->stream_id()) { - *succeeded = false; - return; - } - - if (!allow_real_time_streams_ && - stream_priority == GpuStreamPriority::REAL_TIME) { - *succeeded = false; - return; - } - - auto stream_it = streams_.find(stream_id); - if (stream_it != streams_.end() && - stream_priority != GpuStreamPriority::INHERIT && - stream_priority != stream_it->second.priority()) { - *succeeded = false; - return; - } - - bool offscreen = true; - scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub( - this, sync_point_manager_, task_runner_.get(), share_group, - gfx::GLSurfaceHandle(), mailbox_manager_.get(), preempted_flag_.get(), - subscription_ref_set_.get(), pending_valuebuffer_state_.get(), size, - disallowed_features_, init_params.attribs, init_params.gpu_preference, - init_params.stream_id, route_id, offscreen, watchdog_, - init_params.active_url)); - - if (!router_.AddRoute(route_id, stub.get())) { - DLOG(ERROR) << "GpuChannel::OnCreateOffscreenCommandBuffer(): " - "failed to add route"; - *succeeded = false; - return; - } - - if (stream_it != streams_.end()) { - stream_it->second.AddRoute(route_id); - } else { - StreamState stream(stream_id, stream_priority); - stream.AddRoute(route_id); - streams_.insert(std::make_pair(stream_id, stream)); - } - - stubs_.set(route_id, std::move(stub)); - *succeeded = true; -} - -void GpuChannel::OnDestroyCommandBuffer(int32_t route_id) { - TRACE_EVENT1("gpu", "GpuChannel::OnDestroyCommandBuffer", - "route_id", route_id); - - scoped_ptr<GpuCommandBufferStub> stub = stubs_.take_and_erase(route_id); - - if (!stub) - return; - - router_.RemoveRoute(route_id); - - int32_t stream_id = stub->stream_id(); - auto stream_it = streams_.find(stream_id); - DCHECK(stream_it != streams_.end()); - stream_it->second.RemoveRoute(route_id); - if (!stream_it->second.HasRoutes()) - streams_.erase(stream_it); - - // In case the renderer is currently blocked waiting for a sync reply from the - // stub, we need to make sure to reschedule the GpuChannel here. - if (!stub->IsScheduled()) { - // This stub won't get a chance to reschedule, so update the count now. - OnStubSchedulingChanged(stub.get(), true); - } -} - -void GpuChannel::OnCreateJpegDecoder(int32_t route_id, - IPC::Message* reply_msg) { - if (!jpeg_decoder_) { - jpeg_decoder_.reset(new GpuJpegDecodeAccelerator(this, io_task_runner_)); - } - jpeg_decoder_->AddClient(route_id, reply_msg); -} - -void GpuChannel::CacheShader(const std::string& key, - const std::string& shader) { - gpu_channel_manager_->Send( - new GpuHostMsg_CacheShader(client_id_, key, shader)); -} - -void GpuChannel::AddFilter(IPC::MessageFilter* filter) { - io_task_runner_->PostTask( - FROM_HERE, base::Bind(&GpuChannelMessageFilter::AddChannelFilter, - filter_, make_scoped_refptr(filter))); -} - -void GpuChannel::RemoveFilter(IPC::MessageFilter* filter) { - io_task_runner_->PostTask( - FROM_HERE, base::Bind(&GpuChannelMessageFilter::RemoveChannelFilter, - filter_, make_scoped_refptr(filter))); -} - -uint64_t GpuChannel::GetMemoryUsage() { - // Collect the unique memory trackers in use by the |stubs_|. - std::set<gpu::gles2::MemoryTracker*> unique_memory_trackers; - for (auto& kv : stubs_) - unique_memory_trackers.insert(kv.second->GetMemoryTracker()); - - // Sum the memory usage for all unique memory trackers. - uint64_t size = 0; - for (auto* tracker : unique_memory_trackers) { - size += gpu_channel_manager()->gpu_memory_manager()->GetTrackerMemoryUsage( - tracker); - } - - return size; -} - -scoped_refptr<gl::GLImage> GpuChannel::CreateImageForGpuMemoryBuffer( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - uint32_t internalformat) { - switch (handle.type) { - case gfx::SHARED_MEMORY_BUFFER: { - if (!base::IsValueInRangeForNumericType<size_t>(handle.stride)) - return nullptr; - scoped_refptr<gl::GLImageSharedMemory> image( - new gl::GLImageSharedMemory(size, internalformat)); - if (!image->Initialize(handle.handle, handle.id, format, handle.offset, - handle.stride)) { - return nullptr; - } - - return image; - } - default: { - GpuChannelManager* manager = gpu_channel_manager(); - if (!manager->gpu_memory_buffer_factory()) - return nullptr; - - return manager->gpu_memory_buffer_factory() - ->AsImageFactory() - ->CreateImageForGpuMemoryBuffer(handle, - size, - format, - internalformat, - client_id_); - } - } -} - -void GpuChannel::HandleUpdateValueState( - unsigned int target, const gpu::ValueState& state) { - pending_valuebuffer_state_->UpdateState(target, state); -} - -} // namespace content diff --git a/chromium/content/common/gpu/gpu_channel.h b/chromium/content/common/gpu/gpu_channel.h deleted file mode 100644 index 319f81d40ed..00000000000 --- a/chromium/content/common/gpu/gpu_channel.h +++ /dev/null @@ -1,485 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_GPU_GPU_CHANNEL_H_ -#define CONTENT_COMMON_GPU_GPU_CHANNEL_H_ - -#include <stddef.h> -#include <stdint.h> - -#include <string> - -#include "base/containers/hash_tables.h" -#include "base/containers/scoped_ptr_hash_map.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "base/process/process.h" -#include "base/trace_event/memory_dump_provider.h" -#include "build/build_config.h" -#include "content/common/content_export.h" -#include "content/common/gpu/gpu_command_buffer_stub.h" -#include "content/common/gpu/gpu_memory_manager.h" -#include "content/common/gpu/gpu_result_codes.h" -#include "content/common/gpu/gpu_stream_priority.h" -#include "content/common/message_router.h" -#include "gpu/command_buffer/service/valuebuffer_manager.h" -#include "ipc/ipc_sync_channel.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gl/gl_share_group.h" -#include "ui/gl/gpu_preference.h" - -struct GPUCreateCommandBufferConfig; - -namespace base { -class WaitableEvent; -} - -namespace gpu { -class PreemptionFlag; -class SyncPointOrderData; -class SyncPointManager; -union ValueState; -class ValueStateMap; -namespace gles2 { -class SubscriptionRefSet; -} -} - -namespace IPC { -class MessageFilter; -} - -namespace content { -class GpuChannelManager; -class GpuChannelMessageFilter; -class GpuChannelMessageQueue; -class GpuJpegDecodeAccelerator; -class GpuWatchdog; - -// Encapsulates an IPC channel between the GPU process and one renderer -// process. On the renderer side there's a corresponding GpuChannelHost. -class CONTENT_EXPORT GpuChannel - : public IPC::Listener, - public IPC::Sender, - public gpu::gles2::SubscriptionRefSet::Observer { - public: - // Takes ownership of the renderer process handle. - GpuChannel(GpuChannelManager* gpu_channel_manager, - gpu::SyncPointManager* sync_point_manager, - GpuWatchdog* watchdog, - gfx::GLShareGroup* share_group, - gpu::gles2::MailboxManager* mailbox_manager, - gpu::PreemptionFlag* preempting_flag, - base::SingleThreadTaskRunner* task_runner, - base::SingleThreadTaskRunner* io_task_runner, - int client_id, - uint64_t client_tracing_id, - bool allow_future_sync_points, - bool allow_real_time_streams); - ~GpuChannel() override; - - // Initializes the IPC channel. Caller takes ownership of the client FD in - // the returned handle and is responsible for closing it. - virtual IPC::ChannelHandle Init(base::WaitableEvent* shutdown_event); - - // Get the GpuChannelManager that owns this channel. - GpuChannelManager* gpu_channel_manager() const { - return gpu_channel_manager_; - } - - const std::string& channel_id() const { return channel_id_; } - - virtual base::ProcessId GetClientPID() const; - - int client_id() const { return client_id_; } - - uint64_t client_tracing_id() const { return client_tracing_id_; } - - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner() const { - return io_task_runner_; - } - - // IPC::Listener implementation: - bool OnMessageReceived(const IPC::Message& msg) override; - void OnChannelError() override; - - // IPC::Sender implementation: - bool Send(IPC::Message* msg) override; - - // SubscriptionRefSet::Observer implementation - void OnAddSubscription(unsigned int target) override; - void OnRemoveSubscription(unsigned int target) override; - - // This is called when a command buffer transitions between scheduled and - // descheduled states. When any stub is descheduled, we stop preempting - // other channels. - void OnStubSchedulingChanged(GpuCommandBufferStub* stub, bool scheduled); - - CreateCommandBufferResult CreateViewCommandBuffer( - const gfx::GLSurfaceHandle& window, - const GPUCreateCommandBufferConfig& init_params, - int32_t route_id); - - gfx::GLShareGroup* share_group() const { return share_group_.get(); } - - GpuCommandBufferStub* LookupCommandBuffer(int32_t route_id); - - void LoseAllContexts(); - void MarkAllContextsLost(); - - // Called to add a listener for a particular message routing ID. - // Returns true if succeeded. - bool AddRoute(int32_t route_id, IPC::Listener* listener); - - // Called to remove a listener for a particular message routing ID. - void RemoveRoute(int32_t route_id); - - void SetPreemptingFlag(gpu::PreemptionFlag* flag); - - // If |preemption_flag->IsSet()|, any stub on this channel - // should stop issuing GL commands. Setting this to NULL stops deferral. - void SetPreemptByFlag( - scoped_refptr<gpu::PreemptionFlag> preemption_flag); - - void CacheShader(const std::string& key, const std::string& shader); - - void AddFilter(IPC::MessageFilter* filter); - void RemoveFilter(IPC::MessageFilter* filter); - - uint64_t GetMemoryUsage(); - - scoped_refptr<gl::GLImage> CreateImageForGpuMemoryBuffer( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - uint32_t internalformat); - - bool allow_future_sync_points() const { return allow_future_sync_points_; } - - void HandleUpdateValueState(unsigned int target, - const gpu::ValueState& state); - - // Visible for testing. - const gpu::ValueStateMap* pending_valuebuffer_state() const { - return pending_valuebuffer_state_.get(); - } - - // Visible for testing. - GpuChannelMessageFilter* filter() const { return filter_.get(); } - - // Returns the global order number for the last processed IPC message. - uint32_t GetProcessedOrderNum() const; - - // Returns the global order number for the last unprocessed IPC message. - uint32_t GetUnprocessedOrderNum() const; - - // Returns the shared sync point global order data. - scoped_refptr<gpu::SyncPointOrderData> GetSyncPointOrderData(); - - void HandleMessage(); - - // Some messages such as WaitForGetOffsetInRange and WaitForTokenInRange are - // processed as soon as possible because the client is blocked until they - // are completed. - void HandleOutOfOrderMessage(const IPC::Message& msg); - -#if defined(OS_ANDROID) - const GpuCommandBufferStub* GetOneStub() const; -#endif - - protected: - // The message filter on the io thread. - scoped_refptr<GpuChannelMessageFilter> filter_; - - // Map of routing id to command buffer stub. - base::ScopedPtrHashMap<int32_t, scoped_ptr<GpuCommandBufferStub>> stubs_; - - private: - class StreamState { - public: - StreamState(int32_t id, GpuStreamPriority priority); - ~StreamState(); - - int32_t id() const { return id_; } - GpuStreamPriority priority() const { return priority_; } - - void AddRoute(int32_t route_id); - void RemoveRoute(int32_t route_id); - bool HasRoute(int32_t route_id) const; - bool HasRoutes() const; - - private: - int32_t id_; - GpuStreamPriority priority_; - base::hash_set<int32_t> routes_; - }; - - void OnDestroy(); - - bool OnControlMessageReceived(const IPC::Message& msg); - - void ScheduleHandleMessage(); - - // Message handlers. - void OnCreateOffscreenCommandBuffer( - const gfx::Size& size, - const GPUCreateCommandBufferConfig& init_params, - int32_t route_id, - bool* succeeded); - void OnDestroyCommandBuffer(int32_t route_id); - void OnCreateJpegDecoder(int32_t route_id, IPC::Message* reply_msg); - - // The lifetime of objects of this class is managed by a GpuChannelManager. - // The GpuChannelManager destroy all the GpuChannels that they own when they - // are destroyed. So a raw pointer is safe. - GpuChannelManager* gpu_channel_manager_; - - // Sync point manager. Outlives the channel and is guaranteed to outlive the - // message loop. - gpu::SyncPointManager* sync_point_manager_; - - scoped_ptr<IPC::SyncChannel> channel_; - - // Uniquely identifies the channel within this GPU process. - std::string channel_id_; - - // Used to implement message routing functionality to CommandBuffer objects - MessageRouter router_; - - // Whether the processing of IPCs on this channel is stalled and we should - // preempt other GpuChannels. - scoped_refptr<gpu::PreemptionFlag> preempting_flag_; - - // If non-NULL, all stubs on this channel should stop processing GL - // commands (via their GpuScheduler) when preempted_flag_->IsSet() - scoped_refptr<gpu::PreemptionFlag> preempted_flag_; - - scoped_refptr<GpuChannelMessageQueue> message_queue_; - - // The id of the client who is on the other side of the channel. - int client_id_; - - // The tracing ID used for memory allocations associated with this client. - uint64_t client_tracing_id_; - - // The task runners for the main thread and the io thread. - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; - - // The share group that all contexts associated with a particular renderer - // process use. - scoped_refptr<gfx::GLShareGroup> share_group_; - - scoped_refptr<gpu::gles2::MailboxManager> mailbox_manager_; - - scoped_refptr<gpu::gles2::SubscriptionRefSet> subscription_ref_set_; - - scoped_refptr<gpu::ValueStateMap> pending_valuebuffer_state_; - - scoped_ptr<GpuJpegDecodeAccelerator> jpeg_decoder_; - - gpu::gles2::DisallowedFeatures disallowed_features_; - GpuWatchdog* watchdog_; - - size_t num_stubs_descheduled_; - - // Map of stream id to stream state. - base::hash_map<int32_t, StreamState> streams_; - - bool allow_future_sync_points_; - bool allow_real_time_streams_; - - // Member variables should appear before the WeakPtrFactory, to ensure - // that any WeakPtrs to Controller are invalidated before its members - // variable's destructors are executed, rendering them invalid. - base::WeakPtrFactory<GpuChannel> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(GpuChannel); -}; - -// This filter does three things: -// - it counts and timestamps each message forwarded to the channel -// so that we can preempt other channels if a message takes too long to -// process. To guarantee fairness, we must wait a minimum amount of time -// before preempting and we limit the amount of time that we can preempt in -// one shot (see constants above). -// - it handles the GpuCommandBufferMsg_InsertSyncPoint message on the IO -// thread, generating the sync point ID and responding immediately, and then -// posting a task to insert the GpuCommandBufferMsg_RetireSyncPoint message -// into the channel's queue. -// - it generates mailbox names for clients of the GPU process on the IO thread. -class GpuChannelMessageFilter : public IPC::MessageFilter { - public: - GpuChannelMessageFilter(const base::WeakPtr<GpuChannel>& gpu_channel, - GpuChannelMessageQueue* message_queue, - base::SingleThreadTaskRunner* task_runner, - gpu::PreemptionFlag* preempting_flag, - bool future_sync_points); - - // IPC::MessageFilter implementation. - void OnFilterAdded(IPC::Sender* sender) override; - void OnFilterRemoved() override; - void OnChannelConnected(int32_t peer_pid) override; - void OnChannelError() override; - void OnChannelClosing() override; - bool OnMessageReceived(const IPC::Message& message) override; - - void AddChannelFilter(scoped_refptr<IPC::MessageFilter> filter); - void RemoveChannelFilter(scoped_refptr<IPC::MessageFilter> filter); - - void OnMessageProcessed(); - - void UpdateStubSchedulingState(bool a_stub_is_descheduled); - - bool Send(IPC::Message* message); - - protected: - ~GpuChannelMessageFilter() override; - - private: - enum PreemptionState { - // Either there's no other channel to preempt, there are no messages - // pending processing, or we just finished preempting and have to wait - // before preempting again. - IDLE, - // We are waiting kPreemptWaitTimeMs before checking if we should preempt. - WAITING, - // We can preempt whenever any IPC processing takes more than - // kPreemptWaitTimeMs. - CHECKING, - // We are currently preempting (i.e. no stub is descheduled). - PREEMPTING, - // We would like to preempt, but some stub is descheduled. - WOULD_PREEMPT_DESCHEDULED, - }; - - void UpdatePreemptionState(); - - void TransitionToIdleIfCaughtUp(); - void TransitionToIdle(); - void TransitionToWaiting(); - void TransitionToChecking(); - void TransitionToPreempting(); - void TransitionToWouldPreemptDescheduled(); - - PreemptionState preemption_state_; - - // Maximum amount of time that we can spend in PREEMPTING. - // It is reset when we transition to IDLE. - base::TimeDelta max_preemption_time_; - - base::WeakPtr<GpuChannel> gpu_channel_; - // The message_queue_ is used to handle messages on the main thread. - scoped_refptr<GpuChannelMessageQueue> message_queue_; - IPC::Sender* sender_; - base::ProcessId peer_pid_; - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - scoped_refptr<gpu::PreemptionFlag> preempting_flag_; - std::vector<scoped_refptr<IPC::MessageFilter>> channel_filters_; - - // This timer is created and destroyed on the IO thread. - scoped_ptr<base::OneShotTimer> timer_; - - bool a_stub_is_descheduled_; - - // True if this channel can create future sync points. - bool future_sync_points_; -}; - -struct GpuChannelMessage { - uint32_t order_number; - base::TimeTicks time_received; - IPC::Message message; - - // TODO(dyen): Temporary sync point data, remove once new sync point lands. - bool retire_sync_point; - uint32_t sync_point; - - GpuChannelMessage(const IPC::Message& msg) - : order_number(0), - time_received(base::TimeTicks()), - message(msg), - retire_sync_point(false), - sync_point(0) {} - - private: - DISALLOW_COPY_AND_ASSIGN(GpuChannelMessage); -}; - -class GpuChannelMessageQueue - : public base::RefCountedThreadSafe<GpuChannelMessageQueue> { - public: - static scoped_refptr<GpuChannelMessageQueue> Create( - const base::WeakPtr<GpuChannel>& gpu_channel, - base::SingleThreadTaskRunner* task_runner, - gpu::SyncPointManager* sync_point_manager); - - scoped_refptr<gpu::SyncPointOrderData> GetSyncPointOrderData(); - - // Returns the global order number for the last unprocessed IPC message. - uint32_t GetUnprocessedOrderNum() const; - - // Returns the global order number for the last unprocessed IPC message. - uint32_t GetProcessedOrderNum() const; - - bool HasQueuedMessages() const; - - base::TimeTicks GetNextMessageTimeTick() const; - - GpuChannelMessage* GetNextMessage() const; - - // Should be called before a message begins to be processed. - void BeginMessageProcessing(const GpuChannelMessage* msg); - - // Should be called if a message began processing but did not finish. - void PauseMessageProcessing(const GpuChannelMessage* msg); - - // Should be called after a message returned by GetNextMessage is processed. - // Returns true if there are more messages on the queue. - bool MessageProcessed(); - - void PushBackMessage(const IPC::Message& message); - - bool GenerateSyncPointMessage(const IPC::Message& message, - bool retire_sync_point, - uint32_t* sync_point_number); - - void DeleteAndDisableMessages(); - - private: - friend class base::RefCountedThreadSafe<GpuChannelMessageQueue>; - - GpuChannelMessageQueue(const base::WeakPtr<GpuChannel>& gpu_channel, - base::SingleThreadTaskRunner* task_runner, - gpu::SyncPointManager* sync_point_manager); - ~GpuChannelMessageQueue(); - - void ScheduleHandleMessage(); - - void PushMessageHelper(scoped_ptr<GpuChannelMessage> msg); - - bool enabled_; - - // Both deques own the messages. - std::deque<GpuChannelMessage*> channel_messages_; - - // This lock protects enabled_ and channel_messages_. - mutable base::Lock channel_messages_lock_; - - // Keeps track of sync point related state such as message order numbers. - scoped_refptr<gpu::SyncPointOrderData> sync_point_order_data_; - - base::WeakPtr<GpuChannel> gpu_channel_; - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - gpu::SyncPointManager* sync_point_manager_; - - DISALLOW_COPY_AND_ASSIGN(GpuChannelMessageQueue); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_GPU_CHANNEL_H_ diff --git a/chromium/content/common/gpu/gpu_channel_manager.cc b/chromium/content/common/gpu/gpu_channel_manager.cc deleted file mode 100644 index 8f59e90345d..00000000000 --- a/chromium/content/common/gpu/gpu_channel_manager.cc +++ /dev/null @@ -1,380 +0,0 @@ -// Copyright (c) 2012 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 "content/common/gpu/gpu_channel_manager.h" - -#include <algorithm> -#include <utility> - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/location.h" -#include "base/single_thread_task_runner.h" -#include "base/thread_task_runner_handle.h" -#include "build/build_config.h" -#include "content/common/gpu/gpu_channel.h" -#include "content/common/gpu/gpu_memory_buffer_factory.h" -#include "content/common/gpu/gpu_memory_manager.h" -#include "content/common/gpu/gpu_messages.h" -#include "content/common/message_router.h" -#include "content/public/common/content_switches.h" -#include "gpu/command_buffer/common/value_state.h" -#include "gpu/command_buffer/service/feature_info.h" -#include "gpu/command_buffer/service/gpu_switches.h" -#include "gpu/command_buffer/service/mailbox_manager.h" -#include "gpu/command_buffer/service/memory_program_cache.h" -#include "gpu/command_buffer/service/shader_translator_cache.h" -#include "gpu/command_buffer/service/sync_point_manager.h" -#include "ipc/message_filter.h" -#include "ui/gl/gl_bindings.h" -#include "ui/gl/gl_share_group.h" - -#if defined(OS_CHROMEOS) -#include "content/common/gpu/media/gpu_arc_video_service.h" -#endif - -namespace content { - -namespace { -#if defined(OS_ANDROID) -// Amount of time we expect the GPU to stay powered up without being used. -const int kMaxGpuIdleTimeMs = 40; -// Maximum amount of time we keep pinging the GPU waiting for the client to -// draw. -const int kMaxKeepAliveTimeMs = 200; -#endif - -} - -GpuChannelManager::GpuChannelManager( - IPC::SyncChannel* channel, - GpuWatchdog* watchdog, - base::SingleThreadTaskRunner* task_runner, - base::SingleThreadTaskRunner* io_task_runner, - base::WaitableEvent* shutdown_event, - gpu::SyncPointManager* sync_point_manager, - GpuMemoryBufferFactory* gpu_memory_buffer_factory) - : task_runner_(task_runner), - io_task_runner_(io_task_runner), - channel_(channel), - watchdog_(watchdog), - shutdown_event_(shutdown_event), - share_group_(new gfx::GLShareGroup), - mailbox_manager_(gpu::gles2::MailboxManager::Create()), - gpu_memory_manager_(this), - sync_point_manager_(sync_point_manager), - sync_point_client_waiter_( - sync_point_manager->CreateSyncPointClientWaiter()), - gpu_memory_buffer_factory_(gpu_memory_buffer_factory), - weak_factory_(this) { - DCHECK(task_runner); - DCHECK(io_task_runner); - const base::CommandLine* command_line = - base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kUIPrioritizeInGpuProcess)) - preemption_flag_ = new gpu::PreemptionFlag; -} - -GpuChannelManager::~GpuChannelManager() { - // Destroy channels before anything else because of dependencies. - gpu_channels_.clear(); - if (default_offscreen_surface_.get()) { - default_offscreen_surface_->Destroy(); - default_offscreen_surface_ = NULL; - } -} - -gpu::gles2::ProgramCache* GpuChannelManager::program_cache() { - if (!program_cache_.get() && - (gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary || - gfx::g_driver_gl.ext.b_GL_OES_get_program_binary) && - !base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableGpuProgramCache)) { - program_cache_.reset(new gpu::gles2::MemoryProgramCache()); - } - return program_cache_.get(); -} - -gpu::gles2::ShaderTranslatorCache* -GpuChannelManager::shader_translator_cache() { - if (!shader_translator_cache_.get()) - shader_translator_cache_ = new gpu::gles2::ShaderTranslatorCache; - return shader_translator_cache_.get(); -} - -gpu::gles2::FramebufferCompletenessCache* -GpuChannelManager::framebuffer_completeness_cache() { - if (!framebuffer_completeness_cache_.get()) - framebuffer_completeness_cache_ = - new gpu::gles2::FramebufferCompletenessCache; - return framebuffer_completeness_cache_.get(); -} - -void GpuChannelManager::RemoveChannel(int client_id) { - Send(new GpuHostMsg_DestroyChannel(client_id)); - gpu_channels_.erase(client_id); -} - -int GpuChannelManager::GenerateRouteID() { - static int last_id = 0; - return ++last_id; -} - -void GpuChannelManager::AddRoute(int32_t routing_id, IPC::Listener* listener) { - router_.AddRoute(routing_id, listener); -} - -void GpuChannelManager::RemoveRoute(int32_t routing_id) { - router_.RemoveRoute(routing_id); -} - -GpuChannel* GpuChannelManager::LookupChannel(int32_t client_id) const { - const auto& it = gpu_channels_.find(client_id); - return it != gpu_channels_.end() ? it->second : nullptr; -} - -bool GpuChannelManager::OnControlMessageReceived(const IPC::Message& msg) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(GpuChannelManager, msg) - IPC_MESSAGE_HANDLER(GpuMsg_EstablishChannel, OnEstablishChannel) - IPC_MESSAGE_HANDLER(GpuMsg_CloseChannel, OnCloseChannel) - IPC_MESSAGE_HANDLER(GpuMsg_CreateViewCommandBuffer, - OnCreateViewCommandBuffer) - IPC_MESSAGE_HANDLER(GpuMsg_DestroyGpuMemoryBuffer, OnDestroyGpuMemoryBuffer) -#if defined(OS_CHROMEOS) - IPC_MESSAGE_HANDLER(GpuMsg_CreateArcVideoAcceleratorChannel, - OnCreateArcVideoAcceleratorChannel) -#endif - IPC_MESSAGE_HANDLER(GpuMsg_LoadedShader, OnLoadedShader) - IPC_MESSAGE_HANDLER(GpuMsg_UpdateValueState, OnUpdateValueState) -#if defined(OS_ANDROID) - IPC_MESSAGE_HANDLER(GpuMsg_WakeUpGpu, OnWakeUpGpu); -#endif - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -bool GpuChannelManager::OnMessageReceived(const IPC::Message& msg) { - if (msg.routing_id() == MSG_ROUTING_CONTROL) - return OnControlMessageReceived(msg); - - return router_.RouteMessage(msg); -} - -bool GpuChannelManager::Send(IPC::Message* msg) { - return channel_->Send(msg); -} - -scoped_ptr<GpuChannel> GpuChannelManager::CreateGpuChannel( - int client_id, - uint64_t client_tracing_id, - bool preempts, - bool allow_future_sync_points, - bool allow_real_time_streams) { - return make_scoped_ptr(new GpuChannel( - this, sync_point_manager(), watchdog_, share_group(), mailbox_manager(), - preempts ? preemption_flag() : nullptr, task_runner_.get(), - io_task_runner_.get(), client_id, client_tracing_id, - allow_future_sync_points, allow_real_time_streams)); -} - -void GpuChannelManager::OnEstablishChannel( - const GpuMsg_EstablishChannel_Params& params) { - DCHECK(!params.preempts || !params.preempted); - scoped_ptr<GpuChannel> channel(CreateGpuChannel( - params.client_id, params.client_tracing_id, params.preempts, - params.allow_future_sync_points, params.allow_real_time_streams)); - if (params.preempted) - channel->SetPreemptByFlag(preemption_flag_.get()); - IPC::ChannelHandle channel_handle = channel->Init(shutdown_event_); - - gpu_channels_.set(params.client_id, std::move(channel)); - - Send(new GpuHostMsg_ChannelEstablished(channel_handle)); -} - -void GpuChannelManager::OnCloseChannel( - const IPC::ChannelHandle& channel_handle) { - for (auto it = gpu_channels_.begin(); it != gpu_channels_.end(); ++it) { - if (it->second->channel_id() == channel_handle.name) { - gpu_channels_.erase(it); - return; - } - } -} - -void GpuChannelManager::OnCreateViewCommandBuffer( - const gfx::GLSurfaceHandle& window, - int32_t client_id, - const GPUCreateCommandBufferConfig& init_params, - int32_t route_id) { - CreateCommandBufferResult result = CREATE_COMMAND_BUFFER_FAILED; - - auto it = gpu_channels_.find(client_id); - if (it != gpu_channels_.end()) { - result = it->second->CreateViewCommandBuffer(window, init_params, route_id); - } - - Send(new GpuHostMsg_CommandBufferCreated(result)); -} - -void GpuChannelManager::DestroyGpuMemoryBuffer( - gfx::GpuMemoryBufferId id, - int client_id) { - io_task_runner_->PostTask( - FROM_HERE, base::Bind(&GpuChannelManager::DestroyGpuMemoryBufferOnIO, - base::Unretained(this), id, client_id)); -} - -void GpuChannelManager::DestroyGpuMemoryBufferOnIO( - gfx::GpuMemoryBufferId id, - int client_id) { - gpu_memory_buffer_factory_->DestroyGpuMemoryBuffer(id, client_id); -} - -void GpuChannelManager::OnDestroyGpuMemoryBuffer( - gfx::GpuMemoryBufferId id, - int client_id, - const gpu::SyncToken& sync_token) { - if (sync_token.HasData()) { - scoped_refptr<gpu::SyncPointClientState> release_state = - sync_point_manager()->GetSyncPointClientState( - sync_token.namespace_id(), sync_token.command_buffer_id()); - if (release_state) { - sync_point_client_waiter_->WaitOutOfOrder( - release_state.get(), sync_token.release_count(), - base::Bind(&GpuChannelManager::DestroyGpuMemoryBuffer, - base::Unretained(this), id, client_id)); - return; - } - } - - // No sync token or invalid sync token, destroy immediately. - DestroyGpuMemoryBuffer(id, client_id); -} - -#if defined(OS_CHROMEOS) -void GpuChannelManager::OnCreateArcVideoAcceleratorChannel() { - if (!gpu_arc_video_service_) { - gpu_arc_video_service_.reset( - new GpuArcVideoService(shutdown_event_, io_task_runner_)); - } - - gpu_arc_video_service_->CreateChannel( - base::Bind(&GpuChannelManager::ArcVideoAcceleratorChannelCreated, - weak_factory_.GetWeakPtr())); -} - -void GpuChannelManager::ArcVideoAcceleratorChannelCreated( - const IPC::ChannelHandle& handle) { - Send(new GpuHostMsg_ArcVideoAcceleratorChannelCreated(handle)); -} - -void GpuChannelManager::OnShutdownArcVideoService() { - gpu_arc_video_service_.reset(); -} -#endif - -void GpuChannelManager::OnUpdateValueState( - int client_id, unsigned int target, const gpu::ValueState& state) { - // Only pass updated state to the channel corresponding to the - // render_widget_host where the event originated. - auto it = gpu_channels_.find(client_id); - if (it != gpu_channels_.end()) - it->second->HandleUpdateValueState(target, state); -} - -void GpuChannelManager::OnLoadedShader(const std::string& program_proto) { - if (program_cache()) - program_cache()->LoadProgram(program_proto); -} - -uint32_t GpuChannelManager::GetUnprocessedOrderNum() const { - uint32_t unprocessed_order_num = 0; - for (auto& kv : gpu_channels_) { - unprocessed_order_num = - std::max(unprocessed_order_num, kv.second->GetUnprocessedOrderNum()); - } - return unprocessed_order_num; -} - -uint32_t GpuChannelManager::GetProcessedOrderNum() const { - uint32_t processed_order_num = 0; - for (auto& kv : gpu_channels_) { - processed_order_num = - std::max(processed_order_num, kv.second->GetProcessedOrderNum()); - } - return processed_order_num; -} - -void GpuChannelManager::LoseAllContexts() { - for (auto& kv : gpu_channels_) { - kv.second->MarkAllContextsLost(); - } - task_runner_->PostTask(FROM_HERE, - base::Bind(&GpuChannelManager::OnLoseAllContexts, - weak_factory_.GetWeakPtr())); -} - -void GpuChannelManager::OnLoseAllContexts() { - gpu_channels_.clear(); -} - -gfx::GLSurface* GpuChannelManager::GetDefaultOffscreenSurface() { - if (!default_offscreen_surface_.get()) { - default_offscreen_surface_ = - gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size()); - } - return default_offscreen_surface_.get(); -} - -#if defined(OS_ANDROID) -void GpuChannelManager::DidAccessGpu() { - last_gpu_access_time_ = base::TimeTicks::Now(); -} - -void GpuChannelManager::OnWakeUpGpu() { - begin_wake_up_time_ = base::TimeTicks::Now(); - ScheduleWakeUpGpu(); -} - -void GpuChannelManager::ScheduleWakeUpGpu() { - base::TimeTicks now = base::TimeTicks::Now(); - TRACE_EVENT2("gpu", "GpuChannelManager::ScheduleWakeUp", - "idle_time", (now - last_gpu_access_time_).InMilliseconds(), - "keep_awake_time", (now - begin_wake_up_time_).InMilliseconds()); - if (now - last_gpu_access_time_ < - base::TimeDelta::FromMilliseconds(kMaxGpuIdleTimeMs)) - return; - if (now - begin_wake_up_time_ > - base::TimeDelta::FromMilliseconds(kMaxKeepAliveTimeMs)) - return; - - DoWakeUpGpu(); - - base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, base::Bind(&GpuChannelManager::ScheduleWakeUpGpu, - weak_factory_.GetWeakPtr()), - base::TimeDelta::FromMilliseconds(kMaxGpuIdleTimeMs)); -} - -void GpuChannelManager::DoWakeUpGpu() { - const GpuCommandBufferStub* stub = nullptr; - for (const auto& kv : gpu_channels_) { - const GpuChannel* channel = kv.second; - stub = channel->GetOneStub(); - if (stub) { - DCHECK(stub->decoder()); - break; - } - } - if (!stub || !stub->decoder()->MakeCurrent()) - return; - glFinish(); - DidAccessGpu(); -} -#endif - -} // namespace content diff --git a/chromium/content/common/gpu/gpu_channel_manager.h b/chromium/content/common/gpu/gpu_channel_manager.h deleted file mode 100644 index f195a55c27e..00000000000 --- a/chromium/content/common/gpu/gpu_channel_manager.h +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_GPU_GPU_CHANNEL_MANAGER_H_ -#define CONTENT_COMMON_GPU_GPU_CHANNEL_MANAGER_H_ - -#include <stdint.h> - -#include <deque> -#include <string> -#include <vector> - -#include "base/containers/scoped_ptr_hash_map.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "build/build_config.h" -#include "content/common/content_export.h" -#include "content/common/content_param_traits.h" -#include "content/common/gpu/gpu_memory_manager.h" -#include "content/common/message_router.h" -#include "ipc/ipc_listener.h" -#include "ipc/ipc_sender.h" -#include "ui/gfx/gpu_memory_buffer.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gl/gl_surface.h" - -namespace base { -class WaitableEvent; -} - -namespace gfx { -class GLShareGroup; -} - -namespace gpu { -class PreemptionFlag; -class SyncPointClient; -class SyncPointManager; -struct SyncToken; -union ValueState; -namespace gles2 { -class FramebufferCompletenessCache; -class MailboxManager; -class ProgramCache; -class ShaderTranslatorCache; -} -} - -namespace IPC { -struct ChannelHandle; -class SyncChannel; -} - -struct GPUCreateCommandBufferConfig; -struct GpuMsg_EstablishChannel_Params; - -namespace content { -#if defined(OS_CHROMEOS) -class GpuArcVideoService; -#endif -class GpuChannel; -class GpuMemoryBufferFactory; -class GpuWatchdog; - -// A GpuChannelManager is a thread responsible for issuing rendering commands -// managing the lifetimes of GPU channels and forwarding IPC requests from the -// browser process to them based on the corresponding renderer ID. -class CONTENT_EXPORT GpuChannelManager : public IPC::Listener, - public IPC::Sender { - public: - GpuChannelManager(IPC::SyncChannel* channel, - GpuWatchdog* watchdog, - base::SingleThreadTaskRunner* task_runner, - base::SingleThreadTaskRunner* io_task_runner, - base::WaitableEvent* shutdown_event, - gpu::SyncPointManager* sync_point_manager, - GpuMemoryBufferFactory* gpu_memory_buffer_factory); - ~GpuChannelManager() override; - - // Remove the channel for a particular renderer. - void RemoveChannel(int client_id); - - // Listener overrides. - bool OnMessageReceived(const IPC::Message& msg) override; - - // Sender overrides. - bool Send(IPC::Message* msg) override; - - void LoseAllContexts(); - - int GenerateRouteID(); - void AddRoute(int32_t routing_id, IPC::Listener* listener); - void RemoveRoute(int32_t routing_id); - - gpu::gles2::ProgramCache* program_cache(); - gpu::gles2::ShaderTranslatorCache* shader_translator_cache(); - gpu::gles2::FramebufferCompletenessCache* framebuffer_completeness_cache(); - - GpuMemoryManager* gpu_memory_manager() { return &gpu_memory_manager_; } - - GpuChannel* LookupChannel(int32_t client_id) const; - - gfx::GLSurface* GetDefaultOffscreenSurface(); - - GpuMemoryBufferFactory* gpu_memory_buffer_factory() { - return gpu_memory_buffer_factory_; - } - - // Returns the maximum order number for unprocessed IPC messages across all - // channels. - uint32_t GetUnprocessedOrderNum() const; - - // Returns the maximum order number for processed IPC messages across all - // channels. - uint32_t GetProcessedOrderNum() const; - -#if defined(OS_ANDROID) - void DidAccessGpu(); -#endif - - protected: - virtual scoped_ptr<GpuChannel> CreateGpuChannel(int client_id, - uint64_t client_tracing_id, - bool preempts, - bool allow_future_sync_points, - bool allow_real_time_streams); - - gpu::SyncPointManager* sync_point_manager() const { - return sync_point_manager_; - } - - gfx::GLShareGroup* share_group() const { return share_group_.get(); } - gpu::gles2::MailboxManager* mailbox_manager() const { - return mailbox_manager_.get(); - } - gpu::PreemptionFlag* preemption_flag() const { - return preemption_flag_.get(); - } - - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; - - // These objects manage channels to individual renderer processes there is - // one channel for each renderer process that has connected to this GPU - // process. - base::ScopedPtrHashMap<int32_t, scoped_ptr<GpuChannel>> gpu_channels_; - - private: - // Message handlers. - bool OnControlMessageReceived(const IPC::Message& msg); - void OnEstablishChannel(const GpuMsg_EstablishChannel_Params& params); - void OnCloseChannel(const IPC::ChannelHandle& channel_handle); - void OnVisibilityChanged(int32_t render_view_id, - int32_t client_id, - bool visible); - void OnCreateViewCommandBuffer( - const gfx::GLSurfaceHandle& window, - int32_t client_id, - const GPUCreateCommandBufferConfig& init_params, - int32_t route_id); - void OnLoadedShader(const std::string& shader); - void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, int client_id); - void DestroyGpuMemoryBufferOnIO(gfx::GpuMemoryBufferId id, int client_id); - void OnDestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, - int client_id, - const gpu::SyncToken& sync_token); -#if defined(OS_CHROMEOS) - void OnCreateArcVideoAcceleratorChannel(); - void ArcVideoAcceleratorChannelCreated(const IPC::ChannelHandle& handle); - void OnShutdownArcVideoService(); -#endif - - void OnUpdateValueState(int client_id, - unsigned int target, - const gpu::ValueState& state); -#if defined(OS_ANDROID) - void OnWakeUpGpu(); - void ScheduleWakeUpGpu(); - void DoWakeUpGpu(); -#endif - void OnLoseAllContexts(); - - // Used to send and receive IPC messages from the browser process. - IPC::SyncChannel* const channel_; - MessageRouter router_; - - GpuWatchdog* watchdog_; - - base::WaitableEvent* shutdown_event_; - - scoped_refptr<gfx::GLShareGroup> share_group_; - scoped_refptr<gpu::gles2::MailboxManager> mailbox_manager_; - scoped_refptr<gpu::PreemptionFlag> preemption_flag_; - GpuMemoryManager gpu_memory_manager_; - // SyncPointManager guaranteed to outlive running MessageLoop. - gpu::SyncPointManager* sync_point_manager_; - scoped_ptr<gpu::SyncPointClient> sync_point_client_waiter_; - scoped_ptr<gpu::gles2::ProgramCache> program_cache_; - scoped_refptr<gpu::gles2::ShaderTranslatorCache> shader_translator_cache_; - scoped_refptr<gpu::gles2::FramebufferCompletenessCache> - framebuffer_completeness_cache_; - scoped_refptr<gfx::GLSurface> default_offscreen_surface_; -#if defined(OS_CHROMEOS) - scoped_ptr<GpuArcVideoService> gpu_arc_video_service_; -#endif - GpuMemoryBufferFactory* const gpu_memory_buffer_factory_; -#if defined(OS_ANDROID) - // Last time we know the GPU was powered on. Global for tracking across all - // transport surfaces. - base::TimeTicks last_gpu_access_time_; - base::TimeTicks begin_wake_up_time_; -#endif - - // Member variables should appear before the WeakPtrFactory, to ensure - // that any WeakPtrs to Controller are invalidated before its members - // variable's destructors are executed, rendering them invalid. - base::WeakPtrFactory<GpuChannelManager> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(GpuChannelManager); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_GPU_CHANNEL_MANAGER_H_ diff --git a/chromium/content/common/gpu/gpu_channel_manager_unittest.cc b/chromium/content/common/gpu/gpu_channel_manager_unittest.cc deleted file mode 100644 index bef694808e8..00000000000 --- a/chromium/content/common/gpu/gpu_channel_manager_unittest.cc +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2014 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 <stddef.h> -#include <stdint.h> - -#include "content/common/gpu/gpu_channel.h" -#include "content/common/gpu/gpu_channel_manager.h" -#include "content/common/gpu/gpu_channel_test_common.h" -#include "content/common/gpu/gpu_messages.h" -#include "gpu/command_buffer/common/value_state.h" -#include "gpu/command_buffer/service/gl_utils.h" -#include "gpu/command_buffer/service/valuebuffer_manager.h" -#include "ipc/ipc_test_sink.h" - -using gpu::gles2::ValuebufferManager; -using gpu::ValueState; - -namespace content { - -class GpuChannelManagerTest : public GpuChannelTestCommon { - public: - GpuChannelManagerTest() : GpuChannelTestCommon() {} - ~GpuChannelManagerTest() override {} -}; - -TEST_F(GpuChannelManagerTest, EstablishChannel) { - int32_t kClientId = 1; - uint64_t kClientTracingId = 1; - - ASSERT_TRUE(channel_manager()); - - GpuMsg_EstablishChannel_Params params; - params.client_id = kClientId; - params.client_tracing_id = kClientTracingId; - params.preempts = false; - params.preempted = false; - params.allow_future_sync_points = false; - params.allow_real_time_streams = false; - EXPECT_TRUE( - channel_manager()->OnMessageReceived(GpuMsg_EstablishChannel(params))); - EXPECT_EQ((size_t)1, sink()->message_count()); - const IPC::Message* msg = - sink()->GetUniqueMessageMatching(GpuHostMsg_ChannelEstablished::ID); - ASSERT_TRUE(msg); - base::Tuple<IPC::ChannelHandle> handle; - ASSERT_TRUE(GpuHostMsg_ChannelEstablished::Read(msg, &handle)); - EXPECT_NE("", base::get<0>(handle).name); - sink()->ClearMessages(); - - GpuChannel* channel = channel_manager()->LookupChannel(kClientId); - ASSERT_TRUE(channel); - EXPECT_EQ(base::get<0>(handle).name, channel->channel_id()); -} - -TEST_F(GpuChannelManagerTest, SecureValueStateForwarding) { - int32_t kClientId1 = 111; - uint64_t kClientTracingId1 = 11111; - int32_t kClientId2 = 222; - uint64_t kClientTracingId2 = 22222; - ValueState value_state1; - value_state1.int_value[0] = 1111; - value_state1.int_value[1] = 0; - value_state1.int_value[2] = 0; - value_state1.int_value[3] = 0; - ValueState value_state2; - value_state2.int_value[0] = 3333; - value_state2.int_value[1] = 0; - value_state2.int_value[2] = 0; - value_state2.int_value[3] = 0; - - ASSERT_TRUE(channel_manager()); - - // Initialize gpu channels - GpuMsg_EstablishChannel_Params params; - params.client_id = kClientId1; - params.client_tracing_id = kClientTracingId1; - params.preempts = false; - params.preempted = false; - params.allow_future_sync_points = false; - params.allow_real_time_streams = false; - EXPECT_TRUE( - channel_manager()->OnMessageReceived(GpuMsg_EstablishChannel(params))); - GpuChannel* channel1 = channel_manager()->LookupChannel(kClientId1); - ASSERT_TRUE(channel1); - - params.client_id = kClientId2; - params.client_tracing_id = kClientTracingId2; - EXPECT_TRUE( - channel_manager()->OnMessageReceived(GpuMsg_EstablishChannel(params))); - GpuChannel* channel2 = channel_manager()->LookupChannel(kClientId2); - ASSERT_TRUE(channel2); - - EXPECT_NE(channel1, channel2); - - // Make sure value states are only accessible by proper channels - channel_manager()->OnMessageReceived(GpuMsg_UpdateValueState( - kClientId1, GL_MOUSE_POSITION_CHROMIUM, value_state1)); - channel_manager()->OnMessageReceived(GpuMsg_UpdateValueState( - kClientId2, GL_MOUSE_POSITION_CHROMIUM, value_state2)); - - const gpu::ValueStateMap* pending_value_buffer_state1 = - channel1->pending_valuebuffer_state(); - const gpu::ValueStateMap* pending_value_buffer_state2 = - channel2->pending_valuebuffer_state(); - EXPECT_NE(pending_value_buffer_state1, pending_value_buffer_state2); - - const ValueState* state1 = - pending_value_buffer_state1->GetState(GL_MOUSE_POSITION_CHROMIUM); - const ValueState* state2 = - pending_value_buffer_state2->GetState(GL_MOUSE_POSITION_CHROMIUM); - EXPECT_NE(state1, state2); - - EXPECT_EQ(state1->int_value[0], value_state1.int_value[0]); - EXPECT_EQ(state2->int_value[0], value_state2.int_value[0]); - EXPECT_NE(state1->int_value[0], state2->int_value[0]); -} - -} // namespace content diff --git a/chromium/content/common/gpu/gpu_channel_test_common.cc b/chromium/content/common/gpu/gpu_channel_test_common.cc deleted file mode 100644 index 7fe03759fc9..00000000000 --- a/chromium/content/common/gpu/gpu_channel_test_common.cc +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2015 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 "content/common/gpu/gpu_channel_test_common.h" - -#include "base/test/test_simple_task_runner.h" -#include "base/thread_task_runner_handle.h" -#include "gpu/command_buffer/service/sync_point_manager.h" -#include "ipc/ipc_test_sink.h" - -namespace content { - -TestGpuChannelManager::TestGpuChannelManager( - IPC::TestSink* sink, - base::SingleThreadTaskRunner* task_runner, - base::SingleThreadTaskRunner* io_task_runner, - gpu::SyncPointManager* sync_point_manager, - GpuMemoryBufferFactory* gpu_memory_buffer_factory) - : GpuChannelManager(nullptr, - nullptr, - task_runner, - io_task_runner, - nullptr, - sync_point_manager, - gpu_memory_buffer_factory), - sink_(sink) {} - -TestGpuChannelManager::~TestGpuChannelManager() { - // Clear gpu channels here so that any IPC messages sent are handled using the - // overridden Send method. - gpu_channels_.clear(); -} - -bool TestGpuChannelManager::Send(IPC::Message* msg) { - return sink_->Send(msg); -} - -scoped_ptr<GpuChannel> TestGpuChannelManager::CreateGpuChannel( - int client_id, - uint64_t client_tracing_id, - bool preempts, - bool allow_future_sync_points, - bool allow_real_time_streams) { - return make_scoped_ptr(new TestGpuChannel( - sink_, this, sync_point_manager(), share_group(), mailbox_manager(), - preempts ? preemption_flag() : nullptr, task_runner_.get(), - io_task_runner_.get(), client_id, client_tracing_id, - allow_future_sync_points, allow_real_time_streams)); -} - -TestGpuChannel::TestGpuChannel(IPC::TestSink* sink, - GpuChannelManager* gpu_channel_manager, - gpu::SyncPointManager* sync_point_manager, - gfx::GLShareGroup* share_group, - gpu::gles2::MailboxManager* mailbox_manager, - gpu::PreemptionFlag* preempting_flag, - base::SingleThreadTaskRunner* task_runner, - base::SingleThreadTaskRunner* io_task_runner, - int client_id, - uint64_t client_tracing_id, - bool allow_future_sync_points, - bool allow_real_time_streams) - : GpuChannel(gpu_channel_manager, - sync_point_manager, - nullptr, - share_group, - mailbox_manager, - preempting_flag, - task_runner, - io_task_runner, - client_id, - client_tracing_id, - allow_future_sync_points, - allow_real_time_streams), - sink_(sink) {} - -TestGpuChannel::~TestGpuChannel() { - // Call stubs here so that any IPC messages sent are handled using the - // overridden Send method. - stubs_.clear(); -} - -base::ProcessId TestGpuChannel::GetClientPID() const { - return base::kNullProcessId; -} - -IPC::ChannelHandle TestGpuChannel::Init(base::WaitableEvent* shutdown_event) { - filter_->OnFilterAdded(sink_); - return IPC::ChannelHandle(channel_id()); -} - -bool TestGpuChannel::Send(IPC::Message* msg) { - DCHECK(!msg->is_sync()); - return sink_->Send(msg); -} - -// TODO(sunnyps): Use a mock memory buffer factory when necessary. -GpuChannelTestCommon::GpuChannelTestCommon() - : sink_(new IPC::TestSink), - task_runner_(new base::TestSimpleTaskRunner), - io_task_runner_(new base::TestSimpleTaskRunner), - sync_point_manager_(new gpu::SyncPointManager(false)), - channel_manager_(new TestGpuChannelManager(sink_.get(), - task_runner_.get(), - io_task_runner_.get(), - sync_point_manager_.get(), - nullptr)) {} - -GpuChannelTestCommon::~GpuChannelTestCommon() {} - -} // namespace content diff --git a/chromium/content/common/gpu/gpu_channel_test_common.h b/chromium/content/common/gpu/gpu_channel_test_common.h deleted file mode 100644 index ed2243531dd..00000000000 --- a/chromium/content/common/gpu/gpu_channel_test_common.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2015 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 <stdint.h> - -#include "base/memory/scoped_ptr.h" -#include "content/common/gpu/gpu_channel.h" -#include "content/common/gpu/gpu_channel_manager.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -class TestSimpleTaskRunner; -} // namespace base - -namespace IPC { -class TestSink; -} // namespace IPC - -namespace content { - -class SyncPointManager; - -class TestGpuChannelManager : public GpuChannelManager { - public: - TestGpuChannelManager(IPC::TestSink* sink, - base::SingleThreadTaskRunner* task_runner, - base::SingleThreadTaskRunner* io_task_runner, - gpu::SyncPointManager* sync_point_manager, - GpuMemoryBufferFactory* gpu_memory_buffer_factory); - ~TestGpuChannelManager() override; - - // IPC::Sender implementation. - bool Send(IPC::Message* msg) override; - - protected: - scoped_ptr<GpuChannel> CreateGpuChannel( - int client_id, - uint64_t client_tracing_id, - bool preempts, - bool allow_future_sync_points, - bool allow_real_time_streams) override; - - private: - IPC::TestSink* const sink_; -}; - -class TestGpuChannel : public GpuChannel { - public: - TestGpuChannel(IPC::TestSink* sink, - GpuChannelManager* gpu_channel_manager, - gpu::SyncPointManager* sync_point_manager, - gfx::GLShareGroup* share_group, - gpu::gles2::MailboxManager* mailbox_manager, - gpu::PreemptionFlag* preempting_flag, - base::SingleThreadTaskRunner* task_runner, - base::SingleThreadTaskRunner* io_task_runner, - int client_id, - uint64_t client_tracing_id, - bool allow_future_sync_points, - bool allow_real_time_streams); - ~TestGpuChannel() override; - - base::ProcessId GetClientPID() const override; - - IPC::ChannelHandle Init(base::WaitableEvent* shutdown_event) override; - - // IPC::Sender implementation. - bool Send(IPC::Message* msg) override; - - private: - IPC::TestSink* const sink_; -}; - -class GpuChannelTestCommon : public testing::Test { - public: - GpuChannelTestCommon(); - ~GpuChannelTestCommon() override; - - protected: - IPC::TestSink* sink() { return sink_.get(); } - GpuChannelManager* channel_manager() { return channel_manager_.get(); } - base::TestSimpleTaskRunner* task_runner() { return task_runner_.get(); } - - private: - scoped_ptr<IPC::TestSink> sink_; - scoped_refptr<base::TestSimpleTaskRunner> task_runner_; - scoped_refptr<base::TestSimpleTaskRunner> io_task_runner_; - scoped_ptr<gpu::SyncPointManager> sync_point_manager_; - scoped_ptr<GpuChannelManager> channel_manager_; -}; - -} // namespace content diff --git a/chromium/content/common/gpu/gpu_channel_unittest.cc b/chromium/content/common/gpu/gpu_channel_unittest.cc deleted file mode 100644 index d7a376aef76..00000000000 --- a/chromium/content/common/gpu/gpu_channel_unittest.cc +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright (c) 2015 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 <stdint.h> - -#include "base/test/test_simple_task_runner.h" -#include "content/common/gpu/gpu_channel.h" -#include "content/common/gpu/gpu_channel_manager.h" -#include "content/common/gpu/gpu_channel_test_common.h" -#include "content/common/gpu/gpu_messages.h" -#include "ipc/ipc_test_sink.h" - -namespace content { - -class GpuChannelTest : public GpuChannelTestCommon { - public: - GpuChannelTest() : GpuChannelTestCommon() {} - ~GpuChannelTest() override {} - - GpuChannel* CreateChannel(int32_t client_id, bool allow_real_time_streams) { - DCHECK(channel_manager()); - uint64_t kClientTracingId = 1; - GpuMsg_EstablishChannel_Params params; - params.client_id = client_id; - params.client_tracing_id = kClientTracingId; - params.preempts = false; - params.preempted = false; - params.allow_future_sync_points = false; - params.allow_real_time_streams = allow_real_time_streams; - EXPECT_TRUE( - channel_manager()->OnMessageReceived(GpuMsg_EstablishChannel(params))); - return channel_manager()->LookupChannel(client_id); - } -}; - -TEST_F(GpuChannelTest, CreateViewCommandBuffer) { - int32_t kClientId = 1; - GpuChannel* channel = CreateChannel(kClientId, false); - ASSERT_TRUE(channel); - - gfx::GLSurfaceHandle surface_handle; - int32_t kRouteId = 1; - GPUCreateCommandBufferConfig init_params; - init_params.share_group_id = MSG_ROUTING_NONE; - init_params.stream_id = 0; - init_params.stream_priority = GpuStreamPriority::NORMAL; - init_params.attribs = std::vector<int>(); - init_params.active_url = GURL(); - init_params.gpu_preference = gfx::PreferIntegratedGpu; - channel_manager()->OnMessageReceived(GpuMsg_CreateViewCommandBuffer( - surface_handle, kClientId, init_params, kRouteId)); - - const IPC::Message* msg = - sink()->GetUniqueMessageMatching(GpuHostMsg_CommandBufferCreated::ID); - ASSERT_TRUE(msg); - - base::Tuple<CreateCommandBufferResult> result; - ASSERT_TRUE(GpuHostMsg_CommandBufferCreated::Read(msg, &result)); - - EXPECT_EQ(CREATE_COMMAND_BUFFER_SUCCEEDED, base::get<0>(result)); - - sink()->ClearMessages(); - - GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId); - ASSERT_TRUE(stub); -} - -TEST_F(GpuChannelTest, IncompatibleStreamIds) { - int32_t kClientId = 1; - GpuChannel* channel = CreateChannel(kClientId, false); - ASSERT_TRUE(channel); - - // Create first context. - int32_t kRouteId1 = 1; - int32_t kStreamId1 = 1; - GPUCreateCommandBufferConfig init_params; - init_params.share_group_id = MSG_ROUTING_NONE; - init_params.stream_id = kStreamId1; - init_params.stream_priority = GpuStreamPriority::NORMAL; - init_params.attribs = std::vector<int>(); - init_params.active_url = GURL(); - init_params.gpu_preference = gfx::PreferIntegratedGpu; - channel_manager()->OnMessageReceived(GpuMsg_CreateViewCommandBuffer( - gfx::GLSurfaceHandle(), kClientId, init_params, kRouteId1)); - - const IPC::Message* msg = - sink()->GetUniqueMessageMatching(GpuHostMsg_CommandBufferCreated::ID); - ASSERT_TRUE(msg); - - base::Tuple<CreateCommandBufferResult> result; - ASSERT_TRUE(GpuHostMsg_CommandBufferCreated::Read(msg, &result)); - - EXPECT_EQ(CREATE_COMMAND_BUFFER_SUCCEEDED, base::get<0>(result)); - - sink()->ClearMessages(); - - GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId1); - ASSERT_TRUE(stub); - - // Create second context in same share group but different stream. - int32_t kRouteId2 = 2; - int32_t kStreamId2 = 2; - - init_params.share_group_id = kRouteId1; - init_params.stream_id = kStreamId2; - init_params.stream_priority = GpuStreamPriority::NORMAL; - init_params.attribs = std::vector<int>(); - init_params.active_url = GURL(); - init_params.gpu_preference = gfx::PreferIntegratedGpu; - channel_manager()->OnMessageReceived(GpuMsg_CreateViewCommandBuffer( - gfx::GLSurfaceHandle(), kClientId, init_params, kRouteId2)); - - msg = sink()->GetUniqueMessageMatching(GpuHostMsg_CommandBufferCreated::ID); - ASSERT_TRUE(msg); - - ASSERT_TRUE(GpuHostMsg_CommandBufferCreated::Read(msg, &result)); - - EXPECT_EQ(CREATE_COMMAND_BUFFER_FAILED, base::get<0>(result)); - - sink()->ClearMessages(); - - stub = channel->LookupCommandBuffer(kRouteId2); - ASSERT_FALSE(stub); -} - -TEST_F(GpuChannelTest, IncompatibleStreamPriorities) { - int32_t kClientId = 1; - GpuChannel* channel = CreateChannel(kClientId, false); - ASSERT_TRUE(channel); - - // Create first context. - int32_t kRouteId1 = 1; - int32_t kStreamId1 = 1; - GpuStreamPriority kStreamPriority1 = GpuStreamPriority::NORMAL; - GPUCreateCommandBufferConfig init_params; - init_params.share_group_id = MSG_ROUTING_NONE; - init_params.stream_id = kStreamId1; - init_params.stream_priority = kStreamPriority1; - init_params.attribs = std::vector<int>(); - init_params.active_url = GURL(); - init_params.gpu_preference = gfx::PreferIntegratedGpu; - channel_manager()->OnMessageReceived(GpuMsg_CreateViewCommandBuffer( - gfx::GLSurfaceHandle(), kClientId, init_params, kRouteId1)); - - const IPC::Message* msg = - sink()->GetUniqueMessageMatching(GpuHostMsg_CommandBufferCreated::ID); - ASSERT_TRUE(msg); - - base::Tuple<CreateCommandBufferResult> result; - ASSERT_TRUE(GpuHostMsg_CommandBufferCreated::Read(msg, &result)); - - EXPECT_EQ(CREATE_COMMAND_BUFFER_SUCCEEDED, base::get<0>(result)); - - sink()->ClearMessages(); - - GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId1); - ASSERT_TRUE(stub); - - // Create second context in same share group but different stream. - int32_t kRouteId2 = 2; - int32_t kStreamId2 = kStreamId1; - GpuStreamPriority kStreamPriority2 = GpuStreamPriority::LOW; - - init_params.share_group_id = MSG_ROUTING_NONE; - init_params.stream_id = kStreamId2; - init_params.stream_priority = kStreamPriority2; - init_params.attribs = std::vector<int>(); - init_params.active_url = GURL(); - init_params.gpu_preference = gfx::PreferIntegratedGpu; - channel_manager()->OnMessageReceived(GpuMsg_CreateViewCommandBuffer( - gfx::GLSurfaceHandle(), kClientId, init_params, kRouteId2)); - - msg = sink()->GetUniqueMessageMatching(GpuHostMsg_CommandBufferCreated::ID); - ASSERT_TRUE(msg); - - ASSERT_TRUE(GpuHostMsg_CommandBufferCreated::Read(msg, &result)); - - EXPECT_EQ(CREATE_COMMAND_BUFFER_FAILED, base::get<0>(result)); - - sink()->ClearMessages(); - - stub = channel->LookupCommandBuffer(kRouteId2); - ASSERT_FALSE(stub); -} - -TEST_F(GpuChannelTest, StreamLifetime) { - int32_t kClientId = 1; - GpuChannel* channel = CreateChannel(kClientId, false); - ASSERT_TRUE(channel); - - // Create first context. - int32_t kRouteId1 = 1; - int32_t kStreamId1 = 1; - GpuStreamPriority kStreamPriority1 = GpuStreamPriority::NORMAL; - GPUCreateCommandBufferConfig init_params; - init_params.share_group_id = MSG_ROUTING_NONE; - init_params.stream_id = kStreamId1; - init_params.stream_priority = kStreamPriority1; - init_params.attribs = std::vector<int>(); - init_params.active_url = GURL(); - init_params.gpu_preference = gfx::PreferIntegratedGpu; - channel_manager()->OnMessageReceived(GpuMsg_CreateViewCommandBuffer( - gfx::GLSurfaceHandle(), kClientId, init_params, kRouteId1)); - - const IPC::Message* msg = - sink()->GetUniqueMessageMatching(GpuHostMsg_CommandBufferCreated::ID); - ASSERT_TRUE(msg); - - base::Tuple<CreateCommandBufferResult> result; - ASSERT_TRUE(GpuHostMsg_CommandBufferCreated::Read(msg, &result)); - - EXPECT_EQ(CREATE_COMMAND_BUFFER_SUCCEEDED, base::get<0>(result)); - - sink()->ClearMessages(); - - GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId1); - ASSERT_TRUE(stub); - - { - // GpuChannelHost always calls set_unblock(false) on messages sent to the - // GPU process. - IPC::Message m = GpuChannelMsg_DestroyCommandBuffer(kRouteId1); - m.set_unblock(false); - EXPECT_TRUE(channel->filter()->OnMessageReceived(m)); - task_runner()->RunPendingTasks(); - } - - stub = channel->LookupCommandBuffer(kRouteId1); - ASSERT_FALSE(stub); - - // Create second context in same share group but different stream. - int32_t kRouteId2 = 2; - int32_t kStreamId2 = 2; - GpuStreamPriority kStreamPriority2 = GpuStreamPriority::LOW; - - init_params.share_group_id = MSG_ROUTING_NONE; - init_params.stream_id = kStreamId2; - init_params.stream_priority = kStreamPriority2; - init_params.attribs = std::vector<int>(); - init_params.active_url = GURL(); - init_params.gpu_preference = gfx::PreferIntegratedGpu; - channel_manager()->OnMessageReceived(GpuMsg_CreateViewCommandBuffer( - gfx::GLSurfaceHandle(), kClientId, init_params, kRouteId2)); - - msg = sink()->GetUniqueMessageMatching(GpuHostMsg_CommandBufferCreated::ID); - ASSERT_TRUE(msg); - - ASSERT_TRUE(GpuHostMsg_CommandBufferCreated::Read(msg, &result)); - - EXPECT_EQ(CREATE_COMMAND_BUFFER_SUCCEEDED, base::get<0>(result)); - - sink()->ClearMessages(); - - stub = channel->LookupCommandBuffer(kRouteId2); - ASSERT_TRUE(stub); -} - -TEST_F(GpuChannelTest, RealTimeStreamsDisallowed) { - int32_t kClientId = 1; - bool allow_real_time_streams = false; - GpuChannel* channel = CreateChannel(kClientId, allow_real_time_streams); - ASSERT_TRUE(channel); - - // Create first context. - int32_t kRouteId = 1; - int32_t kStreamId = 1; - GpuStreamPriority kStreamPriority = GpuStreamPriority::REAL_TIME; - GPUCreateCommandBufferConfig init_params; - init_params.share_group_id = MSG_ROUTING_NONE; - init_params.stream_id = kStreamId; - init_params.stream_priority = kStreamPriority; - init_params.attribs = std::vector<int>(); - init_params.active_url = GURL(); - init_params.gpu_preference = gfx::PreferIntegratedGpu; - channel_manager()->OnMessageReceived(GpuMsg_CreateViewCommandBuffer( - gfx::GLSurfaceHandle(), kClientId, init_params, kRouteId)); - - const IPC::Message* msg = - sink()->GetUniqueMessageMatching(GpuHostMsg_CommandBufferCreated::ID); - ASSERT_TRUE(msg); - - base::Tuple<CreateCommandBufferResult> result; - ASSERT_TRUE(GpuHostMsg_CommandBufferCreated::Read(msg, &result)); - - EXPECT_EQ(CREATE_COMMAND_BUFFER_FAILED, base::get<0>(result)); - - sink()->ClearMessages(); - - GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId); - ASSERT_FALSE(stub); -} - -TEST_F(GpuChannelTest, RealTimeStreamsAllowed) { - int32_t kClientId = 1; - bool allow_real_time_streams = true; - GpuChannel* channel = CreateChannel(kClientId, allow_real_time_streams); - ASSERT_TRUE(channel); - - // Create first context. - int32_t kRouteId = 1; - int32_t kStreamId = 1; - GpuStreamPriority kStreamPriority = GpuStreamPriority::REAL_TIME; - GPUCreateCommandBufferConfig init_params; - init_params.share_group_id = MSG_ROUTING_NONE; - init_params.stream_id = kStreamId; - init_params.stream_priority = kStreamPriority; - init_params.attribs = std::vector<int>(); - init_params.active_url = GURL(); - init_params.gpu_preference = gfx::PreferIntegratedGpu; - channel_manager()->OnMessageReceived(GpuMsg_CreateViewCommandBuffer( - gfx::GLSurfaceHandle(), kClientId, init_params, kRouteId)); - - const IPC::Message* msg = - sink()->GetUniqueMessageMatching(GpuHostMsg_CommandBufferCreated::ID); - ASSERT_TRUE(msg); - - base::Tuple<CreateCommandBufferResult> result; - ASSERT_TRUE(GpuHostMsg_CommandBufferCreated::Read(msg, &result)); - - EXPECT_EQ(CREATE_COMMAND_BUFFER_SUCCEEDED, base::get<0>(result)); - - sink()->ClearMessages(); - - GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId); - ASSERT_TRUE(stub); -} - -} // namespace content diff --git a/chromium/content/common/gpu/gpu_command_buffer_stub.cc b/chromium/content/common/gpu/gpu_command_buffer_stub.cc deleted file mode 100644 index 58bfa6a4fb9..00000000000 --- a/chromium/content/common/gpu/gpu_command_buffer_stub.cc +++ /dev/null @@ -1,1269 +0,0 @@ -// Copyright (c) 2012 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 "content/common/gpu/gpu_command_buffer_stub.h" - -#include <utility> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/command_line.h" -#include "base/hash.h" -#include "base/json/json_writer.h" -#include "base/macros.h" -#include "base/memory/shared_memory.h" -#include "base/time/time.h" -#include "base/trace_event/trace_event.h" -#include "build/build_config.h" -#include "content/common/gpu/gpu_channel.h" -#include "content/common/gpu/gpu_channel_manager.h" -#include "content/common/gpu/gpu_memory_manager.h" -#include "content/common/gpu/gpu_memory_tracking.h" -#include "content/common/gpu/gpu_messages.h" -#include "content/common/gpu/gpu_watchdog.h" -#include "content/common/gpu/image_transport_surface.h" -#include "content/common/gpu/media/gpu_video_decode_accelerator.h" -#include "content/common/gpu/media/gpu_video_encode_accelerator.h" -#include "content/public/common/content_client.h" -#include "content/public/common/content_switches.h" -#include "gpu/command_buffer/common/constants.h" -#include "gpu/command_buffer/common/mailbox.h" -#include "gpu/command_buffer/common/sync_token.h" -#include "gpu/command_buffer/service/gl_context_virtual.h" -#include "gpu/command_buffer/service/gl_state_restorer_impl.h" -#include "gpu/command_buffer/service/image_factory.h" -#include "gpu/command_buffer/service/image_manager.h" -#include "gpu/command_buffer/service/logger.h" -#include "gpu/command_buffer/service/mailbox_manager.h" -#include "gpu/command_buffer/service/memory_tracking.h" -#include "gpu/command_buffer/service/query_manager.h" -#include "gpu/command_buffer/service/sync_point_manager.h" -#include "gpu/command_buffer/service/transfer_buffer_manager.h" -#include "gpu/command_buffer/service/valuebuffer_manager.h" -#include "ui/gl/gl_bindings.h" -#include "ui/gl/gl_switches.h" - -#if defined(OS_WIN) -#include "base/win/win_util.h" -#include "content/public/common/sandbox_init.h" -#endif - -#if defined(OS_ANDROID) -#include "content/common/gpu/stream_texture_android.h" -#endif - -namespace content { -struct WaitForCommandState { - WaitForCommandState(int32_t start, int32_t end, IPC::Message* reply) - : start(start), end(end), reply(reply) {} - - int32_t start; - int32_t end; - scoped_ptr<IPC::Message> reply; -}; - -namespace { - -// The GpuCommandBufferMemoryTracker class provides a bridge between the -// ContextGroup's memory type managers and the GpuMemoryManager class. -class GpuCommandBufferMemoryTracker : public gpu::gles2::MemoryTracker { - public: - explicit GpuCommandBufferMemoryTracker(GpuChannel* channel, - uint64_t share_group_tracing_guid) - : tracking_group_( - channel->gpu_channel_manager() - ->gpu_memory_manager() - ->CreateTrackingGroup(channel->GetClientPID(), this)), - client_tracing_id_(channel->client_tracing_id()), - client_id_(channel->client_id()), - share_group_tracing_guid_(share_group_tracing_guid) {} - - void TrackMemoryAllocatedChange( - size_t old_size, size_t new_size) override { - tracking_group_->TrackMemoryAllocatedChange( - old_size, new_size); - } - - bool EnsureGPUMemoryAvailable(size_t size_needed) override { - return tracking_group_->EnsureGPUMemoryAvailable(size_needed); - }; - - uint64_t ClientTracingId() const override { return client_tracing_id_; } - int ClientId() const override { return client_id_; } - uint64_t ShareGroupTracingGUID() const override { - return share_group_tracing_guid_; - } - - private: - ~GpuCommandBufferMemoryTracker() override {} - scoped_ptr<GpuMemoryTrackingGroup> tracking_group_; - const uint64_t client_tracing_id_; - const int client_id_; - const uint64_t share_group_tracing_guid_; - - DISALLOW_COPY_AND_ASSIGN(GpuCommandBufferMemoryTracker); -}; - -// FastSetActiveURL will shortcut the expensive call to SetActiveURL when the -// url_hash matches. -void FastSetActiveURL(const GURL& url, size_t url_hash) { - // Leave the previously set URL in the empty case -- empty URLs are given by - // BlinkPlatformImpl::createOffscreenGraphicsContext3D. Hopefully the - // onscreen context URL was set previously and will show up even when a crash - // occurs during offscreen command processing. - if (url.is_empty()) - return; - static size_t g_last_url_hash = 0; - if (url_hash != g_last_url_hash) { - g_last_url_hash = url_hash; - GetContentClient()->SetActiveURL(url); - } -} - -// The first time polling a fence, delay some extra time to allow other -// stubs to process some work, or else the timing of the fences could -// allow a pattern of alternating fast and slow frames to occur. -const int64_t kHandleMoreWorkPeriodMs = 2; -const int64_t kHandleMoreWorkPeriodBusyMs = 1; - -// Prevents idle work from being starved. -const int64_t kMaxTimeSinceIdleMs = 10; - -class DevToolsChannelData : public base::trace_event::ConvertableToTraceFormat { - public: - static scoped_refptr<base::trace_event::ConvertableToTraceFormat> - CreateForChannel(GpuChannel* channel); - - void AppendAsTraceFormat(std::string* out) const override { - std::string tmp; - base::JSONWriter::Write(*value_, &tmp); - *out += tmp; - } - - private: - explicit DevToolsChannelData(base::Value* value) : value_(value) {} - ~DevToolsChannelData() override {} - scoped_ptr<base::Value> value_; - DISALLOW_COPY_AND_ASSIGN(DevToolsChannelData); -}; - -scoped_refptr<base::trace_event::ConvertableToTraceFormat> -DevToolsChannelData::CreateForChannel(GpuChannel* channel) { - scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue); - res->SetInteger("renderer_pid", channel->GetClientPID()); - res->SetDouble("used_bytes", channel->GetMemoryUsage()); - return new DevToolsChannelData(res.release()); -} - -void RunOnThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner, - const base::Closure& callback) { - if (task_runner->BelongsToCurrentThread()) { - callback.Run(); - } else { - task_runner->PostTask(FROM_HERE, callback); - } -} - -uint64_t GetCommandBufferID(int channel_id, int32_t route_id) { - return (static_cast<uint64_t>(channel_id) << 32) | route_id; -} - -} // namespace - -GpuCommandBufferStub::GpuCommandBufferStub( - GpuChannel* channel, - gpu::SyncPointManager* sync_point_manager, - base::SingleThreadTaskRunner* task_runner, - GpuCommandBufferStub* share_group, - const gfx::GLSurfaceHandle& handle, - gpu::gles2::MailboxManager* mailbox_manager, - gpu::PreemptionFlag* preempt_by_flag, - gpu::gles2::SubscriptionRefSet* subscription_ref_set, - gpu::ValueStateMap* pending_valuebuffer_state, - const gfx::Size& size, - const gpu::gles2::DisallowedFeatures& disallowed_features, - const std::vector<int32_t>& attribs, - gfx::GpuPreference gpu_preference, - int32_t stream_id, - int32_t route_id, - bool offscreen, - GpuWatchdog* watchdog, - const GURL& active_url) - : channel_(channel), - sync_point_manager_(sync_point_manager), - task_runner_(task_runner), - initialized_(false), - handle_(handle), - initial_size_(size), - disallowed_features_(disallowed_features), - requested_attribs_(attribs), - gpu_preference_(gpu_preference), - use_virtualized_gl_context_(false), - command_buffer_id_(GetCommandBufferID(channel->client_id(), route_id)), - stream_id_(stream_id), - route_id_(route_id), - offscreen_(offscreen), - last_flush_count_(0), - watchdog_(watchdog), - waiting_for_sync_point_(false), - previous_processed_num_(0), - preemption_flag_(preempt_by_flag), - active_url_(active_url) { - active_url_hash_ = base::Hash(active_url.possibly_invalid_spec()); - FastSetActiveURL(active_url_, active_url_hash_); - - gpu::gles2::ContextCreationAttribHelper attrib_parser; - attrib_parser.Parse(requested_attribs_); - - if (share_group) { - context_group_ = share_group->context_group_; - DCHECK(context_group_->bind_generates_resource() == - attrib_parser.bind_generates_resource); - } else { - context_group_ = new gpu::gles2::ContextGroup( - mailbox_manager, - new GpuCommandBufferMemoryTracker(channel, command_buffer_id_), - channel_->gpu_channel_manager()->shader_translator_cache(), - channel_->gpu_channel_manager()->framebuffer_completeness_cache(), NULL, - subscription_ref_set, pending_valuebuffer_state, - attrib_parser.bind_generates_resource); - } - -// Virtualize PreferIntegratedGpu contexts by default on OS X to prevent -// performance regressions when enabling FCM. -// http://crbug.com/180463 -#if defined(OS_MACOSX) - if (gpu_preference_ == gfx::PreferIntegratedGpu) - use_virtualized_gl_context_ = true; -#endif - - use_virtualized_gl_context_ |= - context_group_->feature_info()->workarounds().use_virtualized_gl_contexts; - - // MailboxManagerSync synchronization correctness currently depends on having - // only a single context. See crbug.com/510243 for details. - use_virtualized_gl_context_ |= mailbox_manager->UsesSync(); - - if (offscreen && initial_size_.IsEmpty()) { - // If we're an offscreen surface with zero width and/or height, set to a - // non-zero size so that we have a complete framebuffer for operations like - // glClear. - initial_size_ = gfx::Size(1, 1); - } -} - -GpuCommandBufferStub::~GpuCommandBufferStub() { - Destroy(); -} - -GpuMemoryManager* GpuCommandBufferStub::GetMemoryManager() const { - return channel()->gpu_channel_manager()->gpu_memory_manager(); -} - -bool GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) { - TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), - "GPUTask", - "data", - DevToolsChannelData::CreateForChannel(channel())); - FastSetActiveURL(active_url_, active_url_hash_); - - bool have_context = false; - // Ensure the appropriate GL context is current before handling any IPC - // messages directed at the command buffer. This ensures that the message - // handler can assume that the context is current (not necessary for - // RetireSyncPoint or WaitSyncPoint). - if (decoder_.get() && - message.type() != GpuCommandBufferMsg_SetGetBuffer::ID && - message.type() != GpuCommandBufferMsg_WaitForTokenInRange::ID && - message.type() != GpuCommandBufferMsg_WaitForGetOffsetInRange::ID && - message.type() != GpuCommandBufferMsg_RegisterTransferBuffer::ID && - message.type() != GpuCommandBufferMsg_DestroyTransferBuffer::ID && - message.type() != GpuCommandBufferMsg_RetireSyncPoint::ID && - message.type() != GpuCommandBufferMsg_SignalSyncPoint::ID) { - if (!MakeCurrent()) - return false; - have_context = true; - } - - // Always use IPC_MESSAGE_HANDLER_DELAY_REPLY for synchronous message handlers - // here. This is so the reply can be delayed if the scheduler is unscheduled. - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(GpuCommandBufferStub, message) - IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuCommandBufferMsg_Initialize, - OnInitialize); - IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuCommandBufferMsg_SetGetBuffer, - OnSetGetBuffer); - IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_ProduceFrontBuffer, - OnProduceFrontBuffer); - IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuCommandBufferMsg_WaitForTokenInRange, - OnWaitForTokenInRange); - IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuCommandBufferMsg_WaitForGetOffsetInRange, - OnWaitForGetOffsetInRange); - IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_AsyncFlush, OnAsyncFlush); - IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_RegisterTransferBuffer, - OnRegisterTransferBuffer); - IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_DestroyTransferBuffer, - OnDestroyTransferBuffer); - IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuCommandBufferMsg_CreateVideoDecoder, - OnCreateVideoDecoder) - IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuCommandBufferMsg_CreateVideoEncoder, - OnCreateVideoEncoder) - IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_RetireSyncPoint, - OnRetireSyncPoint) - IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SignalSyncPoint, - OnSignalSyncPoint) - IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SignalSyncToken, - OnSignalSyncToken) - IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SignalQuery, - OnSignalQuery) - IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_CreateImage, OnCreateImage); - IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_DestroyImage, OnDestroyImage); - IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_CreateStreamTexture, - OnCreateStreamTexture) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - - CheckCompleteWaits(); - - // Ensure that any delayed work that was created will be handled. - if (have_context) { - if (scheduler_) - scheduler_->ProcessPendingQueries(); - ScheduleDelayedWork( - base::TimeDelta::FromMilliseconds(kHandleMoreWorkPeriodMs)); - } - - DCHECK(handled); - return handled; -} - -bool GpuCommandBufferStub::Send(IPC::Message* message) { - return channel_->Send(message); -} - -bool GpuCommandBufferStub::IsScheduled() { - return (!scheduler_.get() || scheduler_->scheduled()); -} - -void GpuCommandBufferStub::PollWork() { - // Post another delayed task if we have not yet reached the time at which - // we should process delayed work. - base::TimeTicks current_time = base::TimeTicks::Now(); - DCHECK(!process_delayed_work_time_.is_null()); - if (process_delayed_work_time_ > current_time) { - task_runner_->PostDelayedTask( - FROM_HERE, base::Bind(&GpuCommandBufferStub::PollWork, AsWeakPtr()), - process_delayed_work_time_ - current_time); - return; - } - process_delayed_work_time_ = base::TimeTicks(); - - PerformWork(); -} - -void GpuCommandBufferStub::PerformWork() { - TRACE_EVENT0("gpu", "GpuCommandBufferStub::PerformWork"); - - FastSetActiveURL(active_url_, active_url_hash_); - if (decoder_.get() && !MakeCurrent()) - return; - - if (scheduler_) { - uint32_t current_unprocessed_num = - channel()->gpu_channel_manager()->GetUnprocessedOrderNum(); - // We're idle when no messages were processed or scheduled. - bool is_idle = (previous_processed_num_ == current_unprocessed_num); - if (!is_idle && !last_idle_time_.is_null()) { - base::TimeDelta time_since_idle = - base::TimeTicks::Now() - last_idle_time_; - base::TimeDelta max_time_since_idle = - base::TimeDelta::FromMilliseconds(kMaxTimeSinceIdleMs); - - // Force idle when it's been too long since last time we were idle. - if (time_since_idle > max_time_since_idle) - is_idle = true; - } - - if (is_idle) { - last_idle_time_ = base::TimeTicks::Now(); - scheduler_->PerformIdleWork(); - } - - scheduler_->ProcessPendingQueries(); - } - - ScheduleDelayedWork( - base::TimeDelta::FromMilliseconds(kHandleMoreWorkPeriodBusyMs)); -} - -bool GpuCommandBufferStub::HasUnprocessedCommands() { - if (command_buffer_) { - gpu::CommandBuffer::State state = command_buffer_->GetLastState(); - return command_buffer_->GetPutOffset() != state.get_offset && - !gpu::error::IsError(state.error); - } - return false; -} - -void GpuCommandBufferStub::ScheduleDelayedWork(base::TimeDelta delay) { - bool has_more_work = scheduler_.get() && (scheduler_->HasPendingQueries() || - scheduler_->HasMoreIdleWork()); - if (!has_more_work) { - last_idle_time_ = base::TimeTicks(); - return; - } - - base::TimeTicks current_time = base::TimeTicks::Now(); - // |process_delayed_work_time_| is set if processing of delayed work is - // already scheduled. Just update the time if already scheduled. - if (!process_delayed_work_time_.is_null()) { - process_delayed_work_time_ = current_time + delay; - return; - } - - // Idle when no messages are processed between now and when - // PollWork is called. - previous_processed_num_ = - channel()->gpu_channel_manager()->GetProcessedOrderNum(); - if (last_idle_time_.is_null()) - last_idle_time_ = current_time; - - // IsScheduled() returns true after passing all unschedule fences - // and this is when we can start performing idle work. Idle work - // is done synchronously so we can set delay to 0 and instead poll - // for more work at the rate idle work is performed. This also ensures - // that idle work is done as efficiently as possible without any - // unnecessary delays. - if (scheduler_.get() && scheduler_->scheduled() && - scheduler_->HasMoreIdleWork()) { - delay = base::TimeDelta(); - } - - process_delayed_work_time_ = current_time + delay; - task_runner_->PostDelayedTask( - FROM_HERE, base::Bind(&GpuCommandBufferStub::PollWork, AsWeakPtr()), - delay); -} - -bool GpuCommandBufferStub::MakeCurrent() { - if (decoder_->MakeCurrent()) - return true; - DLOG(ERROR) << "Context lost because MakeCurrent failed."; - command_buffer_->SetContextLostReason(decoder_->GetContextLostReason()); - command_buffer_->SetParseError(gpu::error::kLostContext); - CheckContextLost(); - return false; -} - -void GpuCommandBufferStub::Destroy() { - if (wait_for_token_) { - Send(wait_for_token_->reply.release()); - wait_for_token_.reset(); - } - if (wait_for_get_offset_) { - Send(wait_for_get_offset_->reply.release()); - wait_for_get_offset_.reset(); - } - - if (initialized_) { - GpuChannelManager* gpu_channel_manager = channel_->gpu_channel_manager(); - if (handle_.is_null() && !active_url_.is_empty()) { - gpu_channel_manager->Send( - new GpuHostMsg_DidDestroyOffscreenContext(active_url_)); - } - } - - while (!sync_points_.empty()) - OnRetireSyncPoint(sync_points_.front()); - - if (decoder_) - decoder_->set_engine(NULL); - - // The scheduler has raw references to the decoder and the command buffer so - // destroy it before those. - scheduler_.reset(); - - sync_point_client_.reset(); - - bool have_context = false; - if (decoder_ && decoder_->GetGLContext()) { - // Try to make the context current regardless of whether it was lost, so we - // don't leak resources. - have_context = decoder_->GetGLContext()->MakeCurrent(surface_.get()); - } - FOR_EACH_OBSERVER(DestructionObserver, - destruction_observers_, - OnWillDestroyStub()); - - if (decoder_) { - decoder_->Destroy(have_context); - decoder_.reset(); - } - - command_buffer_.reset(); - - // Remove this after crbug.com/248395 is sorted out. - surface_ = NULL; -} - -void GpuCommandBufferStub::OnInitializeFailed(IPC::Message* reply_message) { - Destroy(); - GpuCommandBufferMsg_Initialize::WriteReplyParams( - reply_message, false, gpu::Capabilities()); - Send(reply_message); -} - -void GpuCommandBufferStub::OnInitialize( - base::SharedMemoryHandle shared_state_handle, - IPC::Message* reply_message) { - TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnInitialize"); - DCHECK(!command_buffer_.get()); - - scoped_ptr<base::SharedMemory> shared_state_shm( - new base::SharedMemory(shared_state_handle, false)); - - command_buffer_.reset(new gpu::CommandBufferService( - context_group_->transfer_buffer_manager())); - - bool result = command_buffer_->Initialize(); - DCHECK(result); - - GpuChannelManager* manager = channel_->gpu_channel_manager(); - DCHECK(manager); - - decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group_.get())); - scheduler_.reset(new gpu::GpuScheduler(command_buffer_.get(), - decoder_.get(), - decoder_.get())); - sync_point_client_ = sync_point_manager_->CreateSyncPointClient( - channel_->GetSyncPointOrderData(), gpu::CommandBufferNamespace::GPU_IO, - command_buffer_id_); - - if (preemption_flag_.get()) - scheduler_->SetPreemptByFlag(preemption_flag_); - - decoder_->set_engine(scheduler_.get()); - - if (!handle_.is_null()) { - surface_ = ImageTransportSurface::CreateSurface( - channel_->gpu_channel_manager(), - this, - handle_); - } else { - surface_ = manager->GetDefaultOffscreenSurface(); - } - - if (!surface_.get()) { - DLOG(ERROR) << "Failed to create surface."; - OnInitializeFailed(reply_message); - return; - } - - scoped_refptr<gfx::GLContext> context; - if (use_virtualized_gl_context_ && channel_->share_group()) { - context = channel_->share_group()->GetSharedContext(); - if (!context.get()) { - context = gfx::GLContext::CreateGLContext( - channel_->share_group(), - channel_->gpu_channel_manager()->GetDefaultOffscreenSurface(), - gpu_preference_); - if (!context.get()) { - DLOG(ERROR) << "Failed to create shared context for virtualization."; - OnInitializeFailed(reply_message); - return; - } - channel_->share_group()->SetSharedContext(context.get()); - } - // This should be a non-virtual GL context. - DCHECK(context->GetHandle()); - context = new gpu::GLContextVirtual( - channel_->share_group(), context.get(), decoder_->AsWeakPtr()); - if (!context->Initialize(surface_.get(), gpu_preference_)) { - // TODO(sievers): The real context created above for the default - // offscreen surface might not be compatible with this surface. - // Need to adjust at least GLX to be able to create the initial context - // with a config that is compatible with onscreen and offscreen surfaces. - context = NULL; - - DLOG(ERROR) << "Failed to initialize virtual GL context."; - OnInitializeFailed(reply_message); - return; - } - } - if (!context.get()) { - context = gfx::GLContext::CreateGLContext( - channel_->share_group(), surface_.get(), gpu_preference_); - } - if (!context.get()) { - DLOG(ERROR) << "Failed to create context."; - OnInitializeFailed(reply_message); - return; - } - - if (!context->MakeCurrent(surface_.get())) { - LOG(ERROR) << "Failed to make context current."; - OnInitializeFailed(reply_message); - return; - } - - if (!context->GetGLStateRestorer()) { - context->SetGLStateRestorer( - new gpu::GLStateRestorerImpl(decoder_->AsWeakPtr())); - } - - if (!context_group_->has_program_cache() && - !context_group_->feature_info()->workarounds().disable_program_cache) { - context_group_->set_program_cache( - channel_->gpu_channel_manager()->program_cache()); - } - - // Initialize the decoder with either the view or pbuffer GLContext. - if (!decoder_->Initialize(surface_, context, offscreen_, initial_size_, - disallowed_features_, requested_attribs_)) { - DLOG(ERROR) << "Failed to initialize decoder."; - OnInitializeFailed(reply_message); - return; - } - - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableGPUServiceLogging)) { - decoder_->set_log_commands(true); - } - - decoder_->GetLogger()->SetMsgCallback( - base::Bind(&GpuCommandBufferStub::SendConsoleMessage, - base::Unretained(this))); - decoder_->SetShaderCacheCallback( - base::Bind(&GpuCommandBufferStub::SendCachedShader, - base::Unretained(this))); - decoder_->SetWaitSyncPointCallback( - base::Bind(&GpuCommandBufferStub::OnWaitSyncPoint, - base::Unretained(this))); - decoder_->SetFenceSyncReleaseCallback(base::Bind( - &GpuCommandBufferStub::OnFenceSyncRelease, base::Unretained(this))); - decoder_->SetWaitFenceSyncCallback(base::Bind( - &GpuCommandBufferStub::OnWaitFenceSync, base::Unretained(this))); - - command_buffer_->SetPutOffsetChangeCallback( - base::Bind(&GpuCommandBufferStub::PutChanged, base::Unretained(this))); - command_buffer_->SetGetBufferChangeCallback( - base::Bind(&gpu::GpuScheduler::SetGetBuffer, - base::Unretained(scheduler_.get()))); - command_buffer_->SetParseErrorCallback( - base::Bind(&GpuCommandBufferStub::OnParseError, base::Unretained(this))); - scheduler_->SetSchedulingChangedCallback(base::Bind( - &GpuCommandBufferStub::OnSchedulingChanged, base::Unretained(this))); - - if (watchdog_) { - scheduler_->SetCommandProcessedCallback( - base::Bind(&GpuCommandBufferStub::OnCommandProcessed, - base::Unretained(this))); - } - - const size_t kSharedStateSize = sizeof(gpu::CommandBufferSharedState); - if (!shared_state_shm->Map(kSharedStateSize)) { - DLOG(ERROR) << "Failed to map shared state buffer."; - OnInitializeFailed(reply_message); - return; - } - command_buffer_->SetSharedStateBuffer(gpu::MakeBackingFromSharedMemory( - std::move(shared_state_shm), kSharedStateSize)); - - gpu::Capabilities capabilities = decoder_->GetCapabilities(); - capabilities.future_sync_points = channel_->allow_future_sync_points(); - - GpuCommandBufferMsg_Initialize::WriteReplyParams( - reply_message, true, capabilities); - Send(reply_message); - - if (handle_.is_null() && !active_url_.is_empty()) { - manager->Send(new GpuHostMsg_DidCreateOffscreenContext( - active_url_)); - } - - initialized_ = true; -} - -void GpuCommandBufferStub::OnCreateStreamTexture(uint32_t texture_id, - int32_t stream_id, - bool* succeeded) { -#if defined(OS_ANDROID) - *succeeded = StreamTexture::Create(this, texture_id, stream_id); -#else - *succeeded = false; -#endif -} - -void GpuCommandBufferStub::SetLatencyInfoCallback( - const LatencyInfoCallback& callback) { - latency_info_callback_ = callback; -} - -int32_t GpuCommandBufferStub::GetRequestedAttribute(int attr) const { - // The command buffer is pairs of enum, value - // search for the requested attribute, return the value. - for (std::vector<int32_t>::const_iterator it = requested_attribs_.begin(); - it != requested_attribs_.end(); ++it) { - if (*it++ == attr) { - return *it; - } - } - return -1; -} - -void GpuCommandBufferStub::OnSetGetBuffer(int32_t shm_id, - IPC::Message* reply_message) { - TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnSetGetBuffer"); - if (command_buffer_) - command_buffer_->SetGetBuffer(shm_id); - Send(reply_message); -} - -void GpuCommandBufferStub::OnProduceFrontBuffer(const gpu::Mailbox& mailbox) { - TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnProduceFrontBuffer"); - if (!decoder_) { - LOG(ERROR) << "Can't produce front buffer before initialization."; - return; - } - - decoder_->ProduceFrontBuffer(mailbox); -} - -void GpuCommandBufferStub::OnParseError() { - TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnParseError"); - DCHECK(command_buffer_.get()); - gpu::CommandBuffer::State state = command_buffer_->GetLastState(); - IPC::Message* msg = new GpuCommandBufferMsg_Destroyed( - route_id_, state.context_lost_reason, state.error); - msg->set_unblock(true); - Send(msg); - - // Tell the browser about this context loss as well, so it can - // determine whether client APIs like WebGL need to be immediately - // blocked from automatically running. - GpuChannelManager* gpu_channel_manager = channel_->gpu_channel_manager(); - gpu_channel_manager->Send(new GpuHostMsg_DidLoseContext( - handle_.is_null(), state.context_lost_reason, active_url_)); - - CheckContextLost(); -} - -void GpuCommandBufferStub::OnSchedulingChanged(bool scheduled) { - TRACE_EVENT1("gpu", "GpuCommandBufferStub::OnSchedulingChanged", "scheduled", - scheduled); - channel_->OnStubSchedulingChanged(this, scheduled); -} - -void GpuCommandBufferStub::OnWaitForTokenInRange(int32_t start, - int32_t end, - IPC::Message* reply_message) { - TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnWaitForTokenInRange"); - DCHECK(command_buffer_.get()); - CheckContextLost(); - if (wait_for_token_) - LOG(ERROR) << "Got WaitForToken command while currently waiting for token."; - wait_for_token_ = - make_scoped_ptr(new WaitForCommandState(start, end, reply_message)); - CheckCompleteWaits(); -} - -void GpuCommandBufferStub::OnWaitForGetOffsetInRange( - int32_t start, - int32_t end, - IPC::Message* reply_message) { - TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnWaitForGetOffsetInRange"); - DCHECK(command_buffer_.get()); - CheckContextLost(); - if (wait_for_get_offset_) { - LOG(ERROR) - << "Got WaitForGetOffset command while currently waiting for offset."; - } - wait_for_get_offset_ = - make_scoped_ptr(new WaitForCommandState(start, end, reply_message)); - CheckCompleteWaits(); -} - -void GpuCommandBufferStub::CheckCompleteWaits() { - if (wait_for_token_ || wait_for_get_offset_) { - gpu::CommandBuffer::State state = command_buffer_->GetLastState(); - if (wait_for_token_ && - (gpu::CommandBuffer::InRange( - wait_for_token_->start, wait_for_token_->end, state.token) || - state.error != gpu::error::kNoError)) { - ReportState(); - GpuCommandBufferMsg_WaitForTokenInRange::WriteReplyParams( - wait_for_token_->reply.get(), state); - Send(wait_for_token_->reply.release()); - wait_for_token_.reset(); - } - if (wait_for_get_offset_ && - (gpu::CommandBuffer::InRange(wait_for_get_offset_->start, - wait_for_get_offset_->end, - state.get_offset) || - state.error != gpu::error::kNoError)) { - ReportState(); - GpuCommandBufferMsg_WaitForGetOffsetInRange::WriteReplyParams( - wait_for_get_offset_->reply.get(), state); - Send(wait_for_get_offset_->reply.release()); - wait_for_get_offset_.reset(); - } - } -} - -void GpuCommandBufferStub::OnAsyncFlush( - int32_t put_offset, - uint32_t flush_count, - const std::vector<ui::LatencyInfo>& latency_info) { - TRACE_EVENT1( - "gpu", "GpuCommandBufferStub::OnAsyncFlush", "put_offset", put_offset); - DCHECK(command_buffer_); - - // We received this message out-of-order. This should not happen but is here - // to catch regressions. Ignore the message. - DVLOG_IF(0, flush_count - last_flush_count_ >= 0x8000000U) - << "Received a Flush message out-of-order"; - - if (flush_count > last_flush_count_ && - ui::LatencyInfo::Verify(latency_info, - "GpuCommandBufferStub::OnAsyncFlush") && - !latency_info_callback_.is_null()) { - latency_info_callback_.Run(latency_info); - } - - last_flush_count_ = flush_count; - gpu::CommandBuffer::State pre_state = command_buffer_->GetLastState(); - command_buffer_->Flush(put_offset); - gpu::CommandBuffer::State post_state = command_buffer_->GetLastState(); - - if (pre_state.get_offset != post_state.get_offset) - ReportState(); - -#if defined(OS_ANDROID) - GpuChannelManager* manager = channel_->gpu_channel_manager(); - manager->DidAccessGpu(); -#endif -} - -void GpuCommandBufferStub::OnRegisterTransferBuffer( - int32_t id, - base::SharedMemoryHandle transfer_buffer, - uint32_t size) { - TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnRegisterTransferBuffer"); - - // Take ownership of the memory and map it into this process. - // This validates the size. - scoped_ptr<base::SharedMemory> shared_memory( - new base::SharedMemory(transfer_buffer, false)); - if (!shared_memory->Map(size)) { - DVLOG(0) << "Failed to map shared memory."; - return; - } - - if (command_buffer_) { - command_buffer_->RegisterTransferBuffer( - id, gpu::MakeBackingFromSharedMemory(std::move(shared_memory), size)); - } -} - -void GpuCommandBufferStub::OnDestroyTransferBuffer(int32_t id) { - TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnDestroyTransferBuffer"); - - if (command_buffer_) - command_buffer_->DestroyTransferBuffer(id); -} - -void GpuCommandBufferStub::OnCommandProcessed() { - if (watchdog_) - watchdog_->CheckArmed(); -} - -void GpuCommandBufferStub::ReportState() { command_buffer_->UpdateState(); } - -void GpuCommandBufferStub::PutChanged() { - FastSetActiveURL(active_url_, active_url_hash_); - scheduler_->PutChanged(); -} - -void GpuCommandBufferStub::OnCreateVideoDecoder( - const media::VideoDecodeAccelerator::Config& config, - int32_t decoder_route_id, - IPC::Message* reply_message) { - TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnCreateVideoDecoder"); - GpuVideoDecodeAccelerator* decoder = new GpuVideoDecodeAccelerator( - decoder_route_id, this, channel_->io_task_runner()); - decoder->Initialize(config, reply_message); - // decoder is registered as a DestructionObserver of this stub and will - // self-delete during destruction of this stub. -} - -void GpuCommandBufferStub::OnCreateVideoEncoder( - media::VideoPixelFormat input_format, - const gfx::Size& input_visible_size, - media::VideoCodecProfile output_profile, - uint32_t initial_bitrate, - int32_t encoder_route_id, - IPC::Message* reply_message) { - TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnCreateVideoEncoder"); - GpuVideoEncodeAccelerator* encoder = - new GpuVideoEncodeAccelerator(encoder_route_id, this); - encoder->Initialize(input_format, - input_visible_size, - output_profile, - initial_bitrate, - reply_message); - // encoder is registered as a DestructionObserver of this stub and will - // self-delete during destruction of this stub. -} - -void GpuCommandBufferStub::InsertSyncPoint(uint32_t sync_point, bool retire) { - sync_points_.push_back(sync_point); - if (retire) { - OnMessageReceived( - GpuCommandBufferMsg_RetireSyncPoint(route_id_, sync_point)); - } -} - -void GpuCommandBufferStub::OnRetireSyncPoint(uint32_t sync_point) { - DCHECK(!sync_points_.empty() && sync_points_.front() == sync_point); - sync_points_.pop_front(); - - gpu::gles2::MailboxManager* mailbox_manager = - context_group_->mailbox_manager(); - if (mailbox_manager->UsesSync() && MakeCurrent()) { - // Old sync points are global and do not have a command buffer ID, - // We can simply use the global sync point number as the release count with - // 0 for the command buffer ID (under normal circumstances 0 is invalid so - // will not be used) until the old sync points are replaced. - gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0, 0, - sync_point); - mailbox_manager->PushTextureUpdates(sync_token); - } - - sync_point_manager_->RetireSyncPoint(sync_point); -} - -bool GpuCommandBufferStub::OnWaitSyncPoint(uint32_t sync_point) { - DCHECK(!waiting_for_sync_point_); - DCHECK(scheduler_->scheduled()); - if (!sync_point) - return true; - if (sync_point_manager_->IsSyncPointRetired(sync_point)) { - // Old sync points are global and do not have a command buffer ID, - // We can simply use the global sync point number as the release count with - // 0 for the command buffer ID (under normal circumstances 0 is invalid so - // will not be used) until the old sync points are replaced. - PullTextureUpdates(gpu::CommandBufferNamespace::GPU_IO, 0, sync_point); - return true; - } - - TRACE_EVENT_ASYNC_BEGIN1("gpu", "WaitSyncPoint", this, "GpuCommandBufferStub", - this); - - waiting_for_sync_point_ = true; - sync_point_manager_->AddSyncPointCallback( - sync_point, - base::Bind(&RunOnThread, task_runner_, - base::Bind(&GpuCommandBufferStub::OnWaitSyncPointCompleted, - this->AsWeakPtr(), sync_point))); - - if (!waiting_for_sync_point_) - return true; - - scheduler_->SetScheduled(false); - return false; -} - -void GpuCommandBufferStub::OnWaitSyncPointCompleted(uint32_t sync_point) { - DCHECK(waiting_for_sync_point_); - TRACE_EVENT_ASYNC_END1("gpu", "WaitSyncPoint", this, "GpuCommandBufferStub", - this); - // Old sync points are global and do not have a command buffer ID, - // We can simply use the global sync point number as the release count with - // 0 for the command buffer ID (under normal circumstances 0 is invalid so - // will not be used) until the old sync points are replaced. - PullTextureUpdates(gpu::CommandBufferNamespace::GPU_IO, 0, sync_point); - waiting_for_sync_point_ = false; - scheduler_->SetScheduled(true); -} - -void GpuCommandBufferStub::PullTextureUpdates( - gpu::CommandBufferNamespace namespace_id, - uint64_t command_buffer_id, - uint32_t release) { - gpu::gles2::MailboxManager* mailbox_manager = - context_group_->mailbox_manager(); - if (mailbox_manager->UsesSync() && MakeCurrent()) { - gpu::SyncToken sync_token(namespace_id, 0, command_buffer_id, release); - mailbox_manager->PullTextureUpdates(sync_token); - } -} - -void GpuCommandBufferStub::OnSignalSyncPoint(uint32_t sync_point, uint32_t id) { - sync_point_manager_->AddSyncPointCallback( - sync_point, - base::Bind(&GpuCommandBufferStub::OnSignalAck, this->AsWeakPtr(), id)); -} - -void GpuCommandBufferStub::OnSignalSyncToken(const gpu::SyncToken& sync_token, - uint32_t id) { - scoped_refptr<gpu::SyncPointClientState> release_state = - sync_point_manager_->GetSyncPointClientState( - sync_token.namespace_id(), sync_token.command_buffer_id()); - - if (release_state) { - sync_point_client_->Wait(release_state.get(), sync_token.release_count(), - base::Bind(&GpuCommandBufferStub::OnSignalAck, - this->AsWeakPtr(), id)); - } else { - OnSignalAck(id); - } -} - -void GpuCommandBufferStub::OnSignalAck(uint32_t id) { - Send(new GpuCommandBufferMsg_SignalAck(route_id_, id)); -} - -void GpuCommandBufferStub::OnSignalQuery(uint32_t query_id, uint32_t id) { - if (decoder_) { - gpu::gles2::QueryManager* query_manager = decoder_->GetQueryManager(); - if (query_manager) { - gpu::gles2::QueryManager::Query* query = - query_manager->GetQuery(query_id); - if (query) { - query->AddCallback( - base::Bind(&GpuCommandBufferStub::OnSignalAck, - this->AsWeakPtr(), - id)); - return; - } - } - } - // Something went wrong, run callback immediately. - OnSignalAck(id); -} - -void GpuCommandBufferStub::OnFenceSyncRelease(uint64_t release) { - if (sync_point_client_->client_state()->IsFenceSyncReleased(release)) { - DLOG(ERROR) << "Fence Sync has already been released."; - return; - } - - gpu::gles2::MailboxManager* mailbox_manager = - context_group_->mailbox_manager(); - if (mailbox_manager->UsesSync() && MakeCurrent()) { - gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0, - command_buffer_id_, release); - mailbox_manager->PushTextureUpdates(sync_token); - } - - sync_point_client_->ReleaseFenceSync(release); -} - -bool GpuCommandBufferStub::OnWaitFenceSync( - gpu::CommandBufferNamespace namespace_id, - uint64_t command_buffer_id, - uint64_t release) { - DCHECK(!waiting_for_sync_point_); - DCHECK(scheduler_->scheduled()); - - scoped_refptr<gpu::SyncPointClientState> release_state = - sync_point_manager_->GetSyncPointClientState(namespace_id, - command_buffer_id); - - if (!release_state) - return true; - - if (release_state->IsFenceSyncReleased(release)) { - PullTextureUpdates(namespace_id, command_buffer_id, release); - return true; - } - - TRACE_EVENT_ASYNC_BEGIN1("gpu", "WaitFenceSync", this, "GpuCommandBufferStub", - this); - waiting_for_sync_point_ = true; - sync_point_client_->WaitNonThreadSafe( - release_state.get(), release, task_runner_, - base::Bind(&GpuCommandBufferStub::OnWaitFenceSyncCompleted, - this->AsWeakPtr(), namespace_id, command_buffer_id, release)); - - if (!waiting_for_sync_point_) - return true; - - scheduler_->SetScheduled(false); - return false; -} - -void GpuCommandBufferStub::OnWaitFenceSyncCompleted( - gpu::CommandBufferNamespace namespace_id, - uint64_t command_buffer_id, - uint64_t release) { - DCHECK(waiting_for_sync_point_); - TRACE_EVENT_ASYNC_END1("gpu", "WaitFenceSync", this, "GpuCommandBufferStub", - this); - PullTextureUpdates(namespace_id, command_buffer_id, release); - waiting_for_sync_point_ = false; - scheduler_->SetScheduled(true); -} - -void GpuCommandBufferStub::OnCreateImage( - const GpuCommandBufferMsg_CreateImage_Params& params) { - TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnCreateImage"); - const int32_t id = params.id; - const gfx::GpuMemoryBufferHandle& handle = params.gpu_memory_buffer; - const gfx::Size& size = params.size; - const gfx::BufferFormat& format = params.format; - const uint32_t internalformat = params.internal_format; - const uint64_t image_release_count = params.image_release_count; - - if (!decoder_) - return; - - gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager(); - DCHECK(image_manager); - if (image_manager->LookupImage(id)) { - LOG(ERROR) << "Image already exists with same ID."; - return; - } - - if (!gpu::ImageFactory::IsGpuMemoryBufferFormatSupported( - format, decoder_->GetCapabilities())) { - LOG(ERROR) << "Format is not supported."; - return; - } - - if (!gpu::ImageFactory::IsImageSizeValidForGpuMemoryBufferFormat(size, - format)) { - LOG(ERROR) << "Invalid image size for format."; - return; - } - - if (!gpu::ImageFactory::IsImageFormatCompatibleWithGpuMemoryBufferFormat( - internalformat, format)) { - LOG(ERROR) << "Incompatible image format."; - return; - } - - scoped_refptr<gl::GLImage> image = channel()->CreateImageForGpuMemoryBuffer( - handle, size, format, internalformat); - if (!image.get()) - return; - - image_manager->AddImage(image.get(), id); - if (image_release_count) { - sync_point_client_->ReleaseFenceSync(image_release_count); - } -} - -void GpuCommandBufferStub::OnDestroyImage(int32_t id) { - TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnDestroyImage"); - - if (!decoder_) - return; - - gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager(); - DCHECK(image_manager); - if (!image_manager->LookupImage(id)) { - LOG(ERROR) << "Image with ID doesn't exist."; - return; - } - - image_manager->RemoveImage(id); -} - -void GpuCommandBufferStub::SendConsoleMessage(int32_t id, - const std::string& message) { - GPUCommandBufferConsoleMessage console_message; - console_message.id = id; - console_message.message = message; - IPC::Message* msg = new GpuCommandBufferMsg_ConsoleMsg( - route_id_, console_message); - msg->set_unblock(true); - Send(msg); -} - -void GpuCommandBufferStub::SendCachedShader( - const std::string& key, const std::string& shader) { - channel_->CacheShader(key, shader); -} - -void GpuCommandBufferStub::AddDestructionObserver( - DestructionObserver* observer) { - destruction_observers_.AddObserver(observer); -} - -void GpuCommandBufferStub::RemoveDestructionObserver( - DestructionObserver* observer) { - destruction_observers_.RemoveObserver(observer); -} - -const gpu::gles2::FeatureInfo* GpuCommandBufferStub::GetFeatureInfo() const { - return context_group_->feature_info(); -} - -gpu::gles2::MemoryTracker* GpuCommandBufferStub::GetMemoryTracker() const { - return context_group_->memory_tracker(); -} - -bool GpuCommandBufferStub::CheckContextLost() { - DCHECK(command_buffer_); - gpu::CommandBuffer::State state = command_buffer_->GetLastState(); - bool was_lost = state.error == gpu::error::kLostContext; - - if (was_lost) { - bool was_lost_by_robustness = - decoder_ && decoder_->WasContextLostByRobustnessExtension(); - - // Work around issues with recovery by allowing a new GPU process to launch. - if ((was_lost_by_robustness || - context_group_->feature_info()->workarounds().exit_on_context_lost) && - !base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kSingleProcess) && - !base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kInProcessGPU)) { - LOG(ERROR) << "Exiting GPU process because some drivers cannot recover" - << " from problems."; -#if defined(OS_WIN) - base::win::SetShouldCrashOnProcessDetach(false); -#endif - exit(0); - } - - // Lose all other contexts if the reset was triggered by the robustness - // extension instead of being synthetic. - if (was_lost_by_robustness && - (gfx::GLContext::LosesAllContextsOnContextLost() || - use_virtualized_gl_context_)) { - channel_->LoseAllContexts(); - } - } - - CheckCompleteWaits(); - return was_lost; -} - -void GpuCommandBufferStub::MarkContextLost() { - if (!command_buffer_ || - command_buffer_->GetLastState().error == gpu::error::kLostContext) - return; - - command_buffer_->SetContextLostReason(gpu::error::kUnknown); - if (decoder_) - decoder_->MarkContextLost(gpu::error::kUnknown); - command_buffer_->SetParseError(gpu::error::kLostContext); -} - -void GpuCommandBufferStub::SendSwapBuffersCompleted( - const std::vector<ui::LatencyInfo>& latency_info, - gfx::SwapResult result) { - Send(new GpuCommandBufferMsg_SwapBuffersCompleted(route_id_, latency_info, - result)); -} - -void GpuCommandBufferStub::SendUpdateVSyncParameters(base::TimeTicks timebase, - base::TimeDelta interval) { - Send(new GpuCommandBufferMsg_UpdateVSyncParameters(route_id_, timebase, - interval)); -} - -} // namespace content diff --git a/chromium/content/common/gpu/gpu_command_buffer_stub.h b/chromium/content/common/gpu/gpu_command_buffer_stub.h deleted file mode 100644 index a9374d7b0ec..00000000000 --- a/chromium/content/common/gpu/gpu_command_buffer_stub.h +++ /dev/null @@ -1,307 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_GPU_GPU_COMMAND_BUFFER_STUB_H_ -#define CONTENT_COMMON_GPU_GPU_COMMAND_BUFFER_STUB_H_ - -#include <stddef.h> -#include <stdint.h> - -#include <deque> -#include <string> -#include <vector> - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/observer_list.h" -#include "base/time/time.h" -#include "content/common/content_export.h" -#include "content/common/gpu/gpu_memory_manager.h" -#include "gpu/command_buffer/common/constants.h" -#include "gpu/command_buffer/common/gpu_memory_allocation.h" -#include "gpu/command_buffer/service/command_buffer_service.h" -#include "gpu/command_buffer/service/context_group.h" -#include "gpu/command_buffer/service/gpu_scheduler.h" -#include "ipc/ipc_listener.h" -#include "ipc/ipc_sender.h" -#include "media/video/video_decode_accelerator.h" -#include "ui/events/latency_info.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/gpu_memory_buffer.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gfx/swap_result.h" -#include "ui/gl/gl_surface.h" -#include "ui/gl/gpu_preference.h" -#include "url/gurl.h" - -namespace gpu { -struct Mailbox; -struct SyncToken; -class SyncPointClient; -class SyncPointManager; -class ValueStateMap; -namespace gles2 { -class MailboxManager; -class SubscriptionRefSet; -} -} - -struct GpuCommandBufferMsg_CreateImage_Params; - -namespace content { - -class GpuChannel; -class GpuVideoDecodeAccelerator; -class GpuVideoEncodeAccelerator; -class GpuWatchdog; -struct WaitForCommandState; - -class GpuCommandBufferStub - : public IPC::Listener, - public IPC::Sender, - public base::SupportsWeakPtr<GpuCommandBufferStub> { - public: - class DestructionObserver { - public: - // Called in Destroy(), before the context/surface are released. - virtual void OnWillDestroyStub() = 0; - - protected: - virtual ~DestructionObserver() {} - }; - - typedef base::Callback<void(const std::vector<ui::LatencyInfo>&)> - LatencyInfoCallback; - - GpuCommandBufferStub( - GpuChannel* channel, - gpu::SyncPointManager* sync_point_manager, - base::SingleThreadTaskRunner* task_runner, - GpuCommandBufferStub* share_group, - const gfx::GLSurfaceHandle& handle, - gpu::gles2::MailboxManager* mailbox_manager, - gpu::PreemptionFlag* preempt_by_flag, - gpu::gles2::SubscriptionRefSet* subscription_ref_set, - gpu::ValueStateMap* pending_valuebuffer_state, - const gfx::Size& size, - const gpu::gles2::DisallowedFeatures& disallowed_features, - const std::vector<int32_t>& attribs, - gfx::GpuPreference gpu_preference, - int32_t stream_id, - int32_t route_id, - bool offscreen, - GpuWatchdog* watchdog, - const GURL& active_url); - - ~GpuCommandBufferStub() override; - - // IPC::Listener implementation: - bool OnMessageReceived(const IPC::Message& message) override; - - // IPC::Sender implementation: - bool Send(IPC::Message* msg) override; - - gpu::gles2::MemoryTracker* GetMemoryTracker() const; - - // Whether this command buffer can currently handle IPC messages. - bool IsScheduled(); - - // Whether there are commands in the buffer that haven't been processed. - bool HasUnprocessedCommands(); - - gpu::gles2::GLES2Decoder* decoder() const { return decoder_.get(); } - gpu::GpuScheduler* scheduler() const { return scheduler_.get(); } - GpuChannel* channel() const { return channel_; } - - // Unique command buffer ID for this command buffer stub. - uint64_t command_buffer_id() const { return command_buffer_id_; } - - // Identifies the various GpuCommandBufferStubs in the GPU process belonging - // to the same renderer process. - int32_t route_id() const { return route_id_; } - - // Identifies the stream for this command buffer. - int32_t stream_id() const { return stream_id_; } - - gfx::GpuPreference gpu_preference() { return gpu_preference_; } - - int32_t GetRequestedAttribute(int attr) const; - - // Sends a message to the console. - void SendConsoleMessage(int32_t id, const std::string& message); - - void SendCachedShader(const std::string& key, const std::string& shader); - - gfx::GLSurface* surface() const { return surface_.get(); } - - void AddDestructionObserver(DestructionObserver* observer); - void RemoveDestructionObserver(DestructionObserver* observer); - - // Associates a sync point to this stub. When the stub is destroyed, it will - // retire all sync points that haven't been previously retired. - void InsertSyncPoint(uint32_t sync_point, bool retire); - - void SetLatencyInfoCallback(const LatencyInfoCallback& callback); - - void MarkContextLost(); - - const gpu::gles2::FeatureInfo* GetFeatureInfo() const; - - void SendSwapBuffersCompleted( - const std::vector<ui::LatencyInfo>& latency_info, - gfx::SwapResult result); - void SendUpdateVSyncParameters(base::TimeTicks timebase, - base::TimeDelta interval); - - private: - GpuMemoryManager* GetMemoryManager() const; - - void Destroy(); - - bool MakeCurrent(); - - // Cleans up and sends reply if OnInitialize failed. - void OnInitializeFailed(IPC::Message* reply_message); - - // Message handlers: - void OnInitialize(base::SharedMemoryHandle shared_state_shm, - IPC::Message* reply_message); - void OnSetGetBuffer(int32_t shm_id, IPC::Message* reply_message); - void OnProduceFrontBuffer(const gpu::Mailbox& mailbox); - void OnGetState(IPC::Message* reply_message); - void OnWaitForTokenInRange(int32_t start, - int32_t end, - IPC::Message* reply_message); - void OnWaitForGetOffsetInRange(int32_t start, - int32_t end, - IPC::Message* reply_message); - void OnAsyncFlush(int32_t put_offset, - uint32_t flush_count, - const std::vector<ui::LatencyInfo>& latency_info); - void OnRegisterTransferBuffer(int32_t id, - base::SharedMemoryHandle transfer_buffer, - uint32_t size); - void OnDestroyTransferBuffer(int32_t id); - void OnGetTransferBuffer(int32_t id, IPC::Message* reply_message); - - void OnCreateVideoDecoder(const media::VideoDecodeAccelerator::Config& config, - int32_t route_id, - IPC::Message* reply_message); - void OnCreateVideoEncoder(media::VideoPixelFormat input_format, - const gfx::Size& input_visible_size, - media::VideoCodecProfile output_profile, - uint32_t initial_bitrate, - int32_t route_id, - IPC::Message* reply_message); - - void OnEnsureBackbuffer(); - - void OnRetireSyncPoint(uint32_t sync_point); - bool OnWaitSyncPoint(uint32_t sync_point); - void OnWaitSyncPointCompleted(uint32_t sync_point); - void OnSignalSyncPoint(uint32_t sync_point, uint32_t id); - void OnSignalSyncToken(const gpu::SyncToken& sync_token, uint32_t id); - void OnSignalAck(uint32_t id); - void OnSignalQuery(uint32_t query, uint32_t id); - - void OnFenceSyncRelease(uint64_t release); - bool OnWaitFenceSync(gpu::CommandBufferNamespace namespace_id, - uint64_t command_buffer_id, - uint64_t release); - void OnWaitFenceSyncCompleted(gpu::CommandBufferNamespace namespace_id, - uint64_t command_buffer_id, - uint64_t release); - - void OnCreateImage(const GpuCommandBufferMsg_CreateImage_Params& params); - void OnDestroyImage(int32_t id); - void OnCreateStreamTexture(uint32_t texture_id, - int32_t stream_id, - bool* succeeded); - - void OnCommandProcessed(); - void OnParseError(); - void OnSchedulingChanged(bool scheduled); - - void ReportState(); - - // Wrapper for GpuScheduler::PutChanged that sets the crash report URL. - void PutChanged(); - - // Poll the command buffer to execute work. - void PollWork(); - void PerformWork(); - - // Schedule processing of delayed work. This updates the time at which - // delayed work should be processed. |process_delayed_work_time_| is - // updated to current time + delay. Call this after processing some amount - // of delayed work. - void ScheduleDelayedWork(base::TimeDelta delay); - - bool CheckContextLost(); - void CheckCompleteWaits(); - void PullTextureUpdates(gpu::CommandBufferNamespace namespace_id, - uint64_t command_buffer_id, - uint32_t release); - - // The lifetime of objects of this class is managed by a GpuChannel. The - // GpuChannels destroy all the GpuCommandBufferStubs that they own when they - // are destroyed. So a raw pointer is safe. - GpuChannel* channel_; - - // Outlives the stub. - gpu::SyncPointManager* sync_point_manager_; - - // Task runner for main thread. - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - - // The group of contexts that share namespaces with this context. - scoped_refptr<gpu::gles2::ContextGroup> context_group_; - - bool initialized_; - gfx::GLSurfaceHandle handle_; - gfx::Size initial_size_; - gpu::gles2::DisallowedFeatures disallowed_features_; - std::vector<int32_t> requested_attribs_; - gfx::GpuPreference gpu_preference_; - bool use_virtualized_gl_context_; - const uint64_t command_buffer_id_; - const int32_t stream_id_; - const int32_t route_id_; - const bool offscreen_; - uint32_t last_flush_count_; - - scoped_ptr<gpu::CommandBufferService> command_buffer_; - scoped_ptr<gpu::gles2::GLES2Decoder> decoder_; - scoped_ptr<gpu::GpuScheduler> scheduler_; - scoped_ptr<gpu::SyncPointClient> sync_point_client_; - scoped_refptr<gfx::GLSurface> surface_; - - GpuWatchdog* watchdog_; - - base::ObserverList<DestructionObserver> destruction_observers_; - - // A queue of sync points associated with this stub. - std::deque<uint32_t> sync_points_; - bool waiting_for_sync_point_; - - base::TimeTicks process_delayed_work_time_; - uint32_t previous_processed_num_; - base::TimeTicks last_idle_time_; - - scoped_refptr<gpu::PreemptionFlag> preemption_flag_; - - LatencyInfoCallback latency_info_callback_; - - GURL active_url_; - size_t active_url_hash_; - - scoped_ptr<WaitForCommandState> wait_for_token_; - scoped_ptr<WaitForCommandState> wait_for_get_offset_; - - DISALLOW_COPY_AND_ASSIGN(GpuCommandBufferStub); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_GPU_COMMAND_BUFFER_STUB_H_ diff --git a/chromium/content/common/gpu/gpu_config.h b/chromium/content/common/gpu/gpu_config.h deleted file mode 100644 index 74d5ee05b86..00000000000 --- a/chromium/content/common/gpu/gpu_config.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_GPU_GPU_CONFIG_H_ -#define CONTENT_COMMON_GPU_GPU_CONFIG_H_ - -// This file declares common preprocessor configuration for the GPU process. - -#include "build/build_config.h" - -#endif // CONTENT_COMMON_GPU_GPU_CONFIG_H_ diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory.cc deleted file mode 100644 index 8469e162178..00000000000 --- a/chromium/content/common/gpu/gpu_memory_buffer_factory.cc +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2014 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 "content/common/gpu/gpu_memory_buffer_factory.h" - -#include "base/logging.h" -#include "build/build_config.h" - -#if defined(OS_MACOSX) -#include "content/common/gpu/gpu_memory_buffer_factory_io_surface.h" -#endif - -#if defined(OS_ANDROID) -#include "content/common/gpu/gpu_memory_buffer_factory_surface_texture.h" -#endif - -#if defined(USE_OZONE) -#include "content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.h" -#endif - -namespace content { - -// static -gfx::GpuMemoryBufferType GpuMemoryBufferFactory::GetNativeType() { -#if defined(OS_MACOSX) - return gfx::IO_SURFACE_BUFFER; -#endif -#if defined(OS_ANDROID) - return gfx::SURFACE_TEXTURE_BUFFER; -#endif -#if defined(USE_OZONE) - return gfx::OZONE_NATIVE_PIXMAP; -#endif - return gfx::EMPTY_BUFFER; -} - -// static -scoped_ptr<GpuMemoryBufferFactory> GpuMemoryBufferFactory::CreateNativeType() { -#if defined(OS_MACOSX) - return make_scoped_ptr(new GpuMemoryBufferFactoryIOSurface); -#endif -#if defined(OS_ANDROID) - return make_scoped_ptr(new GpuMemoryBufferFactorySurfaceTexture); -#endif -#if defined(USE_OZONE) - return make_scoped_ptr(new GpuMemoryBufferFactoryOzoneNativePixmap); -#endif - NOTREACHED(); - return nullptr; -} - -} // namespace content diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory.h b/chromium/content/common/gpu/gpu_memory_buffer_factory.h deleted file mode 100644 index 77a50f2775c..00000000000 --- a/chromium/content/common/gpu/gpu_memory_buffer_factory.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2014 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 CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_H_ -#define CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_H_ - -#include <vector> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "content/common/content_export.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/gpu_memory_buffer.h" -#include "ui/gfx/native_widget_types.h" - -namespace gpu { -class ImageFactory; -} - -namespace content { - -class CONTENT_EXPORT GpuMemoryBufferFactory { - public: - virtual ~GpuMemoryBufferFactory() {} - - // Returns the native GPU memory buffer factory type. Returns EMPTY_BUFFER - // type if native buffers are not supported. - static gfx::GpuMemoryBufferType GetNativeType(); - - // Creates a new factory instance for native GPU memory buffers. - static scoped_ptr<GpuMemoryBufferFactory> CreateNativeType(); - - // Creates a new GPU memory buffer instance. A valid handle is returned on - // success. It can be called on any thread. - virtual gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - int client_id, - gfx::PluginWindowHandle surface_handle) = 0; - - // Creates a new GPU memory buffer instance from an existing handle. A valid - // handle is returned on success. It can be called on any thread. - virtual gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - int client_id) = 0; - - // Destroys GPU memory buffer identified by |id|. - // It can be called on any thread. - virtual void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, - int client_id) = 0; - - // Type-checking downcast routine. - virtual gpu::ImageFactory* AsImageFactory() = 0; - - protected: - GpuMemoryBufferFactory() {} - - private: - DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferFactory); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_H_ diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc deleted file mode 100644 index 49fab37b596..00000000000 --- a/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2014 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 "content/common/gpu/gpu_memory_buffer_factory_io_surface.h" - -#include <vector> - -#include "base/logging.h" -#include "content/common/gpu/client/gpu_memory_buffer_impl.h" -#include "ui/gfx/buffer_format_util.h" -#include "ui/gfx/mac/io_surface.h" -#include "ui/gl/gl_image_io_surface.h" - -namespace content { - -GpuMemoryBufferFactoryIOSurface::GpuMemoryBufferFactoryIOSurface() { -} - -GpuMemoryBufferFactoryIOSurface::~GpuMemoryBufferFactoryIOSurface() { -} - -// static -bool GpuMemoryBufferFactoryIOSurface::IsGpuMemoryBufferConfigurationSupported( - gfx::BufferFormat format, - gfx::BufferUsage usage) { - switch (usage) { - case gfx::BufferUsage::GPU_READ: - case gfx::BufferUsage::SCANOUT: - return format == gfx::BufferFormat::BGRA_8888 || - format == gfx::BufferFormat::RGBA_8888; - case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE: - case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT: - return format == gfx::BufferFormat::R_8 || - format == gfx::BufferFormat::BGRA_8888 || - format == gfx::BufferFormat::UYVY_422 || - format == gfx::BufferFormat::YUV_420_BIPLANAR; - } - NOTREACHED(); - return false; -} - -gfx::GpuMemoryBufferHandle -GpuMemoryBufferFactoryIOSurface::CreateGpuMemoryBuffer( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - int client_id, - gfx::PluginWindowHandle surface_handle) { - base::ScopedCFTypeRef<IOSurfaceRef> io_surface( - gfx::CreateIOSurface(size, format)); - if (!io_surface) - return gfx::GpuMemoryBufferHandle(); - - { - base::AutoLock lock(io_surfaces_lock_); - - IOSurfaceMapKey key(id, client_id); - DCHECK(io_surfaces_.find(key) == io_surfaces_.end()); - io_surfaces_[key] = io_surface; - } - - gfx::GpuMemoryBufferHandle handle; - handle.type = gfx::IO_SURFACE_BUFFER; - handle.id = id; - handle.mach_port.reset(IOSurfaceCreateMachPort(io_surface)); - return handle; -} - -gfx::GpuMemoryBufferHandle -GpuMemoryBufferFactoryIOSurface::CreateGpuMemoryBufferFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - int client_id) { - NOTIMPLEMENTED(); - return gfx::GpuMemoryBufferHandle(); -} - -void GpuMemoryBufferFactoryIOSurface::DestroyGpuMemoryBuffer( - gfx::GpuMemoryBufferId id, - int client_id) { - { - base::AutoLock lock(io_surfaces_lock_); - - IOSurfaceMapKey key(id, client_id); - DCHECK(io_surfaces_.find(key) != io_surfaces_.end()); - io_surfaces_.erase(key); - } -} - -gpu::ImageFactory* GpuMemoryBufferFactoryIOSurface::AsImageFactory() { - return this; -} - -scoped_refptr<gl::GLImage> -GpuMemoryBufferFactoryIOSurface::CreateImageForGpuMemoryBuffer( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - unsigned internalformat, - int client_id) { - base::AutoLock lock(io_surfaces_lock_); - - DCHECK_EQ(handle.type, gfx::IO_SURFACE_BUFFER); - IOSurfaceMapKey key(handle.id, client_id); - IOSurfaceMap::iterator it = io_surfaces_.find(key); - if (it == io_surfaces_.end()) - return scoped_refptr<gl::GLImage>(); - - scoped_refptr<gl::GLImageIOSurface> image( - new gl::GLImageIOSurface(size, internalformat)); - if (!image->Initialize(it->second.get(), handle.id, format)) - return scoped_refptr<gl::GLImage>(); - - return image; -} - -} // namespace content diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface.h b/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface.h deleted file mode 100644 index d2fd00dbe3d..00000000000 --- a/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2014 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 CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_IO_SURFACE_H_ -#define CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_IO_SURFACE_H_ - -#include <utility> - -#include <IOSurface/IOSurface.h> - -#include "base/containers/hash_tables.h" -#include "base/mac/scoped_cftyperef.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/synchronization/lock.h" -#include "content/common/content_export.h" -#include "content/common/gpu/gpu_memory_buffer_factory.h" -#include "gpu/command_buffer/service/image_factory.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/gpu_memory_buffer.h" -#include "ui/gfx/mac/io_surface.h" - -namespace gl { -class GLImage; -} - -namespace content { - -class CONTENT_EXPORT GpuMemoryBufferFactoryIOSurface - : public GpuMemoryBufferFactory, - public gpu::ImageFactory { - public: - GpuMemoryBufferFactoryIOSurface(); - ~GpuMemoryBufferFactoryIOSurface() override; - - static bool IsGpuMemoryBufferConfigurationSupported(gfx::BufferFormat format, - gfx::BufferUsage usage); - - // Overridden from GpuMemoryBufferFactory: - gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - int client_id, - gfx::PluginWindowHandle surface_handle) override; - gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - int client_id) override; - void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, - int client_id) override; - gpu::ImageFactory* AsImageFactory() override; - - // Overridden from gpu::ImageFactory: - scoped_refptr<gl::GLImage> CreateImageForGpuMemoryBuffer( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - unsigned internalformat, - int client_id) override; - - private: - typedef std::pair<gfx::IOSurfaceId, int> IOSurfaceMapKey; - typedef base::hash_map<IOSurfaceMapKey, base::ScopedCFTypeRef<IOSurfaceRef>> - IOSurfaceMap; - // TOOD(reveman): Remove |io_surfaces_| and allow IOSurface backed GMBs to be - // used with any GPU process by passing a mach_port to CreateImageCHROMIUM. - IOSurfaceMap io_surfaces_; - base::Lock io_surfaces_lock_; - - DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferFactoryIOSurface); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_IO_SURFACE_H_ diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface_unittest.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface_unittest.cc deleted file mode 100644 index 7f4a13257f4..00000000000 --- a/chromium/content/common/gpu/gpu_memory_buffer_factory_io_surface_unittest.cc +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 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 "content/common/gpu/gpu_memory_buffer_factory_io_surface.h" -#include "content/test/gpu_memory_buffer_factory_test_template.h" - -namespace content { -namespace { - -INSTANTIATE_TYPED_TEST_CASE_P(GpuMemoryBufferFactoryIOSurface, - GpuMemoryBufferFactoryTest, - GpuMemoryBufferFactoryIOSurface); - -} // namespace -} // namespace content diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.cc deleted file mode 100644 index 69fdd3085cb..00000000000 --- a/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.cc +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2014 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 "content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.h" - -#include "ui/gl/gl_image_ozone_native_pixmap.h" -#include "ui/ozone/public/client_native_pixmap.h" -#include "ui/ozone/public/client_native_pixmap_factory.h" -#include "ui/ozone/public/ozone_platform.h" -#include "ui/ozone/public/surface_factory_ozone.h" - -namespace content { - -GpuMemoryBufferFactoryOzoneNativePixmap:: - GpuMemoryBufferFactoryOzoneNativePixmap() {} - -GpuMemoryBufferFactoryOzoneNativePixmap:: - ~GpuMemoryBufferFactoryOzoneNativePixmap() {} - -// static -bool GpuMemoryBufferFactoryOzoneNativePixmap:: - IsGpuMemoryBufferConfigurationSupported(gfx::BufferFormat format, - gfx::BufferUsage usage) { - if (!ui::ClientNativePixmapFactory::GetInstance()) { - // unittests don't have to set ClientNativePixmapFactory. - return false; - } - return ui::ClientNativePixmapFactory::GetInstance()->IsConfigurationSupported( - format, usage); -} - -gfx::GpuMemoryBufferHandle -GpuMemoryBufferFactoryOzoneNativePixmap::CreateGpuMemoryBuffer( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - int client_id, - gfx::PluginWindowHandle surface_handle) { - scoped_refptr<ui::NativePixmap> pixmap = - ui::OzonePlatform::GetInstance() - ->GetSurfaceFactoryOzone() - ->CreateNativePixmap(surface_handle, size, format, usage); - if (!pixmap.get()) { - DLOG(ERROR) << "Failed to create pixmap " << size.width() << "x" - << size.height() << " format " << static_cast<int>(format) - << ", usage " << static_cast<int>(usage); - return gfx::GpuMemoryBufferHandle(); - } - - gfx::GpuMemoryBufferHandle new_handle; - new_handle.type = gfx::OZONE_NATIVE_PIXMAP; - new_handle.id = id; - new_handle.native_pixmap_handle = pixmap->ExportHandle(); - - { - base::AutoLock lock(native_pixmaps_lock_); - NativePixmapMapKey key(id.id, client_id); - DCHECK(native_pixmaps_.find(key) == native_pixmaps_.end()); - native_pixmaps_[key] = pixmap; - } - - return new_handle; -} - -gfx::GpuMemoryBufferHandle -GpuMemoryBufferFactoryOzoneNativePixmap::CreateGpuMemoryBufferFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - int client_id) { - scoped_refptr<ui::NativePixmap> pixmap = - ui::OzonePlatform::GetInstance() - ->GetSurfaceFactoryOzone() - ->CreateNativePixmapFromHandle(handle.native_pixmap_handle); - if (!pixmap.get()) { - DLOG(ERROR) << "Failed to create pixmap from handle"; - return gfx::GpuMemoryBufferHandle(); - } - - gfx::GpuMemoryBufferHandle new_handle; - new_handle.type = gfx::OZONE_NATIVE_PIXMAP; - new_handle.id = id; - new_handle.native_pixmap_handle = pixmap->ExportHandle(); - - { - base::AutoLock lock(native_pixmaps_lock_); - NativePixmapMapKey key(id.id, client_id); - DCHECK(native_pixmaps_.find(key) == native_pixmaps_.end()); - native_pixmaps_[key] = pixmap; - } - - return new_handle; -} - -void GpuMemoryBufferFactoryOzoneNativePixmap::DestroyGpuMemoryBuffer( - gfx::GpuMemoryBufferId id, - int client_id) { - base::AutoLock lock(native_pixmaps_lock_); - auto it = native_pixmaps_.find(NativePixmapMapKey(id.id, client_id)); - DCHECK(it != native_pixmaps_.end()); - native_pixmaps_.erase(it); -} - -gpu::ImageFactory* GpuMemoryBufferFactoryOzoneNativePixmap::AsImageFactory() { - return this; -} - -scoped_refptr<gl::GLImage> -GpuMemoryBufferFactoryOzoneNativePixmap::CreateImageForGpuMemoryBuffer( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - unsigned internalformat, - int client_id) { - DCHECK_EQ(handle.type, gfx::OZONE_NATIVE_PIXMAP); - scoped_refptr<ui::NativePixmap> pixmap; - { - base::AutoLock lock(native_pixmaps_lock_); - NativePixmapMap::iterator it = - native_pixmaps_.find(NativePixmapMapKey(handle.id.id, client_id)); - if (it == native_pixmaps_.end()) { - return nullptr; - } - pixmap = it->second; - } - - scoped_refptr<gfx::GLImageOzoneNativePixmap> image( - new gfx::GLImageOzoneNativePixmap(size, internalformat)); - if (!image->Initialize(pixmap.get(), format)) { - LOG(ERROR) << "Failed to create GLImage"; - return nullptr; - } - return image; -} - -} // namespace content diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.h b/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.h deleted file mode 100644 index f9ea0d25b80..00000000000 --- a/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2014 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 CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_OZONE_NATIVE_PIXMAP_H_ -#define CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_OZONE_NATIVE_PIXMAP_H_ - -#include "base/containers/hash_tables.h" -#include "base/macros.h" -#include "base/synchronization/lock.h" -#include "content/common/content_export.h" -#include "content/common/gpu/gpu_memory_buffer_factory.h" -#include "gpu/command_buffer/service/image_factory.h" -#include "ui/ozone/public/native_pixmap.h" - -namespace gl { -class GLImage; -} - -namespace content { - -class CONTENT_EXPORT GpuMemoryBufferFactoryOzoneNativePixmap - : public GpuMemoryBufferFactory, - public gpu::ImageFactory { - public: - GpuMemoryBufferFactoryOzoneNativePixmap(); - ~GpuMemoryBufferFactoryOzoneNativePixmap() override; - - static bool IsGpuMemoryBufferConfigurationSupported(gfx::BufferFormat format, - gfx::BufferUsage usage); - - // Overridden from GpuMemoryBufferFactory: - gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - int client_id, - gfx::PluginWindowHandle surface_handle) override; - gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - int client_id) override; - void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, - int client_id) override; - gpu::ImageFactory* AsImageFactory() override; - - // Overridden from gpu::ImageFactory: - scoped_refptr<gl::GLImage> CreateImageForGpuMemoryBuffer( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - unsigned internalformat, - int client_id) override; - - private: - using NativePixmapMapKey = std::pair<int, int>; - using NativePixmapMap = - base::hash_map<NativePixmapMapKey, scoped_refptr<ui::NativePixmap>>; - NativePixmapMap native_pixmaps_; - base::Lock native_pixmaps_lock_; - - DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferFactoryOzoneNativePixmap); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_OZONE_NATIVE_PIXMAP_H_ diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap_unittest.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap_unittest.cc deleted file mode 100644 index bdb974702d9..00000000000 --- a/chromium/content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap_unittest.cc +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2015 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 "content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.h" -#include "content/test/gpu_memory_buffer_factory_test_template.h" - -namespace content { -namespace { - -INSTANTIATE_TYPED_TEST_CASE_P(GpuMemoryBufferFactoryOzoneNativePixmap, - GpuMemoryBufferFactoryTest, - GpuMemoryBufferFactoryOzoneNativePixmap); - -INSTANTIATE_TYPED_TEST_CASE_P(GpuMemoryBufferFactoryOzoneNativePixmap, - GpuMemoryBufferFactoryImportTest, - GpuMemoryBufferFactoryOzoneNativePixmap); - -} // namespace -} // namespace content diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture.cc deleted file mode 100644 index a4cf15ed30e..00000000000 --- a/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture.cc +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2014 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 "content/common/gpu/gpu_memory_buffer_factory_surface_texture.h" - -#include "content/common/android/surface_texture_manager.h" -#include "ui/gl/android/surface_texture.h" -#include "ui/gl/gl_image_surface_texture.h" - -namespace content { - -GpuMemoryBufferFactorySurfaceTexture::GpuMemoryBufferFactorySurfaceTexture() { -} - -GpuMemoryBufferFactorySurfaceTexture::~GpuMemoryBufferFactorySurfaceTexture() { -} - -// static -bool GpuMemoryBufferFactorySurfaceTexture:: - IsGpuMemoryBufferConfigurationSupported(gfx::BufferFormat format, - gfx::BufferUsage usage) { - switch (usage) { - case gfx::BufferUsage::GPU_READ: - case gfx::BufferUsage::SCANOUT: - case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT: - return false; - case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE: - return format == gfx::BufferFormat::RGBA_8888; - } - NOTREACHED(); - return false; -} - -gfx::GpuMemoryBufferHandle -GpuMemoryBufferFactorySurfaceTexture::CreateGpuMemoryBuffer( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - int client_id, - gfx::PluginWindowHandle surface_handle) { - // Note: this needs to be 0 as the surface texture implemenation will take - // ownership of the texture and call glDeleteTextures when the GPU service - // attaches the surface texture to a real texture id. glDeleteTextures - // silently ignores 0. - const int kDummyTextureId = 0; - scoped_refptr<gfx::SurfaceTexture> surface_texture = - gfx::SurfaceTexture::Create(kDummyTextureId); - if (!surface_texture.get()) - return gfx::GpuMemoryBufferHandle(); - - SurfaceTextureManager::GetInstance()->RegisterSurfaceTexture( - id.id, client_id, surface_texture.get()); - - { - base::AutoLock lock(surface_textures_lock_); - - SurfaceTextureMapKey key(id.id, client_id); - DCHECK(surface_textures_.find(key) == surface_textures_.end()); - surface_textures_[key] = surface_texture; - } - - gfx::GpuMemoryBufferHandle handle; - handle.type = gfx::SURFACE_TEXTURE_BUFFER; - handle.id = id; - return handle; -} - -gfx::GpuMemoryBufferHandle -GpuMemoryBufferFactorySurfaceTexture::CreateGpuMemoryBufferFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - int client_id) { - NOTIMPLEMENTED(); - return gfx::GpuMemoryBufferHandle(); -} - -void GpuMemoryBufferFactorySurfaceTexture::DestroyGpuMemoryBuffer( - gfx::GpuMemoryBufferId id, - int client_id) { - { - base::AutoLock lock(surface_textures_lock_); - - SurfaceTextureMapKey key(id.id, client_id); - DCHECK(surface_textures_.find(key) != surface_textures_.end()); - surface_textures_.erase(key); - } - - SurfaceTextureManager::GetInstance()->UnregisterSurfaceTexture(id.id, - client_id); -} - -gpu::ImageFactory* GpuMemoryBufferFactorySurfaceTexture::AsImageFactory() { - return this; -} - -scoped_refptr<gl::GLImage> -GpuMemoryBufferFactorySurfaceTexture::CreateImageForGpuMemoryBuffer( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - unsigned internalformat, - int client_id) { - base::AutoLock lock(surface_textures_lock_); - - DCHECK_EQ(handle.type, gfx::SURFACE_TEXTURE_BUFFER); - - SurfaceTextureMapKey key(handle.id.id, client_id); - SurfaceTextureMap::iterator it = surface_textures_.find(key); - if (it == surface_textures_.end()) - return scoped_refptr<gl::GLImage>(); - - scoped_refptr<gl::GLImageSurfaceTexture> image( - new gl::GLImageSurfaceTexture(size)); - if (!image->Initialize(it->second.get())) - return scoped_refptr<gl::GLImage>(); - - return image; -} - -} // namespace content diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture.h b/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture.h deleted file mode 100644 index b9eda55dcbd..00000000000 --- a/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2014 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 CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_SURFACE_TEXTURE_H_ -#define CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_SURFACE_TEXTURE_H_ - -#include <utility> - -#include "base/containers/hash_tables.h" -#include "base/memory/ref_counted.h" -#include "base/synchronization/lock.h" -#include "content/common/content_export.h" -#include "content/common/gpu/gpu_memory_buffer_factory.h" -#include "gpu/command_buffer/service/image_factory.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/gpu_memory_buffer.h" - -namespace gfx { -class SurfaceTexture; -} - -namespace gl { -class GLImage; -} - -namespace content { - -class CONTENT_EXPORT GpuMemoryBufferFactorySurfaceTexture - : public GpuMemoryBufferFactory, - public gpu::ImageFactory { - public: - GpuMemoryBufferFactorySurfaceTexture(); - ~GpuMemoryBufferFactorySurfaceTexture() override; - - static bool IsGpuMemoryBufferConfigurationSupported(gfx::BufferFormat format, - gfx::BufferUsage usage); - - // Overridden from GpuMemoryBufferFactory: - gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - int client_id, - gfx::PluginWindowHandle surface_handle) override; - gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferFromHandle( - const gfx::GpuMemoryBufferHandle& handle, - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - int client_id) override; - void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, - int client_id) override; - gpu::ImageFactory* AsImageFactory() override; - - // Overridden from gpu::ImageFactory: - scoped_refptr<gl::GLImage> CreateImageForGpuMemoryBuffer( - const gfx::GpuMemoryBufferHandle& handle, - const gfx::Size& size, - gfx::BufferFormat format, - unsigned internalformat, - int client_id) override; - - private: - typedef std::pair<int, int> SurfaceTextureMapKey; - typedef base::hash_map<SurfaceTextureMapKey, - scoped_refptr<gfx::SurfaceTexture>> SurfaceTextureMap; - SurfaceTextureMap surface_textures_; - base::Lock surface_textures_lock_; -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_GPU_MEMORY_BUFFER_FACTORY_SURFACE_TEXTURE_H_ diff --git a/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture_unittest.cc b/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture_unittest.cc deleted file mode 100644 index 683860fee17..00000000000 --- a/chromium/content/common/gpu/gpu_memory_buffer_factory_surface_texture_unittest.cc +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 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 "content/common/gpu/gpu_memory_buffer_factory_surface_texture.h" -#include "content/test/gpu_memory_buffer_factory_test_template.h" - -namespace content { -namespace { - -INSTANTIATE_TYPED_TEST_CASE_P(GpuMemoryBufferFactorySurfaceTexture, - GpuMemoryBufferFactoryTest, - GpuMemoryBufferFactorySurfaceTexture); - -} // namespace -} // namespace content diff --git a/chromium/content/common/gpu/gpu_memory_manager.cc b/chromium/content/common/gpu/gpu_memory_manager.cc deleted file mode 100644 index 4b9eb7c2888..00000000000 --- a/chromium/content/common/gpu/gpu_memory_manager.cc +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) 2012 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 "content/common/gpu/gpu_memory_manager.h" - -#include <algorithm> - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/message_loop/message_loop.h" -#include "base/process/process_handle.h" -#include "base/strings/string_number_conversions.h" -#include "base/trace_event/trace_event.h" -#include "content/common/gpu/gpu_channel_manager.h" -#include "content/common/gpu/gpu_memory_tracking.h" -#include "content/common/gpu/gpu_memory_uma_stats.h" -#include "content/common/gpu/gpu_messages.h" -#include "gpu/command_buffer/common/gpu_memory_allocation.h" -#include "gpu/command_buffer/service/gpu_switches.h" - -using gpu::MemoryAllocation; - -namespace content { -namespace { - -const uint64_t kBytesAllocatedStep = 16 * 1024 * 1024; - -void TrackValueChanged(uint64_t old_size, - uint64_t new_size, - uint64_t* total_size) { - DCHECK(new_size > old_size || *total_size >= (old_size - new_size)); - *total_size += (new_size - old_size); -} - -} - -GpuMemoryManager::GpuMemoryManager(GpuChannelManager* channel_manager) - : channel_manager_(channel_manager), - bytes_allocated_current_(0), - bytes_allocated_historical_max_(0) {} - -GpuMemoryManager::~GpuMemoryManager() { - DCHECK(tracking_groups_.empty()); - DCHECK(!bytes_allocated_current_); -} - -void GpuMemoryManager::TrackMemoryAllocatedChange( - GpuMemoryTrackingGroup* tracking_group, - uint64_t old_size, - uint64_t new_size) { - TrackValueChanged(old_size, new_size, &tracking_group->size_); - TrackValueChanged(old_size, new_size, &bytes_allocated_current_); - - if (GetCurrentUsage() > bytes_allocated_historical_max_ + - kBytesAllocatedStep) { - bytes_allocated_historical_max_ = GetCurrentUsage(); - // If we're blowing into new memory usage territory, spam the browser - // process with the most up-to-date information about our memory usage. - SendUmaStatsToBrowser(); - } -} - -bool GpuMemoryManager::EnsureGPUMemoryAvailable(uint64_t /* size_needed */) { - // TODO: Check if there is enough space. Lose contexts until there is. - return true; -} - -uint64_t GpuMemoryManager::GetTrackerMemoryUsage( - gpu::gles2::MemoryTracker* tracker) const { - TrackingGroupMap::const_iterator tracking_group_it = - tracking_groups_.find(tracker); - DCHECK(tracking_group_it != tracking_groups_.end()); - return tracking_group_it->second->GetSize(); -} - -GpuMemoryTrackingGroup* GpuMemoryManager::CreateTrackingGroup( - base::ProcessId pid, gpu::gles2::MemoryTracker* memory_tracker) { - GpuMemoryTrackingGroup* tracking_group = new GpuMemoryTrackingGroup( - pid, memory_tracker, this); - DCHECK(!tracking_groups_.count(tracking_group->GetMemoryTracker())); - tracking_groups_.insert(std::make_pair(tracking_group->GetMemoryTracker(), - tracking_group)); - return tracking_group; -} - -void GpuMemoryManager::OnDestroyTrackingGroup( - GpuMemoryTrackingGroup* tracking_group) { - DCHECK(tracking_groups_.count(tracking_group->GetMemoryTracker())); - tracking_groups_.erase(tracking_group->GetMemoryTracker()); -} - -void GpuMemoryManager::GetVideoMemoryUsageStats( - GPUVideoMemoryUsageStats* video_memory_usage_stats) const { - // For each context group, assign its memory usage to its PID - video_memory_usage_stats->process_map.clear(); - for (TrackingGroupMap::const_iterator i = - tracking_groups_.begin(); i != tracking_groups_.end(); ++i) { - const GpuMemoryTrackingGroup* tracking_group = i->second; - video_memory_usage_stats->process_map[ - tracking_group->GetPid()].video_memory += tracking_group->GetSize(); - } - - // Assign the total across all processes in the GPU process - video_memory_usage_stats->process_map[ - base::GetCurrentProcId()].video_memory = GetCurrentUsage(); - video_memory_usage_stats->process_map[ - base::GetCurrentProcId()].has_duplicates = true; - - video_memory_usage_stats->bytes_allocated = GetCurrentUsage(); - video_memory_usage_stats->bytes_allocated_historical_max = - bytes_allocated_historical_max_; -} - -void GpuMemoryManager::SendUmaStatsToBrowser() { - if (!channel_manager_) - return; - GPUMemoryUmaStats params; - params.bytes_allocated_current = GetCurrentUsage(); - params.bytes_allocated_max = bytes_allocated_historical_max_; - params.context_group_count = tracking_groups_.size(); - channel_manager_->Send(new GpuHostMsg_GpuMemoryUmaStats(params)); -} -} // namespace content diff --git a/chromium/content/common/gpu/gpu_memory_manager.h b/chromium/content/common/gpu/gpu_memory_manager.h deleted file mode 100644 index 7de22e5aa78..00000000000 --- a/chromium/content/common/gpu/gpu_memory_manager.h +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_GPU_GPU_MEMORY_MANAGER_H_ -#define CONTENT_COMMON_GPU_GPU_MEMORY_MANAGER_H_ - -#include <stdint.h> - -#include <list> -#include <map> - -#include "base/cancelable_callback.h" -#include "base/containers/hash_tables.h" -#include "base/gtest_prod_util.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "content/common/content_export.h" -#include "content/public/common/gpu_memory_stats.h" -#include "gpu/command_buffer/common/gpu_memory_allocation.h" -#include "gpu/command_buffer/service/memory_tracking.h" - -namespace content { - -class GpuChannelManager; -class GpuMemoryTrackingGroup; - -class CONTENT_EXPORT GpuMemoryManager : - public base::SupportsWeakPtr<GpuMemoryManager> { - public: - explicit GpuMemoryManager(GpuChannelManager* channel_manager); - ~GpuMemoryManager(); - - // Retrieve GPU Resource consumption statistics for the task manager - void GetVideoMemoryUsageStats( - content::GPUVideoMemoryUsageStats* video_memory_usage_stats) const; - - GpuMemoryTrackingGroup* CreateTrackingGroup( - base::ProcessId pid, gpu::gles2::MemoryTracker* memory_tracker); - - uint64_t GetTrackerMemoryUsage(gpu::gles2::MemoryTracker* tracker) const; - - private: - friend class GpuMemoryManagerTest; - friend class GpuMemoryTrackingGroup; - friend class GpuMemoryManagerClientState; - - typedef std::map<gpu::gles2::MemoryTracker*, GpuMemoryTrackingGroup*> - TrackingGroupMap; - - // Send memory usage stats to the browser process. - void SendUmaStatsToBrowser(); - - // Get the current number of bytes allocated. - uint64_t GetCurrentUsage() const { return bytes_allocated_current_; } - - // GpuMemoryTrackingGroup interface - void TrackMemoryAllocatedChange(GpuMemoryTrackingGroup* tracking_group, - uint64_t old_size, - uint64_t new_size); - void OnDestroyTrackingGroup(GpuMemoryTrackingGroup* tracking_group); - bool EnsureGPUMemoryAvailable(uint64_t size_needed); - - GpuChannelManager* channel_manager_; - - // All context groups' tracking structures - TrackingGroupMap tracking_groups_; - - // The current total memory usage, and historical maximum memory usage - uint64_t bytes_allocated_current_; - uint64_t bytes_allocated_historical_max_; - - DISALLOW_COPY_AND_ASSIGN(GpuMemoryManager); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_GPU_MEMORY_MANAGER_H_ diff --git a/chromium/content/common/gpu/gpu_memory_tracking.cc b/chromium/content/common/gpu/gpu_memory_tracking.cc deleted file mode 100644 index 6fa447b5b87..00000000000 --- a/chromium/content/common/gpu/gpu_memory_tracking.cc +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2012 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 "content/common/gpu/gpu_memory_tracking.h" - -#include "content/common/gpu/gpu_memory_manager.h" - -namespace content { - -GpuMemoryTrackingGroup::GpuMemoryTrackingGroup( - base::ProcessId pid, - gpu::gles2::MemoryTracker* memory_tracker, - GpuMemoryManager* memory_manager) - : pid_(pid), - size_(0), - hibernated_(false), - memory_tracker_(memory_tracker), - memory_manager_(memory_manager) { -} - -GpuMemoryTrackingGroup::~GpuMemoryTrackingGroup() { - memory_manager_->OnDestroyTrackingGroup(this); -} - -void GpuMemoryTrackingGroup::TrackMemoryAllocatedChange(uint64_t old_size, - uint64_t new_size) { - memory_manager_->TrackMemoryAllocatedChange( - this, old_size, new_size); -} - -bool GpuMemoryTrackingGroup::EnsureGPUMemoryAvailable(uint64_t size_needed) { - return memory_manager_->EnsureGPUMemoryAvailable(size_needed); -} - - -} // namespace content diff --git a/chromium/content/common/gpu/gpu_memory_tracking.h b/chromium/content/common/gpu/gpu_memory_tracking.h deleted file mode 100644 index 28892832f96..00000000000 --- a/chromium/content/common/gpu/gpu_memory_tracking.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_GPU_GPU_MEMORY_TRACKING_H_ -#define CONTENT_COMMON_GPU_GPU_MEMORY_TRACKING_H_ - -#include <stdint.h> - -#include "base/process/process.h" -#include "content/common/content_export.h" -#include "gpu/command_buffer/service/memory_tracking.h" - -namespace content { - -class GpuMemoryManager; - -// All decoders in a context group point to a single GpuMemoryTrackingGroup, -// which tracks GPU resource consumption for the entire context group. -class CONTENT_EXPORT GpuMemoryTrackingGroup { - public: - ~GpuMemoryTrackingGroup(); - void TrackMemoryAllocatedChange(uint64_t old_size, uint64_t new_size); - bool EnsureGPUMemoryAvailable(uint64_t size_needed); - base::ProcessId GetPid() const { - return pid_; - } - uint64_t GetSize() const { return size_; } - gpu::gles2::MemoryTracker* GetMemoryTracker() const { - return memory_tracker_; - } - - private: - friend class GpuMemoryManager; - - GpuMemoryTrackingGroup(base::ProcessId pid, - gpu::gles2::MemoryTracker* memory_tracker, - GpuMemoryManager* memory_manager); - - base::ProcessId pid_; - uint64_t size_; - - // Set and used only during the Manage function, to determine which - // non-surface clients should be hibernated. - bool hibernated_; - - gpu::gles2::MemoryTracker* memory_tracker_; - GpuMemoryManager* memory_manager_; -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_GPU_MEMORY_TRACKING_H_ diff --git a/chromium/content/common/gpu/gpu_memory_uma_stats.h b/chromium/content/common/gpu/gpu_memory_uma_stats.h deleted file mode 100644 index 15d874f195c..00000000000 --- a/chromium/content/common/gpu/gpu_memory_uma_stats.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_GPU_GPU_MEMORY_UMA_STATS_H_ -#define CONTENT_COMMON_GPU_GPU_MEMORY_UMA_STATS_H_ - -#include <stddef.h> - -namespace content { - -// Memory usage statistics send periodically to the browser process to report -// in UMA histograms if the GPU process crashes. -struct GPUMemoryUmaStats { - GPUMemoryUmaStats() - : bytes_allocated_current(0), - bytes_allocated_max(0), - context_group_count(0) { - } - - // The number of bytes currently allocated. - size_t bytes_allocated_current; - - // The maximum number of bytes ever allocated at once. - size_t bytes_allocated_max; - - // The number of context groups. - size_t context_group_count; -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_GPU_MEMORY_UMA_STATS_H_ diff --git a/chromium/content/common/gpu/gpu_messages.h b/chromium/content/common/gpu/gpu_messages.h deleted file mode 100644 index cfe01a347a7..00000000000 --- a/chromium/content/common/gpu/gpu_messages.h +++ /dev/null @@ -1,878 +0,0 @@ -// Copyright (c) 2012 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. - -// Multiply-included message file, hence no include guard here, but see below -// for a much smaller-than-usual include guard section. - -#include <stdint.h> - -#include <string> -#include <vector> - -#include "base/memory/shared_memory.h" -#include "build/build_config.h" -#include "content/common/content_export.h" -#include "content/common/content_param_traits.h" -#include "content/common/gpu/gpu_memory_uma_stats.h" -#include "content/common/gpu/gpu_process_launch_causes.h" -#include "content/common/gpu/gpu_result_codes.h" -#include "content/common/gpu/gpu_stream_priority.h" -#include "content/public/common/common_param_traits.h" -#include "content/public/common/gpu_memory_stats.h" -#include "gpu/command_buffer/common/capabilities.h" -#include "gpu/command_buffer/common/command_buffer.h" -#include "gpu/command_buffer/common/constants.h" -#include "gpu/command_buffer/common/gpu_memory_allocation.h" -#include "gpu/command_buffer/common/mailbox.h" -#include "gpu/command_buffer/common/sync_token.h" -#include "gpu/command_buffer/common/value_state.h" -#include "gpu/config/gpu_info.h" -#include "gpu/ipc/gpu_command_buffer_traits.h" -#include "ipc/ipc_channel_handle.h" -#include "ipc/ipc_message_macros.h" -#include "media/base/decrypt_config.h" -#include "media/base/video_types.h" -#include "media/video/jpeg_decode_accelerator.h" -#include "media/video/video_decode_accelerator.h" -#include "media/video/video_encode_accelerator.h" -#include "ui/events/latency_info.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/gpu_memory_buffer.h" -#include "ui/gfx/ipc/gfx_param_traits.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gfx/swap_result.h" -#include "ui/gl/gpu_preference.h" - -#if defined(OS_ANDROID) -#include "content/common/android/surface_texture_peer.h" -#elif defined(OS_MACOSX) -#include "ui/base/cocoa/remote_layer_api.h" -#include "ui/gfx/mac/io_surface.h" -#endif - -#undef IPC_MESSAGE_EXPORT -#define IPC_MESSAGE_EXPORT CONTENT_EXPORT - -#define IPC_MESSAGE_START GpuMsgStart - -IPC_ENUM_TRAITS_MAX_VALUE(content::CauseForGpuLaunch, - content::CAUSE_FOR_GPU_LAUNCH_MAX_ENUM - 1) -IPC_ENUM_TRAITS_MAX_VALUE(content::CreateCommandBufferResult, - content::CREATE_COMMAND_BUFFER_RESULT_LAST) -IPC_ENUM_TRAITS_MAX_VALUE(gfx::GpuPreference, - gfx::GpuPreferenceLast) -IPC_ENUM_TRAITS_MAX_VALUE(content::GpuStreamPriority, - content::GpuStreamPriority::LAST) -IPC_ENUM_TRAITS_MAX_VALUE(gfx::SurfaceType, - gfx::SURFACE_TYPE_LAST) -IPC_ENUM_TRAITS_MAX_VALUE(gfx::SwapResult, gfx::SwapResult::SWAP_RESULT_LAST) -IPC_ENUM_TRAITS_MAX_VALUE(gpu::MemoryAllocation::PriorityCutoff, - gpu::MemoryAllocation::CUTOFF_LAST) -IPC_ENUM_TRAITS_MAX_VALUE(gpu::error::ContextLostReason, - gpu::error::kContextLostReasonLast) -IPC_ENUM_TRAITS_MAX_VALUE(media::JpegDecodeAccelerator::Error, - media::JpegDecodeAccelerator::LARGEST_ERROR_ENUM) -IPC_ENUM_TRAITS_MAX_VALUE(media::VideoEncodeAccelerator::Error, - media::VideoEncodeAccelerator::kErrorMax) -IPC_ENUM_TRAITS_MIN_MAX_VALUE(media::VideoCodecProfile, - media::VIDEO_CODEC_PROFILE_MIN, - media::VIDEO_CODEC_PROFILE_MAX) -IPC_ENUM_TRAITS_MIN_MAX_VALUE(gpu::CollectInfoResult, - gpu::kCollectInfoNone, - gpu::kCollectInfoFatalFailure) -IPC_ENUM_TRAITS_MIN_MAX_VALUE(gpu::VideoCodecProfile, - gpu::VIDEO_CODEC_PROFILE_MIN, - gpu::VIDEO_CODEC_PROFILE_MAX) - -IPC_STRUCT_BEGIN(GPUCreateCommandBufferConfig) - IPC_STRUCT_MEMBER(int32_t, share_group_id) - IPC_STRUCT_MEMBER(int32_t, stream_id) - IPC_STRUCT_MEMBER(content::GpuStreamPriority, stream_priority) - IPC_STRUCT_MEMBER(std::vector<int>, attribs) - IPC_STRUCT_MEMBER(GURL, active_url) - IPC_STRUCT_MEMBER(gfx::GpuPreference, gpu_preference) -IPC_STRUCT_END() - -IPC_STRUCT_BEGIN(GpuMsg_EstablishChannel_Params) - IPC_STRUCT_MEMBER(int, client_id) - IPC_STRUCT_MEMBER(uint64_t, client_tracing_id) - IPC_STRUCT_MEMBER(bool, preempts) - IPC_STRUCT_MEMBER(bool, preempted) - IPC_STRUCT_MEMBER(bool, allow_future_sync_points) - IPC_STRUCT_MEMBER(bool, allow_real_time_streams) -IPC_STRUCT_END() - -IPC_STRUCT_BEGIN(GpuMsg_CreateGpuMemoryBuffer_Params) - IPC_STRUCT_MEMBER(gfx::GpuMemoryBufferId, id) - IPC_STRUCT_MEMBER(gfx::Size, size) - IPC_STRUCT_MEMBER(gfx::BufferFormat, format) - IPC_STRUCT_MEMBER(gfx::BufferUsage, usage) - IPC_STRUCT_MEMBER(int32_t, client_id) - IPC_STRUCT_MEMBER(gfx::PluginWindowHandle, surface_handle) -IPC_STRUCT_END() - -IPC_STRUCT_BEGIN(GpuMsg_CreateGpuMemoryBufferFromHandle_Params) - IPC_STRUCT_MEMBER(gfx::GpuMemoryBufferHandle, handle) - IPC_STRUCT_MEMBER(gfx::GpuMemoryBufferId, id) - IPC_STRUCT_MEMBER(gfx::Size, size) - IPC_STRUCT_MEMBER(gfx::BufferFormat, format) - IPC_STRUCT_MEMBER(int32_t, client_id) -IPC_STRUCT_END() - -#if defined(OS_MACOSX) -IPC_STRUCT_BEGIN(GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params) - IPC_STRUCT_MEMBER(int32_t, surface_id) - // Only one of ca_context_id or io_surface may be non-0. - IPC_STRUCT_MEMBER(CAContextID, ca_context_id) - IPC_STRUCT_MEMBER(gfx::ScopedRefCountedIOSurfaceMachPort, io_surface) - IPC_STRUCT_MEMBER(int32_t, route_id) - IPC_STRUCT_MEMBER(gfx::Size, size) - IPC_STRUCT_MEMBER(float, scale_factor) - IPC_STRUCT_MEMBER(std::vector<ui::LatencyInfo>, latency_info) -IPC_STRUCT_END() - -IPC_STRUCT_BEGIN(AcceleratedSurfaceMsg_BufferPresented_Params) - // The vsync parameters, to synchronize presentation with the display. - IPC_STRUCT_MEMBER(base::TimeTicks, vsync_timebase) - IPC_STRUCT_MEMBER(base::TimeDelta, vsync_interval) -IPC_STRUCT_END() -#endif - -IPC_STRUCT_BEGIN(AcceleratedJpegDecoderMsg_Decode_Params) - IPC_STRUCT_MEMBER(int32_t, input_buffer_id) - IPC_STRUCT_MEMBER(gfx::Size, coded_size) - IPC_STRUCT_MEMBER(base::SharedMemoryHandle, input_buffer_handle) - IPC_STRUCT_MEMBER(uint32_t, input_buffer_size) - IPC_STRUCT_MEMBER(base::SharedMemoryHandle, output_video_frame_handle) - IPC_STRUCT_MEMBER(uint32_t, output_buffer_size) -IPC_STRUCT_END() - -IPC_STRUCT_BEGIN(AcceleratedVideoDecoderMsg_Decode_Params) - IPC_STRUCT_MEMBER(int32_t, bitstream_buffer_id) - IPC_STRUCT_MEMBER(base::SharedMemoryHandle, buffer_handle) - IPC_STRUCT_MEMBER(uint32_t, size) - IPC_STRUCT_MEMBER(base::TimeDelta, presentation_timestamp) - IPC_STRUCT_MEMBER(std::string, key_id) - IPC_STRUCT_MEMBER(std::string, iv) - IPC_STRUCT_MEMBER(std::vector<media::SubsampleEntry>, subsamples) -IPC_STRUCT_END() - -IPC_STRUCT_BEGIN(AcceleratedVideoEncoderMsg_Encode_Params) - IPC_STRUCT_MEMBER(int32_t, frame_id) - IPC_STRUCT_MEMBER(base::TimeDelta, timestamp) - IPC_STRUCT_MEMBER(base::SharedMemoryHandle, buffer_handle) - IPC_STRUCT_MEMBER(uint32_t, buffer_offset) - IPC_STRUCT_MEMBER(uint32_t, buffer_size) - IPC_STRUCT_MEMBER(bool, force_keyframe) -IPC_STRUCT_END() - -IPC_STRUCT_BEGIN(AcceleratedVideoEncoderMsg_Encode_Params2) - IPC_STRUCT_MEMBER(int32_t, frame_id) - IPC_STRUCT_MEMBER(base::TimeDelta, timestamp) - IPC_STRUCT_MEMBER(std::vector<gfx::GpuMemoryBufferHandle>, - gpu_memory_buffer_handles) - IPC_STRUCT_MEMBER(gfx::Size, size) - IPC_STRUCT_MEMBER(bool, force_keyframe) -IPC_STRUCT_END() - -IPC_STRUCT_BEGIN(GPUCommandBufferConsoleMessage) - IPC_STRUCT_MEMBER(int32_t, id) - IPC_STRUCT_MEMBER(std::string, message) -IPC_STRUCT_END() - -#if defined(OS_ANDROID) -IPC_STRUCT_BEGIN(GpuStreamTextureMsg_MatrixChanged_Params) - IPC_STRUCT_MEMBER(float, m00) - IPC_STRUCT_MEMBER(float, m01) - IPC_STRUCT_MEMBER(float, m02) - IPC_STRUCT_MEMBER(float, m03) - IPC_STRUCT_MEMBER(float, m10) - IPC_STRUCT_MEMBER(float, m11) - IPC_STRUCT_MEMBER(float, m12) - IPC_STRUCT_MEMBER(float, m13) - IPC_STRUCT_MEMBER(float, m20) - IPC_STRUCT_MEMBER(float, m21) - IPC_STRUCT_MEMBER(float, m22) - IPC_STRUCT_MEMBER(float, m23) - IPC_STRUCT_MEMBER(float, m30) - IPC_STRUCT_MEMBER(float, m31) - IPC_STRUCT_MEMBER(float, m32) - IPC_STRUCT_MEMBER(float, m33) -IPC_STRUCT_END() -#endif - -IPC_STRUCT_BEGIN(GpuCommandBufferMsg_CreateImage_Params) - IPC_STRUCT_MEMBER(int32_t, id) - IPC_STRUCT_MEMBER(gfx::GpuMemoryBufferHandle, gpu_memory_buffer) - IPC_STRUCT_MEMBER(gfx::Size, size) - IPC_STRUCT_MEMBER(gfx::BufferFormat, format) - IPC_STRUCT_MEMBER(uint32_t, internal_format) - IPC_STRUCT_MEMBER(uint64_t, image_release_count) -IPC_STRUCT_END() - -IPC_STRUCT_TRAITS_BEGIN(gpu::DxDiagNode) - IPC_STRUCT_TRAITS_MEMBER(values) - IPC_STRUCT_TRAITS_MEMBER(children) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(gpu::GPUInfo::GPUDevice) - IPC_STRUCT_TRAITS_MEMBER(vendor_id) - IPC_STRUCT_TRAITS_MEMBER(device_id) - IPC_STRUCT_TRAITS_MEMBER(active) - IPC_STRUCT_TRAITS_MEMBER(vendor_string) - IPC_STRUCT_TRAITS_MEMBER(device_string) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(media::VideoDecodeAccelerator::Config) - IPC_STRUCT_TRAITS_MEMBER(profile) - IPC_STRUCT_TRAITS_MEMBER(is_encrypted) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(gpu::VideoDecodeAcceleratorSupportedProfile) - IPC_STRUCT_TRAITS_MEMBER(profile) - IPC_STRUCT_TRAITS_MEMBER(max_resolution) - IPC_STRUCT_TRAITS_MEMBER(min_resolution) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(gpu::VideoDecodeAcceleratorCapabilities) - IPC_STRUCT_TRAITS_MEMBER(supported_profiles) - IPC_STRUCT_TRAITS_MEMBER(flags) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(gpu::VideoEncodeAcceleratorSupportedProfile) - IPC_STRUCT_TRAITS_MEMBER(profile) - IPC_STRUCT_TRAITS_MEMBER(max_resolution) - IPC_STRUCT_TRAITS_MEMBER(max_framerate_numerator) - IPC_STRUCT_TRAITS_MEMBER(max_framerate_denominator) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(gpu::GPUInfo) - IPC_STRUCT_TRAITS_MEMBER(initialization_time) - IPC_STRUCT_TRAITS_MEMBER(optimus) - IPC_STRUCT_TRAITS_MEMBER(amd_switchable) - IPC_STRUCT_TRAITS_MEMBER(lenovo_dcute) - IPC_STRUCT_TRAITS_MEMBER(gpu) - IPC_STRUCT_TRAITS_MEMBER(secondary_gpus) - IPC_STRUCT_TRAITS_MEMBER(adapter_luid) - IPC_STRUCT_TRAITS_MEMBER(driver_vendor) - IPC_STRUCT_TRAITS_MEMBER(driver_version) - IPC_STRUCT_TRAITS_MEMBER(driver_date) - IPC_STRUCT_TRAITS_MEMBER(pixel_shader_version) - IPC_STRUCT_TRAITS_MEMBER(vertex_shader_version) - IPC_STRUCT_TRAITS_MEMBER(max_msaa_samples) - IPC_STRUCT_TRAITS_MEMBER(machine_model_name) - IPC_STRUCT_TRAITS_MEMBER(machine_model_version) - IPC_STRUCT_TRAITS_MEMBER(gl_version) - IPC_STRUCT_TRAITS_MEMBER(gl_vendor) - IPC_STRUCT_TRAITS_MEMBER(gl_renderer) - IPC_STRUCT_TRAITS_MEMBER(gl_extensions) - IPC_STRUCT_TRAITS_MEMBER(gl_ws_vendor) - IPC_STRUCT_TRAITS_MEMBER(gl_ws_version) - IPC_STRUCT_TRAITS_MEMBER(gl_ws_extensions) - IPC_STRUCT_TRAITS_MEMBER(gl_reset_notification_strategy) - IPC_STRUCT_TRAITS_MEMBER(can_lose_context) - IPC_STRUCT_TRAITS_MEMBER(software_rendering) - IPC_STRUCT_TRAITS_MEMBER(direct_rendering) - IPC_STRUCT_TRAITS_MEMBER(sandboxed) - IPC_STRUCT_TRAITS_MEMBER(process_crash_count) - IPC_STRUCT_TRAITS_MEMBER(in_process_gpu) - IPC_STRUCT_TRAITS_MEMBER(basic_info_state) - IPC_STRUCT_TRAITS_MEMBER(context_info_state) -#if defined(OS_WIN) - IPC_STRUCT_TRAITS_MEMBER(dx_diagnostics_info_state) - IPC_STRUCT_TRAITS_MEMBER(dx_diagnostics) -#endif - IPC_STRUCT_TRAITS_MEMBER(video_decode_accelerator_capabilities) - IPC_STRUCT_TRAITS_MEMBER(video_encode_accelerator_supported_profiles) - IPC_STRUCT_TRAITS_MEMBER(jpeg_decode_accelerator_supported) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(content::GPUVideoMemoryUsageStats::ProcessStats) - IPC_STRUCT_TRAITS_MEMBER(video_memory) - IPC_STRUCT_TRAITS_MEMBER(has_duplicates) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(content::GPUVideoMemoryUsageStats) - IPC_STRUCT_TRAITS_MEMBER(process_map) - IPC_STRUCT_TRAITS_MEMBER(bytes_allocated) - IPC_STRUCT_TRAITS_MEMBER(bytes_allocated_historical_max) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(content::GPUMemoryUmaStats) - IPC_STRUCT_TRAITS_MEMBER(bytes_allocated_current) - IPC_STRUCT_TRAITS_MEMBER(bytes_allocated_max) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(gpu::MemoryAllocation) - IPC_STRUCT_TRAITS_MEMBER(bytes_limit_when_visible) - IPC_STRUCT_TRAITS_MEMBER(priority_cutoff_when_visible) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(gfx::GLSurfaceHandle) - IPC_STRUCT_TRAITS_MEMBER(handle) - IPC_STRUCT_TRAITS_MEMBER(transport_type) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(media::SubsampleEntry) - IPC_STRUCT_TRAITS_MEMBER(clear_bytes) - IPC_STRUCT_TRAITS_MEMBER(cypher_bytes) -IPC_STRUCT_TRAITS_END() - -//------------------------------------------------------------------------------ -// GPU Messages -// These are messages from the browser to the GPU process. - -// Tells the GPU process to initialize itself. The browser explicitly -// requests this be done so that we are guaranteed that the channel is set -// up between the browser and GPU process before doing any work that might -// potentially crash the GPU process. Detection of the child process -// exiting abruptly is predicated on having the IPC channel set up. -IPC_MESSAGE_CONTROL0(GpuMsg_Initialize) - -// Tells the GPU process to shutdown itself. -IPC_MESSAGE_CONTROL0(GpuMsg_Finalize) - -// Tells the GPU process to create a new channel for communication with a -// given client. The channel name is returned in a -// GpuHostMsg_ChannelEstablished message. The client ID is passed so that -// the GPU process reuses an existing channel to that process if it exists. -// This ID is a unique opaque identifier generated by the browser process. -// The client_tracing_id is a unique ID used for the purposes of tracing. -IPC_MESSAGE_CONTROL1(GpuMsg_EstablishChannel, - GpuMsg_EstablishChannel_Params /* params */) - -// Tells the GPU process to close the channel identified by IPC channel -// handle. If no channel can be identified, do nothing. -IPC_MESSAGE_CONTROL1(GpuMsg_CloseChannel, - IPC::ChannelHandle /* channel_handle */) - -// Tells the GPU process to create a new command buffer that renders directly -// to a native view. A corresponding GpuCommandBufferStub is created. -IPC_MESSAGE_CONTROL4(GpuMsg_CreateViewCommandBuffer, - gfx::GLSurfaceHandle, /* compositing_surface */ - int32_t, /* client_id */ - GPUCreateCommandBufferConfig, /* init_params */ - int32_t /* route_id */) - -// Tells the GPU process to create a new gpu memory buffer. -IPC_MESSAGE_CONTROL1(GpuMsg_CreateGpuMemoryBuffer, - GpuMsg_CreateGpuMemoryBuffer_Params) - -// Tells the GPU process to create a new gpu memory buffer from an existing -// handle. -IPC_MESSAGE_CONTROL1(GpuMsg_CreateGpuMemoryBufferFromHandle, - GpuMsg_CreateGpuMemoryBufferFromHandle_Params) - -// Tells the GPU process to destroy buffer. -IPC_MESSAGE_CONTROL3(GpuMsg_DestroyGpuMemoryBuffer, - gfx::GpuMemoryBufferId, /* id */ - int32_t, /* client_id */ - gpu::SyncToken /* sync_token */) - -// Create and initialize a hardware jpeg decoder using the specified route_id. -// Created decoders should be freed with AcceleratedJpegDecoderMsg_Destroy when -// no longer needed. -IPC_SYNC_MESSAGE_CONTROL1_1(GpuMsg_CreateJpegDecoder, - int32_t /* route_id */, - bool /* succeeded */) - -// Tells the GPU process to create a context for collecting graphics card -// information. -IPC_MESSAGE_CONTROL0(GpuMsg_CollectGraphicsInfo) - -// Tells the GPU process to report video_memory information for the task manager -IPC_MESSAGE_CONTROL0(GpuMsg_GetVideoMemoryUsageStats) - -#if defined(OS_MACOSX) -// Tells the GPU process that the browser process has handled the swap -// buffers or post sub-buffer request. -IPC_MESSAGE_ROUTED1(AcceleratedSurfaceMsg_BufferPresented, - AcceleratedSurfaceMsg_BufferPresented_Params) -#endif - -#if defined(OS_ANDROID) -// Tells the GPU process to wake up the GPU because we're about to draw. -IPC_MESSAGE_CONTROL0(GpuMsg_WakeUpGpu) -#endif - -// Tells the GPU process to remove all contexts. -IPC_MESSAGE_CONTROL0(GpuMsg_Clean) - -// Tells the GPU process to crash. -IPC_MESSAGE_CONTROL0(GpuMsg_Crash) - -// Tells the GPU process to hang. -IPC_MESSAGE_CONTROL0(GpuMsg_Hang) - -// Tells the GPU process to disable the watchdog thread. -IPC_MESSAGE_CONTROL0(GpuMsg_DisableWatchdog) - -// Tells the GPU process that the browser has seen a GPU switch. -IPC_MESSAGE_CONTROL0(GpuMsg_GpuSwitched) - -// Sends an input event to the gpu service. -IPC_MESSAGE_CONTROL3(GpuMsg_UpdateValueState, - int, /* client_id */ - unsigned int, /* target */ - gpu::ValueState /* valuestate */) - -//------------------------------------------------------------------------------ -// GPU Host Messages -// These are messages to the browser. - -// A renderer sends this when it wants to create a connection to the GPU -// process. The browser will create the GPU process if necessary, and will -// return a handle to the channel via a GpuChannelEstablished message. -IPC_SYNC_MESSAGE_CONTROL1_3(GpuHostMsg_EstablishGpuChannel, - content::CauseForGpuLaunch, - int /* client id */, - IPC::ChannelHandle /* handle to channel */, - gpu::GPUInfo /* stats about GPU process*/) - -// Response from GPU to a GputMsg_Initialize message. -IPC_MESSAGE_CONTROL2(GpuHostMsg_Initialized, - bool /* result */, - ::gpu::GPUInfo /* gpu_info */) - -// Response from GPU to a GpuHostMsg_EstablishChannel message. -IPC_MESSAGE_CONTROL1(GpuHostMsg_ChannelEstablished, - IPC::ChannelHandle /* channel_handle */) - -// Message from GPU to notify to destroy the channel. -IPC_MESSAGE_CONTROL1(GpuHostMsg_DestroyChannel, int32_t /* client_id */) - -// Message to cache the given shader information. -IPC_MESSAGE_CONTROL3(GpuHostMsg_CacheShader, - int32_t /* client_id */, - std::string /* key */, - std::string /* shader */) - -// Message to the GPU that a shader was loaded from disk. -IPC_MESSAGE_CONTROL1(GpuMsg_LoadedShader, - std::string /* encoded shader */) - -// Respond from GPU to a GpuMsg_CreateViewCommandBuffer message. -IPC_MESSAGE_CONTROL1(GpuHostMsg_CommandBufferCreated, - content::CreateCommandBufferResult /* result */) - -// Response from GPU to a GpuMsg_CreateGpuMemoryBuffer message. -IPC_MESSAGE_CONTROL1(GpuHostMsg_GpuMemoryBufferCreated, - gfx::GpuMemoryBufferHandle /* handle */) - -// Response from GPU to a GpuMsg_CollectGraphicsInfo. -IPC_MESSAGE_CONTROL1(GpuHostMsg_GraphicsInfoCollected, - gpu::GPUInfo /* GPU logging stats */) - -// Response from GPU to a GpuMsg_GetVideoMemory. -IPC_MESSAGE_CONTROL1(GpuHostMsg_VideoMemoryUsageStats, - content::GPUVideoMemoryUsageStats /* GPU memory stats */) - -// Message from GPU to add a GPU log message to the about:gpu page. -IPC_MESSAGE_CONTROL3(GpuHostMsg_OnLogMessage, - int /*severity*/, - std::string /* header */, - std::string /* message */) - - -#if defined(OS_MACOSX) -// Tells the browser that an accelerated surface has swapped. -IPC_MESSAGE_CONTROL1(GpuHostMsg_AcceleratedSurfaceBuffersSwapped, - GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params) -#endif - -#if defined(OS_WIN) -IPC_MESSAGE_CONTROL2(GpuHostMsg_AcceleratedSurfaceCreatedChildWindow, - gfx::PluginWindowHandle /* parent_window */, - gfx::PluginWindowHandle /* child_window */) -#endif - -IPC_MESSAGE_CONTROL1(GpuHostMsg_DidCreateOffscreenContext, - GURL /* url */) - -IPC_MESSAGE_CONTROL3(GpuHostMsg_DidLoseContext, - bool /* offscreen */, - gpu::error::ContextLostReason /* reason */, - GURL /* url */) - -IPC_MESSAGE_CONTROL1(GpuHostMsg_DidDestroyOffscreenContext, - GURL /* url */) - -// Tells the browser about GPU memory usage statistics for UMA logging. -IPC_MESSAGE_CONTROL1(GpuHostMsg_GpuMemoryUmaStats, - content::GPUMemoryUmaStats /* GPU memory UMA stats */) - -// Tells the browser that a context has subscribed to a new target and -// the browser should start sending the corresponding information -IPC_MESSAGE_CONTROL2(GpuHostMsg_AddSubscription, - int32_t /* client_id */, - unsigned int /* target */) - -// Tells the browser that no contexts are subscribed to the target anymore -// so the browser should stop sending the corresponding information -IPC_MESSAGE_CONTROL2(GpuHostMsg_RemoveSubscription, - int32_t /* client_id */, - unsigned int /* target */) - -//------------------------------------------------------------------------------ -// GPU Channel Messages -// These are messages from a renderer process to the GPU process. - -// Tells the GPU process to create a new command buffer that renders to an -// offscreen frame buffer. -IPC_SYNC_MESSAGE_CONTROL3_1(GpuChannelMsg_CreateOffscreenCommandBuffer, - gfx::Size, /* size */ - GPUCreateCommandBufferConfig, /* init_params */ - int32_t, /* route_id */ - bool /* succeeded */) - -// The CommandBufferProxy sends this to the GpuCommandBufferStub in its -// destructor, so that the stub deletes the actual CommandBufferService -// object that it's hosting. -IPC_SYNC_MESSAGE_CONTROL1_0(GpuChannelMsg_DestroyCommandBuffer, - int32_t /* instance_id */) - -// Simple NOP message which can be used as fence to ensure all previous sent -// messages have been received. -IPC_SYNC_MESSAGE_CONTROL0_0(GpuChannelMsg_Nop) - -#if defined(OS_ANDROID) -//------------------------------------------------------------------------------ -// Stream Texture Messages -// Tells the GPU process create and send the java surface texture object to -// the renderer process through the binder thread. -IPC_MESSAGE_ROUTED2(GpuStreamTextureMsg_EstablishPeer, - int32_t, /* primary_id */ - int32_t /* secondary_id */) - -// Tells the GPU process to set the size of StreamTexture from the given -// stream Id. -IPC_MESSAGE_ROUTED1(GpuStreamTextureMsg_SetSize, - gfx::Size /* size */) - -// Tells the service-side instance to start sending frame available -// notifications. -IPC_MESSAGE_ROUTED0(GpuStreamTextureMsg_StartListening) - -// Inform the renderer that a new frame is available. -IPC_MESSAGE_ROUTED0(GpuStreamTextureMsg_FrameAvailable) - -// Inform the renderer process that the transform matrix has changed. -IPC_MESSAGE_ROUTED1(GpuStreamTextureMsg_MatrixChanged, - GpuStreamTextureMsg_MatrixChanged_Params /* params */) -#endif - -//------------------------------------------------------------------------------ -// GPU Command Buffer Messages -// These are messages between a renderer process to the GPU process relating to -// a single OpenGL context. -// Initialize a command buffer with the given number of command entries. -// Returns the shared memory handle for the command buffer mapped to the -// calling process. -IPC_SYNC_MESSAGE_ROUTED1_2(GpuCommandBufferMsg_Initialize, - base::SharedMemoryHandle /* shared_state */, - bool /* result */, - gpu::Capabilities /* capabilities */) - -// Sets the shared memory buffer used for commands. -IPC_SYNC_MESSAGE_ROUTED1_0(GpuCommandBufferMsg_SetGetBuffer, - int32_t /* shm_id */) - -// Produces the front buffer into a mailbox. This allows another context to draw -// the output of this context. -IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_ProduceFrontBuffer, - gpu::Mailbox /* mailbox */) - -// Wait until the token is in a specific range, inclusive. -IPC_SYNC_MESSAGE_ROUTED2_1(GpuCommandBufferMsg_WaitForTokenInRange, - int32_t /* start */, - int32_t /* end */, - gpu::CommandBuffer::State /* state */) - -// Wait until the get offset is in a specific range, inclusive. -IPC_SYNC_MESSAGE_ROUTED2_1(GpuCommandBufferMsg_WaitForGetOffsetInRange, - int32_t /* start */, - int32_t /* end */, - gpu::CommandBuffer::State /* state */) - -// Asynchronously synchronize the put and get offsets of both processes. -// Caller passes its current put offset. Current state (including get offset) -// is returned in shared memory. The input latency info for the current -// frame is also sent to the GPU process. -IPC_MESSAGE_ROUTED3(GpuCommandBufferMsg_AsyncFlush, - int32_t /* put_offset */, - uint32_t /* flush_count */, - std::vector<ui::LatencyInfo> /* latency_info */) - -// Sent by the GPU process to display messages in the console. -IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_ConsoleMsg, - GPUCommandBufferConsoleMessage /* msg */) - -// Register an existing shared memory transfer buffer. The id that can be -// used to identify the transfer buffer from a command buffer. -IPC_MESSAGE_ROUTED3(GpuCommandBufferMsg_RegisterTransferBuffer, - int32_t /* id */, - base::SharedMemoryHandle /* transfer_buffer */, - uint32_t /* size */) - -// Destroy a previously created transfer buffer. -IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_DestroyTransferBuffer, int32_t /* id */) - -// Create and initialize a hardware video decoder using the specified route_id. -// Created decoders should be freed with AcceleratedVideoDecoderMsg_Destroy when -// no longer needed. -IPC_SYNC_MESSAGE_ROUTED2_1(GpuCommandBufferMsg_CreateVideoDecoder, - media::VideoDecodeAccelerator::Config, /* config */ - int32_t, /* route_id */ - bool /* succeeded */) - -// Create and initialize a hardware video encoder using the specified route_id. -// Created encoders should be freed with AcceleratedVideoEncoderMsg_Destroy when -// no longer needed. -IPC_SYNC_MESSAGE_ROUTED5_1(GpuCommandBufferMsg_CreateVideoEncoder, - media::VideoPixelFormat /* input_format */, - gfx::Size /* input_visible_size */, - media::VideoCodecProfile /* output_profile */, - uint32_t /* initial_bitrate */, - int32_t, /* route_id */ - bool /* succeeded */) - -// Tells the proxy that there was an error and the command buffer had to be -// destroyed for some reason. -IPC_MESSAGE_ROUTED2(GpuCommandBufferMsg_Destroyed, - gpu::error::ContextLostReason, /* reason */ - gpu::error::Error /* error */) - -// Tells the browser that SwapBuffers returned and passes latency info -IPC_MESSAGE_ROUTED2(GpuCommandBufferMsg_SwapBuffersCompleted, - std::vector<ui::LatencyInfo> /* latency_info */, - gfx::SwapResult /* result */) - -// Tells the browser about updated parameters for vsync alignment. -IPC_MESSAGE_ROUTED2(GpuCommandBufferMsg_UpdateVSyncParameters, - base::TimeTicks /* timebase */, - base::TimeDelta /* interval */) - -// Inserts a sync point into the channel. This is handled on the IO thread, so -// can be expected to be reasonably fast, but the sync point is actually -// retired in order with respect to the other calls. The sync point is shared -// across channels. -IPC_SYNC_MESSAGE_ROUTED1_1(GpuCommandBufferMsg_InsertSyncPoint, - bool /* retire */, - uint32_t /* sync_point */) - -// Retires the sync point. -IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_RetireSyncPoint, - uint32_t /* sync_point */) - -// Makes this command buffer signal when a sync point is reached, by sending -// back a GpuCommandBufferMsg_SignalSyncPointAck message with the same -// signal_id. -IPC_MESSAGE_ROUTED2(GpuCommandBufferMsg_SignalSyncPoint, - uint32_t /* sync_point */, - uint32_t /* signal_id */) - -IPC_MESSAGE_ROUTED2(GpuCommandBufferMsg_SignalSyncToken, - gpu::SyncToken /* sync_token */, - uint32_t /* signal_id */) - -// Makes this command buffer signal when a query is reached, by sending -// back a GpuCommandBufferMsg_SignalSyncPointAck message with the same -// signal_id. -IPC_MESSAGE_ROUTED2(GpuCommandBufferMsg_SignalQuery, - uint32_t /* query */, - uint32_t /* signal_id */) - -// Response to SignalSyncPoint, SignalSyncToken, and SignalQuery. -IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_SignalAck, uint32_t /* signal_id */) - -// Create an image from an existing gpu memory buffer. The id that can be -// used to identify the image from a command buffer. -IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_CreateImage, - GpuCommandBufferMsg_CreateImage_Params /* params */) - -// Destroy a previously created image. -IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_DestroyImage, int32_t /* id */) - -// Attaches an external image stream to the client texture. -IPC_SYNC_MESSAGE_ROUTED2_1(GpuCommandBufferMsg_CreateStreamTexture, - uint32_t, /* client_texture_id */ - int32_t, /* stream_id */ - bool /* succeeded */) - -//------------------------------------------------------------------------------ -// Accelerated Video Decoder Messages -// These messages are sent from Renderer process to GPU process. - -// Set a CDM on the decoder to handle encrypted buffers. -IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderMsg_SetCdm, - int32_t) /* CDM ID */ - -// Send input buffer for decoding. -IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderMsg_Decode, - AcceleratedVideoDecoderMsg_Decode_Params) - -// Give the texture IDs for the textures the decoder will use for output. -IPC_MESSAGE_ROUTED2(AcceleratedVideoDecoderMsg_AssignPictureBuffers, - std::vector<int32_t>, /* Picture buffer ID */ - std::vector<uint32_t>) /* Texture ID */ - -// Send from Renderer process to the GPU process to recycle the given picture -// buffer for further decoding. -IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderMsg_ReusePictureBuffer, - int32_t) /* Picture buffer ID */ - -// Send flush request to the decoder. -IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderMsg_Flush) - -// Send reset request to the decoder. -IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderMsg_Reset) - -// Send destroy request to the decoder. -IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderMsg_Destroy) - -//------------------------------------------------------------------------------ -// Accelerated Video Decoder Host Messages -// These messages are sent from GPU process to Renderer process. -// Inform AcceleratedVideoDecoderHost that AcceleratedVideoDecoder has been -// created. - -// Notify the CDM setting result. -IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderHostMsg_CdmAttached, - bool) /* success */ - -// Accelerated video decoder has consumed input buffer from transfer buffer. -IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed, - int32_t) /* Processed buffer ID */ - -// Allocate video frames for output of the hardware video decoder. -IPC_MESSAGE_ROUTED3(AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers, - int32_t, /* Number of video frames to generate */ - gfx::Size, /* Requested size of buffer */ - uint32_t) /* Texture target */ - -// Decoder reports that a picture is ready and buffer does not need to be passed -// back to the decoder. -IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderHostMsg_DismissPictureBuffer, - int32_t) /* Picture buffer ID */ - -// Decoder reports that a picture is ready. -IPC_MESSAGE_ROUTED4(AcceleratedVideoDecoderHostMsg_PictureReady, - int32_t, /* Picture buffer ID */ - int32_t, /* Bitstream buffer ID */ - gfx::Rect, /* Visible rectangle */ - bool) /* Buffer is HW overlay capable */ - -// Confirm decoder has been flushed. -IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderHostMsg_FlushDone) - -// Confirm decoder has been reset. -IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderHostMsg_ResetDone) - -// Video decoder has encountered an error. -IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderHostMsg_ErrorNotification, - uint32_t) /* Error ID */ - -//------------------------------------------------------------------------------ -// Accelerated Video Encoder Messages -// These messages are sent from the Renderer process to GPU process. - -// Queue a video frame to the encoder to encode. |frame_id| will be returned -// by AcceleratedVideoEncoderHostMsg_NotifyInputDone. -IPC_MESSAGE_ROUTED1(AcceleratedVideoEncoderMsg_Encode, - AcceleratedVideoEncoderMsg_Encode_Params) - -// Queue a GpuMemoryBuffer backed video frame to the encoder to encode. -// |frame_id| will be returned by -// AcceleratedVideoEncoderHostMsg_NotifyInputDone. -IPC_MESSAGE_ROUTED1(AcceleratedVideoEncoderMsg_Encode2, - AcceleratedVideoEncoderMsg_Encode_Params2) - -// Queue a buffer to the encoder for use in returning output. |buffer_id| will -// be returned by AcceleratedVideoEncoderHostMsg_BitstreamBufferReady. -IPC_MESSAGE_ROUTED3(AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer, - int32_t /* buffer_id */, - base::SharedMemoryHandle /* buffer_handle */, - uint32_t /* buffer_size */) - -// Request a runtime encoding parameter change. -IPC_MESSAGE_ROUTED2(AcceleratedVideoEncoderMsg_RequestEncodingParametersChange, - uint32_t /* bitrate */, - uint32_t /* framerate */) - -//------------------------------------------------------------------------------ -// Accelerated Video Encoder Host Messages -// These messages are sent from GPU process to Renderer process. - -// Notify renderer of the input/output buffer requirements of the encoder. -IPC_MESSAGE_ROUTED3(AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers, - uint32_t /* input_count */, - gfx::Size /* input_coded_size */, - uint32_t /* output_buffer_size */) - -// Notify the renderer that the encoder has finished using an input buffer. -// There is no congruent entry point in the media::VideoEncodeAccelerator -// interface, in VEA this same done condition is indicated by dropping the -// reference to the media::VideoFrame passed to VEA::Encode(). -IPC_MESSAGE_ROUTED1(AcceleratedVideoEncoderHostMsg_NotifyInputDone, - int32_t /* frame_id */) - -// Notify the renderer that an output buffer has been filled with encoded data. -IPC_MESSAGE_ROUTED3(AcceleratedVideoEncoderHostMsg_BitstreamBufferReady, - int32_t /* bitstream_buffer_id */, - uint32_t /* payload_size */, - bool /* key_frame */) - -// Report error condition. -IPC_MESSAGE_ROUTED1(AcceleratedVideoEncoderHostMsg_NotifyError, - media::VideoEncodeAccelerator::Error /* error */) - -// Send destroy request to the encoder. -IPC_MESSAGE_ROUTED0(AcceleratedVideoEncoderMsg_Destroy) - -//------------------------------------------------------------------------------ -// Accelerated JPEG Decoder Messages -// These messages are sent from the Browser process to GPU process. - -// Decode one JPEG image from shared memory |input_buffer_handle| with size -// |input_buffer_size|. The input buffer is associated with |input_buffer_id| -// and the size of JPEG image is |coded_size|. Decoded I420 frame data will -// be put onto shared memory associated with |output_video_frame_handle| -// with size limit |output_buffer_size|. -IPC_MESSAGE_ROUTED1(AcceleratedJpegDecoderMsg_Decode, - AcceleratedJpegDecoderMsg_Decode_Params) - -// Send destroy request to the decoder. -IPC_MESSAGE_ROUTED0(AcceleratedJpegDecoderMsg_Destroy) - -//------------------------------------------------------------------------------ -// Accelerated JPEG Decoder Host Messages -// These messages are sent from the GPU process to Browser process. -// -// Report decode status. -IPC_MESSAGE_ROUTED2(AcceleratedJpegDecoderHostMsg_DecodeAck, - int32_t, /* bitstream_buffer_id */ - media::JpegDecodeAccelerator::Error /* error */) - -#if defined(OS_CHROMEOS) -//------------------------------------------------------------------------------ -// Arc Video Accelerator Messages -// These messages are sent from the Browser process to GPU process. - -// Tells the GPU process to create a new channel for communication with -// ArcVideoAccelerator. The channel is returned using -// GpuHostMsg_ArcVideoAcceleratorChannelCreated message. -IPC_MESSAGE_CONTROL0(GpuMsg_CreateArcVideoAcceleratorChannel) - -// Tells the GPU process to shutdown arc video service and terminate all -// instances of ArcVideoAccelerator. -IPC_MESSAGE_CONTROL0(GpuMsg_ShutdownArcVideoService) - -//------------------------------------------------------------------------------ -// Arc Video Accelerator Host Messages -// These messages are sent from the GPU process to Browser process. - -// Response from GPU to a GpuMsg_CreateArcVideoAcceleratorChannel message. -IPC_MESSAGE_CONTROL1(GpuHostMsg_ArcVideoAcceleratorChannelCreated, - IPC::ChannelHandle /* handle to channel */) -#endif diff --git a/chromium/content/common/gpu/gpu_result_codes.h b/chromium/content/common/gpu/gpu_result_codes.h deleted file mode 100644 index 11f4272a2ae..00000000000 --- a/chromium/content/common/gpu/gpu_result_codes.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 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 CONTENT_COMMON_GPU_GPU_RESULT_CODES_H_ -#define CONTENT_COMMON_GPU_GPU_RESULT_CODES_H_ - -namespace content { - -enum CreateCommandBufferResult { - CREATE_COMMAND_BUFFER_SUCCEEDED, - CREATE_COMMAND_BUFFER_FAILED, - CREATE_COMMAND_BUFFER_FAILED_AND_CHANNEL_LOST, - CREATE_COMMAND_BUFFER_RESULT_LAST = - CREATE_COMMAND_BUFFER_FAILED_AND_CHANNEL_LOST -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_GPU_RESULT_CODES_H_ diff --git a/chromium/content/common/gpu/gpu_stream_priority.h b/chromium/content/common/gpu/gpu_stream_priority.h deleted file mode 100644 index 089fb97e04e..00000000000 --- a/chromium/content/common/gpu/gpu_stream_priority.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2015 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 CONTENT_COMMON_GPU_GPU_STREAM_PRIORITY_H_ -#define CONTENT_COMMON_GPU_GPU_STREAM_PRIORITY_H_ - -namespace content { - -enum class GpuStreamPriority { - REAL_TIME, - NORMAL, - LOW, - INHERIT, - LAST = INHERIT -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_GPU_STREAM_PRIORITY_H_ diff --git a/chromium/content/common/gpu/gpu_surface_lookup.cc b/chromium/content/common/gpu/gpu_surface_lookup.cc deleted file mode 100644 index 61bbc045e5c..00000000000 --- a/chromium/content/common/gpu/gpu_surface_lookup.cc +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2012 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 "content/common/gpu/gpu_surface_lookup.h" - -#include "base/logging.h" - -namespace content { -namespace { -GpuSurfaceLookup* g_instance = NULL; -} // anonymous namespace - -// static -GpuSurfaceLookup* GpuSurfaceLookup::GetInstance() { - DCHECK(g_instance); - return g_instance; -} - -// static -void GpuSurfaceLookup::InitInstance(GpuSurfaceLookup* lookup) { - DCHECK(!g_instance || !lookup); - g_instance = lookup; -} - -#if defined(OS_ANDROID) -gfx::ScopedJavaSurface GpuSurfaceLookup::AcquireJavaSurface(int surface_id) { - NOTIMPLEMENTED(); - return gfx::ScopedJavaSurface(); -} -#endif - -} // namespace content diff --git a/chromium/content/common/gpu/gpu_surface_lookup.h b/chromium/content/common/gpu/gpu_surface_lookup.h deleted file mode 100644 index c47e7e37901..00000000000 --- a/chromium/content/common/gpu/gpu_surface_lookup.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_GPU_GPU_SURFACE_LOOKUP_H_ -#define CONTENT_COMMON_GPU_GPU_SURFACE_LOOKUP_H_ - -#include "base/macros.h" -#include "content/common/content_export.h" -#include "ui/gfx/native_widget_types.h" - -#if defined(OS_ANDROID) -#include "ui/gl/android/scoped_java_surface.h" -#endif - -namespace content { - -// This class provides an interface to look up window surface handles -// that cannot be sent through the IPC channel. -class CONTENT_EXPORT GpuSurfaceLookup { - public: - GpuSurfaceLookup() { } - virtual ~GpuSurfaceLookup() { } - - static GpuSurfaceLookup* GetInstance(); - static void InitInstance(GpuSurfaceLookup* lookup); - - virtual gfx::AcceleratedWidget AcquireNativeWidget(int surface_id) = 0; - -#if defined(OS_ANDROID) - virtual gfx::ScopedJavaSurface AcquireJavaSurface(int surface_id); -#endif - - private: - DISALLOW_COPY_AND_ASSIGN(GpuSurfaceLookup); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_GPU_SURFACE_LOOKUP_H_ diff --git a/chromium/content/common/gpu/gpu_watchdog.h b/chromium/content/common/gpu/gpu_watchdog.h deleted file mode 100644 index 069aeb72737..00000000000 --- a/chromium/content/common/gpu/gpu_watchdog.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_GPU_GPU_WATCHDOG_H_ -#define CONTENT_COMMON_GPU_GPU_WATCHDOG_H_ - -#include "base/macros.h" - -namespace content { - -// Interface for objects that monitor the a GPUProcessor's progress. The -// GPUProcessor will regularly invoke CheckArmed. -class GpuWatchdog { - public: - virtual void CheckArmed() = 0; - - protected: - GpuWatchdog() {} - virtual ~GpuWatchdog() {}; - - private: - DISALLOW_COPY_AND_ASSIGN(GpuWatchdog); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_GPU_WATCHDOG_H_ diff --git a/chromium/content/common/gpu/image_transport_surface.cc b/chromium/content/common/gpu/image_transport_surface.cc deleted file mode 100644 index 192ec9620b6..00000000000 --- a/chromium/content/common/gpu/image_transport_surface.cc +++ /dev/null @@ -1,302 +0,0 @@ -// Copyright (c) 2012 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 "content/common/gpu/image_transport_surface.h" - -#include <stddef.h> -#include <utility> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/command_line.h" -#include "base/trace_event/trace_event.h" -#include "build/build_config.h" -#include "content/common/gpu/gpu_channel.h" -#include "content/common/gpu/gpu_channel_manager.h" -#include "content/common/gpu/gpu_command_buffer_stub.h" -#include "content/common/gpu/gpu_messages.h" -#include "gpu/command_buffer/service/sync_point_manager.h" -#include "ui/gfx/vsync_provider.h" -#include "ui/gl/gl_context.h" -#include "ui/gl/gl_implementation.h" -#include "ui/gl/gl_switches.h" - -namespace content { - -ImageTransportSurface::ImageTransportSurface() {} - -ImageTransportSurface::~ImageTransportSurface() {} - -scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateSurface( - GpuChannelManager* manager, - GpuCommandBufferStub* stub, - const gfx::GLSurfaceHandle& handle) { - scoped_refptr<gfx::GLSurface> surface; - if (handle.transport_type == gfx::NULL_TRANSPORT) { - surface = manager->GetDefaultOffscreenSurface(); - } else { - surface = CreateNativeSurface(manager, stub, handle); - if (!surface.get() || !surface->Initialize()) - return NULL; - } - - return surface; -} - -ImageTransportHelper::ImageTransportHelper(ImageTransportSurface* surface, - GpuChannelManager* manager, - GpuCommandBufferStub* stub, - gfx::PluginWindowHandle handle) - : surface_(surface), - manager_(manager), - stub_(stub->AsWeakPtr()), - handle_(handle) { - route_id_ = manager_->GenerateRouteID(); - manager_->AddRoute(route_id_, this); -} - -ImageTransportHelper::~ImageTransportHelper() { - if (stub_.get()) { - stub_->SetLatencyInfoCallback( - base::Callback<void(const std::vector<ui::LatencyInfo>&)>()); - } - manager_->RemoveRoute(route_id_); -} - -bool ImageTransportHelper::Initialize() { - gpu::gles2::GLES2Decoder* decoder = Decoder(); - - if (!decoder) - return false; - - stub_->SetLatencyInfoCallback( - base::Bind(&ImageTransportHelper::SetLatencyInfo, - base::Unretained(this))); - - return true; -} - -bool ImageTransportHelper::OnMessageReceived(const IPC::Message& message) { -#if defined(OS_MACOSX) - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(ImageTransportHelper, message) - IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_BufferPresented, - OnBufferPresented) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -#else - NOTREACHED(); - return false; -#endif -} - -#if defined(OS_MACOSX) -void ImageTransportHelper::SendAcceleratedSurfaceBuffersSwapped( - GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params) { - // TRACE_EVENT for gpu tests: - TRACE_EVENT_INSTANT2("test_gpu", "SwapBuffers", - TRACE_EVENT_SCOPE_THREAD, - "GLImpl", static_cast<int>(gfx::GetGLImplementation()), - "width", params.size.width()); - // On mac, handle_ is a surface id. See - // GpuProcessTransportFactory::CreatePerCompositorData - params.surface_id = handle_; - params.route_id = route_id_; - manager_->Send(new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params)); -} -#endif - -bool ImageTransportHelper::MakeCurrent() { - gpu::gles2::GLES2Decoder* decoder = Decoder(); - if (!decoder) - return false; - return decoder->MakeCurrent(); -} - -void ImageTransportHelper::SetSwapInterval(gfx::GLContext* context) { - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableGpuVsync)) - context->ForceSwapIntervalZero(true); - else - context->SetSwapInterval(1); -} - -gpu::gles2::GLES2Decoder* ImageTransportHelper::Decoder() { - if (!stub_.get()) - return NULL; - return stub_->decoder(); -} - -#if defined(OS_MACOSX) -void ImageTransportHelper::OnBufferPresented( - const AcceleratedSurfaceMsg_BufferPresented_Params& params) { - surface_->OnBufferPresented(params); -} -#endif - -void ImageTransportHelper::SetLatencyInfo( - const std::vector<ui::LatencyInfo>& latency_info) { - surface_->SetLatencyInfo(latency_info); -} - -PassThroughImageTransportSurface::PassThroughImageTransportSurface( - GpuChannelManager* manager, - GpuCommandBufferStub* stub, - gfx::GLSurface* surface) - : GLSurfaceAdapter(surface), - did_set_swap_interval_(false), - weak_ptr_factory_(this) { - helper_.reset(new ImageTransportHelper(this, - manager, - stub, - gfx::kNullPluginWindow)); -} - -bool PassThroughImageTransportSurface::Initialize() { - // The surface is assumed to have already been initialized. - return helper_->Initialize(); -} - -void PassThroughImageTransportSurface::Destroy() { - GLSurfaceAdapter::Destroy(); -} - -void PassThroughImageTransportSurface::SetLatencyInfo( - const std::vector<ui::LatencyInfo>& latency_info) { - for (size_t i = 0; i < latency_info.size(); i++) - latency_info_.push_back(latency_info[i]); -} - -gfx::SwapResult PassThroughImageTransportSurface::SwapBuffers() { - scoped_ptr<std::vector<ui::LatencyInfo>> latency_info = StartSwapBuffers(); - gfx::SwapResult result = gfx::GLSurfaceAdapter::SwapBuffers(); - FinishSwapBuffers(std::move(latency_info), result); - return result; -} - -void PassThroughImageTransportSurface::SwapBuffersAsync( - const GLSurface::SwapCompletionCallback& callback) { - scoped_ptr<std::vector<ui::LatencyInfo>> latency_info = StartSwapBuffers(); - - // We use WeakPtr here to avoid manual management of life time of an instance - // of this class. Callback will not be called once the instance of this class - // is destroyed. However, this also means that the callback can be run on - // the calling thread only. - gfx::GLSurfaceAdapter::SwapBuffersAsync(base::Bind( - &PassThroughImageTransportSurface::FinishSwapBuffersAsync, - weak_ptr_factory_.GetWeakPtr(), base::Passed(&latency_info), callback)); -} - -gfx::SwapResult PassThroughImageTransportSurface::PostSubBuffer(int x, - int y, - int width, - int height) { - scoped_ptr<std::vector<ui::LatencyInfo>> latency_info = StartSwapBuffers(); - gfx::SwapResult result = - gfx::GLSurfaceAdapter::PostSubBuffer(x, y, width, height); - FinishSwapBuffers(std::move(latency_info), result); - return result; -} - -void PassThroughImageTransportSurface::PostSubBufferAsync( - int x, - int y, - int width, - int height, - const GLSurface::SwapCompletionCallback& callback) { - scoped_ptr<std::vector<ui::LatencyInfo>> latency_info = StartSwapBuffers(); - gfx::GLSurfaceAdapter::PostSubBufferAsync( - x, y, width, height, - base::Bind(&PassThroughImageTransportSurface::FinishSwapBuffersAsync, - weak_ptr_factory_.GetWeakPtr(), base::Passed(&latency_info), - callback)); -} - -gfx::SwapResult PassThroughImageTransportSurface::CommitOverlayPlanes() { - scoped_ptr<std::vector<ui::LatencyInfo>> latency_info = StartSwapBuffers(); - gfx::SwapResult result = gfx::GLSurfaceAdapter::CommitOverlayPlanes(); - FinishSwapBuffers(std::move(latency_info), result); - return result; -} - -void PassThroughImageTransportSurface::CommitOverlayPlanesAsync( - const GLSurface::SwapCompletionCallback& callback) { - scoped_ptr<std::vector<ui::LatencyInfo>> latency_info = StartSwapBuffers(); - gfx::GLSurfaceAdapter::CommitOverlayPlanesAsync(base::Bind( - &PassThroughImageTransportSurface::FinishSwapBuffersAsync, - weak_ptr_factory_.GetWeakPtr(), base::Passed(&latency_info), callback)); -} - -bool PassThroughImageTransportSurface::OnMakeCurrent(gfx::GLContext* context) { - if (!did_set_swap_interval_) { - ImageTransportHelper::SetSwapInterval(context); - did_set_swap_interval_ = true; - } - return true; -} - -#if defined(OS_MACOSX) -void PassThroughImageTransportSurface::OnBufferPresented( - const AcceleratedSurfaceMsg_BufferPresented_Params& /* params */) { - NOTREACHED(); -} -#endif - -gfx::Size PassThroughImageTransportSurface::GetSize() { - return GLSurfaceAdapter::GetSize(); -} - -PassThroughImageTransportSurface::~PassThroughImageTransportSurface() {} - -void PassThroughImageTransportSurface::SendVSyncUpdateIfAvailable() { - gfx::VSyncProvider* vsync_provider = GetVSyncProvider(); - if (vsync_provider) { - vsync_provider->GetVSyncParameters( - base::Bind(&GpuCommandBufferStub::SendUpdateVSyncParameters, - helper_->stub()->AsWeakPtr())); - } -} - -scoped_ptr<std::vector<ui::LatencyInfo>> -PassThroughImageTransportSurface::StartSwapBuffers() { - // GetVsyncValues before SwapBuffers to work around Mali driver bug: - // crbug.com/223558. - SendVSyncUpdateIfAvailable(); - - base::TimeTicks swap_time = base::TimeTicks::Now(); - for (auto& latency : latency_info_) { - latency.AddLatencyNumberWithTimestamp( - ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1); - } - - scoped_ptr<std::vector<ui::LatencyInfo>> latency_info( - new std::vector<ui::LatencyInfo>()); - latency_info->swap(latency_info_); - - return latency_info; -} - -void PassThroughImageTransportSurface::FinishSwapBuffers( - scoped_ptr<std::vector<ui::LatencyInfo>> latency_info, - gfx::SwapResult result) { - base::TimeTicks swap_ack_time = base::TimeTicks::Now(); - for (auto& latency : *latency_info) { - latency.AddLatencyNumberWithTimestamp( - ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0, - swap_ack_time, 1); - } - - helper_->stub()->SendSwapBuffersCompleted(*latency_info, result); -} - -void PassThroughImageTransportSurface::FinishSwapBuffersAsync( - scoped_ptr<std::vector<ui::LatencyInfo>> latency_info, - GLSurface::SwapCompletionCallback callback, - gfx::SwapResult result) { - FinishSwapBuffers(std::move(latency_info), result); - callback.Run(result); -} - -} // namespace content diff --git a/chromium/content/common/gpu/image_transport_surface.h b/chromium/content/common/gpu/image_transport_surface.h deleted file mode 100644 index bfb68928cf6..00000000000 --- a/chromium/content/common/gpu/image_transport_surface.h +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_H_ -#define CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_H_ - -#include <stdint.h> - -#include <vector> - -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "build/build_config.h" -#include "content/common/content_export.h" -#include "ipc/ipc_listener.h" -#include "ipc/ipc_message.h" -#include "ui/events/latency_info.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gfx/swap_result.h" -#include "ui/gl/gl_surface.h" - -#if defined(OS_MACOSX) -struct AcceleratedSurfaceMsg_BufferPresented_Params; -struct GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params; -#endif - -namespace gfx { -class GLSurface; -} - -namespace gpu { -class PreemptionFlag; -namespace gles2 { -class GLES2Decoder; -} -} - -namespace content { -class GpuChannelManager; -class GpuCommandBufferStub; - -// The GPU process is agnostic as to how it displays results. On some platforms -// it renders directly to window. On others it renders offscreen and transports -// the results to the browser process to display. This file provides a simple -// framework for making the offscreen path seem more like the onscreen path. -// -// The ImageTransportSurface class defines an simple interface for events that -// should be responded to. The factory returns an offscreen surface that looks -// a lot like an onscreen surface to the GPU process. -// -// The ImageTransportSurfaceHelper provides some glue to the outside world: -// making sure outside events reach the ImageTransportSurface and -// allowing the ImageTransportSurface to send events to the outside world. - -class ImageTransportSurface { - public: - ImageTransportSurface(); - -#if defined(OS_MACOSX) - virtual void OnBufferPresented( - const AcceleratedSurfaceMsg_BufferPresented_Params& params) = 0; -#endif - virtual void SetLatencyInfo( - const std::vector<ui::LatencyInfo>& latency_info) = 0; - - // Creates a surface with the given attributes. - static scoped_refptr<gfx::GLSurface> CreateSurface( - GpuChannelManager* manager, - GpuCommandBufferStub* stub, - const gfx::GLSurfaceHandle& handle); - -#if defined(OS_MACOSX) - CONTENT_EXPORT static void SetAllowOSMesaForTesting(bool allow); -#endif - - virtual gfx::Size GetSize() = 0; - - protected: - virtual ~ImageTransportSurface(); - - private: - // Creates the appropriate native surface depending on the GL implementation. - // This will be implemented separately by each platform. - // - // This will not be called for texture transport surfaces which are - // cross-platform. The platform implementation should only create the - // surface and should not initialize it. On failure, a null scoped_refptr - // should be returned. - static scoped_refptr<gfx::GLSurface> CreateNativeSurface( - GpuChannelManager* manager, - GpuCommandBufferStub* stub, - const gfx::GLSurfaceHandle& handle); - - DISALLOW_COPY_AND_ASSIGN(ImageTransportSurface); -}; - -class ImageTransportHelper - : public IPC::Listener, - public base::SupportsWeakPtr<ImageTransportHelper> { - public: - // Takes weak pointers to objects that outlive the helper. - ImageTransportHelper(ImageTransportSurface* surface, - GpuChannelManager* manager, - GpuCommandBufferStub* stub, - gfx::PluginWindowHandle handle); - ~ImageTransportHelper() override; - - bool Initialize(); - - // IPC::Listener implementation: - bool OnMessageReceived(const IPC::Message& message) override; - - // Helper send functions. Caller fills in the surface specific params - // like size and surface id. The helper fills in the rest. -#if defined(OS_MACOSX) - void SendAcceleratedSurfaceBuffersSwapped( - GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params); -#endif - - // Make the surface's context current. - bool MakeCurrent(); - - // Set the default swap interval on the surface. - static void SetSwapInterval(gfx::GLContext* context); - - GpuChannelManager* manager() const { return manager_; } - GpuCommandBufferStub* stub() const { return stub_.get(); } - - private: - gpu::gles2::GLES2Decoder* Decoder(); - - // IPC::Message handlers. -#if defined(OS_MACOSX) - void OnBufferPresented( - const AcceleratedSurfaceMsg_BufferPresented_Params& params); -#endif - - // Backbuffer resize callback. - void Resize(gfx::Size size, float scale_factor); - - void SetLatencyInfo(const std::vector<ui::LatencyInfo>& latency_info); - - // Weak pointers that point to objects that outlive this helper. - ImageTransportSurface* surface_; - GpuChannelManager* manager_; - - base::WeakPtr<GpuCommandBufferStub> stub_; - int32_t route_id_; - gfx::PluginWindowHandle handle_; - - DISALLOW_COPY_AND_ASSIGN(ImageTransportHelper); -}; - -// An implementation of ImageTransportSurface that implements GLSurface through -// GLSurfaceAdapter, thereby forwarding GLSurface methods through to it. -class PassThroughImageTransportSurface - : public gfx::GLSurfaceAdapter, - public ImageTransportSurface { - public: - PassThroughImageTransportSurface(GpuChannelManager* manager, - GpuCommandBufferStub* stub, - gfx::GLSurface* surface); - - // GLSurface implementation. - bool Initialize() override; - void Destroy() override; - gfx::SwapResult SwapBuffers() override; - void SwapBuffersAsync(const SwapCompletionCallback& callback) override; - gfx::SwapResult PostSubBuffer(int x, int y, int width, int height) override; - void PostSubBufferAsync(int x, - int y, - int width, - int height, - const SwapCompletionCallback& callback) override; - gfx::SwapResult CommitOverlayPlanes() override; - void CommitOverlayPlanesAsync( - const SwapCompletionCallback& callback) override; - bool OnMakeCurrent(gfx::GLContext* context) override; - - // ImageTransportSurface implementation. -#if defined(OS_MACOSX) - void OnBufferPresented( - const AcceleratedSurfaceMsg_BufferPresented_Params& params) override; -#endif - gfx::Size GetSize() override; - void SetLatencyInfo( - const std::vector<ui::LatencyInfo>& latency_info) override; - - protected: - ~PassThroughImageTransportSurface() override; - - // If updated vsync parameters can be determined, send this information to - // the browser. - virtual void SendVSyncUpdateIfAvailable(); - - scoped_ptr<std::vector<ui::LatencyInfo>> StartSwapBuffers(); - void FinishSwapBuffers(scoped_ptr<std::vector<ui::LatencyInfo>> latency_info, - gfx::SwapResult result); - void FinishSwapBuffersAsync( - scoped_ptr<std::vector<ui::LatencyInfo>> latency_info, - GLSurface::SwapCompletionCallback callback, - gfx::SwapResult result); - - ImageTransportHelper* GetHelper() { return helper_.get(); } - - private: - scoped_ptr<ImageTransportHelper> helper_; - bool did_set_swap_interval_; - std::vector<ui::LatencyInfo> latency_info_; - base::WeakPtrFactory<PassThroughImageTransportSurface> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(PassThroughImageTransportSurface); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_H_ diff --git a/chromium/content/common/gpu/image_transport_surface_android.cc b/chromium/content/common/gpu/image_transport_surface_android.cc deleted file mode 100644 index 79a16c0bbdf..00000000000 --- a/chromium/content/common/gpu/image_transport_surface_android.cc +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2012 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 "content/common/gpu/image_transport_surface.h" - -#include "base/command_line.h" -#include "base/logging.h" -#include "content/common/gpu/gpu_channel.h" -#include "content/common/gpu/gpu_channel_manager.h" -#include "content/common/gpu/gpu_command_buffer_stub.h" -#include "content/common/gpu/gpu_surface_lookup.h" -#include "content/public/common/content_switches.h" -#include "ui/gl/gl_surface_egl.h" - -namespace content { - -// static -scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface( - GpuChannelManager* manager, - GpuCommandBufferStub* stub, - const gfx::GLSurfaceHandle& handle) { - DCHECK(GpuSurfaceLookup::GetInstance()); - DCHECK_EQ(handle.transport_type, gfx::NATIVE_DIRECT); - ANativeWindow* window = - GpuSurfaceLookup::GetInstance()->AcquireNativeWidget(handle.handle); - if (!window) { - LOG(WARNING) << "Failed to acquire native widget."; - return scoped_refptr<gfx::GLSurface>(); - } - scoped_refptr<gfx::GLSurface> surface = - new gfx::NativeViewGLSurfaceEGL(window); - bool initialize_success = surface->Initialize(); - ANativeWindow_release(window); - if (!initialize_success) - return scoped_refptr<gfx::GLSurface>(); - - return scoped_refptr<gfx::GLSurface>( - new PassThroughImageTransportSurface(manager, stub, surface.get())); -} - -} // namespace content diff --git a/chromium/content/common/gpu/image_transport_surface_linux.cc b/chromium/content/common/gpu/image_transport_surface_linux.cc deleted file mode 100644 index db36efea135..00000000000 --- a/chromium/content/common/gpu/image_transport_surface_linux.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2013 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 "content/common/gpu/image_transport_surface.h" - -namespace content { - -// static -scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface( - GpuChannelManager* manager, - GpuCommandBufferStub* stub, - const gfx::GLSurfaceHandle& handle) { - DCHECK(handle.handle); - DCHECK(handle.transport_type == gfx::NATIVE_DIRECT); - scoped_refptr<gfx::GLSurface> surface; -#if defined(USE_OZONE) - surface = gfx::GLSurface::CreateSurfacelessViewGLSurface(handle.handle); -#endif - if (!surface) - surface = gfx::GLSurface::CreateViewGLSurface(handle.handle); - if (!surface) - return surface; - return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface( - manager, stub, surface.get())); -} - -} // namespace content diff --git a/chromium/content/common/gpu/image_transport_surface_mac.mm b/chromium/content/common/gpu/image_transport_surface_mac.mm deleted file mode 100644 index 1059589b084..00000000000 --- a/chromium/content/common/gpu/image_transport_surface_mac.mm +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2014 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 "content/common/gpu/image_transport_surface.h" - -#include "base/macros.h" -#include "content/common/gpu/gpu_messages.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gl/gl_context.h" -#include "ui/gl/gl_implementation.h" -#include "ui/gl/gl_surface_osmesa.h" - -namespace content { - -scoped_refptr<gfx::GLSurface> ImageTransportSurfaceCreateNativeSurface( - GpuChannelManager* manager, - GpuCommandBufferStub* stub, - gfx::PluginWindowHandle handle); - -namespace { - -// A subclass of GLSurfaceOSMesa that doesn't print an error message when -// SwapBuffers() is called. -class DRTSurfaceOSMesa : public gfx::GLSurfaceOSMesa { - public: - // Size doesn't matter, the surface is resized to the right size later. - DRTSurfaceOSMesa() - : GLSurfaceOSMesa(gfx::OSMesaSurfaceFormatRGBA, gfx::Size(1, 1)) {} - - // Implement a subset of GLSurface. - gfx::SwapResult SwapBuffers() override; - - private: - ~DRTSurfaceOSMesa() override {} - DISALLOW_COPY_AND_ASSIGN(DRTSurfaceOSMesa); -}; - -gfx::SwapResult DRTSurfaceOSMesa::SwapBuffers() { - return gfx::SwapResult::SWAP_ACK; -} - -bool g_allow_os_mesa = false; - -} // namespace - -// static -scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface( - GpuChannelManager* manager, - GpuCommandBufferStub* stub, - const gfx::GLSurfaceHandle& surface_handle) { - DCHECK(surface_handle.transport_type == gfx::NATIVE_DIRECT || - surface_handle.transport_type == gfx::NULL_TRANSPORT); - - switch (gfx::GetGLImplementation()) { - case gfx::kGLImplementationDesktopGL: - case gfx::kGLImplementationDesktopGLCoreProfile: - case gfx::kGLImplementationAppleGL: - return ImageTransportSurfaceCreateNativeSurface(manager, stub, - surface_handle.handle); - default: - // Content shell in DRT mode spins up a gpu process which needs an - // image transport surface, but that surface isn't used to read pixel - // baselines. So this is mostly a dummy surface. - if (!g_allow_os_mesa) { - NOTREACHED(); - return scoped_refptr<gfx::GLSurface>(); - } - scoped_refptr<gfx::GLSurface> surface(new DRTSurfaceOSMesa()); - if (!surface.get() || !surface->Initialize()) - return surface; - return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface( - manager, stub, surface.get())); - } -} - -// static -void ImageTransportSurface::SetAllowOSMesaForTesting(bool allow) { - g_allow_os_mesa = allow; -} - -} // namespace content diff --git a/chromium/content/common/gpu/image_transport_surface_overlay_mac.h b/chromium/content/common/gpu/image_transport_surface_overlay_mac.h deleted file mode 100644 index 2103bbf7108..00000000000 --- a/chromium/content/common/gpu/image_transport_surface_overlay_mac.h +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2015 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 CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_OVERLAY_MAC_H_ -#define CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_OVERLAY_MAC_H_ - -#include <list> -#include <vector> - -#import "base/mac/scoped_nsobject.h" -#include "base/timer/timer.h" -#include "content/common/gpu/gpu_command_buffer_stub.h" -#include "content/common/gpu/image_transport_surface.h" -#include "ui/gl/gl_surface.h" -#include "ui/gl/gpu_switching_observer.h" - -@class CAContext; -@class CALayer; - -namespace content { - -class CALayerTree; -class CALayerPartialDamageTree; - -class ImageTransportSurfaceOverlayMac : public gfx::GLSurface, - public ImageTransportSurface, - public ui::GpuSwitchingObserver { - public: - ImageTransportSurfaceOverlayMac(GpuChannelManager* manager, - GpuCommandBufferStub* stub, - gfx::PluginWindowHandle handle); - - // GLSurface implementation - bool Initialize() override; - void Destroy() override; - bool Resize(const gfx::Size& size, - float scale_factor, - bool has_alpha) override; - bool IsOffscreen() override; - gfx::SwapResult SwapBuffers() override; - gfx::SwapResult PostSubBuffer(int x, int y, int width, int height) override; - bool SupportsPostSubBuffer() override; - gfx::Size GetSize() override; - void* GetHandle() override; - bool OnMakeCurrent(gfx::GLContext* context) override; - bool SetBackbufferAllocation(bool allocated) override; - bool ScheduleOverlayPlane(int z_order, - gfx::OverlayTransform transform, - gl::GLImage* image, - const gfx::Rect& bounds_rect, - const gfx::RectF& crop_rect) override; - bool ScheduleCALayer(gl::GLImage* contents_image, - const gfx::RectF& contents_rect, - float opacity, - unsigned background_color, - unsigned edge_aa_mask, - const gfx::RectF& rect, - bool is_clipped, - const gfx::RectF& clip_rect, - const gfx::Transform& transform, - int sorting_context_id) override; - bool IsSurfaceless() const override; - - // ImageTransportSurface implementation - void OnBufferPresented( - const AcceleratedSurfaceMsg_BufferPresented_Params& params) override; - void SetLatencyInfo(const std::vector<ui::LatencyInfo>&) override; - - // ui::GpuSwitchingObserver implementation. - void OnGpuSwitched() override; - - private: - class PendingSwap; - class OverlayPlane; - - ~ImageTransportSurfaceOverlayMac() override; - - gfx::SwapResult SwapBuffersInternal(const gfx::Rect& pixel_damage_rect); - - // Returns true if the front of |pending_swaps_| has completed, or has timed - // out by |now|. - bool IsFirstPendingSwapReadyToDisplay( - const base::TimeTicks& now); - // Sets the CALayer contents to the IOSurface for the front of - // |pending_swaps_|, and removes it from the queue. - void DisplayFirstPendingSwapImmediately(); - // Force that all of |pending_swaps_| displayed immediately, and the list be - // cleared. - void DisplayAndClearAllPendingSwaps(); - // Callback issued during the next vsync period ofter a SwapBuffers call, - // to check if the swap is completed, and display the frame. Note that if - // another SwapBuffers happens before this callback, the pending swap will - // be tested at that time, too. - void CheckPendingSwapsCallback(); - // Function to post the above callback. The argument |now| is passed as an - // argument to avoid redundant calls to base::TimeTicks::Now. - void PostCheckPendingSwapsCallbackIfNeeded(const base::TimeTicks& now); - - // Return the time of |interval_fraction| of the way through the next - // vsync period that starts after |from|. If the vsync parameters are not - // valid then return |from|. - base::TimeTicks GetNextVSyncTimeAfter( - const base::TimeTicks& from, double interval_fraction); - - scoped_ptr<ImageTransportHelper> helper_; - bool use_remote_layer_api_; - base::scoped_nsobject<CAContext> ca_context_; - base::scoped_nsobject<CALayer> ca_root_layer_; - - gfx::Size pixel_size_; - float scale_factor_; - std::vector<ui::LatencyInfo> latency_info_; - - // The renderer ID that all contexts made current to this surface should be - // targeting. - GLint gl_renderer_id_; - - // Planes that have been scheduled, but have not had a subsequent SwapBuffers - // call made yet. - scoped_ptr<CALayerPartialDamageTree> pending_partial_damage_tree_; - scoped_ptr<CALayerTree> pending_ca_layer_tree_; - - // A queue of all frames that have been created by SwapBuffersInternal but - // have not yet been displayed. This queue is checked at the beginning of - // every swap and also by a callback. - std::deque<linked_ptr<PendingSwap>> pending_swaps_; - - // The planes that are currently being displayed on the screen. - scoped_ptr<CALayerPartialDamageTree> current_partial_damage_tree_; - scoped_ptr<CALayerTree> current_ca_layer_tree_; - - // The time of the last swap was issued. If this is more than two vsyncs, then - // use the simpler non-smooth animation path. - base::TimeTicks last_swap_time_; - - // The vsync information provided by the browser. - bool vsync_parameters_valid_; - base::TimeTicks vsync_timebase_; - base::TimeDelta vsync_interval_; - - base::Timer display_pending_swap_timer_; - base::WeakPtrFactory<ImageTransportSurfaceOverlayMac> weak_factory_; -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_OVERLAY_MAC_H_ diff --git a/chromium/content/common/gpu/image_transport_surface_overlay_mac.mm b/chromium/content/common/gpu/image_transport_surface_overlay_mac.mm deleted file mode 100644 index 1b0e3372e2d..00000000000 --- a/chromium/content/common/gpu/image_transport_surface_overlay_mac.mm +++ /dev/null @@ -1,522 +0,0 @@ -// Copyright 2015 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 "content/common/gpu/image_transport_surface_overlay_mac.h" - -#include <CoreGraphics/CoreGraphics.h> -#include <IOSurface/IOSurface.h> -#include <OpenGL/CGLRenderers.h> -#include <OpenGL/CGLTypes.h> -#include <OpenGL/gl.h> -#include <stddef.h> - -#include <algorithm> - -// This type consistently causes problem on Mac, and needs to be dealt with -// in a systemic way. -// http://crbug.com/517208 -#ifndef GL_OES_EGL_image -typedef void* GLeglImageOES; -#endif - -#include "base/mac/scoped_cftyperef.h" -#include "base/trace_event/trace_event.h" -#include "content/common/gpu/ca_layer_partial_damage_tree_mac.h" -#include "content/common/gpu/ca_layer_tree_mac.h" -#include "content/common/gpu/gpu_messages.h" -#include "ui/accelerated_widget_mac/io_surface_context.h" -#include "ui/base/cocoa/animation_utils.h" -#include "ui/base/cocoa/remote_layer_api.h" -#include "ui/gfx/geometry/rect_conversions.h" -#include "ui/gfx/transform.h" -#include "ui/gl/gl_context.h" -#include "ui/gl/gl_fence.h" -#include "ui/gl/gl_image_io_surface.h" -#include "ui/gl/gpu_switching_manager.h" -#include "ui/gl/scoped_api.h" -#include "ui/gl/scoped_cgl.h" - -namespace { - -// Don't let a frame draw until 5% of the way through the next vsync interval -// after the call to SwapBuffers. This slight offset is to ensure that skew -// doesn't result in the frame being presented to the previous vsync interval. -const double kVSyncIntervalFractionForEarliestDisplay = 0.05; - -// After doing a glFlush and putting in a fence in SwapBuffers, post a task to -// query the fence 50% of the way through the next vsync interval. If we are -// trying to animate smoothly, then want to query the fence at the next -// SwapBuffers. For this reason we schedule the callback for a long way into -// the next frame. -const double kVSyncIntervalFractionForDisplayCallback = 0.5; - -// If swaps arrive regularly and nearly at the vsync rate, then attempt to -// make animation smooth (each frame is shown for one vsync interval) by sending -// them to the window server only when their GL work completes. If frames are -// not coming in with each vsync, then just throw them at the window server as -// they come. -const double kMaximumVSyncsBetweenSwapsForSmoothAnimation = 1.5; - -void CheckGLErrors(const char* msg) { - GLenum gl_error; - while ((gl_error = glGetError()) != GL_NO_ERROR) { - LOG(ERROR) << "OpenGL error hit " << msg << ": " << gl_error; - } -} - -void IOSurfaceContextNoOp(scoped_refptr<ui::IOSurfaceContext>) { -} - -} // namespace - -@interface CALayer(Private) --(void)setContentsChanged; -@end - -namespace content { - -scoped_refptr<gfx::GLSurface> ImageTransportSurfaceCreateNativeSurface( - GpuChannelManager* manager, - GpuCommandBufferStub* stub, - gfx::PluginWindowHandle handle) { - return new ImageTransportSurfaceOverlayMac(manager, stub, handle); -} - -class ImageTransportSurfaceOverlayMac::PendingSwap { - public: - PendingSwap() {} - ~PendingSwap() { DCHECK(!gl_fence); } - - gfx::Size pixel_size; - float scale_factor; - gfx::Rect pixel_damage_rect; - - scoped_ptr<CALayerPartialDamageTree> partial_damage_tree; - scoped_ptr<CALayerTree> ca_layer_tree; - std::vector<ui::LatencyInfo> latency_info; - - // A fence object, and the CGL context it was issued in. - base::ScopedTypeRef<CGLContextObj> cgl_context; - scoped_ptr<gfx::GLFence> gl_fence; - - // The earliest time that this frame may be drawn. A frame is not allowed - // to draw until a fraction of the way through the vsync interval after its - // This extra latency is to allow wiggle-room for smoothness. - base::TimeTicks earliest_display_time_allowed; - - // The time that this will wake up and draw, if a following swap does not - // cause it to draw earlier. - base::TimeTicks target_display_time; -}; - -ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac( - GpuChannelManager* manager, - GpuCommandBufferStub* stub, - gfx::PluginWindowHandle handle) - : use_remote_layer_api_(ui::RemoteLayerAPISupported()), - scale_factor_(1), - gl_renderer_id_(0), - vsync_parameters_valid_(false), - display_pending_swap_timer_(true, false), - weak_factory_(this) { - helper_.reset(new ImageTransportHelper(this, manager, stub, handle)); - ui::GpuSwitchingManager::GetInstance()->AddObserver(this); -} - -ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() { - ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this); - Destroy(); -} - -bool ImageTransportSurfaceOverlayMac::Initialize() { - if (!helper_->Initialize()) - return false; - - // Create the CAContext to send this to the GPU process, and the layer for - // the context. - if (use_remote_layer_api_) { - CGSConnectionID connection_id = CGSMainConnectionID(); - ca_context_.reset([ - [CAContext contextWithCGSConnection:connection_id options:@{}] retain]); - ca_root_layer_.reset([[CALayer alloc] init]); - [ca_root_layer_ setGeometryFlipped:YES]; - [ca_root_layer_ setOpaque:YES]; - [ca_context_ setLayer:ca_root_layer_]; - } - return true; -} - -void ImageTransportSurfaceOverlayMac::Destroy() { - DisplayAndClearAllPendingSwaps(); - - current_partial_damage_tree_.reset(); - current_ca_layer_tree_.reset(); -} - -bool ImageTransportSurfaceOverlayMac::IsOffscreen() { - return false; -} - -gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal( - const gfx::Rect& pixel_damage_rect) { - TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffersInternal"); - - // Use the same concept of 'now' for the entire function. The duration of - // this function only affect the result if this function lasts across a vsync - // boundary, in which case smooth animation is out the window anyway. - const base::TimeTicks now = base::TimeTicks::Now(); - - // Decide if the frame should be drawn immediately, or if we should wait until - // its work finishes before drawing immediately. - bool display_immediately = false; - if (vsync_parameters_valid_ && - now - last_swap_time_ > - kMaximumVSyncsBetweenSwapsForSmoothAnimation * vsync_interval_) { - display_immediately = true; - } - last_swap_time_ = now; - - // If the previous swap is ready to display, do it before flushing the - // new swap. It is desirable to always be hitting this path when trying to - // animate smoothly with vsync. - if (!pending_swaps_.empty()) { - if (IsFirstPendingSwapReadyToDisplay(now)) - DisplayFirstPendingSwapImmediately(); - } - - // The remainder of the function will populate the PendingSwap structure and - // then enqueue it. - linked_ptr<PendingSwap> new_swap(new PendingSwap); - new_swap->pixel_size = pixel_size_; - new_swap->scale_factor = scale_factor_; - new_swap->pixel_damage_rect = pixel_damage_rect; - new_swap->partial_damage_tree.swap(pending_partial_damage_tree_); - new_swap->ca_layer_tree.swap(pending_ca_layer_tree_); - new_swap->latency_info.swap(latency_info_); - - // A flush is required to ensure that all content appears in the layer. - { - gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; - TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::glFlush"); - CheckGLErrors("before flushing frame"); - new_swap->cgl_context.reset(CGLGetCurrentContext(), - base::scoped_policy::RETAIN); - if (gfx::GLFence::IsSupported() && !display_immediately) - new_swap->gl_fence.reset(gfx::GLFence::Create()); - else - glFlush(); - CheckGLErrors("while flushing frame"); - } - - // Compute the deadlines for drawing this frame. - if (display_immediately) { - new_swap->earliest_display_time_allowed = now; - new_swap->target_display_time = now; - } else { - new_swap->earliest_display_time_allowed = - GetNextVSyncTimeAfter(now, kVSyncIntervalFractionForEarliestDisplay); - new_swap->target_display_time = - GetNextVSyncTimeAfter(now, kVSyncIntervalFractionForDisplayCallback); - } - - pending_swaps_.push_back(new_swap); - if (display_immediately) - DisplayFirstPendingSwapImmediately(); - else - PostCheckPendingSwapsCallbackIfNeeded(now); - return gfx::SwapResult::SWAP_ACK; -} - -bool ImageTransportSurfaceOverlayMac::IsFirstPendingSwapReadyToDisplay( - const base::TimeTicks& now) { - DCHECK(!pending_swaps_.empty()); - linked_ptr<PendingSwap> swap = pending_swaps_.front(); - - // Frames are disallowed from drawing until the vsync interval after their - // swap is issued. - if (now < swap->earliest_display_time_allowed) - return false; - - // If we've passed that marker, then wait for the work behind the fence to - // complete. - if (swap->gl_fence) { - gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; - gfx::ScopedCGLSetCurrentContext scoped_set_current(swap->cgl_context); - - CheckGLErrors("before waiting on fence"); - if (!swap->gl_fence->HasCompleted()) { - TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::ClientWait"); - swap->gl_fence->ClientWait(); - } - swap->gl_fence.reset(); - CheckGLErrors("after waiting on fence"); - } - return true; -} - -void ImageTransportSurfaceOverlayMac::DisplayFirstPendingSwapImmediately() { - TRACE_EVENT0("gpu", - "ImageTransportSurfaceOverlayMac::DisplayFirstPendingSwapImmediately"); - DCHECK(!pending_swaps_.empty()); - linked_ptr<PendingSwap> swap = pending_swaps_.front(); - - // If there is a fence for this object, delete it. - if (swap->gl_fence) { - gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; - gfx::ScopedCGLSetCurrentContext scoped_set_current(swap->cgl_context); - - CheckGLErrors("before deleting active fence"); - swap->gl_fence.reset(); - CheckGLErrors("while deleting active fence"); - } - - // Update the CALayer hierarchy. - { - gfx::RectF pixel_damage_rect = gfx::RectF(swap->pixel_damage_rect); - ScopedCAActionDisabler disabler; - if (swap->ca_layer_tree) { - swap->ca_layer_tree->CommitScheduledCALayers( - ca_root_layer_.get(), std::move(current_ca_layer_tree_), - swap->scale_factor); - current_ca_layer_tree_.swap(swap->ca_layer_tree); - current_partial_damage_tree_.reset(); - } else if (swap->partial_damage_tree) { - swap->partial_damage_tree->CommitCALayers( - ca_root_layer_.get(), std::move(current_partial_damage_tree_), - swap->scale_factor, swap->pixel_damage_rect); - current_partial_damage_tree_.swap(swap->partial_damage_tree); - current_ca_layer_tree_.reset(); - } else { - TRACE_EVENT0("gpu", "Blank frame: No overlays or CALayers"); - [ca_root_layer_ setSublayers:nil]; - current_partial_damage_tree_.reset(); - current_ca_layer_tree_.reset(); - } - swap->ca_layer_tree.reset(); - swap->partial_damage_tree.reset(); - } - - // Update the latency info to reflect the swap time. - base::TimeTicks swap_time = base::TimeTicks::Now(); - for (auto latency_info : swap->latency_info) { - latency_info.AddLatencyNumberWithTimestamp( - ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1); - latency_info.AddLatencyNumberWithTimestamp( - ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0, - swap_time, 1); - } - - // Send acknowledgement to the browser. - GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; - if (use_remote_layer_api_) { - params.ca_context_id = [ca_context_ contextId]; - } else if (current_partial_damage_tree_) { - params.io_surface.reset(IOSurfaceCreateMachPort( - current_partial_damage_tree_->RootLayerIOSurface())); - } - params.size = swap->pixel_size; - params.scale_factor = swap->scale_factor; - params.latency_info.swap(swap->latency_info); - helper_->SendAcceleratedSurfaceBuffersSwapped(params); - - // Remove this from the queue, and reset any callback timers. - pending_swaps_.pop_front(); -} - -void ImageTransportSurfaceOverlayMac::DisplayAndClearAllPendingSwaps() { - TRACE_EVENT0("gpu", - "ImageTransportSurfaceOverlayMac::DisplayAndClearAllPendingSwaps"); - while (!pending_swaps_.empty()) - DisplayFirstPendingSwapImmediately(); -} - -void ImageTransportSurfaceOverlayMac::CheckPendingSwapsCallback() { - TRACE_EVENT0("gpu", - "ImageTransportSurfaceOverlayMac::CheckPendingSwapsCallback"); - - if (pending_swaps_.empty()) - return; - - const base::TimeTicks now = base::TimeTicks::Now(); - if (IsFirstPendingSwapReadyToDisplay(now)) - DisplayFirstPendingSwapImmediately(); - PostCheckPendingSwapsCallbackIfNeeded(now); -} - -void ImageTransportSurfaceOverlayMac::PostCheckPendingSwapsCallbackIfNeeded( - const base::TimeTicks& now) { - TRACE_EVENT0("gpu", - "ImageTransportSurfaceOverlayMac::PostCheckPendingSwapsCallbackIfNeeded"); - - if (pending_swaps_.empty()) { - display_pending_swap_timer_.Stop(); - } else { - display_pending_swap_timer_.Start( - FROM_HERE, - pending_swaps_.front()->target_display_time - now, - base::Bind(&ImageTransportSurfaceOverlayMac::CheckPendingSwapsCallback, - weak_factory_.GetWeakPtr())); - } -} - -gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() { - return SwapBuffersInternal( - gfx::Rect(0, 0, pixel_size_.width(), pixel_size_.height())); -} - -gfx::SwapResult ImageTransportSurfaceOverlayMac::PostSubBuffer(int x, - int y, - int width, - int height) { - return SwapBuffersInternal(gfx::Rect(x, y, width, height)); -} - -bool ImageTransportSurfaceOverlayMac::SupportsPostSubBuffer() { - return true; -} - -gfx::Size ImageTransportSurfaceOverlayMac::GetSize() { - return gfx::Size(); -} - -void* ImageTransportSurfaceOverlayMac::GetHandle() { - return nullptr; -} - -bool ImageTransportSurfaceOverlayMac::OnMakeCurrent(gfx::GLContext* context) { - // Ensure that the context is on the appropriate GL renderer. The GL renderer - // will generally only change when the GPU changes. - if (gl_renderer_id_ && context) - context->share_group()->SetRendererID(gl_renderer_id_); - return true; -} - -bool ImageTransportSurfaceOverlayMac::SetBackbufferAllocation(bool allocated) { - if (!allocated) { - DisplayAndClearAllPendingSwaps(); - last_swap_time_ = base::TimeTicks(); - } - return true; -} - -bool ImageTransportSurfaceOverlayMac::ScheduleOverlayPlane( - int z_order, - gfx::OverlayTransform transform, - gl::GLImage* image, - const gfx::Rect& pixel_frame_rect, - const gfx::RectF& crop_rect) { - if (transform != gfx::OVERLAY_TRANSFORM_NONE) { - DLOG(ERROR) << "Invalid overlay plane transform."; - return false; - } - if (z_order) { - DLOG(ERROR) << "Invalid non-zero Z order."; - return false; - } - if (pending_partial_damage_tree_) { - DLOG(ERROR) << "Only one overlay per swap is allowed."; - return false; - } - pending_partial_damage_tree_.reset(new CALayerPartialDamageTree( - use_remote_layer_api_, - static_cast<gl::GLImageIOSurface*>(image)->io_surface(), - pixel_frame_rect)); - return true; -} - -bool ImageTransportSurfaceOverlayMac::ScheduleCALayer( - gl::GLImage* contents_image, - const gfx::RectF& contents_rect, - float opacity, - unsigned background_color, - unsigned edge_aa_mask, - const gfx::RectF& rect, - bool is_clipped, - const gfx::RectF& clip_rect, - const gfx::Transform& transform, - int sorting_context_id) { - base::ScopedCFTypeRef<IOSurfaceRef> io_surface; - if (contents_image) { - io_surface = - static_cast<gl::GLImageIOSurface*>(contents_image)->io_surface(); - } - if (!pending_ca_layer_tree_) - pending_ca_layer_tree_.reset(new CALayerTree); - return pending_ca_layer_tree_->ScheduleCALayer( - is_clipped, gfx::ToEnclosingRect(clip_rect), sorting_context_id, - transform, io_surface, contents_rect, gfx::ToEnclosingRect(rect), - background_color, edge_aa_mask, opacity); -} - -bool ImageTransportSurfaceOverlayMac::IsSurfaceless() const { - return true; -} - -void ImageTransportSurfaceOverlayMac::OnBufferPresented( - const AcceleratedSurfaceMsg_BufferPresented_Params& params) { - vsync_timebase_ = params.vsync_timebase; - vsync_interval_ = params.vsync_interval; - vsync_parameters_valid_ = (vsync_interval_ != base::TimeDelta()); - - // Compute |vsync_timebase_| to be the first vsync after time zero. - if (vsync_parameters_valid_) { - vsync_timebase_ -= - vsync_interval_ * - ((vsync_timebase_ - base::TimeTicks()) / vsync_interval_); - } -} - -bool ImageTransportSurfaceOverlayMac::Resize(const gfx::Size& pixel_size, - float scale_factor, - bool has_alpha) { - // Flush through any pending frames. - DisplayAndClearAllPendingSwaps(); - pixel_size_ = pixel_size; - scale_factor_ = scale_factor; - return true; -} - -void ImageTransportSurfaceOverlayMac::SetLatencyInfo( - const std::vector<ui::LatencyInfo>& latency_info) { - latency_info_.insert( - latency_info_.end(), latency_info.begin(), latency_info.end()); -} - -void ImageTransportSurfaceOverlayMac::OnGpuSwitched() { - // Create a new context, and use the GL renderer ID that the new context gets. - scoped_refptr<ui::IOSurfaceContext> context_on_new_gpu = - ui::IOSurfaceContext::Get(ui::IOSurfaceContext::kCALayerContext); - if (!context_on_new_gpu) - return; - GLint context_renderer_id = -1; - if (CGLGetParameter(context_on_new_gpu->cgl_context(), - kCGLCPCurrentRendererID, - &context_renderer_id) != kCGLNoError) { - LOG(ERROR) << "Failed to create test context after GPU switch"; - return; - } - gl_renderer_id_ = context_renderer_id & kCGLRendererIDMatchingMask; - - // Post a task holding a reference to the new GL context. The reason for - // this is to avoid creating-then-destroying the context for every image - // transport surface that is observing the GPU switch. - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&IOSurfaceContextNoOp, context_on_new_gpu)); -} - -base::TimeTicks ImageTransportSurfaceOverlayMac::GetNextVSyncTimeAfter( - const base::TimeTicks& from, double interval_fraction) { - if (!vsync_parameters_valid_) - return from; - - // Compute the previous vsync time. - base::TimeTicks previous_vsync = - vsync_interval_ * ((from - vsync_timebase_) / vsync_interval_) + - vsync_timebase_; - - // Return |interval_fraction| through the next vsync. - return previous_vsync + (1 + interval_fraction) * vsync_interval_; -} - -} // namespace content diff --git a/chromium/content/common/gpu/image_transport_surface_win.cc b/chromium/content/common/gpu/image_transport_surface_win.cc deleted file mode 100644 index 15f43d2a00f..00000000000 --- a/chromium/content/common/gpu/image_transport_surface_win.cc +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2012 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 "content/common/gpu/image_transport_surface.h" - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/compiler_specific.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "base/win/windows_version.h" -#include "content/common/gpu/child_window_surface_win.h" -#include "content/common/gpu/gpu_messages.h" -#include "content/public/common/content_switches.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gl/gl_bindings.h" -#include "ui/gl/gl_context.h" -#include "ui/gl/gl_implementation.h" -#include "ui/gl/gl_surface_egl.h" -#include "ui/gl/vsync_provider_win.h" - -namespace content { - -// static -scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface( - GpuChannelManager* manager, - GpuCommandBufferStub* stub, - const gfx::GLSurfaceHandle& handle) { - DCHECK(handle.handle); - DCHECK_EQ(handle.transport_type, gfx::NATIVE_DIRECT); - - scoped_refptr<gfx::GLSurface> surface; - if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2 && - gfx::GLSurfaceEGL::IsDirectCompositionSupported()) { - scoped_refptr<ChildWindowSurfaceWin> egl_surface( - new ChildWindowSurfaceWin(manager, handle.handle)); - surface = egl_surface; - - // TODO(jbauman): Get frame statistics from DirectComposition - scoped_ptr<gfx::VSyncProvider> vsync_provider( - new gfx::VSyncProviderWin(handle.handle)); - if (!egl_surface->Initialize(std::move(vsync_provider))) - return nullptr; - } else { - surface = gfx::GLSurface::CreateViewGLSurface(handle.handle); - } - - return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface( - manager, stub, surface.get())); -} - -} // namespace content diff --git a/chromium/content/common/gpu/media/OWNERS b/chromium/content/common/gpu/media/OWNERS index 633a1877529..9999d737345 100644 --- a/chromium/content/common/gpu/media/OWNERS +++ b/chromium/content/common/gpu/media/OWNERS @@ -2,3 +2,16 @@ dalecurtis@chromium.org posciak@chromium.org sandersd@chromium.org wuchengli@chromium.org + +# For security review of IPC message files. +per-file *_messages*.h=set noparent +per-file *_messages*.h=dcheng@chromium.org +per-file *_messages*.h=inferno@chromium.org +per-file *_messages*.h=jln@chromium.org +per-file *_messages*.h=jschuh@chromium.org +per-file *_messages*.h=kenrb@chromium.org +per-file *_messages*.h=mkwst@chromium.org +per-file *_messages*.h=nasko@chromium.org +per-file *_messages*.h=palmer@chromium.org +per-file *_messages*.h=tsepez@chromium.org +per-file *_messages*.h=wfh@chromium.org diff --git a/chromium/content/common/gpu/media/android_copying_backing_strategy.cc b/chromium/content/common/gpu/media/android_copying_backing_strategy.cc index f80a16f3d72..b5216154829 100644 --- a/chromium/content/common/gpu/media/android_copying_backing_strategy.cc +++ b/chromium/content/common/gpu/media/android_copying_backing_strategy.cc @@ -8,6 +8,7 @@ #include "base/logging.h" #include "base/trace_event/trace_event.h" #include "content/common/gpu/media/avda_return_on_failure.h" +#include "gpu/command_buffer/service/context_group.h" #include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "media/base/limits.h" @@ -17,24 +18,47 @@ namespace content { -const static GLfloat kIdentityMatrix[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f}; - -AndroidCopyingBackingStrategy::AndroidCopyingBackingStrategy() - : state_provider_(nullptr), surface_texture_id_(0), media_codec_(nullptr) {} +AndroidCopyingBackingStrategy::AndroidCopyingBackingStrategy( + AVDAStateProvider* state_provider) + : state_provider_(state_provider), + surface_texture_id_(0), + media_codec_(nullptr) {} AndroidCopyingBackingStrategy::~AndroidCopyingBackingStrategy() {} -void AndroidCopyingBackingStrategy::Initialize( - AVDAStateProvider* state_provider) { - state_provider_ = state_provider; +gfx::ScopedJavaSurface AndroidCopyingBackingStrategy::Initialize( + int surface_view_id) { + if (surface_view_id != media::VideoDecodeAccelerator::Config::kNoSurfaceID) { + LOG(ERROR) << "The copying strategy should not be initialized with a " + "surface id."; + return gfx::ScopedJavaSurface(); + } + + // Create a texture and attach the SurfaceTexture to it. + glGenTextures(1, &surface_texture_id_); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, surface_texture_id_); + + // Note that the target will be correctly sized, so nearest filtering is all + // that's needed. + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + state_provider_->GetGlDecoder()->RestoreTextureUnitBindings(0); + state_provider_->GetGlDecoder()->RestoreActiveTexture(); + + surface_texture_ = gfx::SurfaceTexture::Create(surface_texture_id_); + + return gfx::ScopedJavaSurface(surface_texture_.get()); } void AndroidCopyingBackingStrategy::Cleanup( bool have_context, const AndroidVideoDecodeAccelerator::OutputBufferMap&) { DCHECK(state_provider_->ThreadChecker().CalledOnValidThread()); + if (copier_) copier_->Destroy(); @@ -42,26 +66,17 @@ void AndroidCopyingBackingStrategy::Cleanup( glDeleteTextures(1, &surface_texture_id_); } +scoped_refptr<gfx::SurfaceTexture> +AndroidCopyingBackingStrategy::GetSurfaceTexture() const { + return surface_texture_; +} + uint32_t AndroidCopyingBackingStrategy::GetTextureTarget() const { return GL_TEXTURE_2D; } -scoped_refptr<gfx::SurfaceTexture> -AndroidCopyingBackingStrategy::CreateSurfaceTexture() { - glGenTextures(1, &surface_texture_id_); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_EXTERNAL_OES, surface_texture_id_); - - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - state_provider_->GetGlDecoder()->RestoreTextureUnitBindings(0); - state_provider_->GetGlDecoder()->RestoreActiveTexture(); - - surface_texture_ = gfx::SurfaceTexture::Create(surface_texture_id_); - - return surface_texture_; +gfx::Size AndroidCopyingBackingStrategy::GetPictureBufferSize() const { + return state_provider_->GetSize(); } void AndroidCopyingBackingStrategy::UseCodecBufferForPictureBuffer( @@ -99,16 +114,19 @@ void AndroidCopyingBackingStrategy::UseCodecBufferForPictureBuffer( surface_texture_->UpdateTexImage(); } - float transfrom_matrix[16]; - surface_texture_->GetTransformMatrix(transfrom_matrix); + float transform_matrix[16]; + surface_texture_->GetTransformMatrix(transform_matrix); - uint32_t picture_buffer_texture_id = picture_buffer.texture_id(); + DCHECK_LE(1u, picture_buffer.texture_ids().size()); + uint32_t picture_buffer_texture_id = picture_buffer.texture_ids()[0]; // Defer initializing the CopyTextureCHROMIUMResourceManager until it is // needed because it takes 10s of milliseconds to initialize. if (!copier_) { copier_.reset(new gpu::CopyTextureCHROMIUMResourceManager()); - copier_->Initialize(state_provider_->GetGlDecoder().get()); + copier_->Initialize(state_provider_->GetGlDecoder().get(), + state_provider_->GetGlDecoder()->GetContextGroup()-> + feature_info()->feature_flags()); } // Here, we copy |surface_texture_id_| to the picture buffer instead of @@ -118,13 +136,11 @@ void AndroidCopyingBackingStrategy::UseCodecBufferForPictureBuffer( // attached. // 2. SurfaceTexture requires us to apply a transform matrix when we show // the texture. - // TODO(hkuang): get the StreamTexture transform matrix in GPU process - // instead of using default matrix crbug.com/226218. copier_->DoCopyTextureWithTransform( state_provider_->GetGlDecoder().get(), GL_TEXTURE_EXTERNAL_OES, surface_texture_id_, GL_TEXTURE_2D, picture_buffer_texture_id, state_provider_->GetSize().width(), state_provider_->GetSize().height(), - false, false, false, kIdentityMatrix); + true, false, false, transform_matrix); } void AndroidCopyingBackingStrategy::CodecChanged( @@ -140,4 +156,37 @@ void AndroidCopyingBackingStrategy::OnFrameAvailable() { // instead preserve the old behavior. } +bool AndroidCopyingBackingStrategy::ArePicturesOverlayable() { + return false; +} + +void AndroidCopyingBackingStrategy::UpdatePictureBufferSize( + media::PictureBuffer* picture_buffer, + const gfx::Size& new_size) { + // This strategy uses 2D textures who's allocated memory is dependent on the + // size. To update size in all places, we must: + // 1) Update the PictureBuffer meta-data + picture_buffer->set_size(new_size); + + // 2) Update the GL texture via glTexImage2D. This step assumes the caller + // has made our GL context current. + DCHECK_LE(1u, picture_buffer->texture_ids().size()); + glBindTexture(GL_TEXTURE_2D, picture_buffer->texture_ids()[0]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, new_size.width(), new_size.height(), + 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + state_provider_->GetGlDecoder()->RestoreActiveTextureUnitBinding( + GL_TEXTURE_2D); + + // 3) Update the CHROMIUM Texture's size. + gpu::gles2::TextureRef* texture_ref = + state_provider_->GetTextureForPicture(*picture_buffer); + RETURN_IF_NULL(texture_ref); + gpu::gles2::TextureManager* texture_manager = + state_provider_->GetGlDecoder()->GetContextGroup()->texture_manager(); + RETURN_IF_NULL(texture_manager); + texture_manager->SetLevelInfo(texture_ref, GetTextureTarget(), 0, GL_RGBA, + new_size.width(), new_size.height(), 1, 0, + GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(new_size)); +} + } // namespace content diff --git a/chromium/content/common/gpu/media/android_copying_backing_strategy.h b/chromium/content/common/gpu/media/android_copying_backing_strategy.h index 17b096aecd5..8980404dfdb 100644 --- a/chromium/content/common/gpu/media/android_copying_backing_strategy.h +++ b/chromium/content/common/gpu/media/android_copying_backing_strategy.h @@ -28,21 +28,25 @@ class AVDAStateProvider; class CONTENT_EXPORT AndroidCopyingBackingStrategy : public AndroidVideoDecodeAccelerator::BackingStrategy { public: - AndroidCopyingBackingStrategy(); + explicit AndroidCopyingBackingStrategy(AVDAStateProvider* state_provider); ~AndroidCopyingBackingStrategy() override; // AndroidVideoDecodeAccelerator::BackingStrategy - void Initialize(AVDAStateProvider*) override; + gfx::ScopedJavaSurface Initialize(int surface_view_id) override; void Cleanup(bool have_context, const AndroidVideoDecodeAccelerator::OutputBufferMap&) override; + scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture() const override; uint32_t GetTextureTarget() const override; - scoped_refptr<gfx::SurfaceTexture> CreateSurfaceTexture() override; + gfx::Size GetPictureBufferSize() const override; void UseCodecBufferForPictureBuffer(int32_t codec_buffer_index, const media::PictureBuffer&) override; void CodecChanged( media::VideoCodecBridge*, const AndroidVideoDecodeAccelerator::OutputBufferMap&) override; void OnFrameAvailable() override; + bool ArePicturesOverlayable() override; + void UpdatePictureBufferSize(media::PictureBuffer* picture_buffer, + const gfx::Size& new_size) override; private: // Used for copy the texture from surface texture to picture buffers. diff --git a/chromium/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc b/chromium/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc index 660785eea90..3e62629745d 100644 --- a/chromium/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc +++ b/chromium/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc @@ -4,30 +4,41 @@ #include "content/common/gpu/media/android_deferred_rendering_backing_strategy.h" +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include "base/android/build_info.h" #include "base/bind.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" #include "base/metrics/histogram.h" -#include "content/common/gpu/gpu_channel.h" #include "content/common/gpu/media/avda_codec_image.h" #include "content/common/gpu/media/avda_return_on_failure.h" #include "content/common/gpu/media/avda_shared_state.h" +#include "gpu/command_buffer/service/context_group.h" +#include "gpu/command_buffer/service/gl_stream_texture_image.h" +#include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h" #include "gpu/command_buffer/service/texture_manager.h" +#include "gpu/ipc/common/gpu_surface_lookup.h" +#include "gpu/ipc/service/gpu_channel.h" #include "ui/gl/android/surface_texture.h" +#include "ui/gl/egl_util.h" #include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_surface_egl.h" +#include "ui/gl/scoped_binders.h" +#include "ui/gl/scoped_make_current.h" namespace content { AndroidDeferredRenderingBackingStrategy:: - AndroidDeferredRenderingBackingStrategy() - : state_provider_(nullptr), media_codec_(nullptr) {} + AndroidDeferredRenderingBackingStrategy(AVDAStateProvider* state_provider) + : state_provider_(state_provider), media_codec_(nullptr) {} AndroidDeferredRenderingBackingStrategy:: ~AndroidDeferredRenderingBackingStrategy() {} -void AndroidDeferredRenderingBackingStrategy::Initialize( - AVDAStateProvider* state_provider) { - state_provider_ = state_provider; +gfx::ScopedJavaSurface AndroidDeferredRenderingBackingStrategy::Initialize( + int surface_view_id) { shared_state_ = new AVDASharedState(); // Create a texture for the SurfaceTexture to use. We don't attach it here @@ -36,6 +47,27 @@ void AndroidDeferredRenderingBackingStrategy::Initialize( glGenTextures(1, &service_id); DCHECK(service_id); shared_state_->set_surface_texture_service_id(service_id); + + gfx::ScopedJavaSurface surface; + if (surface_view_id != media::VideoDecodeAccelerator::Config::kNoSurfaceID) { + surface = gpu::GpuSurfaceLookup::GetInstance()->AcquireJavaSurface( + surface_view_id); + } else { + if (DoesSurfaceTextureDetachWork()) { + // Create a detached SurfaceTexture. Detaching it will silently fail to + // delete texture 0. + surface_texture_ = gfx::SurfaceTexture::Create(0); + surface_texture_->DetachFromGLContext(); + } else { + // Detach doesn't work so well on all platforms. Just attach the + // SurfaceTexture here, and probably context switch later. + surface_texture_ = gfx::SurfaceTexture::Create(service_id); + shared_state_->DidAttachSurfaceTexture(); + } + surface = gfx::ScopedJavaSurface(surface_texture_.get()); + } + + return surface; } void AndroidDeferredRenderingBackingStrategy::Cleanup( @@ -50,6 +82,11 @@ void AndroidDeferredRenderingBackingStrategy::Cleanup( for (const std::pair<int, media::PictureBuffer>& entry : buffers) SetImageForPicture(entry.second, nullptr); + // If we're rendering to a SurfaceTexture we can make a copy of the current + // front buffer so that the PictureBuffer textures are still valid. + if (surface_texture_ && have_context && ShouldCopyPictures()) + CopySurfaceTextureToPictures(buffers); + // Now that no AVDACodecImages refer to the SurfaceTexture's texture, delete // the texture name. GLuint service_id = shared_state_->surface_texture_service_id(); @@ -57,38 +94,35 @@ void AndroidDeferredRenderingBackingStrategy::Cleanup( glDeleteTextures(1, &service_id); } -uint32_t AndroidDeferredRenderingBackingStrategy::GetTextureTarget() const { - return GL_TEXTURE_EXTERNAL_OES; -} - scoped_refptr<gfx::SurfaceTexture> -AndroidDeferredRenderingBackingStrategy::CreateSurfaceTexture() { - // AVDACodecImage will handle attaching this to a texture later. - surface_texture_ = gfx::SurfaceTexture::Create(0); - // Detach from our GL context so that the GLImages can attach. It will - // silently fail to delete texture 0. - surface_texture_->DetachFromGLContext(); - +AndroidDeferredRenderingBackingStrategy::GetSurfaceTexture() const { return surface_texture_; } -gpu::gles2::TextureRef* -AndroidDeferredRenderingBackingStrategy::GetTextureForPicture( - const media::PictureBuffer& picture_buffer) { - RETURN_NULL_IF_NULL(state_provider_->GetGlDecoder()); - gpu::gles2::TextureManager* texture_manager = - state_provider_->GetGlDecoder()->GetContextGroup()->texture_manager(); - RETURN_NULL_IF_NULL(texture_manager); - gpu::gles2::TextureRef* texture_ref = - texture_manager->GetTexture(picture_buffer.internal_texture_id()); - RETURN_NULL_IF_NULL(texture_ref); +uint32_t AndroidDeferredRenderingBackingStrategy::GetTextureTarget() const { + // If we're using a surface texture, then we need an external texture target + // to sample from it. If not, then we'll use 2D transparent textures to draw + // a transparent hole through which to see the SurfaceView. This is normally + // needed only for the devtools inspector, since the overlay mechanism handles + // it otherwise. + return surface_texture_ ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D; +} - return texture_ref; +gfx::Size AndroidDeferredRenderingBackingStrategy::GetPictureBufferSize() + const { + // For SurfaceView, request a 1x1 2D texture to reduce memory during + // initialization. For SurfaceTexture, allocate a picture buffer that is the + // actual frame size. Note that it will be an external texture anyway, so it + // doesn't allocate an image of that size. However, it's still important to + // get the coded size right, so that VideoLayerImpl doesn't try to scale the + // texture when building the quad for it. + return surface_texture_ ? state_provider_->GetSize() : gfx::Size(1, 1); } AVDACodecImage* AndroidDeferredRenderingBackingStrategy::GetImageForPicture( const media::PictureBuffer& picture_buffer) { - gpu::gles2::TextureRef* texture_ref = GetTextureForPicture(picture_buffer); + gpu::gles2::TextureRef* texture_ref = + state_provider_->GetTextureForPicture(picture_buffer); RETURN_NULL_IF_NULL(texture_ref); gl::GLImage* image = texture_ref->texture()->GetLevelImage(GetTextureTarget(), 0); @@ -97,8 +131,9 @@ AVDACodecImage* AndroidDeferredRenderingBackingStrategy::GetImageForPicture( void AndroidDeferredRenderingBackingStrategy::SetImageForPicture( const media::PictureBuffer& picture_buffer, - const scoped_refptr<gl::GLImage>& image) { - gpu::gles2::TextureRef* texture_ref = GetTextureForPicture(picture_buffer); + const scoped_refptr<gpu::gles2::GLStreamTextureImage>& image) { + gpu::gles2::TextureRef* texture_ref = + state_provider_->GetTextureForPicture(picture_buffer); RETURN_IF_NULL(texture_ref); gpu::gles2::TextureManager* texture_manager = @@ -120,15 +155,25 @@ void AndroidDeferredRenderingBackingStrategy::SetImageForPicture( shared_state_->surface_texture_service_id()); static_cast<AVDACodecImage*>(image.get()) - ->setTexture(texture_ref->texture()); + ->SetTexture(texture_ref->texture()); } else { // Clear the unowned service_id, so that this texture is no longer going // to depend on the surface texture at all. texture_ref->texture()->SetUnownedServiceId(0); } - texture_manager->SetLevelImage(texture_ref, GetTextureTarget(), 0, - image.get(), gpu::gles2::Texture::UNBOUND); + // For SurfaceTexture we set the image to UNBOUND so that the implementation + // will call CopyTexImage, which is where AVDACodecImage updates the + // SurfaceTexture to the right frame. + // For SurfaceView we set the image to be BOUND because ScheduleOverlayPlane + // expects it. If something tries to sample from this texture it won't work, + // but there's no way to sample from a SurfaceView anyway, so it doesn't + // matter. The only way to use this texture is to schedule it as an overlay. + const gpu::gles2::Texture::ImageState image_state = + surface_texture_ ? gpu::gles2::Texture::UNBOUND + : gpu::gles2::Texture::BOUND; + texture_manager->SetLevelStreamTextureImage(texture_ref, GetTextureTarget(), + 0, image.get(), image_state); } void AndroidDeferredRenderingBackingStrategy::UseCodecBufferForPictureBuffer( @@ -139,36 +184,53 @@ void AndroidDeferredRenderingBackingStrategy::UseCodecBufferForPictureBuffer( // Notify the AVDACodecImage for picture_buffer that it should use the // decoded buffer codec_buf_index to render this frame. - AVDACodecImage* avImage = GetImageForPicture(picture_buffer); - RETURN_IF_NULL(avImage); - DCHECK_EQ(avImage->GetMediaCodecBufferIndex(), -1); + AVDACodecImage* avda_image = GetImageForPicture(picture_buffer); + RETURN_IF_NULL(avda_image); + DCHECK_EQ(avda_image->GetMediaCodecBufferIndex(), -1); // Note that this is not a race, since we do not re-use a PictureBuffer // until after the CC is done drawing it. - avImage->SetMediaCodecBufferIndex(codec_buf_index); - avImage->SetSize(state_provider_->GetSize()); + avda_image->SetMediaCodecBufferIndex(codec_buf_index); + avda_image->SetSize(state_provider_->GetSize()); } void AndroidDeferredRenderingBackingStrategy::AssignOnePictureBuffer( - const media::PictureBuffer& picture_buffer) { + const media::PictureBuffer& picture_buffer, + bool have_context) { // Attach a GLImage to each texture that will use the surface texture. // We use a refptr here in case SetImageForPicture fails. - scoped_refptr<gl::GLImage> gl_image( + scoped_refptr<gpu::gles2::GLStreamTextureImage> gl_image = new AVDACodecImage(shared_state_, media_codec_, - state_provider_->GetGlDecoder(), surface_texture_)); + state_provider_->GetGlDecoder(), surface_texture_); SetImageForPicture(picture_buffer, gl_image); + + if (!surface_texture_ && have_context) { + // To make devtools work, we're using a 2D texture. Make it transparent, + // so that it draws a hole for the SV to show through. This is only + // because devtools draws and reads back, which skips overlay processing. + // It's unclear why devtools renders twice -- once normally, and once + // including a readback layer. The result is that the device screen + // flashes as we alternately draw the overlay hole and this texture, + // unless we make the texture transparent. + static const uint8_t rgba[] = {0, 0, 0, 0}; + const gfx::Size size(1, 1); + DCHECK_LE(1u, picture_buffer.texture_ids().size()); + glBindTexture(GL_TEXTURE_2D, picture_buffer.texture_ids()[0]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, rgba); + } } void AndroidDeferredRenderingBackingStrategy::ReleaseCodecBufferForPicture( const media::PictureBuffer& picture_buffer) { - AVDACodecImage* avImage = GetImageForPicture(picture_buffer); + AVDACodecImage* avda_image = GetImageForPicture(picture_buffer); // See if there is a media codec buffer still attached to this image. - const int32_t codec_buffer = avImage->GetMediaCodecBufferIndex(); + const int32_t codec_buffer = avda_image->GetMediaCodecBufferIndex(); if (codec_buffer >= 0) { // PictureBuffer wasn't displayed, so release the buffer. media_codec_->ReleaseOutputBuffer(codec_buffer, false); - avImage->SetMediaCodecBufferIndex(-1); + avda_image->SetMediaCodecBufferIndex(-1); } } @@ -181,18 +243,6 @@ void AndroidDeferredRenderingBackingStrategy::ReuseOnePictureBuffer( ReleaseCodecBufferForPicture(picture_buffer); } -void AndroidDeferredRenderingBackingStrategy::DismissOnePictureBuffer( - const media::PictureBuffer& picture_buffer) { - // If there is an outstanding codec buffer attached to this image, then - // release it. - ReleaseCodecBufferForPicture(picture_buffer); - - // This makes sure that the Texture no longer refers to the codec or to the - // SurfaceTexture's service_id. That's important, so that it doesn't refer - // to the texture by name after we've deleted it. - SetImageForPicture(picture_buffer, nullptr); -} - void AndroidDeferredRenderingBackingStrategy::CodecChanged( media::VideoCodecBridge* codec, const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) { @@ -200,9 +250,9 @@ void AndroidDeferredRenderingBackingStrategy::CodecChanged( // doesn't know about them. media_codec_ = codec; for (const std::pair<int, media::PictureBuffer>& entry : buffers) { - AVDACodecImage* avImage = GetImageForPicture(entry.second); - avImage->SetMediaCodec(codec); - avImage->SetMediaCodecBufferIndex(-1); + AVDACodecImage* avda_image = GetImageForPicture(entry.second); + avda_image->SetMediaCodec(codec); + avda_image->SetMediaCodecBufferIndex(-1); } } @@ -210,4 +260,163 @@ void AndroidDeferredRenderingBackingStrategy::OnFrameAvailable() { shared_state_->SignalFrameAvailable(); } +bool AndroidDeferredRenderingBackingStrategy::ArePicturesOverlayable() { + // SurfaceView frames are always overlayable because that's the only way to + // display them. + return !surface_texture_; +} + +void AndroidDeferredRenderingBackingStrategy::UpdatePictureBufferSize( + media::PictureBuffer* picture_buffer, + const gfx::Size& new_size) { + // This strategy uses EGL images which manage the texture size for us. We + // simply update the PictureBuffer meta-data and leave the texture as-is. + picture_buffer->set_size(new_size); +} + +void AndroidDeferredRenderingBackingStrategy::CopySurfaceTextureToPictures( + const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) { + DVLOG(3) << __FUNCTION__; + + // Don't try to copy if the SurfaceTexture was never attached because that + // means it was never updated. + if (!shared_state_->surface_texture_is_attached()) + return; + + gpu::gles2::GLES2Decoder* gl_decoder = state_provider_->GetGlDecoder().get(); + if (!gl_decoder) + return; + + const gfx::Size size = state_provider_->GetSize(); + + // Create a 2D texture to hold a copy of the SurfaceTexture's front buffer. + GLuint tmp_texture_id; + glGenTextures(1, &tmp_texture_id); + { + gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, tmp_texture_id); + // The target texture's size will exactly match the source. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + } + + + + float transform_matrix[16]; + surface_texture_->GetTransformMatrix(transform_matrix); + + gpu::CopyTextureCHROMIUMResourceManager copier; + copier.Initialize( + gl_decoder, + gl_decoder->GetContextGroup()->feature_info()->feature_flags()); + copier.DoCopyTextureWithTransform(gl_decoder, GL_TEXTURE_EXTERNAL_OES, + shared_state_->surface_texture_service_id(), + GL_TEXTURE_2D, tmp_texture_id, size.width(), + size.height(), true, false, false, + transform_matrix); + + // Create an EGLImage from the 2D texture we just copied into. By associating + // the EGLImage with the PictureBuffer textures they will remain valid even + // after we delete the 2D texture and EGLImage. + const EGLImageKHR egl_image = eglCreateImageKHR( + gfx::GLSurfaceEGL::GetHardwareDisplay(), eglGetCurrentContext(), + EGL_GL_TEXTURE_2D_KHR, reinterpret_cast<EGLClientBuffer>(tmp_texture_id), + nullptr /* attrs */); + + glDeleteTextures(1, &tmp_texture_id); + DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + + if (egl_image == EGL_NO_IMAGE_KHR) { + DLOG(ERROR) << "Failed creating EGLImage: " << ui::GetLastEGLErrorString(); + return; + } + + for (const std::pair<int, media::PictureBuffer>& entry : buffers) { + gpu::gles2::TextureRef* texture_ref = + state_provider_->GetTextureForPicture(entry.second); + if (!texture_ref) + continue; + gfx::ScopedTextureBinder texture_binder( + GL_TEXTURE_EXTERNAL_OES, texture_ref->texture()->service_id()); + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image); + DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + } + + EGLBoolean result = + eglDestroyImageKHR(gfx::GLSurfaceEGL::GetHardwareDisplay(), egl_image); + if (result == EGL_FALSE) { + DLOG(ERROR) << "Error destroying EGLImage: " + << ui::GetLastEGLErrorString(); + } +} + +bool AndroidDeferredRenderingBackingStrategy::DoesSurfaceTextureDetachWork() + const { + bool surface_texture_detach_works = true; + if (gpu::gles2::GLES2Decoder* gl_decoder = + state_provider_->GetGlDecoder().get()) { + if (gpu::gles2::ContextGroup* group = gl_decoder->GetContextGroup()) { + if (gpu::gles2::FeatureInfo* feature_info = group->feature_info()) { + surface_texture_detach_works = + !feature_info->workarounds().surface_texture_cant_detach; + } + } + } + + // As a special case, the MicroMax A114 doesn't get the workaround, even + // though it should. Hardcode it here until we get a device and figure out + // why. crbug.com/591600 + if (base::android::BuildInfo::GetInstance()->sdk_int() <= 18) { // JB + const std::string brand( + base::ToLowerASCII(base::android::BuildInfo::GetInstance()->brand())); + if (brand == "micromax") { + const std::string model( + base::ToLowerASCII(base::android::BuildInfo::GetInstance()->model())); + if (model.find("a114") != std::string::npos) + surface_texture_detach_works = false; + } + } + + return surface_texture_detach_works; +} + +bool AndroidDeferredRenderingBackingStrategy::ShouldCopyPictures() const { + // Mali + <= KitKat crashes when we try to do this. We don't know if it's + // due to detaching a surface texture, but it's the same set of devices. + if (!DoesSurfaceTextureDetachWork()) + return false; + + // Other devices are unreliable for other reasons (e.g., EGLImage). + if (gpu::gles2::GLES2Decoder* gl_decoder = + state_provider_->GetGlDecoder().get()) { + if (gpu::gles2::ContextGroup* group = gl_decoder->GetContextGroup()) { + if (gpu::gles2::FeatureInfo* feature_info = group->feature_info()) { + return !feature_info->workarounds().avda_dont_copy_pictures; + } + } + } + + // Samsung Galaxy Tab A, J3, and J1 Mini all like to crash on Lollipop in + // glEGLImageTargetTexture2DOES . Exact models were SM-T280, SM-J320F, + // and SM-j105H. + if (base::android::BuildInfo::GetInstance()->sdk_int() <= 22) { // L MR1 + const std::string brand( + base::ToLowerASCII(base::android::BuildInfo::GetInstance()->brand())); + if (brand == "samsung") { + const std::string model( + base::ToLowerASCII(base::android::BuildInfo::GetInstance()->model())); + if (model.find("sm-t280") != std::string::npos || + model.find("sm-j320f") != std::string::npos || + model.find("sm-j105") != std::string::npos) + return false; + } + } + + // Assume so. + return true; +} + } // namespace content diff --git a/chromium/content/common/gpu/media/android_deferred_rendering_backing_strategy.h b/chromium/content/common/gpu/media/android_deferred_rendering_backing_strategy.h index 6fc1873cf5a..733b25b0a45 100644 --- a/chromium/content/common/gpu/media/android_deferred_rendering_backing_strategy.h +++ b/chromium/content/common/gpu/media/android_deferred_rendering_backing_strategy.h @@ -17,6 +17,7 @@ class GLImage; namespace gpu { namespace gles2 { +class GLStreamTextureImage; class TextureRef; } } @@ -33,42 +34,61 @@ class AVDASharedState; class CONTENT_EXPORT AndroidDeferredRenderingBackingStrategy : public AndroidVideoDecodeAccelerator::BackingStrategy { public: - AndroidDeferredRenderingBackingStrategy(); + explicit AndroidDeferredRenderingBackingStrategy( + AVDAStateProvider* state_provider); ~AndroidDeferredRenderingBackingStrategy() override; // AndroidVideoDecodeAccelerator::BackingStrategy - void Initialize(AVDAStateProvider*) override; + gfx::ScopedJavaSurface Initialize(int surface_view_id) override; void Cleanup(bool have_context, const AndroidVideoDecodeAccelerator::OutputBufferMap&) override; + scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture() const override; uint32_t GetTextureTarget() const override; - scoped_refptr<gfx::SurfaceTexture> CreateSurfaceTexture() override; + gfx::Size GetPictureBufferSize() const override; void UseCodecBufferForPictureBuffer(int32_t codec_buffer_index, const media::PictureBuffer&) override; - void AssignOnePictureBuffer(const media::PictureBuffer&) override; + void AssignOnePictureBuffer(const media::PictureBuffer&, bool) override; void ReuseOnePictureBuffer(const media::PictureBuffer&) override; - void DismissOnePictureBuffer(const media::PictureBuffer&) override; void CodecChanged( media::VideoCodecBridge*, const AndroidVideoDecodeAccelerator::OutputBufferMap&) override; void OnFrameAvailable() override; + bool ArePicturesOverlayable() override; + void UpdatePictureBufferSize(media::PictureBuffer* picture_buffer, + const gfx::Size& new_size) override; private: // Release any codec buffer that is associated with the given picture buffer // back to the codec. It is okay if there is no such buffer. void ReleaseCodecBufferForPicture(const media::PictureBuffer& picture_buffer); - // Return the TextureRef for a given PictureBuffer's texture. - gpu::gles2::TextureRef* GetTextureForPicture(const media::PictureBuffer&); - // Return the AVDACodecImage for a given PictureBuffer's texture. AVDACodecImage* GetImageForPicture(const media::PictureBuffer&); - void SetImageForPicture(const media::PictureBuffer& picture_buffer, - const scoped_refptr<gl::GLImage>& image); + void SetImageForPicture( + const media::PictureBuffer& picture_buffer, + const scoped_refptr<gpu::gles2::GLStreamTextureImage>& image); + + // Make a copy of the SurfaceTexture's front buffer and associate all given + // picture buffer textures with it. The picture buffer textures will not + // dependend on |this|, the SurfaceTexture, the MediaCodec or the VDA, so it's + // used to back the picture buffers when the VDA is being destroyed. + void CopySurfaceTextureToPictures( + const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers); + + // Return true if and only if the surface_texture_cant_detach workaround is + // not set. + bool DoesSurfaceTextureDetachWork() const; + + // Return true if and only if CopySurfaceTextureToPictures is expected to work + // on this device. + bool ShouldCopyPictures() const; scoped_refptr<AVDASharedState> shared_state_; AVDAStateProvider* state_provider_; + // The SurfaceTexture to render to. Non-null after Initialize() if + // we're not rendering to a SurfaceView. scoped_refptr<gfx::SurfaceTexture> surface_texture_; media::VideoCodecBridge* media_codec_; diff --git a/chromium/content/common/gpu/media/android_video_decode_accelerator.cc b/chromium/content/common/gpu/media/android_video_decode_accelerator.cc index 832d8dca218..e4f45ca73b3 100644 --- a/chromium/content/common/gpu/media/android_video_decode_accelerator.cc +++ b/chromium/content/common/gpu/media/android_video_decode_accelerator.cc @@ -7,21 +7,30 @@ #include <stddef.h> #include "base/android/build_info.h" +#include "base/auto_reset.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h" +#include "base/lazy_instance.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" #include "base/metrics/histogram.h" +#include "base/task_runner_util.h" +#include "base/threading/thread_checker.h" #include "base/trace_event/trace_event.h" -#include "content/common/gpu/gpu_channel.h" #include "content/common/gpu/media/android_copying_backing_strategy.h" #include "content/common/gpu/media/android_deferred_rendering_backing_strategy.h" +#include "content/common/gpu/media/avda_return_on_failure.h" +#include "content/common/gpu/media/shared_memory_region.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" +#include "gpu/command_buffer/service/mailbox_manager.h" +#include "gpu/ipc/service/gpu_channel.h" +#include "media/base/android/media_codec_bridge.h" +#include "media/base/android/media_codec_util.h" #include "media/base/bind_to_current_loop.h" #include "media/base/bitstream_buffer.h" #include "media/base/limits.h" -#include "media/base/media_switches.h" +#include "media/base/media.h" #include "media/base/timestamp_constants.h" #include "media/base/video_decoder_config.h" #include "media/video/picture.h" @@ -30,7 +39,6 @@ #include "ui/gl/gl_bindings.h" #if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) -#include "media/base/media_keys.h" #include "media/mojo/services/mojo_cdm_service.h" #endif @@ -92,6 +100,23 @@ static inline const base::TimeDelta IdleTimerTimeOut() { return base::TimeDelta::FromSeconds(1); } +// Time between when we notice an error, and when we actually notify somebody. +// This is to prevent codec errors caused by SurfaceView fullscreen transitions +// from breaking the pipeline, if we're about to be reset anyway. +static inline const base::TimeDelta ErrorPostingDelay() { + return base::TimeDelta::FromSeconds(2); +} + +// For RecordFormatChangedMetric. +enum FormatChangedValue { + CodecInitialized = false, + MissingFormatChanged = true +}; + +static inline void RecordFormatChangedMetric(FormatChangedValue value) { + UMA_HISTOGRAM_BOOLEAN("Media.AVDA.MissingFormatChanged", !!value); +} + // Handle OnFrameAvailable callbacks safely. Since they occur asynchronously, // we take care that the AVDA that wants them still exists. A WeakPtr to // the AVDA would be preferable, except that OnFrameAvailable callbacks can @@ -143,34 +168,166 @@ class AndroidVideoDecodeAccelerator::OnFrameAvailableHandler DISALLOW_COPY_AND_ASSIGN(OnFrameAvailableHandler); }; +// Helper class to share an IO timer for DoIOTask() execution; prevents each +// AVDA instance from starting its own high frequency timer. The intuition +// behind this is that, if we're waiting for long enough, then either (a) +// MediaCodec is broken or (b) MediaCodec is waiting on us to change state +// (e.g., get new demuxed data / get a free picture buffer / return an output +// buffer to MediaCodec). This is inherently a race, since we don't know if +// MediaCodec is broken or just slow. Since the MediaCodec API doesn't let +// us wait on MediaCodec state changes prior to L, we more or less have to +// time out or keep polling forever in some common cases. +class AVDATimerManager { + public: + // Make sure that the construction thread is started for |avda_instance|. + bool StartThread(AndroidVideoDecodeAccelerator* avda_instance) { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (thread_avda_instances_.empty()) { + if (!construction_thread_.Start()) { + LOG(ERROR) << "Failed to start construction thread."; + return false; + } + } + + thread_avda_instances_.insert(avda_instance); + return true; + } + + // |avda_instance| will no longer need the construction thread. Stop the + // thread if this is the last instance. + void StopThread(AndroidVideoDecodeAccelerator* avda_instance) { + DCHECK(thread_checker_.CalledOnValidThread()); + + thread_avda_instances_.erase(avda_instance); + if (thread_avda_instances_.empty()) + construction_thread_.Stop(); + } + + // Request periodic callback of |avda_instance|->DoIOTask(). Does nothing if + // the instance is already registered and the timer started. The first request + // will start the repeating timer on an interval of DecodePollDelay(). + void StartTimer(AndroidVideoDecodeAccelerator* avda_instance) { + DCHECK(thread_checker_.CalledOnValidThread()); + + timer_avda_instances_.insert(avda_instance); + + // If the timer is running, StopTimer() might have been called earlier, if + // so remove the instance from the pending erasures. + if (timer_running_) + pending_erase_.erase(avda_instance); + + if (io_timer_.IsRunning()) + return; + io_timer_.Start(FROM_HERE, DecodePollDelay(), this, + &AVDATimerManager::RunTimer); + } + + // Stop callbacks to |avda_instance|->DoIOTask(). Does nothing if the instance + // is not registered. If there are no instances left, the repeating timer will + // be stopped. + void StopTimer(AndroidVideoDecodeAccelerator* avda_instance) { + DCHECK(thread_checker_.CalledOnValidThread()); + + // If the timer is running, defer erasures to avoid iterator invalidation. + if (timer_running_) { + pending_erase_.insert(avda_instance); + return; + } + + timer_avda_instances_.erase(avda_instance); + if (timer_avda_instances_.empty()) + io_timer_.Stop(); + } + + // Eventually, we should run the timer on this thread. For now, we just keep + // it as a convenience for construction. + scoped_refptr<base::SingleThreadTaskRunner> ConstructionTaskRunner() { + DCHECK(thread_checker_.CalledOnValidThread()); + return construction_thread_.task_runner(); + } + + private: + friend struct base::DefaultLazyInstanceTraits<AVDATimerManager>; + + AVDATimerManager() : construction_thread_("AVDAThread") {} + ~AVDATimerManager() { NOTREACHED(); } + + void RunTimer() { + { + // Call out to all AVDA instances, some of which may attempt to remove + // themselves from the list during this operation; those removals will be + // deferred until after all iterations are complete. + base::AutoReset<bool> scoper(&timer_running_, true); + for (auto* avda : timer_avda_instances_) + avda->DoIOTask(false); + } + + // Take care of any deferred erasures. + for (auto* avda : pending_erase_) + StopTimer(avda); + pending_erase_.clear(); + + // TODO(dalecurtis): We may want to consider chunking this if task execution + // takes too long for the combined timer. + } + + // All AVDA instances that would like us to poll DoIOTask. + std::set<AndroidVideoDecodeAccelerator*> timer_avda_instances_; + + // All AVDA instances that might like to use the construction thread. + std::set<AndroidVideoDecodeAccelerator*> thread_avda_instances_; + + // Since we can't delete while iterating when using a set, defer erasure until + // after iteration complete. + bool timer_running_ = false; + std::set<AndroidVideoDecodeAccelerator*> pending_erase_; + + // Repeating timer responsible for draining pending IO to the codecs. + base::RepeatingTimer io_timer_; + + base::Thread construction_thread_; + + base::ThreadChecker thread_checker_; + + DISALLOW_COPY_AND_ASSIGN(AVDATimerManager); +}; + +static base::LazyInstance<AVDATimerManager>::Leaky g_avda_timer = + LAZY_INSTANCE_INITIALIZER; + +AndroidVideoDecodeAccelerator::CodecConfig::CodecConfig() {} + +AndroidVideoDecodeAccelerator::CodecConfig::~CodecConfig() {} + AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator( - const base::WeakPtr<gpu::gles2::GLES2Decoder> decoder, - const base::Callback<bool(void)>& make_context_current) + const MakeGLContextCurrentCallback& make_context_current_cb, + const GetGLES2DecoderCallback& get_gles2_decoder_cb) : client_(NULL), - make_context_current_(make_context_current), - codec_(media::kCodecH264), + make_context_current_cb_(make_context_current_cb), + get_gles2_decoder_cb_(get_gles2_decoder_cb), is_encrypted_(false), - needs_protected_surface_(false), state_(NO_ERROR), picturebuffers_requested_(false), - gl_decoder_(decoder), + media_drm_bridge_cdm_context_(nullptr), cdm_registration_id_(0), - weak_this_factory_(this) { - if (UseDeferredRenderingStrategy()) - strategy_.reset(new AndroidDeferredRenderingBackingStrategy()); - else - strategy_.reset(new AndroidCopyingBackingStrategy()); -} + pending_input_buf_index_(-1), + error_sequence_token_(0), + defer_errors_(false), + deferred_initialization_pending_(false), + weak_this_factory_(this) {} AndroidVideoDecodeAccelerator::~AndroidVideoDecodeAccelerator() { DCHECK(thread_checker_.CalledOnValidThread()); + g_avda_timer.Pointer()->StopTimer(this); + g_avda_timer.Pointer()->StopThread(this); #if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) - if (cdm_) { - DCHECK(cdm_registration_id_); - static_cast<media::MediaDrmBridge*>(cdm_.get()) - ->UnregisterPlayer(cdm_registration_id_); - } + if (!media_drm_bridge_cdm_context_) + return; + + DCHECK(cdm_registration_id_); + media_drm_bridge_cdm_context_->UnregisterPlayer(cdm_registration_id_); #endif // defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) } @@ -182,76 +339,130 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config, DVLOG(1) << __FUNCTION__ << ": " << config.AsHumanReadableString(); + if (make_context_current_cb_.is_null() || get_gles2_decoder_cb_.is_null()) { + NOTREACHED() << "GL callbacks are required for this VDA"; + return false; + } + DCHECK(client); client_ = client; - codec_ = VideoCodecProfileToVideoCodec(config.profile); + codec_config_ = new CodecConfig(); + codec_config_->codec_ = VideoCodecProfileToVideoCodec(config.profile); + codec_config_->initial_expected_coded_size_ = + config.initial_expected_coded_size; is_encrypted_ = config.is_encrypted; - bool profile_supported = codec_ == media::kCodecVP8 || - codec_ == media::kCodecVP9 || - codec_ == media::kCodecH264; + bool profile_supported = codec_config_->codec_ == media::kCodecVP8 || + codec_config_->codec_ == media::kCodecVP9 || + codec_config_->codec_ == media::kCodecH264; + + // We signalled that we support deferred initialization, so see if the client + // does also. + deferred_initialization_pending_ = config.is_deferred_initialization_allowed; if (!profile_supported) { LOG(ERROR) << "Unsupported profile: " << config.profile; return false; } + // For encrypted streams we postpone configuration until MediaCrypto is + // available. + DCHECK(!is_encrypted_ || deferred_initialization_pending_); + // Only use MediaCodec for VP8/9 if it's likely backed by hardware // or if the stream is encrypted. - if ((codec_ == media::kCodecVP8 || codec_ == media::kCodecVP9) && - !is_encrypted_) { - if (media::VideoCodecBridge::IsKnownUnaccelerated( - codec_, media::MEDIA_CODEC_DECODER)) { - DVLOG(1) << "Initialization failed: " - << (codec_ == media::kCodecVP8 ? "vp8" : "vp9") - << " is not hardware accelerated"; - return false; - } + if ((codec_config_->codec_ == media::kCodecVP8 || + codec_config_->codec_ == media::kCodecVP9) && + !is_encrypted_ && + media::VideoCodecBridge::IsKnownUnaccelerated( + codec_config_->codec_, media::MEDIA_CODEC_DECODER)) { + DVLOG(1) << "Initialization failed: " + << (codec_config_->codec_ == media::kCodecVP8 ? "vp8" : "vp9") + << " is not hardware accelerated"; + return false; } - if (!make_context_current_.Run()) { + auto gles_decoder = get_gles2_decoder_cb_.Run(); + if (!gles_decoder) { + LOG(ERROR) << "Failed to get gles2 decoder instance."; + return false; + } + + const gpu::GpuPreferences& gpu_preferences = + gles_decoder->GetContextGroup()->gpu_preferences(); + + if (UseDeferredRenderingStrategy(gpu_preferences)) { + // TODO(liberato, watk): Figure out what we want to do about zero copy for + // fullscreen external SurfaceView in WebView. http://crbug.com/582170. + DCHECK(!gles_decoder->GetContextGroup()->mailbox_manager()->UsesSync()); + DVLOG(1) << __FUNCTION__ << ", using deferred rendering strategy."; + strategy_.reset(new AndroidDeferredRenderingBackingStrategy(this)); + } else { + DVLOG(1) << __FUNCTION__ << ", using copy back strategy."; + strategy_.reset(new AndroidCopyingBackingStrategy(this)); + } + + if (!make_context_current_cb_.Run()) { LOG(ERROR) << "Failed to make this decoder's GL context current."; return false; } - if (!gl_decoder_) { - LOG(ERROR) << "Failed to get gles2 decoder instance."; + codec_config_->surface_ = strategy_->Initialize(config.surface_id); + if (codec_config_->surface_.IsEmpty()) { + LOG(ERROR) << "Failed to initialize the backing strategy. The returned " + "Java surface is empty."; return false; } - strategy_->Initialize(this); + // TODO(watk,liberato): move this into the strategy. + scoped_refptr<gfx::SurfaceTexture> surface_texture = + strategy_->GetSurfaceTexture(); + if (surface_texture) { + on_frame_available_handler_ = + new OnFrameAvailableHandler(this, surface_texture); + } - surface_texture_ = strategy_->CreateSurfaceTexture(); - on_frame_available_handler_ = - new OnFrameAvailableHandler(this, surface_texture_); + // Start the thread for async configuration, even if we don't need it now. + // ResetCodecState might rebuild the codec later, for example. + if (!g_avda_timer.Pointer()->StartThread(this)) { + LOG(ERROR) << "Failed to start thread for AVDA timer"; + return false; + } - // For encrypted streams we postpone configuration until MediaCrypto is - // available. + // If we are encrypted, then we aren't able to create the codec yet. if (is_encrypted_) return true; - return ConfigureMediaCodec(); + if (deferred_initialization_pending_) { + ConfigureMediaCodecAsynchronously(); + return true; + } + + // If the client doesn't support deferred initialization (WebRTC), then we + // should complete it now and return a meaningful result. + return ConfigureMediaCodecSynchronously(); } void AndroidVideoDecodeAccelerator::SetCdm(int cdm_id) { DVLOG(2) << __FUNCTION__ << ": " << cdm_id; #if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) - using media::MediaDrmBridge; - DCHECK(client_) << "SetCdm() must be called after Initialize()."; - if (cdm_) { + if (media_drm_bridge_cdm_context_) { NOTREACHED() << "We do not support resetting CDM."; - NotifyCdmAttached(false); + NotifyInitializationComplete(false); return; } - cdm_ = media::MojoCdmService::GetCdm(cdm_id); - DCHECK(cdm_); + // Store the CDM to hold a reference to it. + cdm_for_reference_holding_only_ = media::MojoCdmService::LegacyGetCdm(cdm_id); + DCHECK(cdm_for_reference_holding_only_); - // On Android platform the MediaKeys will be its subclass MediaDrmBridge. - MediaDrmBridge* drm_bridge = static_cast<MediaDrmBridge*>(cdm_.get()); + // On Android platform the CdmContext must be a MediaDrmBridgeCdmContext. + media_drm_bridge_cdm_context_ = static_cast<media::MediaDrmBridgeCdmContext*>( + cdm_for_reference_holding_only_->GetCdmContext()); + DCHECK(media_drm_bridge_cdm_context_); // Register CDM callbacks. The callbacks registered will be posted back to // this thread via BindToCurrentLoop. @@ -261,31 +472,30 @@ void AndroidVideoDecodeAccelerator::SetCdm(int cdm_id) { // destructed as well. So the |cdm_unset_cb| will never have a chance to be // called. // TODO(xhwang): Remove |cdm_unset_cb| after it's not used on all platforms. - cdm_registration_id_ = - drm_bridge->RegisterPlayer(media::BindToCurrentLoop(base::Bind( - &AndroidVideoDecodeAccelerator::OnKeyAdded, - weak_this_factory_.GetWeakPtr())), - base::Bind(&base::DoNothing)); + cdm_registration_id_ = media_drm_bridge_cdm_context_->RegisterPlayer( + media::BindToCurrentLoop( + base::Bind(&AndroidVideoDecodeAccelerator::OnKeyAdded, + weak_this_factory_.GetWeakPtr())), + base::Bind(&base::DoNothing)); - drm_bridge->SetMediaCryptoReadyCB(media::BindToCurrentLoop( + media_drm_bridge_cdm_context_->SetMediaCryptoReadyCB(media::BindToCurrentLoop( base::Bind(&AndroidVideoDecodeAccelerator::OnMediaCryptoReady, weak_this_factory_.GetWeakPtr()))); - // Postpone NotifyCdmAttached() call till we create the MediaCodec after - // OnMediaCryptoReady(). - +// Postpone NotifyInitializationComplete() call till we create the MediaCodec +// after OnMediaCryptoReady(). #else NOTIMPLEMENTED(); - NotifyCdmAttached(false); + NotifyInitializationComplete(false); #endif // !defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) } -void AndroidVideoDecodeAccelerator::DoIOTask() { +void AndroidVideoDecodeAccelerator::DoIOTask(bool start_timer) { DCHECK(thread_checker_.CalledOnValidThread()); TRACE_EVENT0("media", "AVDA::DoIOTask"); - if (state_ == ERROR) { + if (state_ == ERROR || state_ == WAITING_FOR_CODEC) { return; } @@ -293,49 +503,69 @@ void AndroidVideoDecodeAccelerator::DoIOTask() { while (DequeueOutput()) did_work = true; - ManageTimer(did_work); + ManageTimer(did_work || start_timer); } bool AndroidVideoDecodeAccelerator::QueueInput() { DCHECK(thread_checker_.CalledOnValidThread()); TRACE_EVENT0("media", "AVDA::QueueInput"); + base::AutoReset<bool> auto_reset(&defer_errors_, true); if (bitstreams_notified_in_advance_.size() > kMaxBitstreamsNotifiedInAdvance) return false; if (pending_bitstream_buffers_.empty()) return false; + if (state_ == WAITING_FOR_KEY) + return false; - int input_buf_index = 0; - media::MediaCodecStatus status = - media_codec_->DequeueInputBuffer(NoWaitTimeOut(), &input_buf_index); + int input_buf_index = pending_input_buf_index_; - if (status == media::MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER) - return false; - if (status == media::MEDIA_CODEC_ERROR) { - POST_ERROR(PLATFORM_FAILURE, "Failed to DequeueInputBuffer"); - return false; + // Do not dequeue a new input buffer if we failed with MEDIA_CODEC_NO_KEY. + // That status does not return this buffer back to the pool of + // available input buffers. We have to reuse it in QueueSecureInputBuffer(). + if (input_buf_index == -1) { + media::MediaCodecStatus status = + media_codec_->DequeueInputBuffer(NoWaitTimeOut(), &input_buf_index); + switch (status) { + case media::MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: + return false; + case media::MEDIA_CODEC_ERROR: + POST_ERROR(PLATFORM_FAILURE, "Failed to DequeueInputBuffer"); + return false; + case media::MEDIA_CODEC_OK: + break; + default: + NOTREACHED() << "Unknown DequeueInputBuffer status " << status; + return false; + } } - DCHECK_EQ(status, media::MEDIA_CODEC_OK); - base::Time queued_time = pending_bitstream_buffers_.front().second; - UMA_HISTOGRAM_TIMES("Media.AVDA.InputQueueTime", - base::Time::Now() - queued_time); - media::BitstreamBuffer bitstream_buffer = - pending_bitstream_buffers_.front().first; + DCHECK_NE(input_buf_index, -1); + + media::BitstreamBuffer bitstream_buffer = pending_bitstream_buffers_.front(); if (bitstream_buffer.id() == -1) { pending_bitstream_buffers_.pop(); TRACE_COUNTER1("media", "AVDA::PendingBitstreamBufferCount", pending_bitstream_buffers_.size()); + DCHECK_NE(state_, ERROR); + state_ = WAITING_FOR_EOS; media_codec_->QueueEOS(input_buf_index); return true; } - scoped_ptr<base::SharedMemory> shm( - new base::SharedMemory(bitstream_buffer.handle(), true)); - if (!shm->Map(bitstream_buffer.size())) { - POST_ERROR(UNREADABLE_INPUT, "Failed to SharedMemory::Map()"); - return false; + scoped_ptr<SharedMemoryRegion> shm; + + if (pending_input_buf_index_ == -1) { + // When |pending_input_buf_index_| is not -1, the buffer is already dequeued + // from MediaCodec, filled with data and bitstream_buffer.handle() is + // closed. + shm.reset(new SharedMemoryRegion(bitstream_buffer, true)); + + if (!shm->Map()) { + POST_ERROR(UNREADABLE_INPUT, "Failed to SharedMemoryRegion::Map()"); + return false; + } } const base::TimeDelta presentation_timestamp = @@ -351,12 +581,16 @@ bool AndroidVideoDecodeAccelerator::QueueInput() { // result in them finding the right timestamp. bitstream_buffers_in_decoder_[presentation_timestamp] = bitstream_buffer.id(); - const uint8_t* memory = static_cast<const uint8_t*>(shm->memory()); + // Notice that |memory| will be null if we repeatedly enqueue the same buffer, + // this happens after MEDIA_CODEC_NO_KEY. + const uint8_t* memory = + shm ? static_cast<const uint8_t*>(shm->memory()) : nullptr; const std::string& key_id = bitstream_buffer.key_id(); const std::string& iv = bitstream_buffer.iv(); const std::vector<media::SubsampleEntry>& subsamples = bitstream_buffer.subsamples(); + media::MediaCodecStatus status; if (key_id.empty() || iv.empty()) { status = media_codec_->QueueInputBuffer(input_buf_index, memory, bitstream_buffer.size(), @@ -372,24 +606,18 @@ bool AndroidVideoDecodeAccelerator::QueueInput() { << " status:" << status; if (status == media::MEDIA_CODEC_NO_KEY) { - // Keep trying to enqueue the front pending buffer. - // - // TODO(timav): Figure out whether stopping the pipeline in response to - // this error and restarting it in OnKeyAdded() has significant benefits - // (e.g. saving power). + // Keep trying to enqueue the same input buffer. + // The buffer is owned by us (not the MediaCodec) and is filled with data. DVLOG(1) << "QueueSecureInputBuffer failed: NO_KEY"; - return true; + pending_input_buf_index_ = input_buf_index; + state_ = WAITING_FOR_KEY; + return false; } + pending_input_buf_index_ = -1; pending_bitstream_buffers_.pop(); TRACE_COUNTER1("media", "AVDA::PendingBitstreamBufferCount", pending_bitstream_buffers_.size()); - - if (status != media::MEDIA_CODEC_OK) { - POST_ERROR(PLATFORM_FAILURE, "Failed to QueueInputBuffer: " << status); - return false; - } - // We should call NotifyEndOfBitstreamBuffer(), when no more decoded output // will be returned from the bitstream buffer. However, MediaCodec API is // not enough to guarantee it. @@ -403,12 +631,18 @@ bool AndroidVideoDecodeAccelerator::QueueInput() { weak_this_factory_.GetWeakPtr(), bitstream_buffer.id())); bitstreams_notified_in_advance_.push_back(bitstream_buffer.id()); + if (status != media::MEDIA_CODEC_OK) { + POST_ERROR(PLATFORM_FAILURE, "Failed to QueueInputBuffer: " << status); + return false; + } + return true; } bool AndroidVideoDecodeAccelerator::DequeueOutput() { DCHECK(thread_checker_.CalledOnValidThread()); TRACE_EVENT0("media", "AVDA::DequeueOutput"); + base::AutoReset<bool> auto_reset(&defer_errors_, true); if (picturebuffers_requested_ && output_picture_buffers_.empty()) return false; @@ -432,10 +666,6 @@ bool AndroidVideoDecodeAccelerator::DequeueOutput() { "presentation_timestamp (ms)", presentation_timestamp.InMilliseconds()); - DVLOG(3) << "AVDA::DequeueOutput: pts:" << presentation_timestamp - << " buf_index:" << buf_index << " offset:" << offset - << " size:" << size << " eos:" << eos; - switch (status) { case media::MEDIA_CODEC_ERROR: POST_ERROR(PLATFORM_FAILURE, "DequeueOutputBuffer failed."); @@ -445,23 +675,30 @@ bool AndroidVideoDecodeAccelerator::DequeueOutput() { return false; case media::MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: { - if (!output_picture_buffers_.empty()) { - // TODO(chcunningham): This will likely dismiss a handful of decoded - // frames that have not yet been drawn and returned to us for re-use. - // Consider a more complicated design that would wait for them to be - // drawn before dismissing. - DismissPictureBuffers(); + if (media_codec_->GetOutputSize(&size_) != media::MEDIA_CODEC_OK) { + POST_ERROR(PLATFORM_FAILURE, "GetOutputSize failed."); + return false; + } + DVLOG(3) << __FUNCTION__ + << " OUTPUT_FORMAT_CHANGED, new size: " << size_.ToString(); + + // Don't request picture buffers if we already have some. This avoids + // having to dismiss the existing buffers which may actively reference + // decoded images. Breaking their connection to the decoded image will + // cause rendering of black frames. Instead, we let the existing + // PictureBuffers live on and we simply update their size the next time + // they're attachted to an image of the new resolution. See the + // size update in |SendDecodedFrameToClient| and https://crbug/587994. + if (output_picture_buffers_.empty() && !picturebuffers_requested_) { + picturebuffers_requested_ = true; + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&AndroidVideoDecodeAccelerator::RequestPictureBuffers, + weak_this_factory_.GetWeakPtr())); + return false; } - picturebuffers_requested_ = true; - int32_t width, height; - media_codec_->GetOutputFormat(&width, &height); - size_ = gfx::Size(width, height); - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&AndroidVideoDecodeAccelerator::RequestPictureBuffers, - weak_this_factory_.GetWeakPtr())); - return false; + return true; } case media::MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: @@ -469,6 +706,9 @@ bool AndroidVideoDecodeAccelerator::DequeueOutput() { case media::MEDIA_CODEC_OK: DCHECK_GE(buf_index, 0); + DVLOG(3) << __FUNCTION__ << ": pts:" << presentation_timestamp + << " buf_index:" << buf_index << " offset:" << offset + << " size:" << size << " eos:" << eos; break; default: @@ -478,12 +718,36 @@ bool AndroidVideoDecodeAccelerator::DequeueOutput() { } while (buf_index < 0); if (eos) { - DVLOG(3) << "AVDA::DequeueOutput: Resetting codec state after EOS"; + DVLOG(3) << __FUNCTION__ << ": Resetting codec state after EOS"; + + // If we were waiting for an EOS, clear the state and reset the MediaCodec + // as normal. Otherwise, enter the ERROR state which will force destruction + // of MediaCodec during ResetCodecState(). + // + // Some Android platforms seem to send an EOS buffer even when we're not + // expecting it. In this case, destroy and reset the codec but don't notify + // flush done since it violates the state machine. http://crbug.com/585959. + const bool was_waiting_for_eos = state_ == WAITING_FOR_EOS; + state_ = was_waiting_for_eos ? NO_ERROR : ERROR; + ResetCodecState(); + // |media_codec_| might still be null. + if (was_waiting_for_eos) { + base::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::NotifyFlushDone, + weak_this_factory_.GetWeakPtr())); + } + return false; + } - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::NotifyFlushDone, - weak_this_factory_.GetWeakPtr())); + if (!picturebuffers_requested_) { + // If, somehow, we get a decoded frame back before a FORMAT_CHANGED + // message, then we might not have any picture buffers to use. This + // isn't supposed to happen (see EncodeDecodeTest.java#617). + // Log a metric to see how common this is. + RecordFormatChangedMetric(FormatChangedValue::MissingFormatChanged); + media_codec_->ReleaseOutputBuffer(buf_index, false); + POST_ERROR(PLATFORM_FAILURE, "Dequeued buffers before FORMAT_CHANGED."); return false; } @@ -515,7 +779,7 @@ bool AndroidVideoDecodeAccelerator::DequeueOutput() { // correction and provides a non-decreasing timestamp sequence, which might // result in timestamp duplicates. Discard the frame if we cannot get the // corresponding buffer id. - DVLOG(3) << "AVDA::DequeueOutput: Releasing buffer with unexpected PTS: " + DVLOG(3) << __FUNCTION__ << ": Releasing buffer with unexpected PTS: " << presentation_timestamp; media_codec_->ReleaseOutputBuffer(buf_index, false); } @@ -532,7 +796,7 @@ void AndroidVideoDecodeAccelerator::SendDecodedFrameToClient( DCHECK(!free_picture_ids_.empty()); TRACE_EVENT0("media", "AVDA::SendDecodedFrameToClient"); - if (!make_context_current_.Run()) { + if (!make_context_current_cb_.Run()) { POST_ERROR(PLATFORM_FAILURE, "Failed to make the GL context current."); return; } @@ -541,46 +805,71 @@ void AndroidVideoDecodeAccelerator::SendDecodedFrameToClient( free_picture_ids_.pop(); TRACE_COUNTER1("media", "AVDA::FreePictureIds", free_picture_ids_.size()); - OutputBufferMap::const_iterator i = - output_picture_buffers_.find(picture_buffer_id); + const auto& i = output_picture_buffers_.find(picture_buffer_id); if (i == output_picture_buffers_.end()) { POST_ERROR(PLATFORM_FAILURE, "Can't find PictureBuffer id: " << picture_buffer_id); return; } + bool size_changed = false; + if (i->second.size() != size_) { + // Size may have changed due to resolution change since the last time this + // PictureBuffer was used. + strategy_->UpdatePictureBufferSize(&i->second, size_); + size_changed = true; + } + // Connect the PictureBuffer to the decoded frame, via whatever // mechanism the strategy likes. strategy_->UseCodecBufferForPictureBuffer(codec_buffer_index, i->second); + const bool allow_overlay = strategy_->ArePicturesOverlayable(); + + media::Picture picture(picture_buffer_id, bitstream_id, gfx::Rect(size_), + allow_overlay); + picture.set_size_changed(size_changed); + base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::NotifyPictureReady, - weak_this_factory_.GetWeakPtr(), - media::Picture(picture_buffer_id, bitstream_id, - gfx::Rect(size_), false))); + weak_this_factory_.GetWeakPtr(), picture)); } void AndroidVideoDecodeAccelerator::Decode( const media::BitstreamBuffer& bitstream_buffer) { DCHECK(thread_checker_.CalledOnValidThread()); - if (bitstream_buffer.id() != -1 && bitstream_buffer.size() == 0) { + + if (bitstream_buffer.id() >= 0 && bitstream_buffer.size() > 0) { + DecodeBuffer(bitstream_buffer); + return; + } + + if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle())) + base::SharedMemory::CloseHandle(bitstream_buffer.handle()); + + if (bitstream_buffer.id() < 0) { + POST_ERROR(INVALID_ARGUMENT, + "Invalid bistream_buffer, id: " << bitstream_buffer.id()); + } else { base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer, weak_this_factory_.GetWeakPtr(), bitstream_buffer.id())); - return; } +} - pending_bitstream_buffers_.push( - std::make_pair(bitstream_buffer, base::Time::Now())); +void AndroidVideoDecodeAccelerator::DecodeBuffer( + const media::BitstreamBuffer& bitstream_buffer) { + pending_bitstream_buffers_.push(bitstream_buffer); TRACE_COUNTER1("media", "AVDA::PendingBitstreamBufferCount", pending_bitstream_buffers_.size()); - DoIOTask(); + DoIOTask(true); } void AndroidVideoDecodeAccelerator::RequestPictureBuffers() { - client_->ProvidePictureBuffers(kNumPictureBuffers, size_, + client_->ProvidePictureBuffers(kNumPictureBuffers, 1, + strategy_->GetPictureBufferSize(), strategy_->GetTextureTarget()); } @@ -595,8 +884,12 @@ void AndroidVideoDecodeAccelerator::AssignPictureBuffers( return; } + const bool have_context = make_context_current_cb_.Run(); + LOG_IF(WARNING, !have_context) + << "Failed to make GL context current for Assign, continuing."; + for (size_t i = 0; i < buffers.size(); ++i) { - if (buffers[i].size() != size_) { + if (buffers[i].size() != strategy_->GetPictureBufferSize()) { POST_ERROR(INVALID_ARGUMENT, "Invalid picture buffer size assigned. Wanted " << size_.ToString() << ", but got " @@ -606,29 +899,17 @@ void AndroidVideoDecodeAccelerator::AssignPictureBuffers( int32_t id = buffers[i].id(); output_picture_buffers_.insert(std::make_pair(id, buffers[i])); free_picture_ids_.push(id); - // Since the client might be re-using |picture_buffer_id| values, forget - // about previously-dismissed IDs now. See ReusePictureBuffer() comment - // about "zombies" for why we maintain this set in the first place. - dismissed_picture_ids_.erase(id); - strategy_->AssignOnePictureBuffer(buffers[i]); + strategy_->AssignOnePictureBuffer(buffers[i], have_context); } TRACE_COUNTER1("media", "AVDA::FreePictureIds", free_picture_ids_.size()); - - DoIOTask(); + DoIOTask(true); } void AndroidVideoDecodeAccelerator::ReusePictureBuffer( int32_t picture_buffer_id) { DCHECK(thread_checker_.CalledOnValidThread()); - // This ReusePictureBuffer() might have been in a pipe somewhere (queued in - // IPC, or in a PostTask either at the sender or receiver) when we sent a - // DismissPictureBuffer() for this |picture_buffer_id|. Account for such - // potential "zombie" IDs here. - if (dismissed_picture_ids_.erase(picture_buffer_id)) - return; - free_picture_ids_.push(picture_buffer_id); TRACE_COUNTER1("media", "AVDA::FreePictureIds", free_picture_ids_.size()); @@ -641,58 +922,139 @@ void AndroidVideoDecodeAccelerator::ReusePictureBuffer( } strategy_->ReuseOnePictureBuffer(i->second); - - DoIOTask(); + DoIOTask(true); } void AndroidVideoDecodeAccelerator::Flush() { DCHECK(thread_checker_.CalledOnValidThread()); - Decode(media::BitstreamBuffer(-1, base::SharedMemoryHandle(), 0)); + DecodeBuffer(media::BitstreamBuffer(-1, base::SharedMemoryHandle(), 0)); } -bool AndroidVideoDecodeAccelerator::ConfigureMediaCodec() { +void AndroidVideoDecodeAccelerator::ConfigureMediaCodecAsynchronously() { DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(surface_texture_.get()); - TRACE_EVENT0("media", "AVDA::ConfigureMediaCodec"); - gfx::ScopedJavaSurface surface(surface_texture_.get()); + // It's probably okay just to return here, since the codec will be configured + // asynchronously. It's unclear that any state for the new request could + // be different, unless somebody modifies |codec_config_| while we're already + // waiting for a codec. One shouldn't do that for thread safety. + DCHECK_NE(state_, WAITING_FOR_CODEC); + + state_ = WAITING_FOR_CODEC; + + // Tell the strategy that we're changing codecs. The codec itself could be + // used normally, since we don't replace it until we're back on the main + // thread. However, if we're using an output surface, then the incoming codec + // might access that surface while the main thread is drawing. Telling the + // strategy to forget the codec avoids this. + if (media_codec_) { + media_codec_.reset(); + strategy_->CodecChanged(nullptr, output_picture_buffers_); + } + + scoped_refptr<base::SingleThreadTaskRunner> task_runner = + g_avda_timer.Pointer()->ConstructionTaskRunner(); + CHECK(task_runner); + + base::PostTaskAndReplyWithResult( + task_runner.get(), FROM_HERE, + base::Bind(&AndroidVideoDecodeAccelerator::ConfigureMediaCodecOnAnyThread, + codec_config_), + base::Bind(&AndroidVideoDecodeAccelerator::OnCodecConfigured, + weak_this_factory_.GetWeakPtr())); +} + +bool AndroidVideoDecodeAccelerator::ConfigureMediaCodecSynchronously() { + state_ = WAITING_FOR_CODEC; + scoped_ptr<media::VideoCodecBridge> media_codec = + ConfigureMediaCodecOnAnyThread(codec_config_); + OnCodecConfigured(std::move(media_codec)); + return !!media_codec_; +} + +scoped_ptr<media::VideoCodecBridge> +AndroidVideoDecodeAccelerator::ConfigureMediaCodecOnAnyThread( + scoped_refptr<CodecConfig> codec_config) { + TRACE_EVENT0("media", "AVDA::ConfigureMediaCodec"); - jobject media_crypto = media_crypto_ ? media_crypto_->obj() : nullptr; + jobject media_crypto = codec_config->media_crypto_ + ? codec_config->media_crypto_->obj() + : nullptr; // |needs_protected_surface_| implies encrypted stream. - DCHECK(!needs_protected_surface_ || media_crypto); + DCHECK(!codec_config->needs_protected_surface_ || media_crypto); + + return scoped_ptr<media::VideoCodecBridge>( + media::VideoCodecBridge::CreateDecoder( + codec_config->codec_, codec_config->needs_protected_surface_, + codec_config->initial_expected_coded_size_, + codec_config->surface_.j_surface().obj(), media_crypto, true)); +} + +void AndroidVideoDecodeAccelerator::OnCodecConfigured( + scoped_ptr<media::VideoCodecBridge> media_codec) { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_EQ(state_, WAITING_FOR_CODEC); + + media_codec_ = std::move(media_codec); + + // Record one instance of the codec being initialized. + RecordFormatChangedMetric(FormatChangedValue::CodecInitialized); - // Pass a dummy 320x240 canvas size and let the codec signal the real size - // when it's known from the bitstream. - media_codec_.reset(media::VideoCodecBridge::CreateDecoder( - codec_, needs_protected_surface_, gfx::Size(320, 240), - surface.j_surface().obj(), media_crypto)); strategy_->CodecChanged(media_codec_.get(), output_picture_buffers_); + + // If we are supposed to notify that initialization is complete, then do so + // now. Otherwise, this is a reconfiguration. + if (deferred_initialization_pending_) { + NotifyInitializationComplete(!!media_codec_); + deferred_initialization_pending_ = false; + } + if (!media_codec_) { - LOG(ERROR) << "Failed to create MediaCodec instance."; - return false; + POST_ERROR(PLATFORM_FAILURE, "Failed to create MediaCodec."); + return; } + state_ = NO_ERROR; + ManageTimer(true); - return true; } void AndroidVideoDecodeAccelerator::ResetCodecState() { DCHECK(thread_checker_.CalledOnValidThread()); + + // If there is already a reset in flight, then that counts. This can really + // only happen if somebody calls Reset. + if (state_ == WAITING_FOR_CODEC) + return; + bitstream_buffers_in_decoder_.clear(); - // We don't dismiss picture buffers here since we might not get a format - // changed message to re-request them, such as during a seek. In that case, - // we want to reuse the existing buffers. However, we're about to invalidate - // all the output buffers, so we must be sure that the strategy no longer - // refers to them. + if (pending_input_buf_index_ != -1) { + // The data for that index exists in the input buffer, but corresponding + // shm block been deleted. Check that it is safe to flush the coec, i.e. + // |pending_bitstream_buffers_| is empty. + // TODO(timav): keep shm block for that buffer and remove this restriction. + DCHECK(pending_bitstream_buffers_.empty()); + pending_input_buf_index_ = -1; + } + + if (state_ == WAITING_FOR_KEY) + state_ = NO_ERROR; + + // We might increment error_sequence_token here to cancel any delayed errors, + // but right now it's unclear that it's safe to do so. If we are in an error + // state because of a codec error, then it would be okay. Otherwise, it's + // less obvious that we are exiting the error state. Since deferred errors + // are only intended for fullscreen transitions right now, we take the more + // conservative approach and let the errors post. + // TODO(liberato): revisit this once we sort out the error state a bit more. // When codec is not in error state we can quickly reset (internally calls // flush()) for JB-MR2 and beyond. Prior to JB-MR2, flush() had several bugs - // (b/8125974, b/8347958) so we must stop() and reconfigure MediaCodec. The - // full reconfigure is much slower and may cause visible freezing if done - // mid-stream. + // (b/8125974, b/8347958) so we must delete the MediaCodec and create a new + // one. The full reconfigure is much slower and may cause visible freezing if + // done mid-stream. if (state_ == NO_ERROR && base::android::BuildInfo::GetInstance()->sdk_int() >= 18) { DVLOG(3) << __FUNCTION__ << " Doing fast MediaCodec reset (flush)."; @@ -702,37 +1064,21 @@ void AndroidVideoDecodeAccelerator::ResetCodecState() { strategy_->CodecChanged(media_codec_.get(), output_picture_buffers_); } else { DVLOG(3) << __FUNCTION__ - << " Doing slow MediaCodec reset (stop/re-configure)."; - io_timer_.Stop(); - media_codec_->Stop(); + << " Deleting the MediaCodec and creating a new one."; + g_avda_timer.Pointer()->StopTimer(this); // Changing the codec will also notify the strategy to forget about any // output buffers it has currently. - ConfigureMediaCodec(); state_ = NO_ERROR; + ConfigureMediaCodecAsynchronously(); } } -void AndroidVideoDecodeAccelerator::DismissPictureBuffers() { - DCHECK(thread_checker_.CalledOnValidThread()); - DVLOG(3) << __FUNCTION__; - - for (const auto& pb : output_picture_buffers_) { - strategy_->DismissOnePictureBuffer(pb.second); - client_->DismissPictureBuffer(pb.first); - dismissed_picture_ids_.insert(pb.first); - } - output_picture_buffers_.clear(); - std::queue<int32_t> empty; - std::swap(free_picture_ids_, empty); - picturebuffers_requested_ = false; -} - void AndroidVideoDecodeAccelerator::Reset() { DCHECK(thread_checker_.CalledOnValidThread()); TRACE_EVENT0("media", "AVDA::Reset"); while (!pending_bitstream_buffers_.empty()) { - int32_t bitstream_buffer_id = pending_bitstream_buffers_.front().first.id(); + int32_t bitstream_buffer_id = pending_bitstream_buffers_.front().id(); pending_bitstream_buffers_.pop(); if (bitstream_buffer_id != -1) { @@ -745,8 +1091,13 @@ void AndroidVideoDecodeAccelerator::Reset() { TRACE_COUNTER1("media", "AVDA::PendingBitstreamBufferCount", 0); bitstreams_notified_in_advance_.clear(); + // Any error that is waiting to post can be ignored. + error_sequence_token_++; + ResetCodecState(); + // Note that |media_codec_| might not yet be ready, but we can still post + // this anyway. base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::NotifyResetDone, weak_this_factory_.GetWeakPtr())); @@ -755,11 +1106,12 @@ void AndroidVideoDecodeAccelerator::Reset() { void AndroidVideoDecodeAccelerator::Destroy() { DCHECK(thread_checker_.CalledOnValidThread()); - bool have_context = make_context_current_.Run(); + bool have_context = make_context_current_cb_.Run(); if (!have_context) LOG(WARNING) << "Failed make GL context current for Destroy, continuing."; - strategy_->Cleanup(have_context, output_picture_buffers_); + if (strategy_) + strategy_->Cleanup(have_context, output_picture_buffers_); // If we have an OnFrameAvailable handler, tell it that we're going away. if (on_frame_available_handler_) { @@ -767,15 +1119,20 @@ void AndroidVideoDecodeAccelerator::Destroy() { on_frame_available_handler_ = nullptr; } + // Note that async codec construction might still be in progress. In that + // case, the codec will be deleted when it completes once we invalidate all + // our weak refs. weak_this_factory_.InvalidateWeakPtrs(); if (media_codec_) { - io_timer_.Stop(); - media_codec_->Stop(); + g_avda_timer.Pointer()->StopTimer(this); + media_codec_.reset(); } delete this; } -bool AndroidVideoDecodeAccelerator::CanDecodeOnIOThread() { +bool AndroidVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { return false; } @@ -790,7 +1147,29 @@ const base::ThreadChecker& AndroidVideoDecodeAccelerator::ThreadChecker() base::WeakPtr<gpu::gles2::GLES2Decoder> AndroidVideoDecodeAccelerator::GetGlDecoder() const { - return gl_decoder_; + return get_gles2_decoder_cb_.Run(); +} + +gpu::gles2::TextureRef* AndroidVideoDecodeAccelerator::GetTextureForPicture( + const media::PictureBuffer& picture_buffer) { + auto gles_decoder = GetGlDecoder(); + RETURN_ON_FAILURE(this, gles_decoder, "Failed to get GL decoder", + ILLEGAL_STATE, nullptr); + RETURN_ON_FAILURE(this, gles_decoder->GetContextGroup(), + "Null gles_decoder->GetContextGroup()", ILLEGAL_STATE, + nullptr); + gpu::gles2::TextureManager* texture_manager = + gles_decoder->GetContextGroup()->texture_manager(); + RETURN_ON_FAILURE(this, texture_manager, "Null texture_manager", + ILLEGAL_STATE, nullptr); + + DCHECK_LE(1u, picture_buffer.internal_texture_ids().size()); + gpu::gles2::TextureRef* texture_ref = + texture_manager->GetTexture(picture_buffer.internal_texture_ids()[0]); + RETURN_ON_FAILURE(this, texture_manager, "Null texture_ref", ILLEGAL_STATE, + nullptr); + + return texture_ref; } void AndroidVideoDecodeAccelerator::OnFrameAvailable() { @@ -802,20 +1181,24 @@ void AndroidVideoDecodeAccelerator::OnFrameAvailable() { void AndroidVideoDecodeAccelerator::PostError( const ::tracked_objects::Location& from_here, media::VideoDecodeAccelerator::Error error) { - base::MessageLoop::current()->PostTask( - from_here, base::Bind(&AndroidVideoDecodeAccelerator::NotifyError, - weak_this_factory_.GetWeakPtr(), error)); + base::MessageLoop::current()->PostDelayedTask( + from_here, + base::Bind(&AndroidVideoDecodeAccelerator::NotifyError, + weak_this_factory_.GetWeakPtr(), error, error_sequence_token_), + (defer_errors_ ? ErrorPostingDelay() : base::TimeDelta())); state_ = ERROR; } void AndroidVideoDecodeAccelerator::OnMediaCryptoReady( - media::MediaDrmBridge::JavaObjectPtr media_crypto, + media::MediaDrmBridgeCdmContext::JavaObjectPtr media_crypto, bool needs_protected_surface) { DVLOG(1) << __FUNCTION__; if (!media_crypto) { LOG(ERROR) << "MediaCrypto is not available, can't play encrypted stream."; - NotifyCdmAttached(false); + cdm_for_reference_holding_only_ = nullptr; + media_drm_bridge_cdm_context_ = nullptr; + NotifyInitializationComplete(false); return; } @@ -825,23 +1208,24 @@ void AndroidVideoDecodeAccelerator::OnMediaCryptoReady( // is not created yet. DCHECK(!media_codec_); - media_crypto_ = std::move(media_crypto); - needs_protected_surface_ = needs_protected_surface; + codec_config_->media_crypto_ = std::move(media_crypto); + codec_config_->needs_protected_surface_ = needs_protected_surface; // After receiving |media_crypto_| we can configure MediaCodec. - const bool success = ConfigureMediaCodec(); - NotifyCdmAttached(success); + ConfigureMediaCodecAsynchronously(); } void AndroidVideoDecodeAccelerator::OnKeyAdded() { DVLOG(1) << __FUNCTION__; - // TODO(timav): Figure out whether stopping the pipeline in response to - // NO_KEY error and restarting it here has significant benefits (e.g. saving - // power). Right now do nothing here. + + if (state_ == WAITING_FOR_KEY) + state_ = NO_ERROR; + + DoIOTask(true); } -void AndroidVideoDecodeAccelerator::NotifyCdmAttached(bool success) { - client_->NotifyCdmAttached(success); +void AndroidVideoDecodeAccelerator::NotifyInitializationComplete(bool success) { + client_->NotifyInitializationComplete(success); } void AndroidVideoDecodeAccelerator::NotifyPictureReady( @@ -863,7 +1247,13 @@ void AndroidVideoDecodeAccelerator::NotifyResetDone() { } void AndroidVideoDecodeAccelerator::NotifyError( - media::VideoDecodeAccelerator::Error error) { + media::VideoDecodeAccelerator::Error error, + int token) { + DVLOG(1) << __FUNCTION__ << ": error: " << error << " token: " << token + << " current: " << error_sequence_token_; + if (token != error_sequence_token_) + return; + client_->NotifyError(error); } @@ -871,45 +1261,72 @@ void AndroidVideoDecodeAccelerator::ManageTimer(bool did_work) { bool should_be_running = true; base::TimeTicks now = base::TimeTicks::Now(); - if (!did_work) { + if (!did_work && !most_recent_work_.is_null()) { // Make sure that we have done work recently enough, else stop the timer. - if (now - most_recent_work_ > IdleTimerTimeOut()) + if (now - most_recent_work_ > IdleTimerTimeOut()) { + most_recent_work_ = base::TimeTicks(); should_be_running = false; + } } else { most_recent_work_ = now; } - if (should_be_running && !io_timer_.IsRunning()) { - io_timer_.Start(FROM_HERE, DecodePollDelay(), this, - &AndroidVideoDecodeAccelerator::DoIOTask); - } else if (!should_be_running && io_timer_.IsRunning()) { - io_timer_.Stop(); - } + if (should_be_running) + g_avda_timer.Pointer()->StartTimer(this); + else + g_avda_timer.Pointer()->StopTimer(this); } // static -bool AndroidVideoDecodeAccelerator::UseDeferredRenderingStrategy() { - return base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableUnifiedMediaPipeline); +bool AndroidVideoDecodeAccelerator::UseDeferredRenderingStrategy( + const gpu::GpuPreferences& gpu_preferences) { + // TODO(liberato, watk): Figure out what we want to do about zero copy for + // fullscreen external SurfaceView in WebView. http://crbug.com/582170. + return !gpu_preferences.enable_threaded_texture_mailboxes; } // static media::VideoDecodeAccelerator::Capabilities -AndroidVideoDecodeAccelerator::GetCapabilities() { +AndroidVideoDecodeAccelerator::GetCapabilities( + const gpu::GpuPreferences& gpu_preferences) { Capabilities capabilities; SupportedProfiles& profiles = capabilities.supported_profiles; - SupportedProfile profile; - - profile.profile = media::VP8PROFILE_ANY; - profile.min_resolution.SetSize(0, 0); - profile.max_resolution.SetSize(1920, 1088); - profiles.push_back(profile); + if (media::MediaCodecUtil::IsVp8DecoderAvailable()) { + SupportedProfile profile; + profile.profile = media::VP8PROFILE_ANY; + profile.min_resolution.SetSize(0, 0); + profile.max_resolution.SetSize(1920, 1088); + // If we know MediaCodec will just create a software codec, prefer our + // internal software decoder instead. It's more up to date and secured + // within the renderer sandbox. However if the content is encrypted, we + // must use MediaCodec anyways since MediaDrm offers no way to decrypt + // the buffers and let us use our internal software decoders. + profile.encrypted_only = media::VideoCodecBridge::IsKnownUnaccelerated( + media::kCodecVP8, media::MEDIA_CODEC_DECODER); + profiles.push_back(profile); + } - profile.profile = media::VP9PROFILE_ANY; - profile.min_resolution.SetSize(0, 0); - profile.max_resolution.SetSize(1920, 1088); - profiles.push_back(profile); + if (media::MediaCodecUtil::IsVp9DecoderAvailable()) { + SupportedProfile profile; + profile.min_resolution.SetSize(0, 0); + profile.max_resolution.SetSize(1920, 1088); + // If we know MediaCodec will just create a software codec, prefer our + // internal software decoder instead. It's more up to date and secured + // within the renderer sandbox. However if the content is encrypted, we + // must use MediaCodec anyways since MediaDrm offers no way to decrypt + // the buffers and let us use our internal software decoders. + profile.encrypted_only = media::VideoCodecBridge::IsKnownUnaccelerated( + media::kCodecVP9, media::MEDIA_CODEC_DECODER); + profile.profile = media::VP9PROFILE_PROFILE0; + profiles.push_back(profile); + profile.profile = media::VP9PROFILE_PROFILE1; + profiles.push_back(profile); + profile.profile = media::VP9PROFILE_PROFILE2; + profiles.push_back(profile); + profile.profile = media::VP9PROFILE_PROFILE3; + profiles.push_back(profile); + } for (const auto& supported_profile : kSupportedH264Profiles) { SupportedProfile profile; @@ -922,9 +1339,15 @@ AndroidVideoDecodeAccelerator::GetCapabilities() { profiles.push_back(profile); } - if (UseDeferredRenderingStrategy()) { - capabilities.flags = media::VideoDecodeAccelerator::Capabilities:: + capabilities.flags = media::VideoDecodeAccelerator::Capabilities:: + SUPPORTS_DEFERRED_INITIALIZATION; + if (UseDeferredRenderingStrategy(gpu_preferences)) { + capabilities.flags |= media::VideoDecodeAccelerator::Capabilities:: NEEDS_ALL_PICTURE_BUFFERS_TO_DECODE; + if (media::MediaCodecUtil::IsSurfaceViewOutputSupported()) { + capabilities.flags |= media::VideoDecodeAccelerator::Capabilities:: + SUPPORTS_EXTERNAL_OUTPUT_SURFACE; + } } return capabilities; diff --git a/chromium/content/common/gpu/media/android_video_decode_accelerator.h b/chromium/content/common/gpu/media/android_video_decode_accelerator.h index 1dd6816a72d..1e0543d3fc5 100644 --- a/chromium/content/common/gpu/media/android_video_decode_accelerator.h +++ b/chromium/content/common/gpu/media/android_video_decode_accelerator.h @@ -18,11 +18,14 @@ #include "base/timer/timer.h" #include "content/common/content_export.h" #include "content/common/gpu/media/avda_state_provider.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" -#include "media/base/android/media_drm_bridge.h" +#include "gpu/command_buffer/service/gpu_preferences.h" +#include "media/base/android/media_drm_bridge_cdm_context.h" #include "media/base/android/sdk_media_codec_bridge.h" #include "media/base/media_keys.h" #include "media/video/video_decode_accelerator.h" +#include "ui/gl/android/scoped_java_surface.h" namespace gfx { class SurfaceTexture; @@ -39,7 +42,7 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator : public media::VideoDecodeAccelerator, public AVDAStateProvider { public: - typedef std::map<int32_t, media::PictureBuffer> OutputBufferMap; + using OutputBufferMap = std::map<int32_t, media::PictureBuffer>; // A BackingStrategy is responsible for making a PictureBuffer's texture // contain the image that a MediaCodec decoder buffer tells it to. @@ -47,20 +50,26 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator public: virtual ~BackingStrategy() {} - // Called after the state provider is given, but before any other - // calls to the BackingStrategy. - virtual void Initialize(AVDAStateProvider* provider) = 0; + // Must be called before anything else. If surface_view_id is not equal to + // |kNoSurfaceID| it refers to a SurfaceView that the strategy must render + // to. + // Returns the Java surface to configure MediaCodec with. + virtual gfx::ScopedJavaSurface Initialize(int surface_view_id) = 0; // Called before the AVDA does any Destroy() work. This will be // the last call that the BackingStrategy receives. virtual void Cleanup(bool have_context, const OutputBufferMap& buffer_map) = 0; + // This returns the SurfaceTexture created by Initialize, or nullptr if + // the strategy was initialized with a SurfaceView. + virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture() const = 0; + // Return the GL texture target that the PictureBuffer textures use. virtual uint32_t GetTextureTarget() const = 0; - // Create and return a surface texture for the MediaCodec to use. - virtual scoped_refptr<gfx::SurfaceTexture> CreateSurfaceTexture() = 0; + // Return the size to use when requesting picture buffers. + virtual gfx::Size GetPictureBufferSize() const = 0; // Make the provided PictureBuffer draw the image that is represented by // the decoded output buffer at codec_buffer_index. @@ -70,16 +79,13 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator // Notify strategy that a picture buffer has been assigned. virtual void AssignOnePictureBuffer( - const media::PictureBuffer& picture_buffer) {} + const media::PictureBuffer& picture_buffer, + bool have_context) {} // Notify strategy that a picture buffer has been reused. virtual void ReuseOnePictureBuffer( const media::PictureBuffer& picture_buffer) {} - // Notify strategy that we are about to dismiss a picture buffer. - virtual void DismissOnePictureBuffer( - const media::PictureBuffer& picture_buffer) {} - // Notify strategy that we have a new android MediaCodec instance. This // happens when we're starting up or re-configuring mid-stream. Any // previously provided codec should no longer be referenced. @@ -91,11 +97,22 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator // Notify the strategy that a frame is available. This callback can happen // on any thread at any time. virtual void OnFrameAvailable() = 0; + + // Whether the pictures produced by this backing strategy are overlayable. + virtual bool ArePicturesOverlayable() = 0; + + // Size may have changed due to resolution change since the last time this + // PictureBuffer was used. Update the size of the picture buffer to + // |new_size| and also update any size-dependent state (e.g. size of + // associated texture). Callers should set the correct GL context prior to + // calling. + virtual void UpdatePictureBufferSize(media::PictureBuffer* picture_buffer, + const gfx::Size& new_size) = 0; }; AndroidVideoDecodeAccelerator( - const base::WeakPtr<gpu::gles2::GLES2Decoder> decoder, - const base::Callback<bool(void)>& make_context_current); + const MakeGLContextCurrentCallback& make_context_current_cb, + const GetGLES2DecoderCallback& get_gles2_decoder_cb); ~AndroidVideoDecodeAccelerator() override; @@ -109,31 +126,98 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator void Flush() override; void Reset() override; void Destroy() override; - bool CanDecodeOnIOThread() override; + bool TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) + override; // AVDAStateProvider implementation: const gfx::Size& GetSize() const override; const base::ThreadChecker& ThreadChecker() const override; base::WeakPtr<gpu::gles2::GLES2Decoder> GetGlDecoder() const override; + gpu::gles2::TextureRef* GetTextureForPicture( + const media::PictureBuffer& picture_buffer) override; void PostError(const ::tracked_objects::Location& from_here, media::VideoDecodeAccelerator::Error error) override; - static media::VideoDecodeAccelerator::Capabilities GetCapabilities(); + static media::VideoDecodeAccelerator::Capabilities GetCapabilities( + const gpu::GpuPreferences& gpu_preferences); // Notifies about SurfaceTexture::OnFrameAvailable. This can happen on any // thread at any time! void OnFrameAvailable(); private: + friend class AVDATimerManager; + + // TODO(timav): evaluate the need for more states in the AVDA state machine. enum State { NO_ERROR, ERROR, + // Set when we are asynchronously constructing the codec. Will transition + // to NO_ERROR or ERROR depending on success. + WAITING_FOR_CODEC, + // Set when we have a codec, but it doesn't yet have a key. + WAITING_FOR_KEY, + WAITING_FOR_EOS, }; - static const base::TimeDelta kDecodePollDelay; + // Configuration info for MediaCodec. + // This is used to shuttle configuration info between threads without needing + // to worry about the lifetime of the AVDA instance. All of these should not + // be modified while |state_| is WAITING_FOR_CODEC. + class CodecConfig : public base::RefCountedThreadSafe<CodecConfig> { + public: + CodecConfig(); + + // Codec type. Used when we configure media codec. + media::VideoCodec codec_ = media::kUnknownVideoCodec; + + // Whether encryption scheme requires to use protected surface. + bool needs_protected_surface_ = false; + + // The surface that MediaCodec is configured to output to. It's created by + // the backing strategy. + gfx::ScopedJavaSurface surface_; + + // The MediaCrypto object is used in the MediaCodec.configure() in case of + // an encrypted stream. + media::MediaDrmBridgeCdmContext::JavaObjectPtr media_crypto_; + + // Initial coded size. The actual size might change at any time, so this + // is only a hint. + gfx::Size initial_expected_coded_size_; + + protected: + friend class base::RefCountedThreadSafe<CodecConfig>; + virtual ~CodecConfig(); + + private: + DISALLOW_COPY_AND_ASSIGN(CodecConfig); + }; // Configures |media_codec_| with the given codec parameters from the client. - bool ConfigureMediaCodec(); + // This configuration will (probably) not be complete before this call + // returns. Multiple calls before completion will be ignored. |state_| + // must be NO_ERROR or WAITING_FOR_CODEC. Note that, once you call this, + // you should be careful to avoid modifying members of |codec_config_| until + // |state_| is no longer WAITING_FOR_CODEC. + void ConfigureMediaCodecAsynchronously(); + + // Like ConfigureMediaCodecAsynchronously, but synchronous. Returns true if + // and only if |media_codec_| is non-null. Since all configuration is done + // synchronously, there is no concern with modifying |codec_config_| after + // this returns. + bool ConfigureMediaCodecSynchronously(); + + // Instantiate a media codec using |codec_config|. + // This may be called on any thread. + static scoped_ptr<media::VideoCodecBridge> ConfigureMediaCodecOnAnyThread( + scoped_refptr<CodecConfig> codec_config); + + // Called on the main thread to update |media_codec_| and complete codec + // configuration. |media_codec| will be null if configuration failed. + void OnCodecConfigured(scoped_ptr<media::VideoCodecBridge> media_codec); // Sends the decoded frame specified by |codec_buffer_index| to the client. void SendDecodedFrameToClient(int32_t codec_buffer_index, @@ -142,7 +226,7 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator // Does pending IO tasks if any. Once this is called, it polls |media_codec_| // until it finishes pending tasks. For the polling, |kDecodePollDelay| is // used. - void DoIOTask(); + void DoIOTask(bool start_timer); // Feeds input data to |media_codec_|. This checks // |pending_bitstream_buffers_| and queues a buffer to |media_codec_|. @@ -157,15 +241,20 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator // Requests picture buffers from the client. void RequestPictureBuffers(); + // Decode the content in the |bitstream_buffer|. Note that a + // |bitstream_buffer| of id as -1 indicates a flush command. + void DecodeBuffer(const media::BitstreamBuffer& bitstream_buffer); + // This callback is called after CDM obtained a MediaCrypto object. - void OnMediaCryptoReady(media::MediaDrmBridge::JavaObjectPtr media_crypto, - bool needs_protected_surface); + void OnMediaCryptoReady( + media::MediaDrmBridgeCdmContext::JavaObjectPtr media_crypto, + bool needs_protected_surface); // This callback is called when a new key is added to CDM. void OnKeyAdded(); - // Notifies the client of the CDM setting result. - void NotifyCdmAttached(bool success); + // Notifies the client of the result of deferred initialization. + void NotifyInitializationComplete(bool success); // Notifies the client about the availability of a picture. void NotifyPictureReady(const media::Picture& picture); @@ -181,7 +270,12 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator void NotifyResetDone(); // Notifies about decoding errors. - void NotifyError(media::VideoDecodeAccelerator::Error error); + // Note: you probably don't want to call this directly. Use PostError or + // RETURN_ON_FAILURE, since we can defer error reporting to keep the pipeline + // from breaking. NotifyError will do so immediately, PostError may wait. + // |token| has to match |error_sequence_token_|, or else it's assumed to be + // from a post that's prior to a previous reset, and ignored. + void NotifyError(media::VideoDecodeAccelerator::Error error, int token); // Start or stop our work-polling timer based on whether we did any work, and // how long it has been since we've done work. Calling this with true will @@ -194,12 +288,9 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator // is still valid and should be processed. void ResetCodecState(); - // Dismiss all |output_picture_buffers_| in preparation for requesting new - // ones. - void DismissPictureBuffers(); - // Return true if and only if we should use deferred rendering. - static bool UseDeferredRenderingStrategy(); + static bool UseDeferredRenderingStrategy( + const gpu::GpuPreferences& gpu_preferences); // Used to DCHECK that we are called on the correct thread. base::ThreadChecker thread_checker_; @@ -208,17 +299,14 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator Client* client_; // Callback to set the correct gl context. - base::Callback<bool(void)> make_context_current_; + MakeGLContextCurrentCallback make_context_current_cb_; - // Codec type. Used when we configure media codec. - media::VideoCodec codec_; + // Callback to get the GLES2Decoder instance. + GetGLES2DecoderCallback get_gles2_decoder_cb_; // Whether the stream is encrypted. bool is_encrypted_; - // Whether encryption scheme requires to use protected surface. - bool needs_protected_surface_; - // The current state of this class. For now, this is used only for setting // error state. State state_; @@ -231,17 +319,9 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator // decoded frames to the client. std::queue<int32_t> free_picture_ids_; - // Picture buffer ids which have been dismissed and not yet re-assigned. Used - // to ignore ReusePictureBuffer calls that were in flight when the - // DismissPictureBuffer call was made. - std::set<int32_t> dismissed_picture_ids_; - // The low-level decoder which Android SDK provides. scoped_ptr<media::VideoCodecBridge> media_codec_; - // A container of texture. Used to set a texture to |media_codec_|. - scoped_refptr<gfx::SurfaceTexture> surface_texture_; - // Set to true after requesting picture buffers to the client. bool picturebuffers_requested_; @@ -249,11 +329,8 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator gfx::Size size_; // Encoded bitstream buffers to be passed to media codec, queued until an - // input buffer is available, along with the time when they were first - // enqueued. - typedef std::queue<std::pair<media::BitstreamBuffer, base::Time> > - PendingBitstreamBuffers; - PendingBitstreamBuffers pending_bitstream_buffers_; + // input buffer is available. + std::queue<media::BitstreamBuffer> pending_bitstream_buffers_; // A map of presentation timestamp to bitstream buffer id for the bitstream // buffers that have been submitted to the decoder but haven't yet produced an @@ -265,12 +342,6 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator // NotifyEndOfBitstreamBuffer() before getting output from the bitstream. std::list<int32_t> bitstreams_notified_in_advance_; - // Owner of the GL context. Used to restore the context state. - base::WeakPtr<gpu::gles2::GLES2Decoder> gl_decoder_; - - // Repeating timer responsible for draining pending IO to the codec. - base::RepeatingTimer io_timer_; - // Backing strategy that we'll use to connect PictureBuffers to frames. scoped_ptr<BackingStrategy> strategy_; @@ -283,16 +354,33 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator // CDM related stuff. - // Holds a ref-count to the CDM. - scoped_refptr<media::MediaKeys> cdm_; + // Holds a ref-count to the CDM to avoid using the CDM after it's destroyed. + scoped_refptr<media::MediaKeys> cdm_for_reference_holding_only_; + + media::MediaDrmBridgeCdmContext* media_drm_bridge_cdm_context_; // MediaDrmBridge requires registration/unregistration of the player, this // registration id is used for this. int cdm_registration_id_; - // The MediaCrypto object is used in the MediaCodec.configure() in case of - // an encrypted stream. - media::MediaDrmBridge::JavaObjectPtr media_crypto_; + // Configuration that we use for MediaCodec. + // Do not update any of its members while |state_| is WAITING_FOR_CODEC. + scoped_refptr<CodecConfig> codec_config_; + + // Index of the dequeued and filled buffer that we keep trying to enqueue. + // Such buffer appears in MEDIA_CODEC_NO_KEY processing. + int pending_input_buf_index_; + + // Monotonically increasing value that is used to prevent old, delayed errors + // from being sent after a reset. + int error_sequence_token_; + + // PostError will defer sending an error if and only if this is true. + bool defer_errors_; + + // True if and only if VDA initialization is deferred, and we have not yet + // called NotifyInitializationComplete. + bool deferred_initialization_pending_; // WeakPtrFactory for posting tasks back to |this|. base::WeakPtrFactory<AndroidVideoDecodeAccelerator> weak_this_factory_; diff --git a/chromium/content/common/gpu/media/android_video_decode_accelerator_unittest.cc b/chromium/content/common/gpu/media/android_video_decode_accelerator_unittest.cc index 3cd79157162..d21ad9e58a8 100644 --- a/chromium/content/common/gpu/media/android_video_decode_accelerator_unittest.cc +++ b/chromium/content/common/gpu/media/android_video_decode_accelerator_unittest.cc @@ -27,13 +27,15 @@ bool MockMakeContextCurrent() { return true; } +static base::WeakPtr<gpu::gles2::GLES2Decoder> MockGetGLES2Decoder( + const base::WeakPtr<gpu::gles2::GLES2Decoder>& decoder) { + return decoder; +} + } // namespace namespace content { -// TODO(felipeg): Add more unit tests to test the ordinary behavior of -// AndroidVideoDecodeAccelerator. -// http://crbug.com/178647 class MockVideoDecodeAcceleratorClient : public media::VideoDecodeAccelerator::Client { public: @@ -42,6 +44,7 @@ class MockVideoDecodeAcceleratorClient // VideoDecodeAccelerator::Client implementation. void ProvidePictureBuffers(uint32_t requested_num_of_buffers, + uint32_t textures_per_buffer, const gfx::Size& dimensions, uint32_t texture_target) override {} void DismissPictureBuffer(int32_t picture_buffer_id) override {} @@ -60,8 +63,6 @@ class AndroidVideoDecodeAcceleratorTest : public testing::Test { void SetUp() override { JNIEnv* env = base::android::AttachCurrentThread(); media::RegisterJni(env); - // TODO(felipeg): fix GL bindings, so that the decoder can perform GL - // calls. // Start message loop because // AndroidVideoDecodeAccelerator::ConfigureMediaCodec() starts a timer task. @@ -72,15 +73,19 @@ class AndroidVideoDecodeAcceleratorTest : public testing::Test { scoped_ptr<MockVideoDecodeAcceleratorClient> client( new MockVideoDecodeAcceleratorClient()); accelerator_.reset(new AndroidVideoDecodeAccelerator( - decoder->AsWeakPtr(), base::Bind(&MockMakeContextCurrent))); + base::Bind(&MockMakeContextCurrent), + base::Bind(&MockGetGLES2Decoder, decoder->AsWeakPtr()))); } bool Configure(media::VideoCodec codec) { AndroidVideoDecodeAccelerator* accelerator = static_cast<AndroidVideoDecodeAccelerator*>(accelerator_.get()); - accelerator->surface_texture_ = gfx::SurfaceTexture::Create(0); - accelerator->codec_ = codec; - return accelerator->ConfigureMediaCodec(); + scoped_refptr<gfx::SurfaceTexture> surface_texture = + gfx::SurfaceTexture::Create(0); + accelerator->codec_config_->surface_ = + gfx::ScopedJavaSurface(surface_texture.get()); + accelerator->codec_config_->codec_ = codec; + return accelerator->ConfigureMediaCodecSynchronously(); } private: diff --git a/chromium/content/common/gpu/media/android_video_encode_accelerator.cc b/chromium/content/common/gpu/media/android_video_encode_accelerator.cc index eb383081d7f..ac2ff39e9b7 100644 --- a/chromium/content/common/gpu/media/android_video_encode_accelerator.cc +++ b/chromium/content/common/gpu/media/android_video_encode_accelerator.cc @@ -7,13 +7,12 @@ #include <set> #include "base/bind.h" -#include "base/command_line.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" #include "base/metrics/histogram.h" -#include "content/common/gpu/gpu_channel.h" -#include "content/public/common/content_switches.h" +#include "content/common/gpu/media/shared_memory_region.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" +#include "gpu/ipc/service/gpu_channel.h" #include "media/base/android/media_codec_util.h" #include "media/base/bitstream_buffer.h" #include "media/base/limits.h" @@ -95,8 +94,6 @@ static bool GetSupportedColorFormatForMime(const std::string& mime, AndroidVideoEncodeAccelerator::AndroidVideoEncodeAccelerator() : num_buffers_at_codec_(0), - num_output_buffers_(-1), - output_buffers_capacity_(0), last_set_bitrate_(0) {} AndroidVideoEncodeAccelerator::~AndroidVideoEncodeAccelerator() { @@ -107,12 +104,6 @@ media::VideoEncodeAccelerator::SupportedProfiles AndroidVideoEncodeAccelerator::GetSupportedProfiles() { SupportedProfiles profiles; -#if defined(ENABLE_WEBRTC) - const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); - if (cmd_line->HasSwitch(switches::kDisableWebRtcHWEncoding)) - return profiles; -#endif - const struct { const media::VideoCodec codec; const media::VideoCodecProfile profile; @@ -123,6 +114,11 @@ AndroidVideoEncodeAccelerator::GetSupportedProfiles() { }; for (const auto& supported_codec : kSupportedCodecs) { + if (supported_codec.codec == media::kCodecVP8 && + !media::MediaCodecUtil::IsVp8EncoderAvailable()) { + continue; + } + if (VideoCodecBridge::IsKnownUnaccelerated(supported_codec.codec, media::MEDIA_CODEC_ENCODER)) { continue; @@ -164,17 +160,24 @@ bool AndroidVideoEncodeAccelerator::Initialize( std::string mime_type; media::VideoCodec codec; + // The client should be prepared to feed at least this many frames into the + // encoder before being returned any output frames, since the encoder may + // need to hold onto some subset of inputs as reference pictures. + uint32_t frame_input_count; if (output_profile == media::VP8PROFILE_ANY) { codec = media::kCodecVP8; mime_type = "video/x-vnd.on2.vp8"; + frame_input_count = 1; } else if (output_profile == media::H264PROFILE_BASELINE || output_profile == media::H264PROFILE_MAIN) { codec = media::kCodecH264; mime_type = "video/avc"; + frame_input_count = 30; } else { return false; } + frame_size_ = input_visible_size; last_set_bitrate_ = initial_bitrate; // Only consider using MediaCodec if it's likely backed by hardware. @@ -202,15 +205,16 @@ bool AndroidVideoEncodeAccelerator::Initialize( return false; } - num_output_buffers_ = media_codec_->GetOutputBuffersCount(); - output_buffers_capacity_ = media_codec_->GetOutputBuffersCapacity(); + // Conservative upper bound for output buffer size: decoded size + 2KB. + const size_t output_buffer_capacity = + VideoFrame::AllocationSize(format, input_visible_size) + 2048; base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&VideoEncodeAccelerator::Client::RequireBitstreamBuffers, client_ptr_factory_->GetWeakPtr(), - num_output_buffers_, + frame_input_count, input_visible_size, - output_buffers_capacity_)); + output_buffer_capacity)); return true; } @@ -238,7 +242,8 @@ void AndroidVideoEncodeAccelerator::Encode( DCHECK(thread_checker_.CalledOnValidThread()); RETURN_ON_FAILURE(frame->format() == media::PIXEL_FORMAT_I420, "Unexpected format", kInvalidArgumentError); - + RETURN_ON_FAILURE(frame->visible_rect().size() == frame_size_, + "Unexpected resolution", kInvalidArgumentError); // MediaCodec doesn't have a way to specify stride for non-Packed formats, so // we insist on being called with packed frames and no cropping :( RETURN_ON_FAILURE(frame->row_bytes(VideoFrame::kYPlane) == @@ -260,9 +265,6 @@ void AndroidVideoEncodeAccelerator::UseOutputBitstreamBuffer( const media::BitstreamBuffer& buffer) { DVLOG(3) << __PRETTY_FUNCTION__ << ": bitstream_buffer_id=" << buffer.id(); DCHECK(thread_checker_.CalledOnValidThread()); - RETURN_ON_FAILURE(buffer.size() >= media_codec_->GetOutputBuffersCapacity(), - "Output buffers too small!", - kInvalidArgumentError); available_bitstream_buffers_.push_back(buffer); DoIOTask(); } @@ -331,7 +333,9 @@ void AndroidVideoEncodeAccelerator::QueueInput() { uint8_t* buffer = NULL; size_t capacity = 0; - media_codec_->GetInputBuffer(input_buf_index, &buffer, &capacity); + status = media_codec_->GetInputBuffer(input_buf_index, &buffer, &capacity); + RETURN_ON_FAILURE(status == media::MEDIA_CODEC_OK, "GetInputBuffer failed.", + kPlatformFailureError); size_t queued_size = VideoFrame::AllocationSize(media::PIXEL_FORMAT_I420, frame->coded_size()); @@ -373,21 +377,6 @@ void AndroidVideoEncodeAccelerator::QueueInput() { pending_frames_.pop(); } -bool AndroidVideoEncodeAccelerator::DoOutputBuffersSuffice() { - // If this returns false ever, then the VEA::Client interface will need to - // grow a DismissBitstreamBuffer() call, and VEA::Client impls will have to be - // prepared to field multiple requests to RequireBitstreamBuffers(). - int count = media_codec_->GetOutputBuffersCount(); - size_t capacity = media_codec_->GetOutputBuffersCapacity(); - bool ret = count <= num_output_buffers_ && - capacity <= output_buffers_capacity_; - LOG_IF(ERROR, !ret) << "Need more/bigger buffers; before: " - << num_output_buffers_ << "x" << output_buffers_capacity_ - << ", now: " << count << "x" << capacity; - UMA_HISTOGRAM_BOOLEAN("Media.AVEA.OutputBuffersSuffice", ret); - return ret; -} - void AndroidVideoEncodeAccelerator::DequeueOutput() { if (!client_ptr_factory_->GetWeakPtr() || available_bitstream_buffers_.empty() || num_buffers_at_codec_ == 0) { @@ -410,13 +399,14 @@ void AndroidVideoEncodeAccelerator::DequeueOutput() { // Unreachable because of previous statement, but included for clarity. return; - case media::MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: // Fall-through. - case media::MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: - RETURN_ON_FAILURE(DoOutputBuffersSuffice(), - "Bitstream now requires more/larger buffers", + case media::MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: + RETURN_ON_FAILURE(false, "Unexpected output format change", kPlatformFailureError); break; + case media::MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: + break; + case media::MEDIA_CODEC_OK: DCHECK_GE(buf_index, 0); break; @@ -429,17 +419,17 @@ void AndroidVideoEncodeAccelerator::DequeueOutput() { media::BitstreamBuffer bitstream_buffer = available_bitstream_buffers_.back(); available_bitstream_buffers_.pop_back(); - scoped_ptr<base::SharedMemory> shm( - new base::SharedMemory(bitstream_buffer.handle(), false)); - RETURN_ON_FAILURE(shm->Map(bitstream_buffer.size()), - "Failed to map SHM", - kPlatformFailureError); - RETURN_ON_FAILURE(size <= shm->mapped_size(), - "Encoded buffer too large: " << size << ">" - << shm->mapped_size(), + scoped_ptr<SharedMemoryRegion> shm( + new SharedMemoryRegion(bitstream_buffer, false)); + RETURN_ON_FAILURE(shm->Map(), "Failed to map SHM", kPlatformFailureError); + RETURN_ON_FAILURE(size <= shm->size(), + "Encoded buffer too large: " << size << ">" << shm->size(), kPlatformFailureError); - media_codec_->CopyFromOutputBuffer(buf_index, offset, shm->memory(), size); + media::MediaCodecStatus status = media_codec_->CopyFromOutputBuffer( + buf_index, offset, shm->memory(), size); + RETURN_ON_FAILURE(status == media::MEDIA_CODEC_OK, + "CopyFromOutputBuffer failed", kPlatformFailureError); media_codec_->ReleaseOutputBuffer(buf_index, false); --num_buffers_at_codec_; diff --git a/chromium/content/common/gpu/media/android_video_encode_accelerator.h b/chromium/content/common/gpu/media/android_video_encode_accelerator.h index 426360dca7c..0de3d1866b1 100644 --- a/chromium/content/common/gpu/media/android_video_encode_accelerator.h +++ b/chromium/content/common/gpu/media/android_video_encode_accelerator.h @@ -67,9 +67,6 @@ class CONTENT_EXPORT AndroidVideoEncodeAccelerator void QueueInput(); void DequeueOutput(); - // Returns true if we don't need more or bigger output buffers. - bool DoOutputBuffersSuffice(); - // Start & stop |io_timer_| if the time seems right. void MaybeStartIOTimer(); void MaybeStopIOTimer(); @@ -103,9 +100,9 @@ class CONTENT_EXPORT AndroidVideoEncodeAccelerator // appearing to move forward. base::TimeDelta fake_input_timestamp_; - // Number of requested output buffers and their capacity. - int num_output_buffers_; // -1 until RequireBitstreamBuffers. - size_t output_buffers_capacity_; // 0 until RequireBitstreamBuffers. + // Resolution of input stream. Set once in initialization and not allowed to + // change after. + gfx::Size frame_size_; uint32_t last_set_bitrate_; // In bps. diff --git a/chromium/content/common/gpu/media/avda_codec_image.cc b/chromium/content/common/gpu/media/avda_codec_image.cc index 1df753d167e..5830433cdf2 100644 --- a/chromium/content/common/gpu/media/avda_codec_image.cc +++ b/chromium/content/common/gpu/media/avda_codec_image.cc @@ -24,16 +24,17 @@ AVDACodecImage::AVDACodecImage( const base::WeakPtr<gpu::gles2::GLES2Decoder>& decoder, const scoped_refptr<gfx::SurfaceTexture>& surface_texture) : shared_state_(shared_state), - codec_buffer_index_(-1), + codec_buffer_index_(kInvalidCodecBufferIndex), media_codec_(codec), decoder_(decoder), surface_texture_(surface_texture), detach_surface_texture_on_destruction_(false), - texture_(0), - need_shader_info_(true), - texmatrix_uniform_location_(-1) { + texture_(0) { + // Default to a sane guess of "flip Y", just in case we can't get + // the matrix on the first call. memset(gl_matrix_, 0, sizeof(gl_matrix_)); - gl_matrix_[0] = gl_matrix_[5] = gl_matrix_[10] = gl_matrix_[15] = 1.0f; + gl_matrix_[0] = gl_matrix_[10] = gl_matrix_[15] = 1.0f; + gl_matrix_[5] = -1.0f; } AVDACodecImage::~AVDACodecImage() {} @@ -55,38 +56,35 @@ bool AVDACodecImage::BindTexImage(unsigned target) { void AVDACodecImage::ReleaseTexImage(unsigned target) {} bool AVDACodecImage::CopyTexImage(unsigned target) { + if (!surface_texture_) + return false; + if (target != GL_TEXTURE_EXTERNAL_OES) return false; - // Verify that the currently bound texture is the right one. If we're not - // copying to a Texture that shares our service_id, then we can't do much. - // This will force a copy. - // TODO(liberato): Fall back to a copy that uses the texture matrix. GLint bound_service_id = 0; glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id); + // We insist that the currently bound texture is the right one. We could + // make a new glimage from a 2D image. if (bound_service_id != shared_state_->surface_texture_service_id()) return false; - // Attach the surface texture to our GL context if needed. + // If the surface texture isn't attached yet, then attach it. Note that this + // will be to the texture in |shared_state_|, because of the checks above. if (!shared_state_->surface_texture_is_attached()) AttachSurfaceTextureToContext(); - // Make sure that we have the right image in the front buffer. - UpdateSurfaceTexture(); - - InstallTextureMatrix(); - - // TODO(liberato): Handle the texture matrix properly. - // Either we can update the shader with it or we can move all of the logic - // to updateTexImage() to the right place in the cc to send it to the shader. - // For now, we just skip it. crbug.com/530681 + // Make sure that we have the right image in the front buffer. Note that the + // bound_service_id is guaranteed to be equal to the surface texture's client + // texture id, so we can skip preserving it if the right context is current. + UpdateSurfaceTexture(kDontRestoreBindings); // By setting image state to UNBOUND instead of COPIED we ensure that // CopyTexImage() is called each time the surface texture is used for drawing. // It would be nice if we could do this via asking for the currently bound // Texture, but the active unit never seems to change. - texture_->SetLevelImage(GL_TEXTURE_EXTERNAL_OES, 0, this, - gpu::gles2::Texture::UNBOUND); + texture_->SetLevelStreamTextureImage(GL_TEXTURE_EXTERNAL_OES, 0, this, + gpu::gles2::Texture::UNBOUND); return true; } @@ -102,16 +100,29 @@ bool AVDACodecImage::ScheduleOverlayPlane(gfx::AcceleratedWidget widget, gfx::OverlayTransform transform, const gfx::Rect& bounds_rect, const gfx::RectF& crop_rect) { - return false; + // This should only be called when we're rendering to a SurfaceView. + if (surface_texture_) { + DVLOG(1) << "Invalid call to ScheduleOverlayPlane; this image is " + "SurfaceTexture backed."; + return false; + } + + if (codec_buffer_index_ != kInvalidCodecBufferIndex) { + media_codec_->ReleaseOutputBuffer(codec_buffer_index_, true); + codec_buffer_index_ = kInvalidCodecBufferIndex; + } + return true; } void AVDACodecImage::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, uint64_t process_tracing_id, const std::string& dump_name) {} -void AVDACodecImage::UpdateSurfaceTexture() { +void AVDACodecImage::UpdateSurfaceTexture(RestoreBindingsMode mode) { + DCHECK(surface_texture_); + // Render via the media codec if needed. - if (codec_buffer_index_ <= -1 || !media_codec_) + if (!IsCodecBufferOutstanding()) return; // The decoder buffer is still pending. @@ -123,15 +134,24 @@ void AVDACodecImage::UpdateSurfaceTexture() { } // Don't bother to check if we're rendered again. - codec_buffer_index_ = -1; + codec_buffer_index_ = kInvalidCodecBufferIndex; // Swap the rendered image to the front. - scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current; - if (!shared_state_->context()->IsCurrent(NULL)) { - scoped_make_current.reset(new ui::ScopedMakeCurrent( - shared_state_->context(), shared_state_->surface())); - } + scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current = MakeCurrentIfNeeded(); + + // If we changed contexts, then we always want to restore it, since the caller + // doesn't know that we're switching contexts. + if (scoped_make_current) + mode = kDoRestoreBindings; + + // Save the current binding if requested. + GLint bound_service_id = 0; + if (mode == kDoRestoreBindings) + glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id); + surface_texture_->UpdateTexImage(); + if (mode == kDoRestoreBindings) + glBindTexture(GL_TEXTURE_EXTERNAL_OES, bound_service_id); // Helpfully, this is already column major. surface_texture_->GetTransformMatrix(gl_matrix_); @@ -153,16 +173,19 @@ void AVDACodecImage::SetMediaCodec(media::MediaCodecBridge* codec) { media_codec_ = codec; } -void AVDACodecImage::setTexture(gpu::gles2::Texture* texture) { +void AVDACodecImage::SetTexture(gpu::gles2::Texture* texture) { texture_ = texture; } void AVDACodecImage::AttachSurfaceTextureToContext() { + DCHECK(surface_texture_); + + // We assume that the currently bound texture is the intended one. + // Attach the surface texture to the first context we're bound on, so that // no context switch is needed later. - - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -170,35 +193,48 @@ void AVDACodecImage::AttachSurfaceTextureToContext() { // We could do this earlier, but SurfaceTexture has context affinity, and we // don't want to require a context switch. surface_texture_->AttachToGLContext(); - shared_state_->did_attach_surface_texture(); -} - -void AVDACodecImage::InstallTextureMatrix() { - // glUseProgram() has been run already -- just modify the uniform. - // Updating this via VideoFrameProvider::Client::DidUpdateMatrix() would - // be a better solution, except that we'd definitely miss a frame at this - // point in drawing. - // Our current method assumes that we'll end up being a stream resource, - // and that the program has a texMatrix uniform that does what we want. - if (need_shader_info_) { - GLint program_id = -1; - glGetIntegerv(GL_CURRENT_PROGRAM, &program_id); - - if (program_id >= 0) { - // This is memorized from cc/output/shader.cc . - const char* uniformName = "texMatrix"; - texmatrix_uniform_location_ = - glGetUniformLocation(program_id, uniformName); - DCHECK(texmatrix_uniform_location_ != -1); - } + shared_state_->DidAttachSurfaceTexture(); +} - // Only try once. - need_shader_info_ = false; +scoped_ptr<ui::ScopedMakeCurrent> AVDACodecImage::MakeCurrentIfNeeded() { + DCHECK(shared_state_->context()); + scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current; + if (!shared_state_->context()->IsCurrent(NULL)) { + scoped_make_current.reset(new ui::ScopedMakeCurrent( + shared_state_->context(), shared_state_->surface())); } - if (texmatrix_uniform_location_ >= 0) { - glUniformMatrix4fv(texmatrix_uniform_location_, 1, false, gl_matrix_); + return scoped_make_current; +} + +void AVDACodecImage::GetTextureMatrix(float matrix[16]) { + if (IsCodecBufferOutstanding() && shared_state_ && surface_texture_) { + // Our current matrix may be stale. Update it if possible. + if (!shared_state_->surface_texture_is_attached()) { + // Don't attach the surface texture permanently. Perhaps we should + // just attach the surface texture in avda and be done with it. + GLuint service_id = 0; + glGenTextures(1, &service_id); + GLint bound_service_id = 0; + glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, service_id); + AttachSurfaceTextureToContext(); + UpdateSurfaceTexture(kDontRestoreBindings); + // Detach the surface texture, which deletes the generated texture. + surface_texture_->DetachFromGLContext(); + shared_state_->DidDetachSurfaceTexture(); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, bound_service_id); + } else { + // Surface texture is already attached, so just update it. + UpdateSurfaceTexture(kDoRestoreBindings); + } } + + memcpy(matrix, gl_matrix_, sizeof(gl_matrix_)); +} + +bool AVDACodecImage::IsCodecBufferOutstanding() const { + return codec_buffer_index_ != kInvalidCodecBufferIndex && media_codec_; } } // namespace content diff --git a/chromium/content/common/gpu/media/avda_codec_image.h b/chromium/content/common/gpu/media/avda_codec_image.h index ef0456a9fba..46547e478c8 100644 --- a/chromium/content/common/gpu/media/avda_codec_image.h +++ b/chromium/content/common/gpu/media/avda_codec_image.h @@ -9,13 +9,17 @@ #include "base/macros.h" #include "content/common/gpu/media/avda_shared_state.h" -#include "ui/gl/gl_image.h" +#include "gpu/command_buffer/service/gl_stream_texture_image.h" + +namespace ui { +class ScopedMakeCurrent; +} namespace content { -// GLImage that renders MediaCodec buffers to a SurfaceTexture as needed -// in order to draw them. -class AVDACodecImage : public gl::GLImage { +// GLImage that renders MediaCodec buffers to a SurfaceTexture or SurfaceView as +// needed in order to draw them. +class AVDACodecImage : public gpu::gles2::GLStreamTextureImage { public: AVDACodecImage(const scoped_refptr<AVDASharedState>&, media::VideoCodecBridge* codec, @@ -44,6 +48,8 @@ class AVDACodecImage : public gl::GLImage { void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, uint64_t process_tracing_id, const std::string& dump_name) override; + // gpu::gles2::GLStreamTextureMatrix implementation + void GetTextureMatrix(float xform[16]) override; public: // Decoded buffer index that has the image for us to display. @@ -58,24 +64,42 @@ class AVDACodecImage : public gl::GLImage { void SetMediaCodec(media::MediaCodecBridge* codec); - void setTexture(gpu::gles2::Texture* texture); + void SetTexture(gpu::gles2::Texture* texture); private: - // Make sure that the surface texture's front buffer is current. - void UpdateSurfaceTexture(); - - // Attach the surface texture to our GL context, with a texture that we - // create for it. + enum { kInvalidCodecBufferIndex = -1 }; + + // Make sure that the surface texture's front buffer is current. This will + // save / restore the current context. It will optionally restore the texture + // bindings in the surface texture's context, based on |mode|. This is + // intended as a hint if we don't need to change contexts. If we do need to + // change contexts, then we'll always preserve the texture bindings in the + // both contexts. In other words, the caller is telling us whether it's + // okay to change the binding in the current context. + enum RestoreBindingsMode { kDontRestoreBindings, kDoRestoreBindings }; + void UpdateSurfaceTexture(RestoreBindingsMode mode); + + // Attach the surface texture to our GL context to whatever texture is bound + // on the active unit. void AttachSurfaceTextureToContext(); - // Install the current texture matrix into the shader. - void InstallTextureMatrix(); + // Make shared_state_->context() current if it isn't already. + scoped_ptr<ui::ScopedMakeCurrent> MakeCurrentIfNeeded(); + + // Return whether or not the current context is in the same share group as + // |surface_texture_|'s client texture. + // TODO(liberato): is this needed? + bool IsCorrectShareGroup() const; + + // Return whether there is a codec buffer that we haven't rendered yet. Will + // return false also if there's no codec or we otherwise can't update. + bool IsCodecBufferOutstanding() const; // Shared state between the AVDA and all AVDACodecImages. scoped_refptr<AVDASharedState> shared_state_; - // Codec's buffer index that we should render to the surface texture, - // or <0 if none. + // The MediaCodec buffer index that we should render. Only valid if not equal + // to |kInvalidCodecBufferIndex|. int codec_buffer_index_; // Our image size. @@ -86,6 +110,8 @@ class AVDACodecImage : public gl::GLImage { const base::WeakPtr<gpu::gles2::GLES2Decoder> decoder_; + // The SurfaceTexture to render to. This is null when rendering to a + // SurfaceView. const scoped_refptr<gfx::SurfaceTexture> surface_texture_; // Should we detach |surface_texture_| from its GL context when we are @@ -95,12 +121,6 @@ class AVDACodecImage : public gl::GLImage { // The texture that we're attached to. gpu::gles2::Texture* texture_; - // Have we cached |texmatrix_uniform_location_| yet? - bool need_shader_info_; - - // Uniform ID of the texture matrix in the shader. - GLint texmatrix_uniform_location_; - // Texture matrix of the front buffer of the surface texture. float gl_matrix_[16]; diff --git a/chromium/content/common/gpu/media/avda_shared_state.cc b/chromium/content/common/gpu/media/avda_shared_state.cc index c182bf05385..7746254fee9 100644 --- a/chromium/content/common/gpu/media/avda_shared_state.cc +++ b/chromium/content/common/gpu/media/avda_shared_state.cc @@ -4,6 +4,7 @@ #include "content/common/gpu/media/avda_shared_state.h" +#include "base/time/time.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/scoped_make_current.h" @@ -21,10 +22,13 @@ void AVDASharedState::SignalFrameAvailable() { } void AVDASharedState::WaitForFrameAvailable() { - frame_available_event_.Wait(); + // 10msec covers >99.9% of cases, so just wait for up to that much before + // giving up. If an error occurs, we might not ever get a notification. + const base::TimeDelta max_wait_time(base::TimeDelta::FromMilliseconds(10)); + frame_available_event_.TimedWait(max_wait_time); } -void AVDASharedState::did_attach_surface_texture() { +void AVDASharedState::DidAttachSurfaceTexture() { context_ = gfx::GLContext::GetCurrent(); surface_ = gfx::GLSurface::GetCurrent(); DCHECK(context_); @@ -33,4 +37,10 @@ void AVDASharedState::did_attach_surface_texture() { surface_texture_is_attached_ = true; } +void AVDASharedState::DidDetachSurfaceTexture() { + context_ = nullptr; + surface_ = nullptr; + surface_texture_is_attached_ = false; +} + } // namespace content diff --git a/chromium/content/common/gpu/media/avda_shared_state.h b/chromium/content/common/gpu/media/avda_shared_state.h index eb62681fcd5..5f80c44d729 100644 --- a/chromium/content/common/gpu/media/avda_shared_state.h +++ b/chromium/content/common/gpu/media/avda_shared_state.h @@ -50,10 +50,19 @@ class AVDASharedState : public base::RefCounted<AVDASharedState> { return surface_texture_is_attached_; } + // TODO(liberato): move the surface texture here and make these calls + // attach / detach it also. There are several changes going on in avda + // concurrently, so I don't want to change that until the dust settles. + // AVDACodecImage would no longer hold the surface texture. + // Call this when the SurfaceTexture is attached to a GL context. This will // update surface_texture_is_attached(), and set the context() and surface() // to match. - void did_attach_surface_texture(); + void DidAttachSurfaceTexture(); + + // Call this when the SurfaceTexture is detached from its GL context. This + // will cause us to forget the last binding. + void DidDetachSurfaceTexture(); private: // Platform gl texture Id for |surface_texture_|. This will be zero if diff --git a/chromium/content/common/gpu/media/avda_state_provider.h b/chromium/content/common/gpu/media/avda_state_provider.h index 2c84f2ed04a..e7dfac62ded 100644 --- a/chromium/content/common/gpu/media/avda_state_provider.h +++ b/chromium/content/common/gpu/media/avda_state_provider.h @@ -8,6 +8,7 @@ #include "base/compiler_specific.h" #include "base/threading/thread_checker.h" #include "content/common/content_export.h" +#include "gpu/command_buffer/service/texture_manager.h" #include "media/video/video_decode_accelerator.h" namespace gfx { @@ -36,6 +37,8 @@ class AVDAStateProvider { virtual const gfx::Size& GetSize() const = 0; virtual const base::ThreadChecker& ThreadChecker() const = 0; virtual base::WeakPtr<gpu::gles2::GLES2Decoder> GetGlDecoder() const = 0; + virtual gpu::gles2::TextureRef* GetTextureForPicture( + const media::PictureBuffer& picture_buffer) = 0; // Helper function to report an error condition and stop decoding. // This will post NotifyError(), and transition to the error state. diff --git a/chromium/content/common/gpu/media/dxva_video_decode_accelerator_win.cc b/chromium/content/common/gpu/media/dxva_video_decode_accelerator_win.cc index 40a3239cb25..e55c9009720 100644 --- a/chromium/content/common/gpu/media/dxva_video_decode_accelerator_win.cc +++ b/chromium/content/common/gpu/media/dxva_video_decode_accelerator_win.cc @@ -21,7 +21,6 @@ #include "base/base_paths_win.h" #include "base/bind.h" #include "base/callback.h" -#include "base/command_line.h" #include "base/debug/alias.h" #include "base/file_version_info.h" #include "base/files/file_path.h" @@ -34,15 +33,14 @@ #include "base/trace_event/trace_event.h" #include "base/win/windows_version.h" #include "build/build_config.h" -#include "content/public/common/content_switches.h" #include "media/base/win/mf_initializer.h" #include "media/video/video_decode_accelerator.h" #include "third_party/angle/include/EGL/egl.h" #include "third_party/angle/include/EGL/eglext.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" +#include "ui/gl/gl_fence.h" #include "ui/gl/gl_surface_egl.h" -#include "ui/gl/gl_switches.h" namespace { @@ -113,6 +111,91 @@ DEFINE_GUID(CLSID_VideoProcessorMFT, DEFINE_GUID(MF_XVP_PLAYBACK_MODE, 0x3c5d293f, 0xad67, 0x4e29, 0xaf, 0x12, 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9); +// Defines the GUID for the Intel H264 DXVA device. +static const GUID DXVA2_Intel_ModeH264_E = { + 0x604F8E68, 0x4951, 0x4c54,{ 0x88, 0xFE, 0xAB, 0xD2, 0x5C, 0x15, 0xB3, 0xD6} +}; + +// R600, R700, Evergreen and Cayman AMD cards. These support DXVA via UVD3 +// or earlier, and don't handle resolutions higher than 1920 x 1088 well. +static const DWORD g_AMDUVD3GPUList[] = { + 0x9400, 0x9401, 0x9402, 0x9403, 0x9405, 0x940a, 0x940b, 0x940f, 0x94c0, + 0x94c1, 0x94c3, 0x94c4, 0x94c5, 0x94c6, 0x94c7, 0x94c8, 0x94c9, 0x94cb, + 0x94cc, 0x94cd, 0x9580, 0x9581, 0x9583, 0x9586, 0x9587, 0x9588, 0x9589, + 0x958a, 0x958b, 0x958c, 0x958d, 0x958e, 0x958f, 0x9500, 0x9501, 0x9504, + 0x9505, 0x9506, 0x9507, 0x9508, 0x9509, 0x950f, 0x9511, 0x9515, 0x9517, + 0x9519, 0x95c0, 0x95c2, 0x95c4, 0x95c5, 0x95c6, 0x95c7, 0x95c9, 0x95cc, + 0x95cd, 0x95ce, 0x95cf, 0x9590, 0x9591, 0x9593, 0x9595, 0x9596, 0x9597, + 0x9598, 0x9599, 0x959b, 0x9610, 0x9611, 0x9612, 0x9613, 0x9614, 0x9615, + 0x9616, 0x9710, 0x9711, 0x9712, 0x9713, 0x9714, 0x9715, 0x9440, 0x9441, + 0x9442, 0x9443, 0x9444, 0x9446, 0x944a, 0x944b, 0x944c, 0x944e, 0x9450, + 0x9452, 0x9456, 0x945a, 0x945b, 0x945e, 0x9460, 0x9462, 0x946a, 0x946b, + 0x947a, 0x947b, 0x9480, 0x9487, 0x9488, 0x9489, 0x948a, 0x948f, 0x9490, + 0x9491, 0x9495, 0x9498, 0x949c, 0x949e, 0x949f, 0x9540, 0x9541, 0x9542, + 0x954e, 0x954f, 0x9552, 0x9553, 0x9555, 0x9557, 0x955f, 0x94a0, 0x94a1, + 0x94a3, 0x94b1, 0x94b3, 0x94b4, 0x94b5, 0x94b9, 0x68e0, 0x68e1, 0x68e4, + 0x68e5, 0x68e8, 0x68e9, 0x68f1, 0x68f2, 0x68f8, 0x68f9, 0x68fa, 0x68fe, + 0x68c0, 0x68c1, 0x68c7, 0x68c8, 0x68c9, 0x68d8, 0x68d9, 0x68da, 0x68de, + 0x68a0, 0x68a1, 0x68a8, 0x68a9, 0x68b0, 0x68b8, 0x68b9, 0x68ba, 0x68be, + 0x68bf, 0x6880, 0x6888, 0x6889, 0x688a, 0x688c, 0x688d, 0x6898, 0x6899, + 0x689b, 0x689e, 0x689c, 0x689d, 0x9802, 0x9803, 0x9804, 0x9805, 0x9806, + 0x9807, 0x9808, 0x9809, 0x980a, 0x9640, 0x9641, 0x9647, 0x9648, 0x964a, + 0x964b, 0x964c, 0x964e, 0x964f, 0x9642, 0x9643, 0x9644, 0x9645, 0x9649, + 0x6720, 0x6721, 0x6722, 0x6723, 0x6724, 0x6725, 0x6726, 0x6727, 0x6728, + 0x6729, 0x6738, 0x6739, 0x673e, 0x6740, 0x6741, 0x6742, 0x6743, 0x6744, + 0x6745, 0x6746, 0x6747, 0x6748, 0x6749, 0x674a, 0x6750, 0x6751, 0x6758, + 0x6759, 0x675b, 0x675d, 0x675f, 0x6840, 0x6841, 0x6842, 0x6843, 0x6849, + 0x6850, 0x6858, 0x6859, 0x6760, 0x6761, 0x6762, 0x6763, 0x6764, 0x6765, + 0x6766, 0x6767, 0x6768, 0x6770, 0x6771, 0x6772, 0x6778, 0x6779, 0x677b, + 0x6700, 0x6701, 0x6702, 0x6703, 0x6704, 0x6705, 0x6706, 0x6707, 0x6708, + 0x6709, 0x6718, 0x6719, 0x671c, 0x671d, 0x671f, 0x683D, 0x9900, 0x9901, + 0x9903, 0x9904, 0x9905, 0x9906, 0x9907, 0x9908, 0x9909, 0x990a, 0x990b, + 0x990c, 0x990d, 0x990e, 0x990f, 0x9910, 0x9913, 0x9917, 0x9918, 0x9919, + 0x9990, 0x9991, 0x9992, 0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998, + 0x9999, 0x999a, 0x999b, 0x999c, 0x999d, 0x99a0, 0x99a2, 0x99a4, +}; + +// Legacy Intel GPUs (Second generation) which have trouble with resolutions +// higher than 1920 x 1088 +static const DWORD g_IntelLegacyGPUList[] = { + 0x102, 0x106, 0x116, 0x126, +}; + +// Provides scoped access to the underlying buffer in an IMFMediaBuffer +// instance. +class MediaBufferScopedPointer { + public: + MediaBufferScopedPointer(IMFMediaBuffer* media_buffer) + : media_buffer_(media_buffer), + buffer_(nullptr), + max_length_(0), + current_length_(0) { + HRESULT hr = media_buffer_->Lock(&buffer_, &max_length_, ¤t_length_); + CHECK(SUCCEEDED(hr)); + } + + ~MediaBufferScopedPointer() { + HRESULT hr = media_buffer_->Unlock(); + CHECK(SUCCEEDED(hr)); + } + + uint8_t* get() { + return buffer_; + } + + DWORD current_length() const { + return current_length_; + } + + private: + base::win::ScopedComPtr<IMFMediaBuffer> media_buffer_; + uint8_t* buffer_; + DWORD max_length_; + DWORD current_length_; + + DISALLOW_COPY_AND_ASSIGN(MediaBufferScopedPointer); +}; + } // namespace namespace content { @@ -122,7 +205,10 @@ static const media::VideoCodecProfile kSupportedProfiles[] = { media::H264PROFILE_MAIN, media::H264PROFILE_HIGH, media::VP8PROFILE_ANY, - media::VP9PROFILE_ANY + media::VP9PROFILE_PROFILE0, + media::VP9PROFILE_PROFILE1, + media::VP9PROFILE_PROFILE2, + media::VP9PROFILE_PROFILE3 }; CreateDXGIDeviceManager DXVAVideoDecodeAccelerator::create_dxgi_device_manager_ @@ -162,10 +248,16 @@ enum { kFlushDecoderSurfaceTimeoutMs = 1, // Maximum iterations where we try to flush the d3d device. kMaxIterationsForD3DFlush = 4, + // Maximum iterations where we try to flush the ANGLE device before reusing + // the texture. + kMaxIterationsForANGLEReuseFlush = 16, // We only request 5 picture buffers from the client which are used to hold // the decoded samples. These buffers are then reused when the client tells // us that it is done with the buffer. kNumPictureBuffers = 5, + // The keyed mutex should always be released before the other thread + // attempts to acquire it, so AcquireSync should always return immediately. + kAcquireSyncWaitMs = 0, }; static IMFSample* CreateEmptySample() { @@ -177,8 +269,9 @@ static IMFSample* CreateEmptySample() { // Creates a Media Foundation sample with one buffer of length |buffer_length| // on a |align|-byte boundary. Alignment must be a perfect power of 2 or 0. -static IMFSample* CreateEmptySampleWithBuffer(int buffer_length, int align) { - CHECK_GT(buffer_length, 0); +static IMFSample* CreateEmptySampleWithBuffer(uint32_t buffer_length, + int align) { + CHECK_GT(buffer_length, 0U); base::win::ScopedComPtr<IMFSample> sample; sample.Attach(CreateEmptySample()); @@ -209,11 +302,11 @@ static IMFSample* CreateEmptySampleWithBuffer(int buffer_length, int align) { // |min_size| specifies the minimum size of the buffer (might be required by // the decoder for input). If no alignment is required, provide 0. static IMFSample* CreateInputSample(const uint8_t* stream, - int size, - int min_size, + uint32_t size, + uint32_t min_size, int alignment) { CHECK(stream); - CHECK_GT(size, 0); + CHECK_GT(size, 0U); base::win::ScopedComPtr<IMFSample> sample; sample.Attach(CreateEmptySampleWithBuffer(std::max(min_size, size), alignment)); @@ -230,28 +323,16 @@ static IMFSample* CreateInputSample(const uint8_t* stream, RETURN_ON_HR_FAILURE(hr, "Failed to lock buffer", NULL); CHECK_EQ(current_length, 0u); - CHECK_GE(static_cast<int>(max_length), size); + CHECK_GE(max_length, size); memcpy(destination, stream, size); - hr = buffer->Unlock(); - RETURN_ON_HR_FAILURE(hr, "Failed to unlock buffer", NULL); - hr = buffer->SetCurrentLength(size); RETURN_ON_HR_FAILURE(hr, "Failed to set buffer length", NULL); - return sample.Detach(); -} - -static IMFSample* CreateSampleFromInputBuffer( - const media::BitstreamBuffer& bitstream_buffer, - DWORD stream_size, - DWORD alignment) { - base::SharedMemory shm(bitstream_buffer.handle(), true); - RETURN_ON_FAILURE(shm.Map(bitstream_buffer.size()), - "Failed in base::SharedMemory::Map", NULL); + hr = buffer->Unlock(); + RETURN_ON_HR_FAILURE(hr, "Failed to unlock buffer", NULL); - return CreateInputSample(reinterpret_cast<const uint8_t*>(shm.memory()), - bitstream_buffer.size(), stream_size, alignment); + return sample.Detach(); } // Helper function to create a COM object instance from a DLL. The alternative @@ -289,55 +370,188 @@ template<class T> base::win::ScopedComPtr<T> QueryDeviceObjectFromANGLE(int object_type) { base::win::ScopedComPtr<T> device_object; - EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); + EGLDisplay egl_display = nullptr; intptr_t egl_device = 0; intptr_t device = 0; + { + TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. GetHardwareDisplay"); + egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); + } + RETURN_ON_FAILURE( gfx::GLSurfaceEGL::HasEGLExtension("EGL_EXT_device_query"), "EGL_EXT_device_query missing", device_object); - PFNEGLQUERYDISPLAYATTRIBEXTPROC QueryDisplayAttribEXT = - reinterpret_cast<PFNEGLQUERYDISPLAYATTRIBEXTPROC>(eglGetProcAddress( - "eglQueryDisplayAttribEXT")); + PFNEGLQUERYDISPLAYATTRIBEXTPROC QueryDisplayAttribEXT = nullptr; - RETURN_ON_FAILURE( - QueryDisplayAttribEXT, - "Failed to get the eglQueryDisplayAttribEXT function from ANGLE", - device_object); + { + TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. eglGetProcAddress"); - PFNEGLQUERYDEVICEATTRIBEXTPROC QueryDeviceAttribEXT = - reinterpret_cast<PFNEGLQUERYDEVICEATTRIBEXTPROC>(eglGetProcAddress( - "eglQueryDeviceAttribEXT")); + QueryDisplayAttribEXT = + reinterpret_cast<PFNEGLQUERYDISPLAYATTRIBEXTPROC>(eglGetProcAddress( + "eglQueryDisplayAttribEXT")); - RETURN_ON_FAILURE( - QueryDeviceAttribEXT, - "Failed to get the eglQueryDeviceAttribEXT function from ANGLE", - device_object); + RETURN_ON_FAILURE( + QueryDisplayAttribEXT, + "Failed to get the eglQueryDisplayAttribEXT function from ANGLE", + device_object); + } - RETURN_ON_FAILURE( - QueryDisplayAttribEXT(egl_display, EGL_DEVICE_EXT, &egl_device), - "The eglQueryDisplayAttribEXT function failed to get the EGL device", - device_object); + PFNEGLQUERYDEVICEATTRIBEXTPROC QueryDeviceAttribEXT = nullptr; + + { + TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. eglGetProcAddress"); + + QueryDeviceAttribEXT = + reinterpret_cast<PFNEGLQUERYDEVICEATTRIBEXTPROC>(eglGetProcAddress( + "eglQueryDeviceAttribEXT")); + + RETURN_ON_FAILURE( + QueryDeviceAttribEXT, + "Failed to get the eglQueryDeviceAttribEXT function from ANGLE", + device_object); + } + + { + TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. QueryDisplayAttribEXT"); + + RETURN_ON_FAILURE( + QueryDisplayAttribEXT(egl_display, EGL_DEVICE_EXT, &egl_device), + "The eglQueryDisplayAttribEXT function failed to get the EGL device", + device_object); + } RETURN_ON_FAILURE( egl_device, "Failed to get the EGL device", device_object); - RETURN_ON_FAILURE( - QueryDeviceAttribEXT( - reinterpret_cast<EGLDeviceEXT>(egl_device), object_type, &device), - "The eglQueryDeviceAttribEXT function failed to get the device", - device_object); + { + TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE. QueryDisplayAttribEXT"); - RETURN_ON_FAILURE(device, "Failed to get the ANGLE device", device_object); + RETURN_ON_FAILURE( + QueryDeviceAttribEXT( + reinterpret_cast<EGLDeviceEXT>(egl_device), object_type, &device), + "The eglQueryDeviceAttribEXT function failed to get the device", + device_object); + + RETURN_ON_FAILURE(device, "Failed to get the ANGLE device", device_object); + } device_object = reinterpret_cast<T*>(device); return device_object; } +H264ConfigChangeDetector::H264ConfigChangeDetector() + : last_sps_id_(0), + last_pps_id_(0), + config_changed_(false), + pending_config_changed_(false) { +} + +H264ConfigChangeDetector::~H264ConfigChangeDetector() { +} + +bool H264ConfigChangeDetector::DetectConfig(const uint8_t* stream, + unsigned int size) { + std::vector<uint8_t> sps; + std::vector<uint8_t> pps; + media::H264NALU nalu; + bool idr_seen = false; + + if (!parser_.get()) + parser_.reset(new media::H264Parser); + + parser_->SetStream(stream, size); + config_changed_ = false; + + while (true) { + media::H264Parser::Result result = parser_->AdvanceToNextNALU(&nalu); + + if (result == media::H264Parser::kEOStream) + break; + + if (result == media::H264Parser::kUnsupportedStream) { + DLOG(ERROR) << "Unsupported H.264 stream"; + return false; + } + + if (result != media::H264Parser::kOk) { + DLOG(ERROR) << "Failed to parse H.264 stream"; + return false; + } + + switch (nalu.nal_unit_type) { + case media::H264NALU::kSPS: + result = parser_->ParseSPS(&last_sps_id_); + if (result == media::H264Parser::kUnsupportedStream) { + DLOG(ERROR) << "Unsupported SPS"; + return false; + } + + if (result != media::H264Parser::kOk) { + DLOG(ERROR) << "Could not parse SPS"; + return false; + } + + sps.assign(nalu.data, nalu.data + nalu.size); + break; + + case media::H264NALU::kPPS: + result = parser_->ParsePPS(&last_pps_id_); + if (result == media::H264Parser::kUnsupportedStream) { + DLOG(ERROR) << "Unsupported PPS"; + return false; + } + if (result != media::H264Parser::kOk) { + DLOG(ERROR) << "Could not parse PPS"; + return false; + } + pps.assign(nalu.data, nalu.data + nalu.size); + break; + + case media::H264NALU::kIDRSlice: + idr_seen = true; + // If we previously detected a configuration change, and see an IDR + // slice next time around, we need to flag a configuration change. + if (pending_config_changed_) { + config_changed_ = true; + pending_config_changed_ = false; + } + break; + + default: + break; + } + } + + if (!sps.empty() && sps != last_sps_) { + if (!last_sps_.empty()) { + // Flag configuration changes after we see an IDR slice. + if (idr_seen) { + config_changed_ = true; + } else { + pending_config_changed_ = true; + } + } + last_sps_.swap(sps); + } + + if (!pps.empty() && pps != last_pps_) { + if (!last_pps_.empty()) { + // Flag configuration changes after we see an IDR slice. + if (idr_seen) { + config_changed_ = true; + } else { + pending_config_changed_ = true; + } + } + last_pps_.swap(pps); + } + return true; +} // Maintains information about a DXVA picture buffer, i.e. whether it is // available for rendering, the texture information, etc. @@ -349,7 +563,11 @@ struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer { EGLConfig egl_config); ~DXVAPictureBuffer(); - void ReusePictureBuffer(); + bool InitializeTexture(const DXVAVideoDecodeAccelerator& decoder, + bool use_rgb); + + bool ReusePictureBuffer(); + void ResetReuseFence(); // Copies the output sample data to the picture buffer provided by the // client. // The dest_surface parameter contains the decoded bits. @@ -375,20 +593,37 @@ struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer { return picture_buffer_.size(); } + bool waiting_to_reuse() const { return waiting_to_reuse_; } + + gfx::GLFence* reuse_fence() { return reuse_fence_.get(); } + // Called when the source surface |src_surface| is copied to the destination // |dest_surface| - void CopySurfaceComplete(IDirect3DSurface9* src_surface, + bool CopySurfaceComplete(IDirect3DSurface9* src_surface, IDirect3DSurface9* dest_surface); private: explicit DXVAPictureBuffer(const media::PictureBuffer& buffer); bool available_; + + // This is true if the decoder is currently waiting on the fence before + // reusing the buffer. + bool waiting_to_reuse_; media::PictureBuffer picture_buffer_; EGLSurface decoding_surface_; + scoped_ptr<gfx::GLFence> reuse_fence_; + + HANDLE texture_share_handle_; base::win::ScopedComPtr<IDirect3DTexture9> decoding_texture_; base::win::ScopedComPtr<ID3D11Texture2D> dx11_decoding_texture_; + base::win::ScopedComPtr<IDXGIKeyedMutex> egl_keyed_mutex_; + base::win::ScopedComPtr<IDXGIKeyedMutex> dx11_keyed_mutex_; + + // This is the last value that was used to release the keyed mutex. + uint64_t keyed_mutex_value_; + // The following |IDirect3DSurface9| interface pointers are used to hold // references on the surfaces during the course of a StretchRect operation // to copy the source surface to the target. The references are released @@ -422,6 +657,9 @@ DXVAVideoDecodeAccelerator::DXVAPictureBuffer::Create( eglGetConfigAttrib(egl_display, egl_config, EGL_BIND_TO_TEXTURE_RGB, &use_rgb); + if (!picture_buffer->InitializeTexture(decoder, !!use_rgb)) + return linked_ptr<DXVAPictureBuffer>(nullptr); + EGLint attrib_list[] = { EGL_WIDTH, buffer.size().width(), EGL_HEIGHT, buffer.size().height(), @@ -430,59 +668,84 @@ DXVAVideoDecodeAccelerator::DXVAPictureBuffer::Create( EGL_NONE }; - picture_buffer->decoding_surface_ = eglCreatePbufferSurface( - egl_display, - egl_config, - attrib_list); + picture_buffer->decoding_surface_ = eglCreatePbufferFromClientBuffer( + egl_display, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, + picture_buffer->texture_share_handle_, egl_config, attrib_list); RETURN_ON_FAILURE(picture_buffer->decoding_surface_, "Failed to create surface", linked_ptr<DXVAPictureBuffer>(NULL)); + if (decoder.d3d11_device_ && decoder.use_keyed_mutex_) { + void* keyed_mutex = nullptr; + EGLBoolean ret = eglQuerySurfacePointerANGLE( + egl_display, picture_buffer->decoding_surface_, + EGL_DXGI_KEYED_MUTEX_ANGLE, &keyed_mutex); + RETURN_ON_FAILURE(keyed_mutex && ret == EGL_TRUE, + "Failed to query ANGLE keyed mutex", + linked_ptr<DXVAPictureBuffer>(nullptr)); + picture_buffer->egl_keyed_mutex_ = base::win::ScopedComPtr<IDXGIKeyedMutex>( + static_cast<IDXGIKeyedMutex*>(keyed_mutex)); + } + picture_buffer->use_rgb_ = !!use_rgb; + return picture_buffer; +} - HANDLE share_handle = NULL; - EGLBoolean ret = eglQuerySurfacePointerANGLE( - egl_display, - picture_buffer->decoding_surface_, - EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, - &share_handle); +bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::InitializeTexture( + const DXVAVideoDecodeAccelerator& decoder, + bool use_rgb) { + DCHECK(!texture_share_handle_); + if (decoder.d3d11_device_) { + D3D11_TEXTURE2D_DESC desc; + desc.Width = picture_buffer_.size().width(); + desc.Height = picture_buffer_.size().height(); + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = decoder.use_keyed_mutex_ + ? D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX + : D3D11_RESOURCE_MISC_SHARED; + + HRESULT hr = decoder.d3d11_device_->CreateTexture2D( + &desc, nullptr, dx11_decoding_texture_.Receive()); + RETURN_ON_HR_FAILURE(hr, "Failed to create texture", false); + if (decoder.use_keyed_mutex_) { + hr = dx11_keyed_mutex_.QueryFrom(dx11_decoding_texture_.get()); + RETURN_ON_HR_FAILURE(hr, "Failed to get keyed mutex", false); + } - RETURN_ON_FAILURE(share_handle && ret == EGL_TRUE, - "Failed to query ANGLE surface pointer", - linked_ptr<DXVAPictureBuffer>(NULL)); + base::win::ScopedComPtr<IDXGIResource> resource; + hr = resource.QueryFrom(dx11_decoding_texture_.get()); + DCHECK(SUCCEEDED(hr)); + hr = resource->GetSharedHandle(&texture_share_handle_); + RETURN_ON_FAILURE(SUCCEEDED(hr) && texture_share_handle_, + "Failed to query shared handle", false); - HRESULT hr = E_FAIL; - if (decoder.d3d11_device_) { - base::win::ScopedComPtr<ID3D11Resource> resource; - hr = decoder.d3d11_device_->OpenSharedResource( - share_handle, - __uuidof(ID3D11Resource), - reinterpret_cast<void**>(resource.Receive())); - RETURN_ON_HR_FAILURE(hr, "Failed to open shared resource", - linked_ptr<DXVAPictureBuffer>(NULL)); - hr = picture_buffer->dx11_decoding_texture_.QueryFrom(resource.get()); } else { + HRESULT hr = E_FAIL; hr = decoder.d3d9_device_ex_->CreateTexture( - buffer.size().width(), - buffer.size().height(), - 1, - D3DUSAGE_RENDERTARGET, - use_rgb ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8, - D3DPOOL_DEFAULT, - picture_buffer->decoding_texture_.Receive(), - &share_handle); - } - RETURN_ON_HR_FAILURE(hr, "Failed to create texture", - linked_ptr<DXVAPictureBuffer>(NULL)); - picture_buffer->use_rgb_ = !!use_rgb; - return picture_buffer; + picture_buffer_.size().width(), picture_buffer_.size().height(), 1, + D3DUSAGE_RENDERTARGET, use_rgb ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, decoding_texture_.Receive(), &texture_share_handle_); + RETURN_ON_HR_FAILURE(hr, "Failed to create texture", false); + RETURN_ON_FAILURE(texture_share_handle_, "Failed to query shared handle", + false); + } + return true; } DXVAVideoDecodeAccelerator::DXVAPictureBuffer::DXVAPictureBuffer( const media::PictureBuffer& buffer) : available_(true), + waiting_to_reuse_(false), picture_buffer_(buffer), decoding_surface_(NULL), - use_rgb_(true) { -} + texture_share_handle_(nullptr), + keyed_mutex_value_(0), + use_rgb_(true) {} DXVAVideoDecodeAccelerator::DXVAPictureBuffer::~DXVAPictureBuffer() { if (decoding_surface_) { @@ -500,7 +763,7 @@ DXVAVideoDecodeAccelerator::DXVAPictureBuffer::~DXVAPictureBuffer() { } } -void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() { +bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() { DCHECK(decoding_surface_); EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); eglReleaseTexImage( @@ -510,7 +773,21 @@ void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() { decoder_surface_.Release(); target_surface_.Release(); decoder_dx11_texture_.Release(); + waiting_to_reuse_ = false; set_available(true); + if (egl_keyed_mutex_) { + HRESULT hr = egl_keyed_mutex_->ReleaseSync(++keyed_mutex_value_); + RETURN_ON_FAILURE(hr == S_OK, "Could not release sync mutex", false); + } + return true; +} + +void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ResetReuseFence() { + if (!reuse_fence_ || !reuse_fence_->ResetSupported()) + reuse_fence_.reset(gfx::GLFence::Create()); + else + reuse_fence_->ResetState(); + waiting_to_reuse_ = true; } bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer:: @@ -525,8 +802,9 @@ bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer:: // when we receive a notification that the copy was completed or when the // DXVAPictureBuffer instance is destroyed. decoder_dx11_texture_ = dx11_texture; - decoder->CopyTexture(dx11_texture, dx11_decoding_texture_.get(), NULL, - id(), input_buffer_id); + decoder->CopyTexture(dx11_texture, dx11_decoding_texture_.get(), + dx11_keyed_mutex_, keyed_mutex_value_, NULL, id(), + input_buffer_id); return true; } D3DSURFACE_DESC surface_desc; @@ -566,7 +844,7 @@ bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer:: return true; } -void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::CopySurfaceComplete( +bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::CopySurfaceComplete( IDirect3DSurface9* src_surface, IDirect3DSurface9* dest_surface) { DCHECK(!available()); @@ -574,7 +852,7 @@ void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::CopySurfaceComplete( GLint current_texture = 0; glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); - glBindTexture(GL_TEXTURE_2D, picture_buffer_.texture_id()); + glBindTexture(GL_TEXTURE_2D, picture_buffer_.texture_ids()[0]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -587,6 +865,12 @@ void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::CopySurfaceComplete( DCHECK(decoder_dx11_texture_.get()); decoder_dx11_texture_.Release(); } + if (egl_keyed_mutex_) { + keyed_mutex_value_++; + HRESULT result = + egl_keyed_mutex_->AcquireSync(keyed_mutex_value_, kAcquireSyncWaitMs); + RETURN_ON_FAILURE(result == S_OK, "Could not acquire sync mutex", false); + } EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); eglBindTexImage( @@ -596,6 +880,7 @@ void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::CopySurfaceComplete( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, current_texture); + return true; } DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo( @@ -608,8 +893,9 @@ DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo( DXVAVideoDecodeAccelerator::PendingSampleInfo::~PendingSampleInfo() {} DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( - const base::Callback<bool(void)>& make_context_current, - gfx::GLContext* gl_context) + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + bool enable_accelerated_vpx_decode) : client_(NULL), dev_manager_reset_token_(0), dx11_dev_manager_reset_token_(0), @@ -618,14 +904,16 @@ DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( pictures_requested_(false), inputs_before_decode_(0), sent_drain_message_(false), - make_context_current_(make_context_current), + get_gl_context_cb_(get_gl_context_cb), + make_context_current_cb_(make_context_current_cb), codec_(media::kUnknownVideoCodec), decoder_thread_("DXVAVideoDecoderThread"), pending_flush_(false), use_dx11_(false), + use_keyed_mutex_(false), dx11_video_format_converter_media_type_needs_init_(true), - gl_context_(gl_context), using_angle_device_(false), + enable_accelerated_vpx_decode_(enable_accelerated_vpx_decode), weak_this_factory_(this) { weak_ptr_ = weak_this_factory_.GetWeakPtr(); memset(&input_stream_info_, 0, sizeof(input_stream_info_)); @@ -638,6 +926,11 @@ DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { bool DXVAVideoDecodeAccelerator::Initialize(const Config& config, Client* client) { + if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { + NOTREACHED() << "GL callbacks are required for this VDA"; + return false; + } + if (config.is_encrypted) { NOTREACHED() << "Encrypted streams are not supported for this VDA"; return false; @@ -695,6 +988,10 @@ bool DXVAVideoDecodeAccelerator::Initialize(const Config& config, PLATFORM_FAILURE, false); + RETURN_AND_NOTIFY_ON_FAILURE(gfx::GLFence::IsSupported(), + "GL fences are unsupported", PLATFORM_FAILURE, + false); + State state = GetState(); RETURN_AND_NOTIFY_ON_FAILURE((state == kUninitialized), "Initialize: invalid state: " << state, ILLEGAL_STATE, false); @@ -717,6 +1014,10 @@ bool DXVAVideoDecodeAccelerator::Initialize(const Config& config, "Send MFT_MESSAGE_NOTIFY_START_OF_STREAM notification failed", PLATFORM_FAILURE, false); + config_ = config; + + config_change_detector_.reset(new H264ConfigChangeDetector); + SetState(kNormal); StartDecoderThread(); @@ -883,15 +1184,28 @@ void DXVAVideoDecodeAccelerator::Decode( const media::BitstreamBuffer& bitstream_buffer) { DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); + // SharedMemory will take over the ownership of handle. + base::SharedMemory shm(bitstream_buffer.handle(), true); + State state = GetState(); RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped || state == kFlushing), "Invalid state: " << state, ILLEGAL_STATE,); + if (bitstream_buffer.id() < 0) { + RETURN_AND_NOTIFY_ON_FAILURE( + false, "Invalid bitstream_buffer, id: " << bitstream_buffer.id(), + INVALID_ARGUMENT, ); + } base::win::ScopedComPtr<IMFSample> sample; - sample.Attach(CreateSampleFromInputBuffer(bitstream_buffer, - input_stream_info_.cbSize, - input_stream_info_.cbAlignment)); + RETURN_AND_NOTIFY_ON_FAILURE(shm.Map(bitstream_buffer.size()), + "Failed in base::SharedMemory::Map", + PLATFORM_FAILURE, ); + + sample.Attach(CreateInputSample( + reinterpret_cast<const uint8_t*>(shm.memory()), bitstream_buffer.size(), + std::min<uint32_t>(bitstream_buffer.size(), input_stream_info_.cbSize), + input_stream_info_.cbAlignment)); RETURN_AND_NOTIFY_ON_FAILURE(sample.get(), "Failed to create input sample", PLATFORM_FAILURE, ); @@ -919,6 +1233,7 @@ void DXVAVideoDecodeAccelerator::AssignPictureBuffers( // and mark these buffers as available for use. for (size_t buffer_index = 0; buffer_index < buffers.size(); ++buffer_index) { + DCHECK_LE(1u, buffers[buffer_index].texture_ids().size()); linked_ptr<DXVAPictureBuffer> picture_buffer = DXVAPictureBuffer::Create(*this, buffers[buffer_index], egl_config_); RETURN_AND_NOTIFY_ON_FAILURE(picture_buffer.get(), @@ -956,17 +1271,70 @@ void DXVAVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_buffer_id) { // us that we can now recycle this picture buffer, so if we were waiting to // dispose of it we now can. if (it == output_picture_buffers_.end()) { - it = stale_output_picture_buffers_.find(picture_buffer_id); - RETURN_AND_NOTIFY_ON_FAILURE(it != stale_output_picture_buffers_.end(), - "Invalid picture id: " << picture_buffer_id, INVALID_ARGUMENT,); - main_thread_task_runner_->PostTask( - FROM_HERE, - base::Bind(&DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer, - weak_this_factory_.GetWeakPtr(), picture_buffer_id)); + if (!stale_output_picture_buffers_.empty()) { + it = stale_output_picture_buffers_.find(picture_buffer_id); + RETURN_AND_NOTIFY_ON_FAILURE(it != stale_output_picture_buffers_.end(), + "Invalid picture id: " << picture_buffer_id, INVALID_ARGUMENT,); + main_thread_task_runner_->PostTask( + FROM_HERE, + base::Bind(&DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer, + weak_this_factory_.GetWeakPtr(), picture_buffer_id)); + } + return; + } + + if (it->second->available() || it->second->waiting_to_reuse()) + return; + + if (use_keyed_mutex_ || using_angle_device_) { + RETURN_AND_NOTIFY_ON_FAILURE(it->second->ReusePictureBuffer(), + "Failed to reuse picture buffer", + PLATFORM_FAILURE, ); + + ProcessPendingSamples(); + if (pending_flush_) { + decoder_thread_task_runner_->PostTask( + FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, + base::Unretained(this))); + } + } else { + RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(), + "Failed to make context current", + PLATFORM_FAILURE, ); + it->second->ResetReuseFence(); + + WaitForOutputBuffer(picture_buffer_id, 0); + } +} + +void DXVAVideoDecodeAccelerator::WaitForOutputBuffer(int32_t picture_buffer_id, + int count) { + DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); + OutputBuffers::iterator it = output_picture_buffers_.find(picture_buffer_id); + if (it == output_picture_buffers_.end()) + return; + + DXVAPictureBuffer* picture_buffer = it->second.get(); + + DCHECK(!picture_buffer->available()); + DCHECK(picture_buffer->waiting_to_reuse()); + + gfx::GLFence* fence = picture_buffer->reuse_fence(); + RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(), + "Failed to make context current", + PLATFORM_FAILURE, ); + if (count <= kMaxIterationsForANGLEReuseFlush && !fence->HasCompleted()) { + main_thread_task_runner_->PostDelayedTask( + FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::WaitForOutputBuffer, + weak_this_factory_.GetWeakPtr(), + picture_buffer_id, count + 1), + base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); return; } + RETURN_AND_NOTIFY_ON_FAILURE(picture_buffer->ReusePictureBuffer(), + "Failed to reuse picture buffer", + PLATFORM_FAILURE, ); - it->second->ReusePictureBuffer(); ProcessPendingSamples(); if (pending_flush_) { decoder_thread_task_runner_->PostTask( @@ -1046,7 +1414,9 @@ void DXVAVideoDecodeAccelerator::Destroy() { delete this; } -bool DXVAVideoDecodeAccelerator::CanDecodeOnIOThread() { +bool DXVAVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { return false; } @@ -1057,17 +1427,19 @@ GLenum DXVAVideoDecodeAccelerator::GetSurfaceInternalFormat() const { // static media::VideoDecodeAccelerator::SupportedProfiles DXVAVideoDecodeAccelerator::GetSupportedProfiles() { + TRACE_EVENT0("gpu,startup", + "DXVAVideoDecodeAccelerator::GetSupportedProfiles"); + // TODO(henryhsu): Need to ensure the profiles are actually supported. SupportedProfiles profiles; for (const auto& supported_profile : kSupportedProfiles) { + std::pair<int, int> min_resolution = GetMinResolution(supported_profile); + std::pair<int, int> max_resolution = GetMaxResolution(supported_profile); + SupportedProfile profile; profile.profile = supported_profile; - // Windows Media Foundation H.264 decoding does not support decoding videos - // with any dimension smaller than 48 pixels: - // http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815 - profile.min_resolution.SetSize(48, 48); - // Use 1088 to account for 16x16 macroblocks. - profile.max_resolution.SetSize(1920, 1088); + profile.min_resolution.SetSize(min_resolution.first, min_resolution.second); + profile.max_resolution.SetSize(max_resolution.first, max_resolution.second); profiles.push_back(profile); } return profiles; @@ -1077,17 +1449,224 @@ DXVAVideoDecodeAccelerator::GetSupportedProfiles() { void DXVAVideoDecodeAccelerator::PreSandboxInitialization() { ::LoadLibrary(L"MFPlat.dll"); ::LoadLibrary(L"msmpeg2vdec.dll"); + ::LoadLibrary(L"mf.dll"); + ::LoadLibrary(L"dxva2.dll"); if (base::win::GetVersion() > base::win::VERSION_WIN7) { LoadLibrary(L"msvproc.dll"); } else { - LoadLibrary(L"dxva2.dll"); #if defined(ENABLE_DX11_FOR_WIN7) LoadLibrary(L"mshtmlmedia.dll"); #endif } } +// static +std::pair<int, int> DXVAVideoDecodeAccelerator::GetMinResolution( + media::VideoCodecProfile profile) { + TRACE_EVENT0("gpu,startup", + "DXVAVideoDecodeAccelerator::GetMinResolution"); + std::pair<int, int> min_resolution; + if (profile >= media::H264PROFILE_BASELINE && + profile <= media::H264PROFILE_HIGH) { + // Windows Media Foundation H.264 decoding does not support decoding videos + // with any dimension smaller than 48 pixels: + // http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815 + min_resolution = std::make_pair(48, 48); + } else { + // TODO(ananta) + // Detect this properly for VP8/VP9 profiles. + min_resolution = std::make_pair(16, 16); + } + return min_resolution; +} + +// static +std::pair<int, int> DXVAVideoDecodeAccelerator::GetMaxResolution( + const media::VideoCodecProfile profile) { + TRACE_EVENT0("gpu,startup", + "DXVAVideoDecodeAccelerator::GetMaxResolution"); + std::pair<int, int> max_resolution; + if (profile >= media::H264PROFILE_BASELINE && + profile <= media::H264PROFILE_HIGH) { + max_resolution = GetMaxH264Resolution(); + } else { + // TODO(ananta) + // Detect this properly for VP8/VP9 profiles. + max_resolution = std::make_pair(4096, 2160); + } + return max_resolution; +} + +std::pair<int, int> DXVAVideoDecodeAccelerator::GetMaxH264Resolution() { + TRACE_EVENT0("gpu,startup", + "DXVAVideoDecodeAccelerator::GetMaxH264Resolution"); + // The H.264 resolution detection operation is expensive. This static flag + // allows us to run the detection once. + static bool resolution_detected = false; + // Use 1088 to account for 16x16 macroblocks. + static std::pair<int, int> max_resolution = std::make_pair(1920, 1088); + if (resolution_detected) + return max_resolution; + + resolution_detected = true; + + // On Windows 7 the maximum resolution supported by media foundation is + // 1920 x 1088. + if (base::win::GetVersion() == base::win::VERSION_WIN7) + return max_resolution; + + // To detect if a driver supports the desired resolutions, we try and create + // a DXVA decoder instance for that resolution and profile. If that succeeds + // we assume that the driver supports H/W H.264 decoding for that resolution. + HRESULT hr = E_FAIL; + base::win::ScopedComPtr<ID3D11Device> device; + + { + TRACE_EVENT0("gpu,startup", + "GetMaxH264Resolution. QueryDeviceObjectFromANGLE"); + + device = QueryDeviceObjectFromANGLE<ID3D11Device>(EGL_D3D11_DEVICE_ANGLE); + if (!device.get()) + return max_resolution; + } + + base::win::ScopedComPtr<ID3D11VideoDevice> video_device; + hr = device.QueryInterface(IID_ID3D11VideoDevice, + video_device.ReceiveVoid()); + if (FAILED(hr)) + return max_resolution; + + GUID decoder_guid = {}; + + { + TRACE_EVENT0("gpu,startup", + "GetMaxH264Resolution. H.264 guid search begin"); + // Enumerate supported video profiles and look for the H264 profile. + bool found = false; + UINT profile_count = video_device->GetVideoDecoderProfileCount(); + for (UINT profile_idx = 0; profile_idx < profile_count; profile_idx++) { + GUID profile_id = {}; + hr = video_device->GetVideoDecoderProfile(profile_idx, &profile_id); + if (SUCCEEDED(hr) && + (profile_id == DXVA2_ModeH264_E || + profile_id == DXVA2_Intel_ModeH264_E)) { + decoder_guid = profile_id; + found = true; + break; + } + } + if (!found) + return max_resolution; + } + + // Legacy AMD drivers with UVD3 or earlier and some Intel GPU's crash while + // creating surfaces larger than 1920 x 1088. + if (IsLegacyGPU(device.get())) + return max_resolution; + + // We look for the following resolutions in the driver. + // TODO(ananta) + // Look into whether this list needs to be expanded. + static std::pair<int, int> resolution_array[] = { + // Use 1088 to account for 16x16 macroblocks. + std::make_pair(1920, 1088), + std::make_pair(2560, 1440), + std::make_pair(3840, 2160), + std::make_pair(4096, 2160), + std::make_pair(4096, 2304), + }; + + { + TRACE_EVENT0("gpu,startup", + "GetMaxH264Resolution. Resolution search begin"); + + for (size_t res_idx = 0; res_idx < arraysize(resolution_array); + res_idx++) { + D3D11_VIDEO_DECODER_DESC desc = {}; + desc.Guid = decoder_guid; + desc.SampleWidth = resolution_array[res_idx].first; + desc.SampleHeight = resolution_array[res_idx].second; + desc.OutputFormat = DXGI_FORMAT_NV12; + UINT config_count = 0; + hr = video_device->GetVideoDecoderConfigCount(&desc, &config_count); + if (FAILED(hr) || config_count == 0) + return max_resolution; + + D3D11_VIDEO_DECODER_CONFIG config = {}; + hr = video_device->GetVideoDecoderConfig(&desc, 0, &config); + if (FAILED(hr)) + return max_resolution; + + base::win::ScopedComPtr<ID3D11VideoDecoder> video_decoder; + hr = video_device->CreateVideoDecoder(&desc, &config, + video_decoder.Receive()); + if (!video_decoder.get()) + return max_resolution; + + max_resolution = resolution_array[res_idx]; + } + } + return max_resolution; +} + +// static +bool DXVAVideoDecodeAccelerator::IsLegacyGPU(ID3D11Device* device) { + static const int kAMDGPUId1 = 0x1002; + static const int kAMDGPUId2 = 0x1022; + static const int kIntelGPU = 0x8086; + + static bool legacy_gpu = true; + // This flag ensures that we determine the GPU type once. + static bool legacy_gpu_determined = false; + + if (legacy_gpu_determined) + return legacy_gpu; + + legacy_gpu_determined = true; + + base::win::ScopedComPtr<IDXGIDevice> dxgi_device; + HRESULT hr = dxgi_device.QueryFrom(device); + if (FAILED(hr)) + return legacy_gpu; + + base::win::ScopedComPtr<IDXGIAdapter> adapter; + hr = dxgi_device->GetAdapter(adapter.Receive()); + if (FAILED(hr)) + return legacy_gpu; + + DXGI_ADAPTER_DESC adapter_desc = {}; + hr = adapter->GetDesc(&adapter_desc); + if (FAILED(hr)) + return legacy_gpu; + + // We check if the device is an Intel or an AMD device and whether it is in + // the global list defined by the g_AMDUVD3GPUList and g_IntelLegacyGPUList + // arrays above. If yes then the device is treated as a legacy device. + if ((adapter_desc.VendorId == kAMDGPUId1) || + adapter_desc.VendorId == kAMDGPUId2) { + { + TRACE_EVENT0("gpu,startup", + "DXVAVideoDecodeAccelerator::IsLegacyGPU. AMD check"); + for (size_t i = 0; i < arraysize(g_AMDUVD3GPUList); i++) { + if (adapter_desc.DeviceId == g_AMDUVD3GPUList[i]) + return legacy_gpu; + } + } + } else if (adapter_desc.VendorId == kIntelGPU) { + { + TRACE_EVENT0("gpu,startup", + "DXVAVideoDecodeAccelerator::IsLegacyGPU. Intel check"); + for (size_t i = 0; i < arraysize(g_IntelLegacyGPUList); i++) { + if (adapter_desc.DeviceId == g_IntelLegacyGPUList[i]) + return legacy_gpu; + } + } + } + legacy_gpu = false; + return legacy_gpu; +} + bool DXVAVideoDecodeAccelerator::InitDecoder(media::VideoCodecProfile profile) { HMODULE decoder_dll = NULL; @@ -1104,24 +1683,26 @@ bool DXVAVideoDecodeAccelerator::InitDecoder(media::VideoCodecProfile profile) { "msmpeg2vdec.dll required for decoding is not loaded", false); - // Check version of DLL, version 6.7.7140 is blacklisted due to high crash + // Check version of DLL, version 6.1.7140 is blacklisted due to high crash // rates in browsers loading that DLL. If that is the version installed we // fall back to software decoding. See crbug/403440. - FileVersionInfo* version_info = - FileVersionInfo::CreateFileVersionInfoForModule(decoder_dll); + scoped_ptr<FileVersionInfo> version_info( + FileVersionInfo::CreateFileVersionInfoForModule(decoder_dll)); RETURN_ON_FAILURE(version_info, "unable to get version of msmpeg2vdec.dll", false); base::string16 file_version = version_info->file_version(); RETURN_ON_FAILURE(file_version.find(L"6.1.7140") == base::string16::npos, - "blacklisted version of msmpeg2vdec.dll 6.7.7140", + "blacklisted version of msmpeg2vdec.dll 6.1.7140", false); codec_ = media::kCodecH264; clsid = __uuidof(CMSH264DecoderMFT); - } else if ((profile == media::VP8PROFILE_ANY || - profile == media::VP9PROFILE_ANY) && - base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableAcceleratedVpxDecode)) { + } else if (enable_accelerated_vpx_decode_ && + (profile == media::VP8PROFILE_ANY || + profile == media::VP9PROFILE_PROFILE0 || + profile == media::VP9PROFILE_PROFILE1 || + profile == media::VP9PROFILE_PROFILE2 || + profile == media::VP9PROFILE_PROFILE3)) { int program_files_key = base::DIR_PROGRAM_FILES; if (base::win::OSInfo::GetInstance()->wow64_status() == base::win::OSInfo::WOW64_ENABLED) { @@ -1230,19 +1811,24 @@ bool DXVAVideoDecodeAccelerator::CheckDecoderDxvaSupport() { DVLOG(1) << "Failed to set Low latency mode on decoder. Error: " << hr; } + auto gl_context = get_gl_context_cb_.Run(); + RETURN_ON_FAILURE(gl_context, "Couldn't get GL context", false); + // The decoder should use DX11 iff // 1. The underlying H/W decoder supports it. // 2. We have a pointer to the MFCreateDXGIDeviceManager function needed for // this. This should always be true for Windows 8+. // 3. ANGLE is using DX11. - DCHECK(gl_context_); if (create_dxgi_device_manager_ && - (gl_context_->GetGLRenderer().find("Direct3D11") != - std::string::npos)) { + (gl_context->GetGLRenderer().find("Direct3D11") != std::string::npos)) { UINT32 dx11_aware = 0; attributes->GetUINT32(MF_SA_D3D11_AWARE, &dx11_aware); use_dx11_ = !!dx11_aware; } + + use_keyed_mutex_ = + use_dx11_ && gfx::GLSurfaceEGL::HasEGLExtension("EGL_ANGLE_keyed_mutex"); + return true; } @@ -1436,8 +2022,9 @@ void DXVAVideoDecodeAccelerator::ProcessPendingSamples() { if (!output_picture_buffers_.size()) return; - RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), - "Failed to make context current", PLATFORM_FAILURE,); + RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(), + "Failed to make context current", + PLATFORM_FAILURE, ); OutputBuffers::iterator index; @@ -1449,7 +2036,6 @@ void DXVAVideoDecodeAccelerator::ProcessPendingSamples() { PendingSampleInfo* pending_sample = NULL; { base::AutoLock lock(decoder_lock_); - PendingSampleInfo& sample_info = pending_output_samples_.front(); if (sample_info.picture_buffer_id != -1) continue; @@ -1533,13 +2119,22 @@ void DXVAVideoDecodeAccelerator::Invalidate() { if (GetState() == kUninitialized) return; + // Best effort to make the GL context current. + make_context_current_cb_.Run(); + decoder_thread_.Stop(); weak_this_factory_.InvalidateWeakPtrs(); output_picture_buffers_.clear(); stale_output_picture_buffers_.clear(); pending_output_samples_.clear(); - pending_input_buffers_.clear(); + // We want to continue processing pending input after detecting a config + // change. + if (GetState() != kConfigChange) + pending_input_buffers_.clear(); decoder_.Release(); + pictures_requested_ = false; + + config_change_detector_.reset(); if (use_dx11_) { if (video_format_converter_mft_.get()) { @@ -1552,6 +2147,7 @@ void DXVAVideoDecodeAccelerator::Invalidate() { d3d11_device_manager_.Release(); d3d11_query_.Release(); dx11_video_format_converter_media_type_needs_init_ = true; + multi_threaded_.Release(); } else { d3d9_.Release(); d3d9_device_ex_.Release(); @@ -1591,10 +2187,8 @@ void DXVAVideoDecodeAccelerator::RequestPictureBuffers(int width, int height) { DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); // This task could execute after the decoder has been torn down. if (GetState() != kUninitialized && client_) { - client_->ProvidePictureBuffers( - kNumPictureBuffers, - gfx::Size(width, height), - GL_TEXTURE_2D); + client_->ProvidePictureBuffers(kNumPictureBuffers, 1, + gfx::Size(width, height), GL_TEXTURE_2D); } } @@ -1706,13 +2300,31 @@ void DXVAVideoDecodeAccelerator::DecodeInternal( return; } + // Check if the resolution, bit rate, etc changed in the stream. If yes we + // reinitialize the decoder to ensure that the stream decodes correctly. + bool config_changed = false; + + HRESULT hr = CheckConfigChanged(sample.get(), &config_changed); + RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to check video stream config", + PLATFORM_FAILURE,); + + if (config_changed) { + pending_input_buffers_.push_back(sample); + main_thread_task_runner_->PostTask( + FROM_HERE, + base::Bind(&DXVAVideoDecodeAccelerator::ConfigChanged, + weak_this_factory_.GetWeakPtr(), + config_)); + return; + } + if (!inputs_before_decode_) { TRACE_EVENT_ASYNC_BEGIN0("gpu", "DXVAVideoDecodeAccelerator.Decoding", this); } inputs_before_decode_++; - HRESULT hr = decoder_->ProcessInput(0, sample.get(), 0); + hr = decoder_->ProcessInput(0, sample.get(), 0); // As per msdn if the decoder returns MF_E_NOTACCEPTING then it means that it // has enough data to produce one or more output samples. In this case the // recommended options are to @@ -1790,7 +2402,7 @@ void DXVAVideoDecodeAccelerator::HandleResolutionChanged(int width, main_thread_task_runner_->PostTask( FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::DismissStaleBuffers, - weak_this_factory_.GetWeakPtr())); + weak_this_factory_.GetWeakPtr(), false)); main_thread_task_runner_->PostTask( FROM_HERE, @@ -1800,13 +2412,17 @@ void DXVAVideoDecodeAccelerator::HandleResolutionChanged(int width, height)); } -void DXVAVideoDecodeAccelerator::DismissStaleBuffers() { +void DXVAVideoDecodeAccelerator::DismissStaleBuffers(bool force) { + RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(), + "Failed to make context current", + PLATFORM_FAILURE, ); + OutputBuffers::iterator index; for (index = output_picture_buffers_.begin(); index != output_picture_buffers_.end(); ++index) { - if (index->second->available()) { + if (force || index->second->available()) { DVLOG(1) << "Dismissing picture id: " << index->second->id(); client_->DismissPictureBuffer(index->second->id()); } else { @@ -1821,6 +2437,10 @@ void DXVAVideoDecodeAccelerator::DismissStaleBuffers() { void DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer( int32_t picture_buffer_id) { + RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(), + "Failed to make context current", + PLATFORM_FAILURE, ); + OutputBuffers::iterator it = stale_output_picture_buffers_.find( picture_buffer_id); DCHECK(it != stale_output_picture_buffers_.end()); @@ -1935,13 +2555,15 @@ void DXVAVideoDecodeAccelerator::CopySurfaceComplete( if (picture_buffer->available()) return; - RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), - "Failed to make context current", PLATFORM_FAILURE,); + RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(), + "Failed to make context current", + PLATFORM_FAILURE, ); DCHECK(!output_picture_buffers_.empty()); - picture_buffer->CopySurfaceComplete(src_surface, - dest_surface); + bool result = picture_buffer->CopySurfaceComplete(src_surface, dest_surface); + RETURN_AND_NOTIFY_ON_FAILURE(result, "Failed to complete copying surface", + PLATFORM_FAILURE, ); NotifyPictureReady(picture_buffer->id(), input_buffer_id); @@ -1964,11 +2586,14 @@ void DXVAVideoDecodeAccelerator::CopySurfaceComplete( base::Unretained(this))); } -void DXVAVideoDecodeAccelerator::CopyTexture(ID3D11Texture2D* src_texture, - ID3D11Texture2D* dest_texture, - IMFSample* video_frame, - int picture_buffer_id, - int input_buffer_id) { +void DXVAVideoDecodeAccelerator::CopyTexture( + ID3D11Texture2D* src_texture, + ID3D11Texture2D* dest_texture, + base::win::ScopedComPtr<IDXGIKeyedMutex> dest_keyed_mutex, + uint64_t keyed_mutex_value, + IMFSample* video_frame, + int picture_buffer_id, + int input_buffer_id) { HRESULT hr = E_FAIL; DCHECK(use_dx11_); @@ -2005,14 +2630,11 @@ void DXVAVideoDecodeAccelerator::CopyTexture(ID3D11Texture2D* src_texture, } decoder_thread_task_runner_->PostTask( - FROM_HERE, - base::Bind(&DXVAVideoDecodeAccelerator::CopyTexture, - base::Unretained(this), - src_texture, - dest_texture, - input_sample_for_conversion.Detach(), - picture_buffer_id, - input_buffer_id)); + FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopyTexture, + base::Unretained(this), src_texture, dest_texture, + dest_keyed_mutex, keyed_mutex_value, + input_sample_for_conversion.Detach(), + picture_buffer_id, input_buffer_id)); return; } @@ -2023,6 +2645,13 @@ void DXVAVideoDecodeAccelerator::CopyTexture(ID3D11Texture2D* src_texture, DCHECK(video_format_converter_mft_.get()); + if (dest_keyed_mutex) { + HRESULT hr = + dest_keyed_mutex->AcquireSync(keyed_mutex_value, kAcquireSyncWaitMs); + RETURN_AND_NOTIFY_ON_FAILURE( + hr == S_OK, "D3D11 failed to acquire keyed mutex for texture.", + PLATFORM_FAILURE, ); + } // The video processor MFT requires output samples to be allocated by the // caller. We create a sample with a buffer backed with the ID3D11Texture2D // interface exposed by ANGLE. This works nicely as this ensures that the @@ -2077,18 +2706,27 @@ void DXVAVideoDecodeAccelerator::CopyTexture(ID3D11Texture2D* src_texture, "Failed to convert output sample format.", PLATFORM_FAILURE,); } - d3d11_device_context_->Flush(); - d3d11_device_context_->End(d3d11_query_.get()); + if (dest_keyed_mutex) { + HRESULT hr = dest_keyed_mutex->ReleaseSync(keyed_mutex_value + 1); + RETURN_AND_NOTIFY_ON_FAILURE(hr == S_OK, "Failed to release keyed mutex.", + PLATFORM_FAILURE, ); - decoder_thread_task_runner_->PostDelayedTask( - FROM_HERE, - base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, - base::Unretained(this), 0, - reinterpret_cast<IDirect3DSurface9*>(NULL), - reinterpret_cast<IDirect3DSurface9*>(NULL), - picture_buffer_id, input_buffer_id), - base::TimeDelta::FromMilliseconds( - kFlushDecoderSurfaceTimeoutMs)); + main_thread_task_runner_->PostTask( + FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, + weak_this_factory_.GetWeakPtr(), nullptr, nullptr, + picture_buffer_id, input_buffer_id)); + } else { + d3d11_device_context_->Flush(); + d3d11_device_context_->End(d3d11_query_.get()); + + decoder_thread_task_runner_->PostDelayedTask( + FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, + base::Unretained(this), 0, + reinterpret_cast<IDirect3DSurface9*>(NULL), + reinterpret_cast<IDirect3DSurface9*>(NULL), + picture_buffer_id, input_buffer_id), + base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); + } } void DXVAVideoDecodeAccelerator::FlushDecoder( @@ -2290,12 +2928,6 @@ bool DXVAVideoDecodeAccelerator::SetTransformOutputType( RETURN_ON_HR_FAILURE(hr, "Failed to set media type attributes", false); } hr = transform->SetOutputType(0, media_type.get(), 0); // No flags - if (FAILED(hr)) { - base::debug::Alias(&hr); - // TODO(ananta) - // Remove this CHECK when this stabilizes in the field. - CHECK(false); - } RETURN_ON_HR_FAILURE(hr, "Failed to set output type", false); return true; } @@ -2304,4 +2936,39 @@ bool DXVAVideoDecodeAccelerator::SetTransformOutputType( return false; } +HRESULT DXVAVideoDecodeAccelerator::CheckConfigChanged( + IMFSample* sample, bool* config_changed) { + if (codec_ != media::kCodecH264) + return S_FALSE; + + base::win::ScopedComPtr<IMFMediaBuffer> buffer; + HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive()); + RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from input sample", hr); + + MediaBufferScopedPointer scoped_media_buffer(buffer.get()); + + if (!config_change_detector_->DetectConfig( + scoped_media_buffer.get(), + scoped_media_buffer.current_length())) { + RETURN_ON_HR_FAILURE(E_FAIL, "Failed to detect H.264 stream config", + E_FAIL); + } + *config_changed = config_change_detector_->config_changed(); + return S_OK; +} + +void DXVAVideoDecodeAccelerator::ConfigChanged( + const Config& config) { + DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); + + SetState(kConfigChange); + DismissStaleBuffers(true); + Invalidate(); + Initialize(config_, client_); + decoder_thread_task_runner_->PostTask( + FROM_HERE, + base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, + base::Unretained(this))); +} + } // namespace content diff --git a/chromium/content/common/gpu/media/dxva_video_decode_accelerator_win.h b/chromium/content/common/gpu/media/dxva_video_decode_accelerator_win.h index d3aeda62c9b..01c15e62430 100644 --- a/chromium/content/common/gpu/media/dxva_video_decode_accelerator_win.h +++ b/chromium/content/common/gpu/media/dxva_video_decode_accelerator_win.h @@ -7,6 +7,7 @@ #include <d3d11.h> #include <d3d9.h> +#include <initguid.h> #include <stdint.h> // Work around bug in this header by disabling the relevant warning for it. // https://connect.microsoft.com/VisualStudio/feedback/details/911260/dxva2api-h-in-win8-sdk-triggers-c4201-with-w4 @@ -29,6 +30,8 @@ #include "base/threading/thread.h" #include "base/win/scoped_comptr.h" #include "content/common/content_export.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" +#include "media/filters/h264_parser.h" #include "media/video/video_decode_accelerator.h" interface IMFSample; @@ -44,6 +47,43 @@ typedef HRESULT (WINAPI* CreateDXGIDeviceManager)( namespace content { +// Provides functionality to detect H.264 stream configuration changes. +// TODO(ananta) +// Move this to a common place so that all VDA's can use this. +class H264ConfigChangeDetector { + public: + H264ConfigChangeDetector(); + ~H264ConfigChangeDetector(); + + // Detects stream configuration changes. + // Returns false on failure. + bool DetectConfig(const uint8_t* stream, unsigned int size); + + bool config_changed() const { + return config_changed_; + } + + private: + // These fields are used to track the SPS/PPS in the H.264 bitstream and + // are eventually compared against the SPS/PPS in the bitstream to detect + // a change. + int last_sps_id_; + std::vector<uint8_t> last_sps_; + int last_pps_id_; + std::vector<uint8_t> last_pps_; + // Set to true if we detect a stream configuration change. + bool config_changed_; + // We want to indicate configuration changes only after we see IDR slices. + // This flag tracks that we potentially have a configuration change which + // we want to honor after we see an IDR slice. + bool pending_config_changed_; + + scoped_ptr<media::H264Parser> parser_; + + DISALLOW_COPY_AND_ASSIGN(H264ConfigChangeDetector); +}; + + // Class to provide a DXVA 2.0 based accelerator using the Microsoft Media // foundation APIs via the VideoDecodeAccelerator interface. // This class lives on a single thread and DCHECKs that it is never accessed @@ -57,12 +97,14 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator kResetting, // upon received Reset(), before ResetDone() kStopped, // upon output EOS received. kFlushing, // upon flush request received. + kConfigChange, // stream configuration change detected. }; // Does not take ownership of |client| which must outlive |*this|. - explicit DXVAVideoDecodeAccelerator( - const base::Callback<bool(void)>& make_context_current, - gfx::GLContext* gl_context); + DXVAVideoDecodeAccelerator( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + bool enable_accelerated_vpx_decode); ~DXVAVideoDecodeAccelerator() override; // media::VideoDecodeAccelerator implementation. @@ -74,7 +116,10 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator void Flush() override; void Reset() override; void Destroy() override; - bool CanDecodeOnIOThread() override; + bool TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) + override; GLenum GetSurfaceInternalFormat() const override; static media::VideoDecodeAccelerator::SupportedProfiles @@ -87,6 +132,23 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator typedef void* EGLConfig; typedef void* EGLSurface; + // Returns the minimum resolution for the |profile| passed in. + static std::pair<int, int> GetMinResolution( + const media::VideoCodecProfile profile); + + // Returns the maximum resolution for the |profile| passed in. + static std::pair<int, int> GetMaxResolution( + const media::VideoCodecProfile profile); + + // Returns the maximum resolution for H264 video. + static std::pair<int, int> GetMaxH264Resolution(); + + // Certain AMD GPU drivers like R600, R700, Evergreen and Cayman and + // some second generation Intel GPU drivers crash if we create a video + // device with a resolution higher then 1920 x 1088. This function + // checks if the GPU is in this list and if yes returns true. + static bool IsLegacyGPU(ID3D11Device* device); + // Creates and initializes an instance of the D3D device and the // corresponding device manager. The device manager instance is eventually // passed to the IMFTransform interface implemented by the decoder. @@ -178,7 +240,7 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator typedef std::map<int32_t, linked_ptr<DXVAPictureBuffer>> OutputBuffers; // Tells the client to dismiss the stale picture buffers passed in. - void DismissStaleBuffers(); + void DismissStaleBuffers(bool force); // Called after the client indicates we can recycle a stale picture buffer. void DeferredDismissStaleBuffer(int32_t picture_buffer_id); @@ -191,10 +253,6 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator // the decoder thread. Thread safe. State GetState(); - // Worker function for the Decoder Reset functionality. Executes on the - // decoder thread and queues tasks on the main thread as needed. - void ResetHelper(); - // Starts the thread used for decoding. void StartDecoderThread(); @@ -222,6 +280,8 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator // is the sample containing the frame to be copied. void CopyTexture(ID3D11Texture2D* src_texture, ID3D11Texture2D* dest_texture, + base::win::ScopedComPtr<IDXGIKeyedMutex> dest_keyed_mutex, + uint64_t keyed_mutex_value, IMFSample* video_frame, int picture_buffer_id, int input_buffer_id); @@ -235,6 +295,10 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator int picture_buffer_id, int input_buffer_id); + // Polls to wait for GPU commands to be finished on the picture buffer + // before reusing it. + void WaitForOutputBuffer(int32_t picture_buffer_id, int count); + // Initializes the DX11 Video format converter media types. // Returns true on success. bool InitializeDX11VideoFormatConverterMediaType(int width, int height); @@ -257,6 +321,18 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator int width, int height); + // Checks if the resolution, bitrate etc of the stream changed. We do this + // by keeping track of the SPS/PPS frames and if they change we assume + // that the configuration changed. + // Returns S_OK or S_FALSE on succcess. + // The |config_changed| parameter is set to true if we detect a change in the + // stream. + HRESULT CheckConfigChanged(IMFSample* sample, bool* config_changed); + + // Called when we detect a stream configuration change. We reinitialize the + // decoder here. + void ConfigChanged(const Config& config); + // To expose client callbacks from VideoDecodeAccelerator. media::VideoDecodeAccelerator::Client* client_; @@ -340,8 +416,10 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator typedef std::list<base::win::ScopedComPtr<IMFSample>> PendingInputs; PendingInputs pending_input_buffers_; + // Callback to get current GLContext. + GetGLContextCallback get_gl_context_cb_; // Callback to set the correct gl context. - base::Callback<bool(void)> make_context_current_; + MakeGLContextCurrentCallback make_context_current_cb_; // Which codec we are decoding with hardware acceleration. media::VideoCodec codec_; @@ -373,16 +451,30 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator // H/W decoding. bool use_dx11_; + // True if we should use DXGI keyed mutexes to synchronize between the two + // contexts. + bool use_keyed_mutex_; + // Set to true if the DX11 video format converter input media types need to // be initialized. Defaults to true. bool dx11_video_format_converter_media_type_needs_init_; - // The GLContext to be used by the decoder. - scoped_refptr<gfx::GLContext> gl_context_; - // Set to true if we are sharing ANGLE's device. bool using_angle_device_; + // Enables experimental hardware acceleration for VP8/VP9 video decoding. + const bool enable_accelerated_vpx_decode_; + + // The media foundation H.264 decoder has problems handling changes like + // resolution change, bitrate change etc. If we reinitialize the decoder + // when these changes occur then, the decoder works fine. The + // H264ConfigChangeDetector class provides functionality to check if the + // stream configuration changed. + scoped_ptr<H264ConfigChangeDetector> config_change_detector_; + + // Contains the initialization parameters for the video. + Config config_; + // WeakPtrFactory for posting tasks back to |this|. base::WeakPtrFactory<DXVAVideoDecodeAccelerator> weak_this_factory_; diff --git a/chromium/content/common/gpu/media/fake_video_decode_accelerator.cc b/chromium/content/common/gpu/media/fake_video_decode_accelerator.cc index 7524dd18ebf..01ac07dcd3b 100644 --- a/chromium/content/common/gpu/media/fake_video_decode_accelerator.cc +++ b/chromium/content/common/gpu/media/fake_video_decode_accelerator.cc @@ -29,17 +29,14 @@ static const unsigned int kNumBuffers = media::limits::kMaxVideoFrames + (media::limits::kMaxVideoFrames & 1u); FakeVideoDecodeAccelerator::FakeVideoDecodeAccelerator( - gfx::GLContext* gl, - gfx::Size size, - const base::Callback<bool(void)>& make_context_current) + const gfx::Size& size, + const MakeGLContextCurrentCallback& make_context_current_cb) : child_task_runner_(base::ThreadTaskRunnerHandle::Get()), client_(NULL), - make_context_current_(make_context_current), - gl_(gl), + make_context_current_cb_(make_context_current_cb), frame_buffer_size_(size), flushing_(false), - weak_this_factory_(this) { -} + weak_this_factory_(this) {} FakeVideoDecodeAccelerator::~FakeVideoDecodeAccelerator() { } @@ -59,14 +56,23 @@ bool FakeVideoDecodeAccelerator::Initialize(const Config& config, // V4L2VideoDecodeAccelerator waits until first decode call to ask for buffers // This class asks for it on initialization instead. client_ = client; - client_->ProvidePictureBuffers(kNumBuffers, - frame_buffer_size_, + client_->ProvidePictureBuffers(kNumBuffers, 1, frame_buffer_size_, kDefaultTextureTarget); return true; } void FakeVideoDecodeAccelerator::Decode( const media::BitstreamBuffer& bitstream_buffer) { + // We won't really read from the bitstream_buffer, close the handle. + if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle())) + base::SharedMemory::CloseHandle(bitstream_buffer.handle()); + + if (bitstream_buffer.id() < 0) { + LOG(ERROR) << "Invalid bitstream: id=" << bitstream_buffer.id(); + client_->NotifyError(INVALID_ARGUMENT); + return; + } + int bitstream_buffer_id = bitstream_buffer.id(); queued_bitstream_ids_.push(bitstream_buffer_id); child_task_runner_->PostTask( @@ -93,12 +99,13 @@ void FakeVideoDecodeAccelerator::AssignPictureBuffers( memset(black_data.get(), 0, frame_buffer_size_.width() * frame_buffer_size_.height() * 4); - if (!make_context_current_.Run()) { + if (!make_context_current_cb_.Run()) { LOG(ERROR) << "ReusePictureBuffer(): could not make context current"; return; } for (size_t index = 0; index < buffers.size(); ++index) { - glBindTexture(GL_TEXTURE_2D, buffers[index].texture_id()); + DCHECK_LE(1u, buffers[index].texture_ids().size()); + glBindTexture(GL_TEXTURE_2D, buffers[index].texture_ids()[0]); // Every other frame white and the rest black. uint8_t* data = index % 2 ? white_data.get() : black_data.get(); glTexImage2D(GL_TEXTURE_2D, @@ -152,8 +159,10 @@ void FakeVideoDecodeAccelerator::Destroy() { delete this; } -bool FakeVideoDecodeAccelerator::CanDecodeOnIOThread() { - return true; +bool FakeVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { + return false; } void FakeVideoDecodeAccelerator::DoPictureReady() { diff --git a/chromium/content/common/gpu/media/fake_video_decode_accelerator.h b/chromium/content/common/gpu/media/fake_video_decode_accelerator.h index 7dcbfda2e77..10d47822b45 100644 --- a/chromium/content/common/gpu/media/fake_video_decode_accelerator.h +++ b/chromium/content/common/gpu/media/fake_video_decode_accelerator.h @@ -13,6 +13,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "content/common/content_export.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" #include "media/video/video_decode_accelerator.h" #include "ui/gfx/geometry/size_f.h" #include "ui/gl/gl_context.h" @@ -23,9 +24,8 @@ class CONTENT_EXPORT FakeVideoDecodeAccelerator : public media::VideoDecodeAccelerator { public: FakeVideoDecodeAccelerator( - gfx::GLContext* gl, - gfx::Size size, - const base::Callback<bool(void)>& make_context_current); + const gfx::Size& size, + const MakeGLContextCurrentCallback& make_context_current_cb); ~FakeVideoDecodeAccelerator() override; bool Initialize(const Config& config, Client* client) override; @@ -36,7 +36,10 @@ class CONTENT_EXPORT FakeVideoDecodeAccelerator void Flush() override; void Reset() override; void Destroy() override; - bool CanDecodeOnIOThread() override; + bool TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) + override; private: void DoPictureReady(); @@ -49,8 +52,7 @@ class CONTENT_EXPORT FakeVideoDecodeAccelerator Client* client_; // Make our context current before running any GL entry points. - base::Callback<bool(void)> make_context_current_; - gfx::GLContext* gl_; + MakeGLContextCurrentCallback make_context_current_cb_; // Output picture size. gfx::Size frame_buffer_size_; diff --git a/chromium/content/common/gpu/media/gpu_arc_video_service.cc b/chromium/content/common/gpu/media/gpu_arc_video_service.cc deleted file mode 100644 index 91d36980ad1..00000000000 --- a/chromium/content/common/gpu/media/gpu_arc_video_service.cc +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2016 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 "content/common/gpu/media/gpu_arc_video_service.h" - -#include "base/logging.h" -#include "content/common/gpu/gpu_messages.h" -#include "ipc/ipc_listener.h" -#include "ipc/ipc_message_macros.h" -#include "ipc/ipc_sync_channel.h" - -namespace content { - -// TODO(kcwu) implement ArcVideoAccelerator::Client. -class GpuArcVideoService::AcceleratorStub : public IPC::Listener, - public IPC::Sender { - public: - // |owner| outlives AcceleratorStub. - explicit AcceleratorStub(GpuArcVideoService* owner) : owner_(owner) {} - - ~AcceleratorStub() override { - DCHECK(thread_checker_.CalledOnValidThread()); - channel_->Close(); - } - - IPC::ChannelHandle CreateChannel( - base::WaitableEvent* shutdown_event, - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) { - IPC::ChannelHandle handle = - IPC::Channel::GenerateVerifiedChannelID("arc-video"); - channel_ = IPC::SyncChannel::Create(handle, IPC::Channel::MODE_SERVER, this, - io_task_runner, false, shutdown_event); - base::ScopedFD client_fd = channel_->TakeClientFileDescriptor(); - DCHECK(client_fd.is_valid()); - handle.socket = base::FileDescriptor(std::move(client_fd)); - return handle; - } - - // IPC::Sender implementation: - bool Send(IPC::Message* msg) override { - DCHECK(msg); - return channel_->Send(msg); - } - - // IPC::Listener implementation: - void OnChannelError() override { - DCHECK(thread_checker_.CalledOnValidThread()); - // RemoveClient will delete |this|. - owner_->RemoveClient(this); - } - - // IPC::Listener implementation: - bool OnMessageReceived(const IPC::Message& msg) override { - DCHECK(thread_checker_.CalledOnValidThread()); - - // TODO(kcwu) Add handlers here. - return false; - } - - private: - base::ThreadChecker thread_checker_; - GpuArcVideoService* const owner_; - scoped_ptr<IPC::SyncChannel> channel_; -}; - -GpuArcVideoService::GpuArcVideoService( - base::WaitableEvent* shutdown_event, - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) - : shutdown_event_(shutdown_event), io_task_runner_(io_task_runner) {} - -GpuArcVideoService::~GpuArcVideoService() {} - -void GpuArcVideoService::CreateChannel(const CreateChannelCallback& callback) { - DCHECK(thread_checker_.CalledOnValidThread()); - - scoped_ptr<AcceleratorStub> stub(new AcceleratorStub(this)); - - IPC::ChannelHandle handle = - stub->CreateChannel(shutdown_event_, io_task_runner_); - accelerator_stubs_[stub.get()] = std::move(stub); - - callback.Run(handle); -} - -void GpuArcVideoService::RemoveClient(AcceleratorStub* stub) { - DCHECK(thread_checker_.CalledOnValidThread()); - - accelerator_stubs_.erase(stub); -} - -} // namespace content diff --git a/chromium/content/common/gpu/media/gpu_arc_video_service.h b/chromium/content/common/gpu/media/gpu_arc_video_service.h deleted file mode 100644 index 131150c9f94..00000000000 --- a/chromium/content/common/gpu/media/gpu_arc_video_service.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2016 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 CONTENT_COMMON_GPU_MEDIA_GPU_ARC_VIDEO_SERVICE_H_ -#define CONTENT_COMMON_GPU_MEDIA_GPU_ARC_VIDEO_SERVICE_H_ - -#include <map> - -#include "base/callback.h" -#include "base/threading/thread_checker.h" - -namespace base { -class SingleThreadTaskRunner; -class WaitableEvent; -} - -namespace IPC { -struct ChannelHandle; -} - -namespace content { - -// GpuArcVideoService manages life-cycle and IPC message translation for -// ArcVideoAccelerator. -// -// For each creation request from GpuChannelManager, GpuArcVideoService will -// create a new IPC channel. -class GpuArcVideoService { - public: - class AcceleratorStub; - using CreateChannelCallback = base::Callback<void(const IPC::ChannelHandle&)>; - - // |shutdown_event| should signal an event when this process is about to be - // shut down in order to notify our new IPC channel to terminate. - GpuArcVideoService( - base::WaitableEvent* shutdown_event, - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner); - - // Upon deletion, all ArcVideoAccelerator will be deleted and the associated - // IPC channels are closed. - ~GpuArcVideoService(); - - // Creates a new accelerator stub. The creation result will be sent back via - // |callback|. - void CreateChannel(const CreateChannelCallback& callback); - - // Removes the reference of |stub| (and trigger deletion) from this class. - void RemoveClient(AcceleratorStub* stub); - - private: - base::ThreadChecker thread_checker_; - - // Shutdown event of GPU process. - base::WaitableEvent* shutdown_event_; - - // GPU io thread task runner. - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; - - // Bookkeeping all accelerator stubs. - std::map<AcceleratorStub*, scoped_ptr<AcceleratorStub>> accelerator_stubs_; - - DISALLOW_COPY_AND_ASSIGN(GpuArcVideoService); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_MEDIA_GPU_ARC_VIDEO_SERVICE_H_ diff --git a/chromium/content/common/gpu/media/gpu_jpeg_decode_accelerator.cc b/chromium/content/common/gpu/media/gpu_jpeg_decode_accelerator.cc index 7408e46d927..3e256073e84 100644 --- a/chromium/content/common/gpu/media/gpu_jpeg_decode_accelerator.cc +++ b/chromium/content/common/gpu/media/gpu_jpeg_decode_accelerator.cc @@ -13,13 +13,14 @@ #include "base/memory/shared_memory.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" +#include "base/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" -#include "content/common/gpu/gpu_channel.h" -#include "content/common/gpu/gpu_messages.h" +#include "gpu/ipc/service/gpu_channel.h" #include "ipc/ipc_message_macros.h" #include "ipc/message_filter.h" #include "media/filters/jpeg_parser.h" +#include "media/gpu/ipc/common/media_messages.h" #include "ui/gfx/geometry/size.h" #if defined(OS_CHROMEOS) @@ -41,12 +42,6 @@ void DecodeFinished(scoped_ptr<base::SharedMemory> shm) { } bool VerifyDecodeParams(const AcceleratedJpegDecoderMsg_Decode_Params& params) { - if (params.input_buffer_id < 0) { - LOG(ERROR) << "BitstreamBuffer id " << params.input_buffer_id - << " out of range"; - return false; - } - const int kJpegMaxDimension = UINT16_MAX; if (params.coded_size.IsEmpty() || params.coded_size.width() > kJpegMaxDimension || @@ -55,11 +50,6 @@ bool VerifyDecodeParams(const AcceleratedJpegDecoderMsg_Decode_Params& params) { return false; } - if (!base::SharedMemory::IsHandleValid(params.input_buffer_handle)) { - LOG(ERROR) << "invalid input_buffer_handle"; - return false; - } - if (!base::SharedMemory::IsHandleValid(params.output_video_frame_handle)) { LOG(ERROR) << "invalid output_video_frame_handle"; return false; @@ -163,13 +153,12 @@ class GpuJpegDecodeAccelerator::MessageFilter : public IPC::MessageFilter { void AddClientOnIOThread(int32_t route_id, Client* client, - IPC::Message* reply_msg) { + base::Callback<void(bool)> response) { DCHECK(io_task_runner_->BelongsToCurrentThread()); DCHECK(client_map_.count(route_id) == 0); client_map_[route_id] = client; - GpuMsg_CreateJpegDecoder::WriteReplyParams(reply_msg, true); - SendOnIOThread(reply_msg); + response.Run(true); } void OnDestroyOnIOThread(const int32_t* route_id) { @@ -208,34 +197,28 @@ class GpuJpegDecodeAccelerator::MessageFilter : public IPC::MessageFilter { if (!VerifyDecodeParams(params)) { NotifyDecodeStatusOnIOThread( - *route_id, params.input_buffer_id, + *route_id, params.input_buffer.id(), media::JpegDecodeAccelerator::INVALID_ARGUMENT); - if (base::SharedMemory::IsHandleValid(params.input_buffer_handle)) - base::SharedMemory::CloseHandle(params.input_buffer_handle); if (base::SharedMemory::IsHandleValid(params.output_video_frame_handle)) base::SharedMemory::CloseHandle(params.output_video_frame_handle); return; } // For handles in |params|, from now on, |params.output_video_frame_handle| - // is taken cared by scoper. |params.input_buffer_handle| need to be closed - // manually for early exits. + // is taken cared by scoper. |params.input_buffer.handle()| need to be + // closed manually for early exits. scoped_ptr<base::SharedMemory> output_shm( new base::SharedMemory(params.output_video_frame_handle, false)); if (!output_shm->Map(params.output_buffer_size)) { LOG(ERROR) << "Could not map output shared memory for input buffer id " - << params.input_buffer_id; + << params.input_buffer.id(); NotifyDecodeStatusOnIOThread( - *route_id, params.input_buffer_id, + *route_id, params.input_buffer.id(), media::JpegDecodeAccelerator::PLATFORM_FAILURE); - base::SharedMemory::CloseHandle(params.input_buffer_handle); + base::SharedMemory::CloseHandle(params.input_buffer.handle()); return; } - media::BitstreamBuffer input_buffer(params.input_buffer_id, - params.input_buffer_handle, - params.input_buffer_size); - uint8_t* shm_memory = static_cast<uint8_t*>(output_shm->memory()); scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapExternalSharedMemory( @@ -250,11 +233,11 @@ class GpuJpegDecodeAccelerator::MessageFilter : public IPC::MessageFilter { base::TimeDelta()); // timestamp if (!frame.get()) { LOG(ERROR) << "Could not create VideoFrame for input buffer id " - << params.input_buffer_id; + << params.input_buffer.id(); NotifyDecodeStatusOnIOThread( - *route_id, params.input_buffer_id, + *route_id, params.input_buffer.id(), media::JpegDecodeAccelerator::PLATFORM_FAILURE); - base::SharedMemory::CloseHandle(params.input_buffer_handle); + base::SharedMemory::CloseHandle(params.input_buffer.handle()); return; } frame->AddDestructionObserver( @@ -262,7 +245,7 @@ class GpuJpegDecodeAccelerator::MessageFilter : public IPC::MessageFilter { DCHECK_GT(client_map_.count(*route_id), 0u); Client* client = client_map_[*route_id]; - client->Decode(input_buffer, frame); + client->Decode(params.input_buffer, frame); } protected: @@ -309,7 +292,7 @@ class GpuJpegDecodeAccelerator::MessageFilter : public IPC::MessageFilter { }; GpuJpegDecodeAccelerator::GpuJpegDecodeAccelerator( - GpuChannel* channel, + gpu::GpuChannel* channel, const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) : channel_(channel), child_task_runner_(base::ThreadTaskRunnerHandle::Get()), @@ -325,7 +308,7 @@ GpuJpegDecodeAccelerator::~GpuJpegDecodeAccelerator() { } void GpuJpegDecodeAccelerator::AddClient(int32_t route_id, - IPC::Message* reply_msg) { + base::Callback<void(bool)> response) { DCHECK(CalledOnValidThread()); // When adding non-chromeos platforms, VideoCaptureGpuJpegDecoder::Initialize @@ -350,8 +333,7 @@ void GpuJpegDecodeAccelerator::AddClient(int32_t route_id, if (!accelerator) { DLOG(ERROR) << "JPEG accelerator Initialize failed"; - GpuMsg_CreateJpegDecoder::WriteReplyParams(reply_msg, false); - Send(reply_msg); + response.Run(false); return; } client->set_accelerator(std::move(accelerator)); @@ -372,7 +354,7 @@ void GpuJpegDecodeAccelerator::AddClient(int32_t route_id, // here instead of making the code unnecessary complicated. io_task_runner_->PostTask( FROM_HERE, base::Bind(&MessageFilter::AddClientOnIOThread, filter_, - route_id, client.release(), reply_msg)); + route_id, client.release(), response)); } void GpuJpegDecodeAccelerator::NotifyDecodeStatus( diff --git a/chromium/content/common/gpu/media/gpu_jpeg_decode_accelerator.h b/chromium/content/common/gpu/media/gpu_jpeg_decode_accelerator.h index 0fc316e026f..680dac578e0 100644 --- a/chromium/content/common/gpu/media/gpu_jpeg_decode_accelerator.h +++ b/chromium/content/common/gpu/media/gpu_jpeg_decode_accelerator.h @@ -20,9 +20,11 @@ namespace base { class SingleThreadTaskRunner; } -namespace content { +namespace gpu { class GpuChannel; +} +namespace content { class GpuJpegDecodeAccelerator : public IPC::Sender, public base::NonThreadSafe, @@ -30,11 +32,11 @@ class GpuJpegDecodeAccelerator public: // |channel| must outlive this object. GpuJpegDecodeAccelerator( - GpuChannel* channel, + gpu::GpuChannel* channel, const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner); ~GpuJpegDecodeAccelerator() override; - void AddClient(int32_t route_id, IPC::Message* reply_msg); + void AddClient(int32_t route_id, base::Callback<void(bool)> response); void NotifyDecodeStatus(int32_t route_id, int32_t bitstream_buffer_id, @@ -61,10 +63,10 @@ class GpuJpegDecodeAccelerator static scoped_ptr<media::JpegDecodeAccelerator> CreateVaapiJDA( const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner); - // The lifetime of objects of this class is managed by a GpuChannel. The + // The lifetime of objects of this class is managed by a gpu::GpuChannel. The // GpuChannels destroy all the GpuJpegDecodeAccelerator that they own when // they are destroyed. So a raw pointer is safe. - GpuChannel* channel_; + gpu::GpuChannel* channel_; // The message filter to run JpegDecodeAccelerator::Decode on IO thread. scoped_refptr<MessageFilter> filter_; diff --git a/chromium/content/common/gpu/media/gpu_video_accelerator_util.cc b/chromium/content/common/gpu/media/gpu_video_accelerator_util.cc deleted file mode 100644 index 7692fddc40a..00000000000 --- a/chromium/content/common/gpu/media/gpu_video_accelerator_util.cc +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2015 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 "content/common/gpu/media/gpu_video_accelerator_util.h" - -namespace content { - -// Make sure the enum values of media::VideoCodecProfile and -// gpu::VideoCodecProfile match. -#define STATIC_ASSERT_ENUM_MATCH(name) \ - static_assert( \ - media::name == static_cast<media::VideoCodecProfile>(gpu::name), \ - #name " value must match in media and gpu.") - -STATIC_ASSERT_ENUM_MATCH(VIDEO_CODEC_PROFILE_UNKNOWN); -STATIC_ASSERT_ENUM_MATCH(VIDEO_CODEC_PROFILE_MIN); -STATIC_ASSERT_ENUM_MATCH(H264PROFILE_BASELINE); -STATIC_ASSERT_ENUM_MATCH(H264PROFILE_MAIN); -STATIC_ASSERT_ENUM_MATCH(H264PROFILE_EXTENDED); -STATIC_ASSERT_ENUM_MATCH(H264PROFILE_HIGH); -STATIC_ASSERT_ENUM_MATCH(H264PROFILE_HIGH10PROFILE); -STATIC_ASSERT_ENUM_MATCH(H264PROFILE_HIGH422PROFILE); -STATIC_ASSERT_ENUM_MATCH(H264PROFILE_HIGH444PREDICTIVEPROFILE); -STATIC_ASSERT_ENUM_MATCH(H264PROFILE_SCALABLEBASELINE); -STATIC_ASSERT_ENUM_MATCH(H264PROFILE_SCALABLEHIGH); -STATIC_ASSERT_ENUM_MATCH(H264PROFILE_STEREOHIGH); -STATIC_ASSERT_ENUM_MATCH(H264PROFILE_MULTIVIEWHIGH); -STATIC_ASSERT_ENUM_MATCH(VP8PROFILE_ANY); -STATIC_ASSERT_ENUM_MATCH(VP9PROFILE_ANY); -STATIC_ASSERT_ENUM_MATCH(VIDEO_CODEC_PROFILE_MAX); - -// static -media::VideoDecodeAccelerator::Capabilities -GpuVideoAcceleratorUtil::ConvertGpuToMediaDecodeCapabilities( - const gpu::VideoDecodeAcceleratorCapabilities& gpu_capabilities) { - media::VideoDecodeAccelerator::Capabilities capabilities; - capabilities.supported_profiles = - ConvertGpuToMediaDecodeProfiles(gpu_capabilities.supported_profiles); - capabilities.flags = gpu_capabilities.flags; - return capabilities; -} - -// static -media::VideoDecodeAccelerator::SupportedProfiles -GpuVideoAcceleratorUtil::ConvertGpuToMediaDecodeProfiles(const - gpu::VideoDecodeAcceleratorSupportedProfiles& gpu_profiles) { - media::VideoDecodeAccelerator::SupportedProfiles profiles; - for (const auto& gpu_profile : gpu_profiles) { - media::VideoDecodeAccelerator::SupportedProfile profile; - profile.profile = - static_cast<media::VideoCodecProfile>(gpu_profile.profile); - profile.max_resolution = gpu_profile.max_resolution; - profile.min_resolution = gpu_profile.min_resolution; - profiles.push_back(profile); - } - return profiles; -} - -// static -gpu::VideoDecodeAcceleratorCapabilities -GpuVideoAcceleratorUtil::ConvertMediaToGpuDecodeCapabilities( - const media::VideoDecodeAccelerator::Capabilities& media_capabilities) { - gpu::VideoDecodeAcceleratorCapabilities capabilities; - capabilities.supported_profiles = - ConvertMediaToGpuDecodeProfiles(media_capabilities.supported_profiles); - capabilities.flags = media_capabilities.flags; - return capabilities; -} - -// static -gpu::VideoDecodeAcceleratorSupportedProfiles -GpuVideoAcceleratorUtil::ConvertMediaToGpuDecodeProfiles(const - media::VideoDecodeAccelerator::SupportedProfiles& media_profiles) { - gpu::VideoDecodeAcceleratorSupportedProfiles profiles; - for (const auto& media_profile : media_profiles) { - gpu::VideoDecodeAcceleratorSupportedProfile profile; - profile.profile = - static_cast<gpu::VideoCodecProfile>(media_profile.profile); - profile.max_resolution = media_profile.max_resolution; - profile.min_resolution = media_profile.min_resolution; - profiles.push_back(profile); - } - return profiles; -} - -// static -media::VideoEncodeAccelerator::SupportedProfiles -GpuVideoAcceleratorUtil::ConvertGpuToMediaEncodeProfiles(const - gpu::VideoEncodeAcceleratorSupportedProfiles& gpu_profiles) { - media::VideoEncodeAccelerator::SupportedProfiles profiles; - for (const auto& gpu_profile : gpu_profiles) { - media::VideoEncodeAccelerator::SupportedProfile profile; - profile.profile = - static_cast<media::VideoCodecProfile>(gpu_profile.profile); - profile.max_resolution = gpu_profile.max_resolution; - profile.max_framerate_numerator = gpu_profile.max_framerate_numerator; - profile.max_framerate_denominator = gpu_profile.max_framerate_denominator; - profiles.push_back(profile); - } - return profiles; -} - -// static -gpu::VideoEncodeAcceleratorSupportedProfiles -GpuVideoAcceleratorUtil::ConvertMediaToGpuEncodeProfiles(const - media::VideoEncodeAccelerator::SupportedProfiles& media_profiles) { - gpu::VideoEncodeAcceleratorSupportedProfiles profiles; - for (const auto& media_profile : media_profiles) { - gpu::VideoEncodeAcceleratorSupportedProfile profile; - profile.profile = - static_cast<gpu::VideoCodecProfile>(media_profile.profile); - profile.max_resolution = media_profile.max_resolution; - profile.max_framerate_numerator = media_profile.max_framerate_numerator; - profile.max_framerate_denominator = media_profile.max_framerate_denominator; - profiles.push_back(profile); - } - return profiles; -} - -// static -void GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles( - const media::VideoDecodeAccelerator::SupportedProfiles& new_profiles, - media::VideoDecodeAccelerator::SupportedProfiles* media_profiles) { - for (const auto& profile : new_profiles) { - bool duplicate = false; - for (const auto& media_profile : *media_profiles) { - if (media_profile.profile == profile.profile) { - duplicate = true; - break; - } - } - if (!duplicate) - media_profiles->push_back(profile); - } -} - -// static -void GpuVideoAcceleratorUtil::InsertUniqueEncodeProfiles( - const media::VideoEncodeAccelerator::SupportedProfiles& new_profiles, - media::VideoEncodeAccelerator::SupportedProfiles* media_profiles) { - for (const auto& profile : new_profiles) { - bool duplicate = false; - for (const auto& media_profile : *media_profiles) { - if (media_profile.profile == profile.profile) { - duplicate = true; - break; - } - } - if (!duplicate) - media_profiles->push_back(profile); - } -} - -} // namespace content diff --git a/chromium/content/common/gpu/media/gpu_video_accelerator_util.h b/chromium/content/common/gpu/media/gpu_video_accelerator_util.h deleted file mode 100644 index e39034e191e..00000000000 --- a/chromium/content/common/gpu/media/gpu_video_accelerator_util.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2015 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 CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_ACCELERATOR_UTIL_H_ -#define CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_ACCELERATOR_UTIL_H_ - -#include <vector> - -#include "gpu/config/gpu_info.h" -#include "media/video/video_decode_accelerator.h" -#include "media/video/video_encode_accelerator.h" - -namespace content { - -class GpuVideoAcceleratorUtil { - public: - // Convert decoder gpu capabilities to media capabilities. - static media::VideoDecodeAccelerator::Capabilities - ConvertGpuToMediaDecodeCapabilities( - const gpu::VideoDecodeAcceleratorCapabilities& gpu_capabilities); - - // Convert decoder gpu profiles to media profiles. - static media::VideoDecodeAccelerator::SupportedProfiles - ConvertGpuToMediaDecodeProfiles(const - gpu::VideoDecodeAcceleratorSupportedProfiles& gpu_profiles); - - // Convert decoder media capabilities to gpu capabilities. - static gpu::VideoDecodeAcceleratorCapabilities - ConvertMediaToGpuDecodeCapabilities( - const media::VideoDecodeAccelerator::Capabilities& media_capabilities); - - // Convert decoder media profiles to gpu profiles. - static gpu::VideoDecodeAcceleratorSupportedProfiles - ConvertMediaToGpuDecodeProfiles(const - media::VideoDecodeAccelerator::SupportedProfiles& media_profiles); - - // Convert encoder gpu profiles to media profiles. - static media::VideoEncodeAccelerator::SupportedProfiles - ConvertGpuToMediaEncodeProfiles(const - gpu::VideoEncodeAcceleratorSupportedProfiles& gpu_profiles); - - // Convert encoder media profiles to gpu profiles. - static gpu::VideoEncodeAcceleratorSupportedProfiles - ConvertMediaToGpuEncodeProfiles(const - media::VideoEncodeAccelerator::SupportedProfiles& media_profiles); - - // Insert |new_profiles| into |media_profiles|, ensuring no duplicates are - // inserted. - static void InsertUniqueDecodeProfiles( - const media::VideoDecodeAccelerator::SupportedProfiles& new_profiles, - media::VideoDecodeAccelerator::SupportedProfiles* media_profiles); - - // Insert |new_profiles| into |media_profiles|, ensuring no duplicates are - // inserted. - static void InsertUniqueEncodeProfiles( - const media::VideoEncodeAccelerator::SupportedProfiles& new_profiles, - media::VideoEncodeAccelerator::SupportedProfiles* media_profiles); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_ACCELERATOR_UTIL_H_ diff --git a/chromium/content/common/gpu/media/gpu_video_decode_accelerator.cc b/chromium/content/common/gpu/media/gpu_video_decode_accelerator.cc index 5424a5ff32d..3d30266f05a 100644 --- a/chromium/content/common/gpu/media/gpu_video_decode_accelerator.cc +++ b/chromium/content/common/gpu/media/gpu_video_decode_accelerator.cc @@ -7,7 +7,6 @@ #include <vector> #include "base/bind.h" -#include "base/command_line.h" #include "base/location.h" #include "base/logging.h" #include "base/memory/ref_counted.h" @@ -15,47 +14,36 @@ #include "base/stl_util.h" #include "base/thread_task_runner_handle.h" #include "build/build_config.h" - -#include "content/common/gpu/gpu_channel.h" -#include "content/common/gpu/gpu_messages.h" -#include "content/common/gpu/media/gpu_video_accelerator_util.h" -#include "content/public/common/content_switches.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.h" #include "gpu/command_buffer/common/command_buffer.h" +#include "gpu/command_buffer/service/gpu_preferences.h" +#include "gpu/ipc/service/gpu_channel.h" +#include "gpu/ipc/service/gpu_channel_manager.h" #include "ipc/ipc_message_macros.h" #include "ipc/ipc_message_utils.h" #include "ipc/message_filter.h" #include "media/base/limits.h" +#include "media/gpu/ipc/common/gpu_video_accelerator_util.h" +#include "media/gpu/ipc/common/media_messages.h" +#include "ui/gfx/geometry/size.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_image.h" -#include "ui/gl/gl_surface_egl.h" - -#if defined(OS_WIN) -#include "base/win/windows_version.h" -#include "content/common/gpu/media/dxva_video_decode_accelerator_win.h" -#elif defined(OS_MACOSX) -#include "content/common/gpu/media/vt_video_decode_accelerator_mac.h" -#elif defined(OS_CHROMEOS) -#if defined(USE_V4L2_CODEC) -#include "content/common/gpu/media/v4l2_device.h" -#include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h" -#include "content/common/gpu/media/v4l2_video_decode_accelerator.h" -#endif -#if defined(ARCH_CPU_X86_FAMILY) -#include "content/common/gpu/media/vaapi_video_decode_accelerator.h" -#include "ui/gl/gl_implementation.h" -#endif -#elif defined(USE_OZONE) -#include "media/ozone/media_ozone_platform.h" -#elif defined(OS_ANDROID) -#include "content/common/gpu/media/android_video_decode_accelerator.h" -#endif - -#include "ui/gfx/geometry/size.h" namespace content { +namespace { +static gfx::GLContext* GetGLContext( + const base::WeakPtr<gpu::GpuCommandBufferStub>& stub) { + if (!stub) { + DLOG(ERROR) << "Stub is gone; no GLContext."; + return nullptr; + } + + return stub->decoder()->GetGLContext(); +} + static bool MakeDecoderContextCurrent( - const base::WeakPtr<GpuCommandBufferStub> stub) { + const base::WeakPtr<gpu::GpuCommandBufferStub>& stub) { if (!stub) { DLOG(ERROR) << "Stub is gone; won't MakeCurrent()."; return false; @@ -69,6 +57,43 @@ static bool MakeDecoderContextCurrent( return true; } +#if (defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)) || defined(OS_MACOSX) +static bool BindImage(const base::WeakPtr<gpu::GpuCommandBufferStub>& stub, + uint32_t client_texture_id, + uint32_t texture_target, + const scoped_refptr<gl::GLImage>& image, + bool can_bind_to_sampler) { + if (!stub) { + DLOG(ERROR) << "Stub is gone; won't BindImage()."; + return false; + } + + gpu::gles2::GLES2Decoder* command_decoder = stub->decoder(); + gpu::gles2::TextureManager* texture_manager = + command_decoder->GetContextGroup()->texture_manager(); + gpu::gles2::TextureRef* ref = texture_manager->GetTexture(client_texture_id); + if (ref) { + texture_manager->SetLevelImage(ref, texture_target, 0, image.get(), + can_bind_to_sampler + ? gpu::gles2::Texture::BOUND + : gpu::gles2::Texture::UNBOUND); + } + + return true; +} +#endif + +static base::WeakPtr<gpu::gles2::GLES2Decoder> GetGLES2Decoder( + const base::WeakPtr<gpu::GpuCommandBufferStub>& stub) { + if (!stub) { + DLOG(ERROR) << "Stub is gone; no GLES2Decoder."; + return base::WeakPtr<gpu::gles2::GLES2Decoder>(); + } + + return stub->decoder()->AsWeakPtr(); +} +} // anonymous namespace + // DebugAutoLock works like AutoLock but only acquires the lock when // DCHECK is on. #if DCHECK_IS_ON() @@ -103,7 +128,7 @@ class GpuVideoDecodeAccelerator::MessageFilter : public IPC::MessageFilter { IPC_BEGIN_MESSAGE_MAP(MessageFilter, msg) IPC_MESSAGE_FORWARD(AcceleratedVideoDecoderMsg_Decode, owner_, GpuVideoDecodeAccelerator::OnDecode) - IPC_MESSAGE_UNHANDLED(return false;) + IPC_MESSAGE_UNHANDLED(return false) IPC_END_MESSAGE_MAP() return true; } @@ -129,19 +154,25 @@ class GpuVideoDecodeAccelerator::MessageFilter : public IPC::MessageFilter { GpuVideoDecodeAccelerator::GpuVideoDecodeAccelerator( int32_t host_route_id, - GpuCommandBufferStub* stub, + gpu::GpuCommandBufferStub* stub, const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) : host_route_id_(host_route_id), stub_(stub), texture_target_(0), + textures_per_buffer_(0), filter_removed_(true, false), child_task_runner_(base::ThreadTaskRunnerHandle::Get()), io_task_runner_(io_task_runner), weak_factory_for_io_(this) { DCHECK(stub_); stub_->AddDestructionObserver(this); - make_context_current_ = + get_gl_context_cb_ = base::Bind(&GetGLContext, stub_->AsWeakPtr()); + make_context_current_cb_ = base::Bind(&MakeDecoderContextCurrent, stub_->AsWeakPtr()); +#if (defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)) || defined(OS_MACOSX) + bind_image_cb_ = base::Bind(&BindImage, stub_->AsWeakPtr()); +#endif + get_gles2_decoder_cb_ = base::Bind(&GetGLES2Decoder, stub_->AsWeakPtr()); } GpuVideoDecodeAccelerator::~GpuVideoDecodeAccelerator() { @@ -152,41 +183,10 @@ GpuVideoDecodeAccelerator::~GpuVideoDecodeAccelerator() { // static gpu::VideoDecodeAcceleratorCapabilities -GpuVideoDecodeAccelerator::GetCapabilities() { - media::VideoDecodeAccelerator::Capabilities capabilities; - const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); - if (cmd_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) - return gpu::VideoDecodeAcceleratorCapabilities(); - - // Query supported profiles for each VDA. The order of querying VDAs should - // be the same as the order of initializing VDAs. Then the returned profile - // can be initialized by corresponding VDA successfully. -#if defined(OS_WIN) - capabilities.supported_profiles = - DXVAVideoDecodeAccelerator::GetSupportedProfiles(); -#elif defined(OS_CHROMEOS) - media::VideoDecodeAccelerator::SupportedProfiles vda_profiles; -#if defined(USE_V4L2_CODEC) - vda_profiles = V4L2VideoDecodeAccelerator::GetSupportedProfiles(); - GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles( - vda_profiles, &capabilities.supported_profiles); - vda_profiles = V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles(); - GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles( - vda_profiles, &capabilities.supported_profiles); -#endif -#if defined(ARCH_CPU_X86_FAMILY) - vda_profiles = VaapiVideoDecodeAccelerator::GetSupportedProfiles(); - GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles( - vda_profiles, &capabilities.supported_profiles); -#endif -#elif defined(OS_MACOSX) - capabilities.supported_profiles = - VTVideoDecodeAccelerator::GetSupportedProfiles(); -#elif defined(OS_ANDROID) - capabilities = AndroidVideoDecodeAccelerator::GetCapabilities(); -#endif - return GpuVideoAcceleratorUtil::ConvertMediaToGpuDecodeCapabilities( - capabilities); +GpuVideoDecodeAccelerator::GetCapabilities( + const gpu::GpuPreferences& gpu_preferences) { + return GpuVideoDecodeAcceleratorFactoryImpl::GetDecoderCapabilities( + gpu_preferences); } bool GpuVideoDecodeAccelerator::OnMessageReceived(const IPC::Message& msg) { @@ -209,14 +209,16 @@ bool GpuVideoDecodeAccelerator::OnMessageReceived(const IPC::Message& msg) { return handled; } -void GpuVideoDecodeAccelerator::NotifyCdmAttached(bool success) { - if (!Send(new AcceleratedVideoDecoderHostMsg_CdmAttached(host_route_id_, - success))) - DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_CdmAttached) failed"; +void GpuVideoDecodeAccelerator::NotifyInitializationComplete(bool success) { + if (!Send(new AcceleratedVideoDecoderHostMsg_InitializationComplete( + host_route_id_, success))) + DLOG(ERROR) + << "Send(AcceleratedVideoDecoderHostMsg_InitializationComplete) failed"; } void GpuVideoDecodeAccelerator::ProvidePictureBuffers( uint32_t requested_num_of_buffers, + uint32_t textures_per_buffer, const gfx::Size& dimensions, uint32_t texture_target) { if (dimensions.width() > media::limits::kMaxDimension || @@ -226,14 +228,13 @@ void GpuVideoDecodeAccelerator::ProvidePictureBuffers( return; } if (!Send(new AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers( - host_route_id_, - requested_num_of_buffers, - dimensions, - texture_target))) { + host_route_id_, requested_num_of_buffers, textures_per_buffer, + dimensions, texture_target))) { DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers) " << "failed"; } texture_dimensions_ = dimensions; + textures_per_buffer_ = textures_per_buffer; texture_target_ = texture_target; } @@ -265,7 +266,7 @@ void GpuVideoDecodeAccelerator::PictureReady( if (!Send(new AcceleratedVideoDecoderHostMsg_PictureReady( host_route_id_, picture.picture_buffer_id(), picture.bitstream_buffer_id(), picture.visible_rect(), - picture.allow_overlay()))) { + picture.allow_overlay(), picture.size_changed()))) { DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_PictureReady) failed"; } } @@ -327,161 +328,51 @@ bool GpuVideoDecodeAccelerator::Send(IPC::Message* message) { return stub_->channel()->Send(message); } -void GpuVideoDecodeAccelerator::Initialize( - const media::VideoDecodeAccelerator::Config& config, - IPC::Message* init_done_msg) { +bool GpuVideoDecodeAccelerator::Initialize( + const media::VideoDecodeAccelerator::Config& config) { DCHECK(!video_decode_accelerator_); - if (!stub_->channel()->AddRoute(host_route_id_, this)) { + if (!stub_->channel()->AddRoute(host_route_id_, stub_->stream_id(), this)) { DLOG(ERROR) << "Initialize(): failed to add route"; - SendCreateDecoderReply(init_done_msg, false); + return false; } #if !defined(OS_WIN) // Ensure we will be able to get a GL context at all before initializing // non-Windows VDAs. - if (!make_context_current_.Run()) { - SendCreateDecoderReply(init_done_msg, false); - return; - } + if (!make_context_current_cb_.Run()) + return false; #endif - // Array of Create..VDA() function pointers, maybe applicable to the current - // platform. This list is ordered by priority of use and it should be the - // same as the order of querying supported profiles of VDAs. - const GpuVideoDecodeAccelerator::CreateVDAFp create_vda_fps[] = { - &GpuVideoDecodeAccelerator::CreateDXVAVDA, - &GpuVideoDecodeAccelerator::CreateV4L2VDA, - &GpuVideoDecodeAccelerator::CreateV4L2SliceVDA, - &GpuVideoDecodeAccelerator::CreateVaapiVDA, - &GpuVideoDecodeAccelerator::CreateVTVDA, - &GpuVideoDecodeAccelerator::CreateOzoneVDA, - &GpuVideoDecodeAccelerator::CreateAndroidVDA}; - - for (const auto& create_vda_function : create_vda_fps) { - video_decode_accelerator_ = (this->*create_vda_function)(); - if (!video_decode_accelerator_ || - !video_decode_accelerator_->Initialize(config, this)) - continue; - - if (video_decode_accelerator_->CanDecodeOnIOThread()) { - filter_ = new MessageFilter(this, host_route_id_); - stub_->channel()->AddFilter(filter_.get()); - } - SendCreateDecoderReply(init_done_msg, true); - return; - } - video_decode_accelerator_.reset(); - LOG(ERROR) << "HW video decode not available for profile " << config.profile - << (config.is_encrypted ? " with encryption" : ""); - SendCreateDecoderReply(init_done_msg, false); -} + scoped_ptr<GpuVideoDecodeAcceleratorFactoryImpl> vda_factory = + GpuVideoDecodeAcceleratorFactoryImpl::CreateWithGLES2Decoder( + get_gl_context_cb_, make_context_current_cb_, bind_image_cb_, + get_gles2_decoder_cb_); -scoped_ptr<media::VideoDecodeAccelerator> -GpuVideoDecodeAccelerator::CreateDXVAVDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; -#if defined(OS_WIN) - if (base::win::GetVersion() >= base::win::VERSION_WIN7) { - DVLOG(0) << "Initializing DXVA HW decoder for windows."; - decoder.reset(new DXVAVideoDecodeAccelerator(make_context_current_, - stub_->decoder()->GetGLContext())); - } else { - NOTIMPLEMENTED() << "HW video decode acceleration not available."; + if (!vda_factory) { + LOG(ERROR) << "Failed creating the VDA factory"; + return false; } -#endif - return decoder; -} -scoped_ptr<media::VideoDecodeAccelerator> -GpuVideoDecodeAccelerator::CreateV4L2VDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; -#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) - scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); - if (device.get()) { - decoder.reset(new V4L2VideoDecodeAccelerator( - gfx::GLSurfaceEGL::GetHardwareDisplay(), - stub_->decoder()->GetGLContext()->GetHandle(), - weak_factory_for_io_.GetWeakPtr(), - make_context_current_, - device, - io_task_runner_)); + const gpu::GpuPreferences& gpu_preferences = + stub_->channel()->gpu_channel_manager()->gpu_preferences(); + video_decode_accelerator_ = + vda_factory->CreateVDA(this, config, gpu_preferences); + if (!video_decode_accelerator_) { + LOG(ERROR) << "HW video decode not available for profile " << config.profile + << (config.is_encrypted ? " with encryption" : ""); + return false; } -#endif - return decoder; -} -scoped_ptr<media::VideoDecodeAccelerator> -GpuVideoDecodeAccelerator::CreateV4L2SliceVDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; -#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) - scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); - if (device.get()) { - decoder.reset(new V4L2SliceVideoDecodeAccelerator( - device, - gfx::GLSurfaceEGL::GetHardwareDisplay(), - stub_->decoder()->GetGLContext()->GetHandle(), - weak_factory_for_io_.GetWeakPtr(), - make_context_current_, - io_task_runner_)); + // Attempt to set up performing decoding tasks on IO thread, if supported by + // the VDA. + if (video_decode_accelerator_->TryToSetupDecodeOnSeparateThread( + weak_factory_for_io_.GetWeakPtr(), io_task_runner_)) { + filter_ = new MessageFilter(this, host_route_id_); + stub_->channel()->AddFilter(filter_.get()); } -#endif - return decoder; -} -void GpuVideoDecodeAccelerator::BindImage(uint32_t client_texture_id, - uint32_t texture_target, - scoped_refptr<gl::GLImage> image) { - gpu::gles2::GLES2Decoder* command_decoder = stub_->decoder(); - gpu::gles2::TextureManager* texture_manager = - command_decoder->GetContextGroup()->texture_manager(); - gpu::gles2::TextureRef* ref = texture_manager->GetTexture(client_texture_id); - if (ref) { - texture_manager->SetLevelImage(ref, texture_target, 0, image.get(), - gpu::gles2::Texture::BOUND); - } -} - -scoped_ptr<media::VideoDecodeAccelerator> -GpuVideoDecodeAccelerator::CreateVaapiVDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; -#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) - decoder.reset(new VaapiVideoDecodeAccelerator( - make_context_current_, base::Bind(&GpuVideoDecodeAccelerator::BindImage, - base::Unretained(this)))); -#endif - return decoder; -} - -scoped_ptr<media::VideoDecodeAccelerator> -GpuVideoDecodeAccelerator::CreateVTVDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; -#if defined(OS_MACOSX) - decoder.reset(new VTVideoDecodeAccelerator( - make_context_current_, base::Bind(&GpuVideoDecodeAccelerator::BindImage, - base::Unretained(this)))); -#endif - return decoder; -} - -scoped_ptr<media::VideoDecodeAccelerator> -GpuVideoDecodeAccelerator::CreateOzoneVDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; -#if !defined(OS_CHROMEOS) && defined(USE_OZONE) - media::MediaOzonePlatform* platform = - media::MediaOzonePlatform::GetInstance(); - decoder.reset(platform->CreateVideoDecodeAccelerator(make_context_current_)); -#endif - return decoder; -} - -scoped_ptr<media::VideoDecodeAccelerator> -GpuVideoDecodeAccelerator::CreateAndroidVDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; -#if defined(OS_ANDROID) - decoder.reset(new AndroidVideoDecodeAccelerator(stub_->decoder()->AsWeakPtr(), - make_context_current_)); -#endif - return decoder; + return true; } void GpuVideoDecodeAccelerator::OnSetCdm(int cdm_id) { @@ -489,40 +380,17 @@ void GpuVideoDecodeAccelerator::OnSetCdm(int cdm_id) { video_decode_accelerator_->SetCdm(cdm_id); } -// Runs on IO thread if video_decode_accelerator_->CanDecodeOnIOThread() is -// true, otherwise on the main thread. +// Runs on IO thread if VDA::TryToSetupDecodeOnSeparateThread() succeeded, +// otherwise on the main thread. void GpuVideoDecodeAccelerator::OnDecode( - const AcceleratedVideoDecoderMsg_Decode_Params& params) { + const media::BitstreamBuffer& bitstream_buffer) { DCHECK(video_decode_accelerator_); - if (params.bitstream_buffer_id < 0) { - DLOG(ERROR) << "BitstreamBuffer id " << params.bitstream_buffer_id - << " out of range"; - if (child_task_runner_->BelongsToCurrentThread()) { - NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); - } else { - child_task_runner_->PostTask( - FROM_HERE, - base::Bind(&GpuVideoDecodeAccelerator::NotifyError, - base::Unretained(this), - media::VideoDecodeAccelerator::INVALID_ARGUMENT)); - } - return; - } - - media::BitstreamBuffer bitstream_buffer(params.bitstream_buffer_id, - params.buffer_handle, params.size, - params.presentation_timestamp); - if (!params.key_id.empty()) { - bitstream_buffer.SetDecryptConfig( - media::DecryptConfig(params.key_id, params.iv, params.subsamples)); - } - video_decode_accelerator_->Decode(bitstream_buffer); } void GpuVideoDecodeAccelerator::OnAssignPictureBuffers( const std::vector<int32_t>& buffer_ids, - const std::vector<uint32_t>& texture_ids) { + const std::vector<media::PictureBuffer::TextureIds>& texture_ids) { if (buffer_ids.size() != texture_ids.size()) { NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); return; @@ -540,51 +408,65 @@ void GpuVideoDecodeAccelerator::OnAssignPictureBuffers( NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); return; } - gpu::gles2::TextureRef* texture_ref = texture_manager->GetTexture( - texture_ids[i]); - if (!texture_ref) { - DLOG(ERROR) << "Failed to find texture id " << texture_ids[i]; - NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); - return; - } - gpu::gles2::Texture* info = texture_ref->texture(); - if (info->target() != texture_target_) { - DLOG(ERROR) << "Texture target mismatch for texture id " - << texture_ids[i]; + media::PictureBuffer::TextureIds buffer_texture_ids = texture_ids[i]; + media::PictureBuffer::TextureIds service_ids; + if (buffer_texture_ids.size() != textures_per_buffer_) { + DLOG(ERROR) << "Requested " << textures_per_buffer_ + << " textures per picture buffer, got " + << buffer_texture_ids.size(); NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); return; } - if (texture_target_ == GL_TEXTURE_EXTERNAL_OES || - texture_target_ == GL_TEXTURE_RECTANGLE_ARB) { - // These textures have their dimensions defined by the underlying storage. - // Use |texture_dimensions_| for this size. - texture_manager->SetLevelInfo( - texture_ref, texture_target_, 0, GL_RGBA, texture_dimensions_.width(), - texture_dimensions_.height(), 1, 0, GL_RGBA, 0, gfx::Rect()); - } else { - // For other targets, texture dimensions should already be defined. - GLsizei width = 0, height = 0; - info->GetLevelSize(texture_target_, 0, &width, &height, nullptr); - if (width != texture_dimensions_.width() || - height != texture_dimensions_.height()) { - DLOG(ERROR) << "Size mismatch for texture id " << texture_ids[i]; + for (size_t j = 0; j < textures_per_buffer_; j++) { + gpu::gles2::TextureRef* texture_ref = + texture_manager->GetTexture(buffer_texture_ids[j]); + if (!texture_ref) { + DLOG(ERROR) << "Failed to find texture id " << buffer_texture_ids[j]; NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); return; } - - // TODO(dshwang): after moving to D3D11, remove this. crbug.com/438691 - GLenum format = - video_decode_accelerator_.get()->GetSurfaceInternalFormat(); - if (format != GL_RGBA) { - texture_manager->SetLevelInfo(texture_ref, texture_target_, 0, format, - width, height, 1, 0, format, 0, - gfx::Rect()); + gpu::gles2::Texture* info = texture_ref->texture(); + if (info->target() != texture_target_) { + DLOG(ERROR) << "Texture target mismatch for texture id " + << buffer_texture_ids[j]; + NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); + return; + } + if (texture_target_ == GL_TEXTURE_EXTERNAL_OES || + texture_target_ == GL_TEXTURE_RECTANGLE_ARB) { + // These textures have their dimensions defined by the underlying + // storage. + // Use |texture_dimensions_| for this size. + texture_manager->SetLevelInfo(texture_ref, texture_target_, 0, GL_RGBA, + texture_dimensions_.width(), + texture_dimensions_.height(), 1, 0, + GL_RGBA, 0, gfx::Rect()); + } else { + // For other targets, texture dimensions should already be defined. + GLsizei width = 0, height = 0; + info->GetLevelSize(texture_target_, 0, &width, &height, nullptr); + if (width != texture_dimensions_.width() || + height != texture_dimensions_.height()) { + DLOG(ERROR) << "Size mismatch for texture id " + << buffer_texture_ids[j]; + NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); + return; + } + + // TODO(dshwang): after moving to D3D11, remove this. crbug.com/438691 + GLenum format = + video_decode_accelerator_.get()->GetSurfaceInternalFormat(); + if (format != GL_RGBA) { + texture_manager->SetLevelInfo(texture_ref, texture_target_, 0, format, + width, height, 1, 0, format, 0, + gfx::Rect()); + } } + service_ids.push_back(texture_ref->service_id()); + textures.push_back(texture_ref); } buffers.push_back(media::PictureBuffer(buffer_ids[i], texture_dimensions_, - texture_ref->service_id(), - texture_ids[i])); - textures.push_back(texture_ref); + service_ids, buffer_texture_ids)); } video_decode_accelerator_->AssignPictureBuffers(buffers); DebugAutoLock auto_lock(debug_uncleared_textures_lock_); @@ -637,10 +519,4 @@ void GpuVideoDecodeAccelerator::SetTextureCleared( uncleared_textures_.erase(it); } -void GpuVideoDecodeAccelerator::SendCreateDecoderReply(IPC::Message* message, - bool succeeded) { - GpuCommandBufferMsg_CreateVideoDecoder::WriteReplyParams(message, succeeded); - Send(message); -} - } // namespace content diff --git a/chromium/content/common/gpu/media/gpu_video_decode_accelerator.h b/chromium/content/common/gpu/media/gpu_video_decode_accelerator.h index eb6459b37c3..47859d957f9 100644 --- a/chromium/content/common/gpu/media/gpu_video_decode_accelerator.h +++ b/chromium/content/common/gpu/media/gpu_video_decode_accelerator.h @@ -15,15 +15,19 @@ #include "base/memory/ref_counted.h" #include "base/memory/shared_memory.h" #include "base/synchronization/waitable_event.h" -#include "content/common/gpu/gpu_command_buffer_stub.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" #include "gpu/command_buffer/service/texture_manager.h" #include "gpu/config/gpu_info.h" +#include "gpu/ipc/service/gpu_command_buffer_stub.h" +#include "gpu/ipc/service/gpu_command_buffer_stub.h" #include "ipc/ipc_listener.h" #include "ipc/ipc_sender.h" #include "media/video/video_decode_accelerator.h" #include "ui/gfx/geometry/size.h" -struct AcceleratedVideoDecoderMsg_Decode_Params; +namespace gpu { +struct GpuPreferences; +} // namespace gpu namespace content { @@ -31,27 +35,29 @@ class GpuVideoDecodeAccelerator : public IPC::Listener, public IPC::Sender, public media::VideoDecodeAccelerator::Client, - public GpuCommandBufferStub::DestructionObserver { + public gpu::GpuCommandBufferStub::DestructionObserver { public: // Each of the arguments to the constructor must outlive this object. // |stub->decoder()| will be made current around any operation that touches // the underlying VDA so that it can make GL calls safely. GpuVideoDecodeAccelerator( int32_t host_route_id, - GpuCommandBufferStub* stub, + gpu::GpuCommandBufferStub* stub, const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner); // Static query for the capabilities, which includes the supported profiles. // This query calls the appropriate platform-specific version. The returned // capabilities will not contain duplicate supported profile entries. - static gpu::VideoDecodeAcceleratorCapabilities GetCapabilities(); + static gpu::VideoDecodeAcceleratorCapabilities GetCapabilities( + const gpu::GpuPreferences& gpu_preferences); // IPC::Listener implementation. bool OnMessageReceived(const IPC::Message& message) override; // media::VideoDecodeAccelerator::Client implementation. - void NotifyCdmAttached(bool success) override; + void NotifyInitializationComplete(bool success) override; void ProvidePictureBuffers(uint32_t requested_num_of_buffers, + uint32_t textures_per_buffer, const gfx::Size& dimensions, uint32_t texture_target) override; void DismissPictureBuffer(int32_t picture_buffer_id) override; @@ -69,33 +75,22 @@ class GpuVideoDecodeAccelerator // Initialize VDAs from the set of VDAs supported for current platform until // one of them succeeds for given |config|. Send the |init_done_msg| when - // done. filter_ is passed to GpuCommandBufferStub channel only if the chosen - // VDA can decode on IO thread. - void Initialize(const media::VideoDecodeAccelerator::Config& config, - IPC::Message* init_done_msg); + // done. filter_ is passed to gpu::GpuCommandBufferStub channel only if the + // chosen VDA can decode on IO thread. + bool Initialize(const media::VideoDecodeAccelerator::Config& config); private: - typedef scoped_ptr<media::VideoDecodeAccelerator>( - GpuVideoDecodeAccelerator::*CreateVDAFp)(); - class MessageFilter; - scoped_ptr<media::VideoDecodeAccelerator> CreateDXVAVDA(); - scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2VDA(); - scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2SliceVDA(); - scoped_ptr<media::VideoDecodeAccelerator> CreateVaapiVDA(); - scoped_ptr<media::VideoDecodeAccelerator> CreateVTVDA(); - scoped_ptr<media::VideoDecodeAccelerator> CreateOzoneVDA(); - scoped_ptr<media::VideoDecodeAccelerator> CreateAndroidVDA(); - // We only allow self-delete, from OnWillDestroyStub(), after cleanup there. ~GpuVideoDecodeAccelerator() override; // Handlers for IPC messages. void OnSetCdm(int cdm_id); - void OnDecode(const AcceleratedVideoDecoderMsg_Decode_Params& params); - void OnAssignPictureBuffers(const std::vector<int32_t>& buffer_ids, - const std::vector<uint32_t>& texture_ids); + void OnDecode(const media::BitstreamBuffer& bitstream_buffer); + void OnAssignPictureBuffers( + const std::vector<int32_t>& buffer_ids, + const std::vector<media::PictureBuffer::TextureIds>& texture_ids); void OnReusePictureBuffer(int32_t picture_buffer_id); void OnFlush(); void OnReset(); @@ -107,28 +102,28 @@ class GpuVideoDecodeAccelerator // Sets the texture to cleared. void SetTextureCleared(const media::Picture& picture); - // Helper for replying to the creation request. - void SendCreateDecoderReply(IPC::Message* message, bool succeeded); - - // Helper to bind |image| to the texture specified by |client_texture_id|. - void BindImage(uint32_t client_texture_id, - uint32_t texture_target, - scoped_refptr<gl::GLImage> image); - // Route ID to communicate with the host. const int32_t host_route_id_; - // Unowned pointer to the underlying GpuCommandBufferStub. |this| is + // Unowned pointer to the underlying gpu::GpuCommandBufferStub. |this| is // registered as a DestuctionObserver of |stub_| and will self-delete when // |stub_| is destroyed. - GpuCommandBufferStub* const stub_; + gpu::GpuCommandBufferStub* const stub_; // The underlying VideoDecodeAccelerator. scoped_ptr<media::VideoDecodeAccelerator> video_decode_accelerator_; + // Callback to return current GLContext, if available. + GetGLContextCallback get_gl_context_cb_; + // Callback for making the relevant context current for GL calls. - // Returns false if failed. - base::Callback<bool(void)> make_context_current_; + MakeGLContextCurrentCallback make_context_current_cb_; + + // Callback to bind a GLImage to a given texture id and target. + BindGLImageCallback bind_image_cb_; + + // Callback to return a WeakPtr to GLES2Decoder. + GetGLES2DecoderCallback get_gles2_decoder_cb_; // The texture dimensions as requested by ProvidePictureBuffers(). gfx::Size texture_dimensions_; @@ -136,6 +131,10 @@ class GpuVideoDecodeAccelerator // The texture target as requested by ProvidePictureBuffers(). uint32_t texture_target_; + // The number of textures per picture buffer as requests by + // ProvidePictureBuffers() + uint32_t textures_per_buffer_; + // The message filter to run VDA::Decode on IO thread if VDA supports it. scoped_refptr<MessageFilter> filter_; diff --git a/chromium/content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.cc b/chromium/content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.cc new file mode 100644 index 00000000000..048314863d9 --- /dev/null +++ b/chromium/content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.cc @@ -0,0 +1,242 @@ +// Copyright 2016 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 "content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.h" + +#include "content/common/gpu/media/gpu_video_decode_accelerator.h" +#include "gpu/command_buffer/service/gpu_preferences.h" +#include "media/gpu/ipc/common/gpu_video_accelerator_util.h" + +#if defined(OS_WIN) +#include "base/win/windows_version.h" +#include "content/common/gpu/media/dxva_video_decode_accelerator_win.h" +#elif defined(OS_MACOSX) +#include "content/common/gpu/media/vt_video_decode_accelerator_mac.h" +#elif defined(OS_CHROMEOS) +#if defined(USE_V4L2_CODEC) +#include "content/common/gpu/media/v4l2_device.h" +#include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h" +#include "content/common/gpu/media/v4l2_video_decode_accelerator.h" +#include "ui/gl/gl_surface_egl.h" +#endif +#if defined(ARCH_CPU_X86_FAMILY) +#include "content/common/gpu/media/vaapi_video_decode_accelerator.h" +#include "ui/gl/gl_implementation.h" +#endif +#elif defined(OS_ANDROID) +#include "content/common/gpu/media/android_video_decode_accelerator.h" +#endif + +namespace content { + +namespace { +static base::WeakPtr<gpu::gles2::GLES2Decoder> GetEmptyGLES2Decoder() { + NOTREACHED() << "VDA requests a GLES2Decoder, but client did not provide it"; + return base::WeakPtr<gpu::gles2::GLES2Decoder>(); +} +} + +// static +scoped_ptr<GpuVideoDecodeAcceleratorFactoryImpl> +GpuVideoDecodeAcceleratorFactoryImpl::Create( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb) { + return make_scoped_ptr(new GpuVideoDecodeAcceleratorFactoryImpl( + get_gl_context_cb, make_context_current_cb, bind_image_cb, + base::Bind(&GetEmptyGLES2Decoder))); +} + +// static +scoped_ptr<GpuVideoDecodeAcceleratorFactoryImpl> +GpuVideoDecodeAcceleratorFactoryImpl::CreateWithGLES2Decoder( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb, + const GetGLES2DecoderCallback& get_gles2_decoder_cb) { + return make_scoped_ptr(new GpuVideoDecodeAcceleratorFactoryImpl( + get_gl_context_cb, make_context_current_cb, bind_image_cb, + get_gles2_decoder_cb)); +} + +// static +gpu::VideoDecodeAcceleratorCapabilities +GpuVideoDecodeAcceleratorFactoryImpl::GetDecoderCapabilities( + const gpu::GpuPreferences& gpu_preferences) { + media::VideoDecodeAccelerator::Capabilities capabilities; + if (gpu_preferences.disable_accelerated_video_decode) + return gpu::VideoDecodeAcceleratorCapabilities(); + + // Query VDAs for their capabilities and construct a set of supported + // profiles for current platform. This must be done in the same order as in + // CreateVDA(), as we currently preserve additional capabilities (such as + // resolutions supported) only for the first VDA supporting the given codec + // profile (instead of calculating a superset). + // TODO(posciak,henryhsu): improve this so that we choose a superset of + // resolutions and other supported profile parameters. +#if defined(OS_WIN) + capabilities.supported_profiles = + DXVAVideoDecodeAccelerator::GetSupportedProfiles(); +#elif defined(OS_CHROMEOS) + media::VideoDecodeAccelerator::SupportedProfiles vda_profiles; +#if defined(USE_V4L2_CODEC) + vda_profiles = V4L2VideoDecodeAccelerator::GetSupportedProfiles(); + media::GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles( + vda_profiles, &capabilities.supported_profiles); + vda_profiles = V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles(); + media::GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles( + vda_profiles, &capabilities.supported_profiles); +#endif +#if defined(ARCH_CPU_X86_FAMILY) + vda_profiles = VaapiVideoDecodeAccelerator::GetSupportedProfiles(); + media::GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles( + vda_profiles, &capabilities.supported_profiles); +#endif +#elif defined(OS_MACOSX) + capabilities.supported_profiles = + VTVideoDecodeAccelerator::GetSupportedProfiles(); +#elif defined(OS_ANDROID) + capabilities = + AndroidVideoDecodeAccelerator::GetCapabilities(gpu_preferences); +#endif + return media::GpuVideoAcceleratorUtil::ConvertMediaToGpuDecodeCapabilities( + capabilities); +} + +scoped_ptr<media::VideoDecodeAccelerator> +GpuVideoDecodeAcceleratorFactoryImpl::CreateVDA( + media::VideoDecodeAccelerator::Client* client, + const media::VideoDecodeAccelerator::Config& config, + const gpu::GpuPreferences& gpu_preferences) { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (gpu_preferences.disable_accelerated_video_decode) + return nullptr; + + // Array of Create..VDA() function pointers, potentially usable on current + // platform. This list is ordered by priority, from most to least preferred, + // if applicable. This list must be in the same order as the querying order + // in GetDecoderCapabilities() above. + using CreateVDAFp = scoped_ptr<media::VideoDecodeAccelerator> ( + GpuVideoDecodeAcceleratorFactoryImpl::*)(const gpu::GpuPreferences&) + const; + const CreateVDAFp create_vda_fps[] = { +#if defined(OS_WIN) + &GpuVideoDecodeAcceleratorFactoryImpl::CreateDXVAVDA, +#endif +#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) + &GpuVideoDecodeAcceleratorFactoryImpl::CreateV4L2VDA, + &GpuVideoDecodeAcceleratorFactoryImpl::CreateV4L2SVDA, +#endif +#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) + &GpuVideoDecodeAcceleratorFactoryImpl::CreateVaapiVDA, +#endif +#if defined(OS_MACOSX) + &GpuVideoDecodeAcceleratorFactoryImpl::CreateVTVDA, +#endif +#if defined(OS_ANDROID) + &GpuVideoDecodeAcceleratorFactoryImpl::CreateAndroidVDA, +#endif + }; + + scoped_ptr<media::VideoDecodeAccelerator> vda; + + for (const auto& create_vda_function : create_vda_fps) { + vda = (this->*create_vda_function)(gpu_preferences); + if (vda && vda->Initialize(config, client)) + return vda; + } + + return nullptr; +} + +#if defined(OS_WIN) +scoped_ptr<media::VideoDecodeAccelerator> +GpuVideoDecodeAcceleratorFactoryImpl::CreateDXVAVDA( + const gpu::GpuPreferences& gpu_preferences) const { + scoped_ptr<media::VideoDecodeAccelerator> decoder; + if (base::win::GetVersion() >= base::win::VERSION_WIN7) { + DVLOG(0) << "Initializing DXVA HW decoder for windows."; + decoder.reset(new DXVAVideoDecodeAccelerator( + get_gl_context_cb_, make_context_current_cb_, + gpu_preferences.enable_accelerated_vpx_decode)); + } + return decoder; +} +#endif + +#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) +scoped_ptr<media::VideoDecodeAccelerator> +GpuVideoDecodeAcceleratorFactoryImpl::CreateV4L2VDA( + const gpu::GpuPreferences& gpu_preferences) const { + scoped_ptr<media::VideoDecodeAccelerator> decoder; + scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); + if (device.get()) { + decoder.reset(new V4L2VideoDecodeAccelerator( + gfx::GLSurfaceEGL::GetHardwareDisplay(), get_gl_context_cb_, + make_context_current_cb_, device)); + } + return decoder; +} + +scoped_ptr<media::VideoDecodeAccelerator> +GpuVideoDecodeAcceleratorFactoryImpl::CreateV4L2SVDA( + const gpu::GpuPreferences& gpu_preferences) const { + scoped_ptr<media::VideoDecodeAccelerator> decoder; + scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); + if (device.get()) { + decoder.reset(new V4L2SliceVideoDecodeAccelerator( + device, gfx::GLSurfaceEGL::GetHardwareDisplay(), get_gl_context_cb_, + make_context_current_cb_)); + } + return decoder; +} +#endif + +#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) +scoped_ptr<media::VideoDecodeAccelerator> +GpuVideoDecodeAcceleratorFactoryImpl::CreateVaapiVDA( + const gpu::GpuPreferences& gpu_preferences) const { + scoped_ptr<media::VideoDecodeAccelerator> decoder; + decoder.reset(new VaapiVideoDecodeAccelerator(make_context_current_cb_, + bind_image_cb_)); + return decoder; +} +#endif + +#if defined(OS_MACOSX) +scoped_ptr<media::VideoDecodeAccelerator> +GpuVideoDecodeAcceleratorFactoryImpl::CreateVTVDA( + const gpu::GpuPreferences& gpu_preferences) const { + scoped_ptr<media::VideoDecodeAccelerator> decoder; + decoder.reset( + new VTVideoDecodeAccelerator(make_context_current_cb_, bind_image_cb_)); + return decoder; +} +#endif + +#if defined(OS_ANDROID) +scoped_ptr<media::VideoDecodeAccelerator> +GpuVideoDecodeAcceleratorFactoryImpl::CreateAndroidVDA( + const gpu::GpuPreferences& gpu_preferences) const { + scoped_ptr<media::VideoDecodeAccelerator> decoder; + decoder.reset(new AndroidVideoDecodeAccelerator(make_context_current_cb_, + get_gles2_decoder_cb_)); + return decoder; +} +#endif + +GpuVideoDecodeAcceleratorFactoryImpl::GpuVideoDecodeAcceleratorFactoryImpl( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb, + const GetGLES2DecoderCallback& get_gles2_decoder_cb) + : get_gl_context_cb_(get_gl_context_cb), + make_context_current_cb_(make_context_current_cb), + bind_image_cb_(bind_image_cb), + get_gles2_decoder_cb_(get_gles2_decoder_cb) {} + +GpuVideoDecodeAcceleratorFactoryImpl::~GpuVideoDecodeAcceleratorFactoryImpl() {} + +} // namespace content diff --git a/chromium/content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.h b/chromium/content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.h new file mode 100644 index 00000000000..2d4c10b8c32 --- /dev/null +++ b/chromium/content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.h @@ -0,0 +1,123 @@ +// Copyright 2016 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 CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_DECODE_ACCELERATOR_FACTORY_IMPL_H_ +#define CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_DECODE_ACCELERATOR_FACTORY_IMPL_H_ + +#include "base/callback.h" +#include "base/threading/thread_checker.h" +#include "content/common/content_export.h" +#include "gpu/command_buffer/service/gpu_preferences.h" +#include "gpu/config/gpu_info.h" +#include "media/video/video_decode_accelerator.h" + +namespace gfx { +class GLContext; +} + +namespace gl { +class GLImage; +} + +namespace gpu { +struct GpuPreferences; + +namespace gles2 { +class GLES2Decoder; +} +} + +namespace content { + +// TODO(posciak): this class should be an implementation of +// content::GpuVideoDecodeAcceleratorFactory, however that can only be achieved +// once this is moved out of content/common, see crbug.com/597150 and related. +class CONTENT_EXPORT GpuVideoDecodeAcceleratorFactoryImpl { +public: + ~GpuVideoDecodeAcceleratorFactoryImpl(); + + // Return current GLContext. + using GetGLContextCallback = base::Callback<gfx::GLContext*(void)>; + + // Make the applicable GL context current. To be called by VDAs before + // executing any GL calls. Return true on success, false otherwise. + using MakeGLContextCurrentCallback = base::Callback<bool(void)>; + + // Bind |image| to |client_texture_id| given |texture_target|. If + // |can_bind_to_sampler| is true, then the image may be used as a sampler + // directly, otherwise a copy to a staging buffer is required. + // Return true on success, false otherwise. + using BindGLImageCallback = + base::Callback<bool(uint32_t client_texture_id, + uint32_t texture_target, + const scoped_refptr<gl::GLImage>& image, + bool can_bind_to_sampler)>; + + // Return a WeakPtr to a GLES2Decoder, if one is available. + using GetGLES2DecoderCallback = + base::Callback<base::WeakPtr<gpu::gles2::GLES2Decoder>(void)>; + + static scoped_ptr<GpuVideoDecodeAcceleratorFactoryImpl> Create( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb); + + static scoped_ptr<GpuVideoDecodeAcceleratorFactoryImpl> + CreateWithGLES2Decoder( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb, + const GetGLES2DecoderCallback& get_gles2_decoder_cb); + + static gpu::VideoDecodeAcceleratorCapabilities GetDecoderCapabilities( + const gpu::GpuPreferences& gpu_preferences); + + scoped_ptr<media::VideoDecodeAccelerator> CreateVDA( + media::VideoDecodeAccelerator::Client* client, + const media::VideoDecodeAccelerator::Config& config, + const gpu::GpuPreferences& gpu_preferences); + + private: + GpuVideoDecodeAcceleratorFactoryImpl( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb, + const GetGLES2DecoderCallback& get_gles2_decoder_cb); + +#if defined(OS_WIN) + scoped_ptr<media::VideoDecodeAccelerator> CreateDXVAVDA( + const gpu::GpuPreferences& gpu_preferences) const; +#endif +#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) + scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2VDA( + const gpu::GpuPreferences& gpu_preferences) const; + scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2SVDA( + const gpu::GpuPreferences& gpu_preferences) const; +#endif +#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) + scoped_ptr<media::VideoDecodeAccelerator> CreateVaapiVDA( + const gpu::GpuPreferences& gpu_preferences) const; +#endif +#if defined(OS_MACOSX) + scoped_ptr<media::VideoDecodeAccelerator> CreateVTVDA( + const gpu::GpuPreferences& gpu_preferences) const; +#endif +#if defined(OS_ANDROID) + scoped_ptr<media::VideoDecodeAccelerator> CreateAndroidVDA( + const gpu::GpuPreferences& gpu_preferences) const; +#endif + + const GetGLContextCallback get_gl_context_cb_; + const MakeGLContextCurrentCallback make_context_current_cb_; + const BindGLImageCallback bind_image_cb_; + const GetGLES2DecoderCallback get_gles2_decoder_cb_; + + base::ThreadChecker thread_checker_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(GpuVideoDecodeAcceleratorFactoryImpl); +}; + +} // namespace content + +#endif // CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_DECODE_ACCELERATOR_FACTORY_IMPL_H_ diff --git a/chromium/content/common/gpu/media/gpu_video_decode_accelerator_helpers.h b/chromium/content/common/gpu/media/gpu_video_decode_accelerator_helpers.h new file mode 100644 index 00000000000..1717f592603 --- /dev/null +++ b/chromium/content/common/gpu/media/gpu_video_decode_accelerator_helpers.h @@ -0,0 +1,59 @@ +// Copyright 2016 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 CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_DECODE_ACCELERATOR_HELPERS_H_ +#define CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_DECODE_ACCELERATOR_HELPERS_H_ + +#include "base/callback.h" +#include "base/memory/weak_ptr.h" + +namespace gfx { +class GLContext; +} + +namespace gl { +class GLImage; +} + +namespace gpu { +namespace gles2 { +class GLES2Decoder; +} +} + +namespace content { + +// Helpers/defines for specific VideoDecodeAccelerator implementations in GPU +// process. Which callbacks are required depends on the implementation. +// +// Note that these callbacks may be called more than once, and so must own/share +// ownership of any objects bound to them. +// +// Unless specified otherwise, these callbacks must be executed on the GPU Child +// thread (i.e. the thread which the VDAs are initialized on). + +// Return current GLContext. +using GetGLContextCallback = base::Callback<gfx::GLContext*(void)>; + +// Make the applicable GL context current. To be called by VDAs before +// executing any GL calls. Return true on success, false otherwise. +using MakeGLContextCurrentCallback = base::Callback<bool(void)>; + +// Bind |image| to |client_texture_id| given |texture_target|. If +// |can_bind_to_sampler| is true, then the image may be used as a sampler +// directly, otherwise a copy to a staging buffer is required. +// Return true on success, false otherwise. +using BindGLImageCallback = + base::Callback<bool(uint32_t client_texture_id, + uint32_t texture_target, + const scoped_refptr<gl::GLImage>& image, + bool can_bind_to_sampler)>; + +// Return a WeakPtr to a GLES2Decoder, if one is available. +using GetGLES2DecoderCallback = + base::Callback<base::WeakPtr<gpu::gles2::GLES2Decoder>(void)>; + +} // namespace content + +#endif // CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_DECODE_ACCELERATOR_HELPERS_H_ diff --git a/chromium/content/common/gpu/media/gpu_video_encode_accelerator.cc b/chromium/content/common/gpu/media/gpu_video_encode_accelerator.cc index 7dd9a082b1d..7b1457e88f1 100644 --- a/chromium/content/common/gpu/media/gpu_video_encode_accelerator.cc +++ b/chromium/content/common/gpu/media/gpu_video_encode_accelerator.cc @@ -11,15 +11,15 @@ #include "base/numerics/safe_math.h" #include "base/sys_info.h" #include "build/build_config.h" -#include "content/common/gpu/client/gpu_memory_buffer_impl.h" -#include "content/common/gpu/gpu_channel.h" -#include "content/common/gpu/gpu_messages.h" -#include "content/common/gpu/media/gpu_video_accelerator_util.h" -#include "content/public/common/content_switches.h" +#include "gpu/ipc/client/gpu_memory_buffer_impl.h" +#include "gpu/ipc/service/gpu_channel.h" +#include "gpu/ipc/service/gpu_channel_manager.h" #include "ipc/ipc_message_macros.h" #include "media/base/bind_to_current_loop.h" #include "media/base/limits.h" #include "media/base/video_frame.h" +#include "media/gpu/ipc/common/gpu_video_accelerator_util.h" +#include "media/gpu/ipc/common/media_messages.h" #if defined(OS_CHROMEOS) #if defined(USE_V4L2_CODEC) @@ -30,20 +30,14 @@ #endif #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC) #include "content/common/gpu/media/android_video_encode_accelerator.h" +#elif defined(OS_MACOSX) +#include "content/common/gpu/media/vt_video_encode_accelerator_mac.h" #endif namespace content { -namespace { - -// Allocation and destruction of buffer are done on the Browser process, so we -// don't need to handle synchronization here. -void DestroyGpuMemoryBuffer(const gpu::SyncToken& sync_token) {} - -} // namespace - static bool MakeDecoderContextCurrent( - const base::WeakPtr<GpuCommandBufferStub> stub) { + const base::WeakPtr<gpu::GpuCommandBufferStub> stub) { if (!stub) { DLOG(ERROR) << "Stub is gone; won't MakeCurrent()."; return false; @@ -57,8 +51,9 @@ static bool MakeDecoderContextCurrent( return true; } -GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator(int32_t host_route_id, - GpuCommandBufferStub* stub) +GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator( + int32_t host_route_id, + gpu::GpuCommandBufferStub* stub) : host_route_id_(host_route_id), stub_(stub), input_format_(media::PIXEL_FORMAT_UNKNOWN), @@ -75,12 +70,11 @@ GpuVideoEncodeAccelerator::~GpuVideoEncodeAccelerator() { DCHECK(!encoder_); } -void GpuVideoEncodeAccelerator::Initialize( +bool GpuVideoEncodeAccelerator::Initialize( media::VideoPixelFormat input_format, const gfx::Size& input_visible_size, media::VideoCodecProfile output_profile, - uint32_t initial_bitrate, - IPC::Message* init_done_msg) { + uint32_t initial_bitrate) { DVLOG(2) << "GpuVideoEncodeAccelerator::Initialize(): " "input_format=" << input_format << ", input_visible_size=" << input_visible_size.ToString() @@ -88,11 +82,10 @@ void GpuVideoEncodeAccelerator::Initialize( << ", initial_bitrate=" << initial_bitrate; DCHECK(!encoder_); - if (!stub_->channel()->AddRoute(host_route_id_, this)) { + if (!stub_->channel()->AddRoute(host_route_id_, stub_->stream_id(), this)) { DLOG(ERROR) << "GpuVideoEncodeAccelerator::Initialize(): " "failed to add route"; - SendCreateEncoderReply(init_done_msg, false); - return; + return false; } if (input_visible_size.width() > media::limits::kMaxDimension || @@ -101,12 +94,14 @@ void GpuVideoEncodeAccelerator::Initialize( DLOG(ERROR) << "GpuVideoEncodeAccelerator::Initialize(): " "input_visible_size " << input_visible_size.ToString() << " too large"; - SendCreateEncoderReply(init_done_msg, false); - return; + return false; } - std::vector<GpuVideoEncodeAccelerator::CreateVEAFp> - create_vea_fps = CreateVEAFps(); + const gpu::GpuPreferences& gpu_preferences = + stub_->channel()->gpu_channel_manager()->gpu_preferences(); + + std::vector<GpuVideoEncodeAccelerator::CreateVEAFp> create_vea_fps = + CreateVEAFps(gpu_preferences); // Try all possible encoders and use the first successful encoder. for (size_t i = 0; i < create_vea_fps.size(); ++i) { encoder_ = (*create_vea_fps[i])(); @@ -117,14 +112,13 @@ void GpuVideoEncodeAccelerator::Initialize( this)) { input_format_ = input_format; input_visible_size_ = input_visible_size; - SendCreateEncoderReply(init_done_msg, true); - return; + return true; } } encoder_.reset(); DLOG(ERROR) << "GpuVideoEncodeAccelerator::Initialize(): VEA initialization failed"; - SendCreateEncoderReply(init_done_msg, false); + return false; } bool GpuVideoEncodeAccelerator::OnMessageReceived(const IPC::Message& message) { @@ -176,10 +170,11 @@ void GpuVideoEncodeAccelerator::OnWillDestroyStub() { // static gpu::VideoEncodeAcceleratorSupportedProfiles -GpuVideoEncodeAccelerator::GetSupportedProfiles() { +GpuVideoEncodeAccelerator::GetSupportedProfiles( + const gpu::GpuPreferences& gpu_preferences) { media::VideoEncodeAccelerator::SupportedProfiles profiles; - std::vector<GpuVideoEncodeAccelerator::CreateVEAFp> - create_vea_fps = CreateVEAFps(); + std::vector<GpuVideoEncodeAccelerator::CreateVEAFp> create_vea_fps = + CreateVEAFps(gpu_preferences); for (size_t i = 0; i < create_vea_fps.size(); ++i) { scoped_ptr<media::VideoEncodeAccelerator> @@ -188,55 +183,73 @@ GpuVideoEncodeAccelerator::GetSupportedProfiles() { continue; media::VideoEncodeAccelerator::SupportedProfiles vea_profiles = encoder->GetSupportedProfiles(); - GpuVideoAcceleratorUtil::InsertUniqueEncodeProfiles( - vea_profiles, &profiles); + media::GpuVideoAcceleratorUtil::InsertUniqueEncodeProfiles(vea_profiles, + &profiles); } - return GpuVideoAcceleratorUtil::ConvertMediaToGpuEncodeProfiles(profiles); + return media::GpuVideoAcceleratorUtil::ConvertMediaToGpuEncodeProfiles( + profiles); } // static std::vector<GpuVideoEncodeAccelerator::CreateVEAFp> -GpuVideoEncodeAccelerator::CreateVEAFps() { +GpuVideoEncodeAccelerator::CreateVEAFps( + const gpu::GpuPreferences& gpu_preferences) { std::vector<GpuVideoEncodeAccelerator::CreateVEAFp> create_vea_fps; +#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateV4L2VEA); - create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateVaapiVEA); - create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateAndroidVEA); +#endif +#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) + if (!gpu_preferences.disable_vaapi_accelerated_video_encode) + create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateVaapiVEA); +#endif +#if defined(OS_ANDROID) && defined(ENABLE_WEBRTC) + if (!gpu_preferences.disable_web_rtc_hw_encoding) + create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateAndroidVEA); +#endif +#if defined(OS_MACOSX) + create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateVTVEA); +#endif return create_vea_fps; } +#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) // static scoped_ptr<media::VideoEncodeAccelerator> GpuVideoEncodeAccelerator::CreateV4L2VEA() { scoped_ptr<media::VideoEncodeAccelerator> encoder; -#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kEncoder); if (device) encoder.reset(new V4L2VideoEncodeAccelerator(device)); -#endif return encoder; } +#endif +#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) // static scoped_ptr<media::VideoEncodeAccelerator> GpuVideoEncodeAccelerator::CreateVaapiVEA() { - scoped_ptr<media::VideoEncodeAccelerator> encoder; -#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) - const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); - if (!cmd_line->HasSwitch(switches::kDisableVaapiAcceleratedVideoEncode)) - encoder.reset(new VaapiVideoEncodeAccelerator()); -#endif - return encoder; + return make_scoped_ptr<media::VideoEncodeAccelerator>( + new VaapiVideoEncodeAccelerator()); } +#endif +#if defined(OS_ANDROID) && defined(ENABLE_WEBRTC) // static scoped_ptr<media::VideoEncodeAccelerator> GpuVideoEncodeAccelerator::CreateAndroidVEA() { - scoped_ptr<media::VideoEncodeAccelerator> encoder; -#if defined(OS_ANDROID) && defined(ENABLE_WEBRTC) - encoder.reset(new AndroidVideoEncodeAccelerator()); + return make_scoped_ptr<media::VideoEncodeAccelerator>( + new AndroidVideoEncodeAccelerator()); +} #endif - return encoder; + +#if defined(OS_MACOSX) +// static +scoped_ptr<media::VideoEncodeAccelerator> +GpuVideoEncodeAccelerator::CreateVTVEA() { + return make_scoped_ptr<media::VideoEncodeAccelerator>( + new VTVideoEncodeAccelerator()); } +#endif void GpuVideoEncodeAccelerator::OnEncode( const AcceleratedVideoEncoderMsg_Encode_Params& params) { @@ -315,79 +328,8 @@ void GpuVideoEncodeAccelerator::OnEncode2( << params.frame_id << ", size=" << params.size.ToString() << ", force_keyframe=" << params.force_keyframe << ", handle type=" << params.gpu_memory_buffer_handles[0].type; - DCHECK_EQ(media::PIXEL_FORMAT_I420, input_format_); - DCHECK_EQ(media::VideoFrame::NumPlanes(input_format_), - params.gpu_memory_buffer_handles.size()); - - bool map_result = true; - uint8_t* data[media::VideoFrame::kMaxPlanes]; - int32_t strides[media::VideoFrame::kMaxPlanes]; - ScopedVector<gfx::GpuMemoryBuffer> buffers; - const auto& handles = params.gpu_memory_buffer_handles; - for (size_t i = 0; i < handles.size(); ++i) { - const size_t width = - media::VideoFrame::Columns(i, input_format_, params.size.width()); - const size_t height = - media::VideoFrame::Rows(i, input_format_, params.size.height()); - scoped_ptr<gfx::GpuMemoryBuffer> buffer = - GpuMemoryBufferImpl::CreateFromHandle( - handles[i], gfx::Size(width, height), gfx::BufferFormat::R_8, - gfx::BufferUsage::GPU_READ_CPU_READ_WRITE, - media::BindToCurrentLoop(base::Bind(&DestroyGpuMemoryBuffer))); - - // TODO(emircan): Refactor such that each frame is mapped once. - // See http://crbug/536938. - if (!buffer.get() || !buffer->Map()) { - map_result = false; - continue; - } - - data[i] = reinterpret_cast<uint8_t*>(buffer->memory(0)); - strides[i] = buffer->stride(0); - buffers.push_back(buffer.release()); - } - - if (!map_result) { - DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode2(): " - << "failed to map buffers"; - NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); - return; - } - - if (!encoder_) - return; - - if (params.frame_id < 0) { - DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode2(): invalid frame_id=" - << params.frame_id; - NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); - return; - } - - scoped_refptr<media::VideoFrame> frame = - media::VideoFrame::WrapExternalYuvData( - input_format_, - input_coded_size_, - gfx::Rect(input_visible_size_), - input_visible_size_, - strides[media::VideoFrame::kYPlane], - strides[media::VideoFrame::kUPlane], - strides[media::VideoFrame::kVPlane], - data[media::VideoFrame::kYPlane], - data[media::VideoFrame::kUPlane], - data[media::VideoFrame::kVPlane], - params.timestamp); - if (!frame.get()) { - DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode2(): " - << "could not create a frame"; - NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); - return; - } - frame->AddDestructionObserver(media::BindToCurrentLoop( - base::Bind(&GpuVideoEncodeAccelerator::EncodeFrameFinished2, - weak_this_factory_.GetWeakPtr(), params.frame_id, - base::Passed(&buffers)))); - encoder_->Encode(frame, params.force_keyframe); + // Encoding GpuMemoryBuffer backed frames is not supported. + NOTREACHED(); } void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer( @@ -439,25 +381,8 @@ void GpuVideoEncodeAccelerator::EncodeFrameFinished( // Just let |shm| fall out of scope. } -void GpuVideoEncodeAccelerator::EncodeFrameFinished2( - int32_t frame_id, - ScopedVector<gfx::GpuMemoryBuffer> buffers) { - // TODO(emircan): Consider calling Unmap() in dtor. - for (const auto& buffer : buffers) - buffer->Unmap(); - Send(new AcceleratedVideoEncoderHostMsg_NotifyInputDone(host_route_id_, - frame_id)); - // Just let |buffers| fall out of scope. -} - void GpuVideoEncodeAccelerator::Send(IPC::Message* message) { stub_->channel()->Send(message); } -void GpuVideoEncodeAccelerator::SendCreateEncoderReply(IPC::Message* message, - bool succeeded) { - GpuCommandBufferMsg_CreateVideoEncoder::WriteReplyParams(message, succeeded); - Send(message); -} - } // namespace content diff --git a/chromium/content/common/gpu/media/gpu_video_encode_accelerator.h b/chromium/content/common/gpu/media/gpu_video_encode_accelerator.h index ecc14f28e99..2c2db293db3 100644 --- a/chromium/content/common/gpu/media/gpu_video_encode_accelerator.h +++ b/chromium/content/common/gpu/media/gpu_video_encode_accelerator.h @@ -13,8 +13,8 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" -#include "content/common/gpu/gpu_command_buffer_stub.h" #include "gpu/config/gpu_info.h" +#include "gpu/ipc/service/gpu_command_buffer_stub.h" #include "ipc/ipc_listener.h" #include "media/video/video_encode_accelerator.h" #include "ui/gfx/geometry/size.h" @@ -26,6 +26,10 @@ namespace base { class SharedMemory; } // namespace base +namespace gpu { +struct GpuPreferences; +} // namespace gpu + namespace content { // This class encapsulates the GPU process view of a VideoEncodeAccelerator, @@ -34,18 +38,18 @@ namespace content { class GpuVideoEncodeAccelerator : public IPC::Listener, public media::VideoEncodeAccelerator::Client, - public GpuCommandBufferStub::DestructionObserver { + public gpu::GpuCommandBufferStub::DestructionObserver { public: - GpuVideoEncodeAccelerator(int32_t host_route_id, GpuCommandBufferStub* stub); + GpuVideoEncodeAccelerator(int32_t host_route_id, + gpu::GpuCommandBufferStub* stub); ~GpuVideoEncodeAccelerator() override; // Initialize this accelerator with the given parameters and send // |init_done_msg| when complete. - void Initialize(media::VideoPixelFormat input_format, + bool Initialize(media::VideoPixelFormat input_format, const gfx::Size& input_visible_size, media::VideoCodecProfile output_profile, - uint32_t initial_bitrate, - IPC::Message* init_done_msg); + uint32_t initial_bitrate); // IPC::Listener implementation bool OnMessageReceived(const IPC::Message& message) override; @@ -59,23 +63,34 @@ class GpuVideoEncodeAccelerator bool key_frame) override; void NotifyError(media::VideoEncodeAccelerator::Error error) override; - // GpuCommandBufferStub::DestructionObserver implementation. + // gpu::GpuCommandBufferStub::DestructionObserver implementation. void OnWillDestroyStub() override; // Static query for supported profiles. This query calls the appropriate // platform-specific version. The returned supported profiles vector will // not contain duplicates. - static gpu::VideoEncodeAcceleratorSupportedProfiles GetSupportedProfiles(); + static gpu::VideoEncodeAcceleratorSupportedProfiles GetSupportedProfiles( + const gpu::GpuPreferences& gpu_preferences); private: typedef scoped_ptr<media::VideoEncodeAccelerator>(*CreateVEAFp)(); // Return a set of VEA Create function pointers applicable to the current // platform. - static std::vector<CreateVEAFp> CreateVEAFps(); + static std::vector<CreateVEAFp> CreateVEAFps( + const gpu::GpuPreferences& gpu_preferences); +#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) static scoped_ptr<media::VideoEncodeAccelerator> CreateV4L2VEA(); +#endif +#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) static scoped_ptr<media::VideoEncodeAccelerator> CreateVaapiVEA(); +#endif +#if defined(OS_ANDROID) && defined(ENABLE_WEBRTC) static scoped_ptr<media::VideoEncodeAccelerator> CreateAndroidVEA(); +#endif +#if defined(OS_MACOSX) + static scoped_ptr<media::VideoEncodeAccelerator> CreateVTVEA(); +#endif // IPC handlers, proxying media::VideoEncodeAccelerator for the renderer // process. @@ -90,19 +105,15 @@ class GpuVideoEncodeAccelerator void EncodeFrameFinished(int32_t frame_id, scoped_ptr<base::SharedMemory> shm); - void EncodeFrameFinished2(int32_t frame_id, - ScopedVector<gfx::GpuMemoryBuffer> buffers); void Send(IPC::Message* message); - // Helper for replying to the creation request. - void SendCreateEncoderReply(IPC::Message* message, bool succeeded); // Route ID to communicate with the host. const uint32_t host_route_id_; - // Unowned pointer to the underlying GpuCommandBufferStub. |this| is + // Unowned pointer to the underlying gpu::GpuCommandBufferStub. |this| is // registered as a DestuctionObserver of |stub_| and will self-delete when // |stub_| is destroyed. - GpuCommandBufferStub* const stub_; + gpu::GpuCommandBufferStub* const stub_; // Owned pointer to the underlying VideoEncodeAccelerator. scoped_ptr<media::VideoEncodeAccelerator> encoder_; diff --git a/chromium/content/common/gpu/media/media_channel.cc b/chromium/content/common/gpu/media/media_channel.cc new file mode 100644 index 00000000000..7baeba075e4 --- /dev/null +++ b/chromium/content/common/gpu/media/media_channel.cc @@ -0,0 +1,145 @@ +// Copyright 2016 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 "content/common/gpu/media/media_channel.h" + +#include "content/common/gpu/media/gpu_video_decode_accelerator.h" +#include "content/common/gpu/media/gpu_video_encode_accelerator.h" +#include "gpu/ipc/service/gpu_channel.h" +#include "media/gpu/ipc/common/media_messages.h" + +namespace content { + +namespace { + +void SendCreateJpegDecoderResult( + scoped_ptr<IPC::Message> reply_message, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, + base::WeakPtr<gpu::GpuChannel> channel, + scoped_refptr<gpu::GpuChannelMessageFilter> filter, + bool result) { + GpuChannelMsg_CreateJpegDecoder::WriteReplyParams(reply_message.get(), + result); + if (io_task_runner->BelongsToCurrentThread()) { + filter->Send(reply_message.release()); + } else if (channel) { + channel->Send(reply_message.release()); + } +} + +} // namespace + +class MediaChannelDispatchHelper { + public: + MediaChannelDispatchHelper(MediaChannel* channel, int32_t routing_id) + : channel_(channel), routing_id_(routing_id) {} + + bool Send(IPC::Message* msg) { return channel_->Send(msg); } + + void OnCreateVideoDecoder(const media::VideoDecodeAccelerator::Config& config, + int32_t decoder_route_id, + IPC::Message* reply_message) { + channel_->OnCreateVideoDecoder(routing_id_, config, decoder_route_id, + reply_message); + } + + void OnCreateVideoEncoder(const media::CreateVideoEncoderParams& params, + IPC::Message* reply_message) { + channel_->OnCreateVideoEncoder(routing_id_, params, reply_message); + } + + private: + MediaChannel* const channel_; + const int32_t routing_id_; + DISALLOW_COPY_AND_ASSIGN(MediaChannelDispatchHelper); +}; + +MediaChannel::MediaChannel(gpu::GpuChannel* channel) : channel_(channel) {} + +MediaChannel::~MediaChannel() {} + +bool MediaChannel::Send(IPC::Message* msg) { + return channel_->Send(msg); +} + +bool MediaChannel::OnMessageReceived(const IPC::Message& message) { + MediaChannelDispatchHelper helper(this, message.routing_id()); + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(MediaChannel, message) + IPC_MESSAGE_FORWARD_DELAY_REPLY( + GpuCommandBufferMsg_CreateVideoDecoder, &helper, + MediaChannelDispatchHelper::OnCreateVideoDecoder) + IPC_MESSAGE_FORWARD_DELAY_REPLY( + GpuCommandBufferMsg_CreateVideoEncoder, &helper, + MediaChannelDispatchHelper::OnCreateVideoEncoder) + IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuChannelMsg_CreateJpegDecoder, + OnCreateJpegDecoder) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void MediaChannel::OnCreateJpegDecoder(int32_t route_id, + IPC::Message* reply_msg) { + scoped_ptr<IPC::Message> msg(reply_msg); + if (!jpeg_decoder_) { + jpeg_decoder_.reset( + new GpuJpegDecodeAccelerator(channel_, channel_->io_task_runner())); + } + jpeg_decoder_->AddClient( + route_id, base::Bind(&SendCreateJpegDecoderResult, base::Passed(&msg), + channel_->io_task_runner(), channel_->AsWeakPtr(), + make_scoped_refptr(channel_->filter()))); +} + +void MediaChannel::OnCreateVideoDecoder( + int32_t command_buffer_route_id, + const media::VideoDecodeAccelerator::Config& config, + int32_t decoder_route_id, + IPC::Message* reply_message) { + TRACE_EVENT0("gpu", "MediaChannel::OnCreateVideoDecoder"); + gpu::GpuCommandBufferStub* stub = + channel_->LookupCommandBuffer(command_buffer_route_id); + if (!stub) { + reply_message->set_reply_error(); + Send(reply_message); + return; + } + GpuVideoDecodeAccelerator* decoder = new GpuVideoDecodeAccelerator( + decoder_route_id, stub, stub->channel()->io_task_runner()); + bool succeeded = decoder->Initialize(config); + GpuCommandBufferMsg_CreateVideoDecoder::WriteReplyParams(reply_message, + succeeded); + Send(reply_message); + + // decoder is registered as a DestructionObserver of this stub and will + // self-delete during destruction of this stub. +} + +void MediaChannel::OnCreateVideoEncoder( + int32_t command_buffer_route_id, + const media::CreateVideoEncoderParams& params, + IPC::Message* reply_message) { + TRACE_EVENT0("gpu", "MediaChannel::OnCreateVideoEncoder"); + gpu::GpuCommandBufferStub* stub = + channel_->LookupCommandBuffer(command_buffer_route_id); + if (!stub) { + reply_message->set_reply_error(); + Send(reply_message); + return; + } + GpuVideoEncodeAccelerator* encoder = + new GpuVideoEncodeAccelerator(params.encoder_route_id, stub); + bool succeeded = + encoder->Initialize(params.input_format, params.input_visible_size, + params.output_profile, params.initial_bitrate); + GpuCommandBufferMsg_CreateVideoEncoder::WriteReplyParams(reply_message, + succeeded); + Send(reply_message); + + // encoder is registered as a DestructionObserver of this stub and will + // self-delete during destruction of this stub. +} + +} // namespace content diff --git a/chromium/content/common/gpu/media/media_channel.h b/chromium/content/common/gpu/media/media_channel.h new file mode 100644 index 00000000000..7cfe0378587 --- /dev/null +++ b/chromium/content/common/gpu/media/media_channel.h @@ -0,0 +1,57 @@ +// Copyright 2016 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 CONTENT_COMMON_GPU_MEDIA_MEDIA_CHANNEL_H_ +#define CONTENT_COMMON_GPU_MEDIA_MEDIA_CHANNEL_H_ + +#include "content/common/gpu/media/gpu_jpeg_decode_accelerator.h" +#include "ipc/ipc_listener.h" +#include "ipc/ipc_sender.h" +#include "media/video/video_decode_accelerator.h" + +namespace media { +struct CreateVideoEncoderParams; +} + +namespace gpu { +class GpuChannel; +class GpuCommandBufferStub; +} + +namespace content { + +class MediaChannelDispatchHelper; + +class MediaChannel : public IPC::Listener, public IPC::Sender { + public: + explicit MediaChannel(gpu::GpuChannel* channel); + ~MediaChannel() override; + + // IPC::Sender implementation: + bool Send(IPC::Message* msg) override; + + private: + friend class MediaChannelDispatchHelper; + + // IPC::Listener implementation: + bool OnMessageReceived(const IPC::Message& message) override; + + // Message handlers. + void OnCreateJpegDecoder(int32_t route_id, IPC::Message* reply_msg); + void OnCreateVideoDecoder(int32_t command_buffer_route_id, + const media::VideoDecodeAccelerator::Config& config, + int32_t route_id, + IPC::Message* reply_message); + void OnCreateVideoEncoder(int32_t command_buffer_route_id, + const media::CreateVideoEncoderParams& params, + IPC::Message* reply_message); + + gpu::GpuChannel* const channel_; + scoped_ptr<GpuJpegDecodeAccelerator> jpeg_decoder_; + DISALLOW_COPY_AND_ASSIGN(MediaChannel); +}; + +} // namespace content + +#endif // CONTENT_COMMON_GPU_MEDIA_MEDIA_CHANNEL_H_ diff --git a/chromium/content/common/gpu/media/media_service.cc b/chromium/content/common/gpu/media/media_service.cc new file mode 100644 index 00000000000..89ec8b1fe50 --- /dev/null +++ b/chromium/content/common/gpu/media/media_service.cc @@ -0,0 +1,40 @@ +// Copyright 2016 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 "content/common/gpu/media/media_service.h" + +#include <utility> + +#include "content/common/gpu/media/gpu_video_decode_accelerator.h" +#include "content/common/gpu/media/gpu_video_encode_accelerator.h" +#include "content/common/gpu/media/media_channel.h" +#include "gpu/ipc/service/gpu_channel.h" +#include "gpu/ipc/service/gpu_channel_manager.h" +#include "ipc/ipc_message_macros.h" +#include "ipc/param_traits_macros.h" + +namespace content { + +MediaService::MediaService(gpu::GpuChannelManager* channel_manager) + : channel_manager_(channel_manager) {} + +MediaService::~MediaService() {} + +void MediaService::AddChannel(int32_t client_id) { + gpu::GpuChannel* gpu_channel = channel_manager_->LookupChannel(client_id); + DCHECK(gpu_channel); + scoped_ptr<MediaChannel> media_channel(new MediaChannel(gpu_channel)); + gpu_channel->SetUnhandledMessageListener(media_channel.get()); + media_channels_.set(client_id, std::move(media_channel)); +} + +void MediaService::RemoveChannel(int32_t client_id) { + media_channels_.erase(client_id); +} + +void MediaService::DestroyAllChannels() { + media_channels_.clear(); +} + +} // namespace content diff --git a/chromium/content/common/gpu/media/media_service.h b/chromium/content/common/gpu/media/media_service.h new file mode 100644 index 00000000000..15dca82260a --- /dev/null +++ b/chromium/content/common/gpu/media/media_service.h @@ -0,0 +1,42 @@ +// Copyright 2016 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 CONTENT_COMMON_GPU_MEDIA_MEDIA_SERVICE_H_ +#define CONTENT_COMMON_GPU_MEDIA_MEDIA_SERVICE_H_ + +#include <stdint.h> + +#include "base/containers/scoped_ptr_hash_map.h" +#include "base/macros.h" +#include "ipc/ipc_listener.h" +#include "ipc/ipc_sender.h" +#include "media/video/video_decode_accelerator.h" + +namespace gpu { +class GpuChannel; +class GpuChannelManager; +} + +namespace content { + +class MediaChannel; + +class MediaService { + public: + MediaService(gpu::GpuChannelManager* channel_manager); + ~MediaService(); + + void AddChannel(int32_t client_id); + void RemoveChannel(int32_t client_id); + void DestroyAllChannels(); + + private: + gpu::GpuChannelManager* const channel_manager_; + base::ScopedPtrHashMap<int32_t, scoped_ptr<MediaChannel>> media_channels_; + DISALLOW_COPY_AND_ASSIGN(MediaService); +}; + +} // namespace content + +#endif // CONTENT_COMMON_GPU_MEDIA_MEDIA_SERVICE_H_ diff --git a/chromium/content/common/gpu/media/rendering_helper.cc b/chromium/content/common/gpu/media/rendering_helper.cc index 85bfe0a840d..2a19428b2d0 100644 --- a/chromium/content/common/gpu/media/rendering_helper.cc +++ b/chromium/content/common/gpu/media/rendering_helper.cc @@ -160,6 +160,9 @@ RenderingHelperParams::RenderingHelperParams() : rendering_fps(0), warm_up_iterations(0), render_as_thumbnails(false) { } +RenderingHelperParams::RenderingHelperParams( + const RenderingHelperParams& other) = default; + RenderingHelperParams::~RenderingHelperParams() {} VideoFrameTexture::VideoFrameTexture(uint32_t texture_target, @@ -179,6 +182,9 @@ RenderingHelper::RenderedVideo::RenderedVideo() : is_flushing(false), frames_to_drop(0) { } +RenderingHelper::RenderedVideo::RenderedVideo(const RenderedVideo& other) = + default; + RenderingHelper::RenderedVideo::~RenderedVideo() { } @@ -665,12 +671,8 @@ void RenderingHelper::DeleteTexture(uint32_t texture_id) { CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); } -scoped_refptr<gfx::GLContext> RenderingHelper::GetGLContext() { - return gl_context_; -} - -void* RenderingHelper::GetGLContextHandle() { - return gl_context_->GetHandle(); +gfx::GLContext* RenderingHelper::GetGLContext() { + return gl_context_.get(); } void* RenderingHelper::GetGLDisplay() { diff --git a/chromium/content/common/gpu/media/rendering_helper.h b/chromium/content/common/gpu/media/rendering_helper.h index 8a6c28bd3f7..250d382ac61 100644 --- a/chromium/content/common/gpu/media/rendering_helper.h +++ b/chromium/content/common/gpu/media/rendering_helper.h @@ -54,6 +54,7 @@ class VideoFrameTexture : public base::RefCounted<VideoFrameTexture> { struct RenderingHelperParams { RenderingHelperParams(); + RenderingHelperParams(const RenderingHelperParams& other); ~RenderingHelperParams(); // The rendering FPS. @@ -135,10 +136,7 @@ class RenderingHelper { void* GetGLDisplay(); // Get the GL context. - scoped_refptr<gfx::GLContext> GetGLContext(); - - // Get the platform specific handle to the OpenGL context. - void* GetGLContextHandle(); + gfx::GLContext* GetGLContext(); // Get rendered thumbnails as RGB. // Sets alpha_solid to true if the alpha channel is entirely 0xff. @@ -165,6 +163,7 @@ class RenderingHelper { std::queue<scoped_refptr<VideoFrameTexture> > pending_frames; RenderedVideo(); + RenderedVideo(const RenderedVideo& other); ~RenderedVideo(); }; diff --git a/chromium/content/common/gpu/media/shared_memory_region.cc b/chromium/content/common/gpu/media/shared_memory_region.cc new file mode 100644 index 00000000000..4ee6a242578 --- /dev/null +++ b/chromium/content/common/gpu/media/shared_memory_region.cc @@ -0,0 +1,42 @@ +// Copyright (c) 2015 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 "base/sys_info.h" +#include "content/common/gpu/media/shared_memory_region.h" + +namespace content { + +SharedMemoryRegion::SharedMemoryRegion(const base::SharedMemoryHandle& handle, + off_t offset, + size_t size, + bool read_only) + : shm_(handle, read_only), + offset_(offset), + size_(size), + alignment_size_(offset % base::SysInfo::VMAllocationGranularity()) { + DCHECK_GE(offset_, 0) << "Invalid offset: " << offset_; +} + +SharedMemoryRegion::SharedMemoryRegion( + const media::BitstreamBuffer& bitstream_buffer, + bool read_only) + : SharedMemoryRegion(bitstream_buffer.handle(), + bitstream_buffer.offset(), + bitstream_buffer.size(), + read_only) {} + +bool SharedMemoryRegion::Map() { + if (offset_ < 0) { + DVLOG(1) << "Invalid offset: " << offset_; + return false; + } + return shm_.MapAt(offset_ - alignment_size_, size_ + alignment_size_); +} + +void* SharedMemoryRegion::memory() { + int8_t* addr = reinterpret_cast<int8_t*>(shm_.memory()); + return addr ? addr + alignment_size_ : nullptr; +} + +} // namespace content diff --git a/chromium/content/common/gpu/media/shared_memory_region.h b/chromium/content/common/gpu/media/shared_memory_region.h new file mode 100644 index 00000000000..f7c5db29982 --- /dev/null +++ b/chromium/content/common/gpu/media/shared_memory_region.h @@ -0,0 +1,57 @@ +// Copyright (c) 2015 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 CONTENT_COMMON_GPU_MEDIA_SHARED_MEMORY_REGION_H_ +#define CONTENT_COMMON_GPU_MEDIA_SHARED_MEMORY_REGION_H_ + +#include "base/memory/shared_memory.h" +#include "media/base/bitstream_buffer.h" + +namespace content { + +// Helper class to access a region of a SharedMemory. Different from +// SharedMemory, in which the |offset| of function MapAt() must be aligned to +// the value of |SysInfo::VMAllocationGranularity()|, the |offset| of a +// SharedMemoryRegion needs not to be aligned, this class hides the details +// and returns the mapped address of the given offset. +class SharedMemoryRegion { + public: + // Creates a SharedMemoryRegion. + // The mapped memory region begins at |offset| bytes from the start of the + // shared memory and the length is |size|. It will take the ownership of + // the |handle| and release the resource when being destroyed. Different + // from SharedMemory, the |offset| needs not to be aligned to the value of + // |SysInfo::VMAllocationGranularity()|. + SharedMemoryRegion(const base::SharedMemoryHandle& handle, + off_t offset, + size_t size, + bool read_only); + + // Creates a SharedMemoryRegion from the given |bistream_buffer|. + SharedMemoryRegion(const media::BitstreamBuffer& bitstream_buffer, + bool read_only); + + // Maps the shared memory into the caller's address space. + // Return true on success, false otherwise. + bool Map(); + + // Gets a pointer to the mapped region if it has been mapped via Map(). + // Returns |nullptr| if it is not mapped. The returned pointer points + // to the memory at the offset previously passed to the constructor. + void* memory(); + + size_t size() const { return size_; } + + private: + base::SharedMemory shm_; + off_t offset_; + size_t size_; + size_t alignment_size_; + + DISALLOW_COPY_AND_ASSIGN(SharedMemoryRegion); +}; + +} // namespace content + +#endif // CONTENT_COMMON_GPU_MEDIA_SHARED_MEMORY_REGION_H_ diff --git a/chromium/content/common/gpu/media/v4l2_image_processor.cc b/chromium/content/common/gpu/media/v4l2_image_processor.cc index f0cf3977774..340a1484335 100644 --- a/chromium/content/common/gpu/media/v4l2_image_processor.cc +++ b/chromium/content/common/gpu/media/v4l2_image_processor.cc @@ -468,24 +468,22 @@ void V4L2ImageProcessor::Enqueue() { } } - // TODO(posciak): Fix this to be non-Exynos specific. - // Exynos GSC is liable to race conditions if more than one output buffer is - // simultaneously enqueued, so enqueue just one. - if (output_buffer_queued_count_ == 0 && !free_output_buffers_.empty()) { - const int old_outputs_queued = output_buffer_queued_count_; + const int old_outputs_queued = output_buffer_queued_count_; + while (!free_output_buffers_.empty()) { if (!EnqueueOutputRecord()) return; - if (old_outputs_queued == 0 && output_buffer_queued_count_ != 0) { - // We just started up a previously empty queue. - // Queue state changed; signal interrupt. - if (!device_->SetDevicePollInterrupt()) - return; - // Start VIDIOC_STREAMON if we haven't yet. - if (!output_streamon_) { - __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON, &type); - output_streamon_ = true; - } + } + + if (old_outputs_queued == 0 && output_buffer_queued_count_ != 0) { + // We just started up a previously empty queue. + // Queue state changed; signal interrupt. + if (!device_->SetDevicePollInterrupt()) + return; + // Start VIDIOC_STREAMON if we haven't yet. + if (!output_streamon_) { + __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON, &type); + output_streamon_ = true; } } DCHECK_LE(output_buffer_queued_count_, 1); diff --git a/chromium/content/common/gpu/media/v4l2_jpeg_decode_accelerator.cc b/chromium/content/common/gpu/media/v4l2_jpeg_decode_accelerator.cc index 06091a36b4d..0121eadbc09 100644 --- a/chromium/content/common/gpu/media/v4l2_jpeg_decode_accelerator.cc +++ b/chromium/content/common/gpu/media/v4l2_jpeg_decode_accelerator.cc @@ -112,10 +112,11 @@ V4L2JpegDecodeAccelerator::BufferRecord::~BufferRecord() { } V4L2JpegDecodeAccelerator::JobRecord::JobRecord( - media::BitstreamBuffer bitstream_buffer, + const media::BitstreamBuffer& bitstream_buffer, scoped_refptr<media::VideoFrame> video_frame) - : bitstream_buffer(bitstream_buffer), out_frame(video_frame) { -} + : bitstream_buffer_id(bitstream_buffer.id()), + shm(bitstream_buffer, true), + out_frame(video_frame) {} V4L2JpegDecodeAccelerator::JobRecord::~JobRecord() { } @@ -233,6 +234,14 @@ void V4L2JpegDecodeAccelerator::Decode( << ", size=" << bitstream_buffer.size(); DCHECK(io_task_runner_->BelongsToCurrentThread()); + if (bitstream_buffer.id() < 0) { + LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id(); + if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle())) + base::SharedMemory::CloseHandle(bitstream_buffer.handle()); + PostNotifyError(bitstream_buffer.id(), INVALID_ARGUMENT); + return; + } + if (video_frame->format() != media::PIXEL_FORMAT_I420) { PostNotifyError(bitstream_buffer.id(), UNSUPPORTED_JPEG); return; @@ -260,11 +269,9 @@ bool V4L2JpegDecodeAccelerator::IsSupported() { void V4L2JpegDecodeAccelerator::DecodeTask(scoped_ptr<JobRecord> job_record) { DCHECK(decoder_task_runner_->BelongsToCurrentThread()); - job_record->shm.reset( - new base::SharedMemory(job_record->bitstream_buffer.handle(), true)); - if (!job_record->shm->Map(job_record->bitstream_buffer.size())) { + if (!job_record->shm.Map()) { PLOG(ERROR) << __func__ << ": could not map bitstream_buffer"; - PostNotifyError(job_record->bitstream_buffer.id(), UNREADABLE_INPUT); + PostNotifyError(job_record->bitstream_buffer_id, UNREADABLE_INPUT); return; } input_jobs_.push(make_linked_ptr(job_record.release())); @@ -288,7 +295,7 @@ bool V4L2JpegDecodeAccelerator::ShouldRecreateInputBuffers() { linked_ptr<JobRecord> job_record = input_jobs_.front(); // Check input buffer size is enough return (input_buffer_map_.empty() || - (job_record->bitstream_buffer.size() + sizeof(kDefaultDhtSeg)) > + (job_record->shm.size() + sizeof(kDefaultDhtSeg)) > input_buffer_map_.front().length); } @@ -333,8 +340,7 @@ bool V4L2JpegDecodeAccelerator::CreateInputBuffers() { // The input image may miss huffman table. We didn't parse the image before, // so we create more to avoid the situation of not enough memory. // Reserve twice size to avoid recreating input buffer frequently. - size_t reserve_size = - (job_record->bitstream_buffer.size() + sizeof(kDefaultDhtSeg)) * 2; + size_t reserve_size = (job_record->shm.size() + sizeof(kDefaultDhtSeg)) * 2; struct v4l2_format format; memset(&format, 0, sizeof(format)); format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; @@ -711,17 +717,16 @@ void V4L2JpegDecodeAccelerator::Dequeue() { // V4L2_PIX_FMT_YUV420. if (!CopyOutputImage(output_buffer_pixelformat_, output_record.address, output_buffer_coded_size_, job_record->out_frame)) { - PostNotifyError(job_record->bitstream_buffer.id(), PLATFORM_FAILURE); + PostNotifyError(job_record->bitstream_buffer_id, PLATFORM_FAILURE); return; } DVLOG(3) << "Decoding finished, returning bitstream buffer, id=" - << job_record->bitstream_buffer.id(); + << job_record->bitstream_buffer_id; child_task_runner_->PostTask( - FROM_HERE, - base::Bind(&V4L2JpegDecodeAccelerator::VideoFrameReady, weak_ptr_, - job_record->bitstream_buffer.id())); + FROM_HERE, base::Bind(&V4L2JpegDecodeAccelerator::VideoFrameReady, + weak_ptr_, job_record->bitstream_buffer_id)); } } } @@ -819,10 +824,9 @@ bool V4L2JpegDecodeAccelerator::EnqueueInputRecord() { DCHECK(!input_record.at_device); // It will add default huffman segment if it's missing. - if (!AddHuffmanTable(job_record->shm->memory(), - job_record->bitstream_buffer.size(), + if (!AddHuffmanTable(job_record->shm.memory(), job_record->shm.size(), input_record.address, input_record.length)) { - PostNotifyError(job_record->bitstream_buffer.id(), PARSE_JPEG_FAILED); + PostNotifyError(job_record->bitstream_buffer_id, PARSE_JPEG_FAILED); return false; } @@ -836,8 +840,9 @@ bool V4L2JpegDecodeAccelerator::EnqueueInputRecord() { running_jobs_.push(job_record); free_input_buffers_.pop_back(); - DVLOG(3) << __func__ << ": enqueued frame id=" - << job_record->bitstream_buffer.id() << " to device."; + DVLOG(3) << __func__ + << ": enqueued frame id=" << job_record->bitstream_buffer_id + << " to device."; return true; } diff --git a/chromium/content/common/gpu/media/v4l2_jpeg_decode_accelerator.h b/chromium/content/common/gpu/media/v4l2_jpeg_decode_accelerator.h index 435808012ec..bef33b22c10 100644 --- a/chromium/content/common/gpu/media/v4l2_jpeg_decode_accelerator.h +++ b/chromium/content/common/gpu/media/v4l2_jpeg_decode_accelerator.h @@ -18,6 +18,7 @@ #include "base/single_thread_task_runner.h" #include "base/threading/thread.h" #include "content/common/content_export.h" +#include "content/common/gpu/media/shared_memory_region.h" #include "content/common/gpu/media/v4l2_device.h" #include "media/base/bitstream_buffer.h" #include "media/base/video_frame.h" @@ -58,16 +59,16 @@ class CONTENT_EXPORT V4L2JpegDecodeAccelerator // the time of submission we may not have one available (and don't need one // to submit input to the device). struct JobRecord { - JobRecord(media::BitstreamBuffer bitstream_buffer, + JobRecord(const media::BitstreamBuffer& bitstream_buffer, scoped_refptr<media::VideoFrame> video_frame); ~JobRecord(); - // Input image buffer. - media::BitstreamBuffer bitstream_buffer; + // Input image buffer ID. + int32_t bitstream_buffer_id; + // Memory mapped from |bitstream_buffer|. + SharedMemoryRegion shm; // Output frame buffer. scoped_refptr<media::VideoFrame> out_frame; - // Memory mapped from |bitstream_buffer|. - scoped_ptr<base::SharedMemory> shm; }; void EnqueueInput(); diff --git a/chromium/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc b/chromium/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc index 4c3b724daa5..80087232b65 100644 --- a/chromium/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc +++ b/chromium/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc @@ -19,9 +19,11 @@ #include "base/macros.h" #include "base/numerics/safe_conversions.h" #include "base/strings/stringprintf.h" +#include "content/common/gpu/media/shared_memory_region.h" #include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h" #include "media/base/bind_to_current_loop.h" #include "media/base/media_switches.h" +#include "ui/gl/gl_context.h" #include "ui/gl/scoped_binders.h" #define LOGF(level) LOG(level) << __FUNCTION__ << "(): " @@ -169,14 +171,12 @@ struct V4L2SliceVideoDecodeAccelerator::BitstreamBufferRef { BitstreamBufferRef( base::WeakPtr<VideoDecodeAccelerator::Client>& client, const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, - base::SharedMemory* shm, - size_t size, + SharedMemoryRegion* shm, int32_t input_id); ~BitstreamBufferRef(); const base::WeakPtr<VideoDecodeAccelerator::Client> client; const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner; - const scoped_ptr<base::SharedMemory> shm; - const size_t size; + const scoped_ptr<SharedMemoryRegion> shm; off_t bytes_used; const int32_t input_id; }; @@ -184,13 +184,11 @@ struct V4L2SliceVideoDecodeAccelerator::BitstreamBufferRef { V4L2SliceVideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef( base::WeakPtr<VideoDecodeAccelerator::Client>& client, const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, - base::SharedMemory* shm, - size_t size, + SharedMemoryRegion* shm, int32_t input_id) : client(client), client_task_runner(client_task_runner), shm(shm), - size(size), bytes_used(0), input_id(input_id) {} @@ -382,15 +380,11 @@ V4L2VP8Picture::~V4L2VP8Picture() { V4L2SliceVideoDecodeAccelerator::V4L2SliceVideoDecodeAccelerator( const scoped_refptr<V4L2Device>& device, EGLDisplay egl_display, - EGLContext egl_context, - const base::WeakPtr<Client>& io_client, - const base::Callback<bool(void)>& make_context_current, - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb) : input_planes_count_(0), output_planes_count_(0), child_task_runner_(base::ThreadTaskRunnerHandle::Get()), - io_task_runner_(io_task_runner), - io_client_(io_client), device_(device), decoder_thread_("V4L2SliceVideoDecodeAcceleratorThread"), device_poll_thread_("V4L2SliceVideoDecodeAcceleratorDevicePollThread"), @@ -406,9 +400,9 @@ V4L2SliceVideoDecodeAccelerator::V4L2SliceVideoDecodeAccelerator( surface_set_change_pending_(false), picture_clearing_count_(0), pictures_assigned_(false, false), - make_context_current_(make_context_current), egl_display_(egl_display), - egl_context_(egl_context), + get_gl_context_cb_(get_gl_context_cb), + make_context_current_cb_(make_context_current_cb), weak_this_factory_(this) { weak_this_ = weak_this_factory_.GetWeakPtr(); } @@ -444,6 +438,11 @@ bool V4L2SliceVideoDecodeAccelerator::Initialize(const Config& config, DCHECK(child_task_runner_->BelongsToCurrentThread()); DCHECK_EQ(state_, kUninitialized); + if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { + NOTREACHED() << "GL callbacks are required for this VDA"; + return false; + } + if (config.is_encrypted) { NOTREACHED() << "Encrypted streams are not supported for this VDA"; return false; @@ -459,6 +458,14 @@ bool V4L2SliceVideoDecodeAccelerator::Initialize(const Config& config, client_ptr_factory_.reset( new base::WeakPtrFactory<VideoDecodeAccelerator::Client>(client)); client_ = client_ptr_factory_->GetWeakPtr(); + // If we haven't been set up to decode on separate thread via + // TryToSetupDecodeOnSeparateThread(), use the main thread/client for + // decode tasks. + if (!decode_task_runner_) { + decode_task_runner_ = child_task_runner_; + DCHECK(!decode_client_); + decode_client_ = client_; + } video_profile_ = config.profile; @@ -485,7 +492,7 @@ bool V4L2SliceVideoDecodeAccelerator::Initialize(const Config& config, } // We need the context to be initialized to query extensions. - if (!make_context_current_.Run()) { + if (!make_context_current_cb_.Run()) { LOG(ERROR) << "Initialize(): could not make context current"; return false; } @@ -750,7 +757,7 @@ bool V4L2SliceVideoDecodeAccelerator::CreateOutputBuffers() { child_task_runner_->PostTask( FROM_HERE, base::Bind(&VideoDecodeAccelerator::Client::ProvidePictureBuffers, - client_, num_pictures, coded_size_, + client_, num_pictures, 1, coded_size_, device_->GetTextureTarget())); // Wait for the client to call AssignPictureBuffers() on the Child thread. @@ -1182,7 +1189,15 @@ void V4L2SliceVideoDecodeAccelerator::Decode( const media::BitstreamBuffer& bitstream_buffer) { DVLOGF(3) << "input_id=" << bitstream_buffer.id() << ", size=" << bitstream_buffer.size(); - DCHECK(io_task_runner_->BelongsToCurrentThread()); + DCHECK(decode_task_runner_->BelongsToCurrentThread()); + + if (bitstream_buffer.id() < 0) { + LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id(); + if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle())) + base::SharedMemory::CloseHandle(bitstream_buffer.handle()); + NOTIFY_ERROR(INVALID_ARGUMENT); + return; + } decoder_thread_task_runner_->PostTask( FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::DecodeTask, @@ -1196,10 +1211,9 @@ void V4L2SliceVideoDecodeAccelerator::DecodeTask( DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef( - io_client_, io_task_runner_, - new base::SharedMemory(bitstream_buffer.handle(), true), - bitstream_buffer.size(), bitstream_buffer.id())); - if (!bitstream_record->shm->Map(bitstream_buffer.size())) { + decode_client_, decode_task_runner_, + new SharedMemoryRegion(bitstream_buffer, true), bitstream_buffer.id())); + if (!bitstream_record->shm->Map()) { LOGF(ERROR) << "Could not map bitstream_buffer"; NOTIFY_ERROR(UNREADABLE_INPUT); return; @@ -1231,7 +1245,7 @@ bool V4L2SliceVideoDecodeAccelerator::TrySetNewBistreamBuffer() { const uint8_t* const data = reinterpret_cast<const uint8_t*>( decoder_current_bitstream_buffer_->shm->memory()); - const size_t data_size = decoder_current_bitstream_buffer_->size; + const size_t data_size = decoder_current_bitstream_buffer_->shm->size(); decoder_->SetStream(data, data_size); return true; @@ -1442,8 +1456,9 @@ void V4L2SliceVideoDecodeAccelerator::AssignPictureBuffers( return; } - if (!make_context_current_.Run()) { - DLOG(ERROR) << "could not make context current"; + gfx::GLContext* gl_context = get_gl_context_cb_.Run(); + if (!gl_context || !make_context_current_cb_.Run()) { + DLOG(ERROR) << "No GL context"; NOTIFY_ERROR(PLATFORM_FAILURE); return; } @@ -1481,13 +1496,10 @@ void V4L2SliceVideoDecodeAccelerator::AssignPictureBuffers( DCHECK_EQ(output_record.picture_id, -1); DCHECK_EQ(output_record.cleared, false); - EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, - egl_context_, - buffers[i].texture_id(), - coded_size_, - i, - output_format_fourcc_, - output_planes_count_); + DCHECK_LE(1u, buffers[i].texture_ids().size()); + EGLImageKHR egl_image = device_->CreateEGLImage( + egl_display_, gl_context->GetHandle(), buffers[i].texture_ids()[0], + buffers[i].size(), i, output_format_fourcc_, output_planes_count_); if (egl_image == EGL_NO_IMAGE_KHR) { LOGF(ERROR) << "Could not create EGLImageKHR"; // Ownership of EGLImages allocated in previous iterations of this loop @@ -1511,7 +1523,7 @@ void V4L2SliceVideoDecodeAccelerator::ReusePictureBuffer( DCHECK(child_task_runner_->BelongsToCurrentThread()); DVLOGF(4) << "picture_buffer_id=" << picture_buffer_id; - if (!make_context_current_.Run()) { + if (!make_context_current_cb_.Run()) { LOGF(ERROR) << "could not make context current"; NOTIFY_ERROR(PLATFORM_FAILURE); return; @@ -1587,7 +1599,7 @@ void V4L2SliceVideoDecodeAccelerator::FlushTask() { // which - when reached - will trigger flush sequence. decoder_input_queue_.push( linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( - io_client_, io_task_runner_, nullptr, 0, kFlushBufferId))); + decode_client_, decode_task_runner_, nullptr, kFlushBufferId))); return; } @@ -2501,12 +2513,14 @@ void V4L2SliceVideoDecodeAccelerator::SendPictureReady() { bool cleared = pending_picture_ready_.front().cleared; const media::Picture& picture = pending_picture_ready_.front().picture; if (cleared && picture_clearing_count_ == 0) { - DVLOGF(4) << "Posting picture ready to IO for: " + DVLOGF(4) << "Posting picture ready to decode task runner for: " << picture.picture_buffer_id(); - // This picture is cleared. Post it to IO thread to reduce latency. This - // should be the case after all pictures are cleared at the beginning. - io_task_runner_->PostTask( - FROM_HERE, base::Bind(&Client::PictureReady, io_client_, picture)); + // This picture is cleared. It can be posted to a thread different than + // the main GPU thread to reduce latency. This should be the case after + // all pictures are cleared at the beginning. + decode_task_runner_->PostTask( + FROM_HERE, + base::Bind(&Client::PictureReady, decode_client_, picture)); pending_picture_ready_.pop(); } else if (!cleared || resetting_or_flushing) { DVLOGF(3) << "cleared=" << pending_picture_ready_.front().cleared @@ -2544,7 +2558,11 @@ void V4L2SliceVideoDecodeAccelerator::PictureCleared() { SendPictureReady(); } -bool V4L2SliceVideoDecodeAccelerator::CanDecodeOnIOThread() { +bool V4L2SliceVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { + decode_client_ = decode_client_; + decode_task_runner_ = decode_task_runner; return true; } diff --git a/chromium/content/common/gpu/media/v4l2_slice_video_decode_accelerator.h b/chromium/content/common/gpu/media/v4l2_slice_video_decode_accelerator.h index dd72eb7a6dd..cc11da302a1 100644 --- a/chromium/content/common/gpu/media/v4l2_slice_video_decode_accelerator.h +++ b/chromium/content/common/gpu/media/v4l2_slice_video_decode_accelerator.h @@ -19,6 +19,7 @@ #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "content/common/content_export.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" #include "content/common/gpu/media/h264_decoder.h" #include "content/common/gpu/media/v4l2_device.h" #include "content/common/gpu/media/vp8_decoder.h" @@ -38,10 +39,8 @@ class CONTENT_EXPORT V4L2SliceVideoDecodeAccelerator V4L2SliceVideoDecodeAccelerator( const scoped_refptr<V4L2Device>& device, EGLDisplay egl_display, - EGLContext egl_context, - const base::WeakPtr<Client>& io_client_, - const base::Callback<bool(void)>& make_context_current, - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner); + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb); ~V4L2SliceVideoDecodeAccelerator() override; // media::VideoDecodeAccelerator implementation. @@ -53,7 +52,10 @@ class CONTENT_EXPORT V4L2SliceVideoDecodeAccelerator void Flush() override; void Reset() override; void Destroy() override; - bool CanDecodeOnIOThread() override; + bool TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) + override; static media::VideoDecodeAccelerator::SupportedProfiles GetSupportedProfiles(); @@ -282,8 +284,8 @@ class CONTENT_EXPORT V4L2SliceVideoDecodeAccelerator // GPU Child thread task runner. const scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_; - // IO thread task runner. - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + // Task runner Decode() and PictureReady() run on. + scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner_; // WeakPtr<> pointing to |this| for use in posting tasks from the decoder or // device worker threads back to the child thread. @@ -295,8 +297,8 @@ class CONTENT_EXPORT V4L2SliceVideoDecodeAccelerator scoped_ptr<base::WeakPtrFactory<VideoDecodeAccelerator::Client>> client_ptr_factory_; base::WeakPtr<VideoDecodeAccelerator::Client> client_; - // Callbacks to |io_client_| must be executed on |io_task_runner_|. - base::WeakPtr<Client> io_client_; + // Callbacks to |decode_client_| must be executed on |decode_task_runner_|. + base::WeakPtr<Client> decode_client_; // V4L2 device in use. scoped_refptr<V4L2Device> device_; @@ -381,12 +383,13 @@ class CONTENT_EXPORT V4L2SliceVideoDecodeAccelerator // to avoid races with potential Reset requests. base::WaitableEvent pictures_assigned_; - // Make the GL context current callback. - base::Callback<bool(void)> make_context_current_; - // EGL state EGLDisplay egl_display_; - EGLContext egl_context_; + + // Callback to get current GLContext. + GetGLContextCallback get_gl_context_cb_; + // Callback to set the correct gl context. + MakeGLContextCurrentCallback make_context_current_cb_; // The WeakPtrFactory for |weak_this_|. base::WeakPtrFactory<V4L2SliceVideoDecodeAccelerator> weak_this_factory_; diff --git a/chromium/content/common/gpu/media/v4l2_video_decode_accelerator.cc b/chromium/content/common/gpu/media/v4l2_video_decode_accelerator.cc index f9311257ed7..719dbf7a80f 100644 --- a/chromium/content/common/gpu/media/v4l2_video_decode_accelerator.cc +++ b/chromium/content/common/gpu/media/v4l2_video_decode_accelerator.cc @@ -15,16 +15,17 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/macros.h" -#include "base/memory/shared_memory.h" #include "base/message_loop/message_loop.h" #include "base/numerics/safe_conversions.h" #include "base/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" +#include "content/common/gpu/media/shared_memory_region.h" #include "content/common/gpu/media/v4l2_video_decode_accelerator.h" #include "media/base/media_switches.h" #include "media/filters/h264_parser.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gl/gl_context.h" #include "ui/gl/scoped_binders.h" #define NOTIFY_ERROR(x) \ @@ -65,14 +66,12 @@ struct V4L2VideoDecodeAccelerator::BitstreamBufferRef { BitstreamBufferRef( base::WeakPtr<Client>& client, scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, - base::SharedMemory* shm, - size_t size, + scoped_ptr<SharedMemoryRegion> shm, int32_t input_id); ~BitstreamBufferRef(); const base::WeakPtr<Client> client; const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner; - const scoped_ptr<base::SharedMemory> shm; - const size_t size; + const scoped_ptr<SharedMemoryRegion> shm; size_t bytes_used; const int32_t input_id; }; @@ -94,13 +93,11 @@ struct V4L2VideoDecodeAccelerator::PictureRecord { V4L2VideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef( base::WeakPtr<Client>& client, scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, - base::SharedMemory* shm, - size_t size, + scoped_ptr<SharedMemoryRegion> shm, int32_t input_id) : client(client), client_task_runner(client_task_runner), - shm(shm), - size(size), + shm(std::move(shm)), bytes_used(0), input_id(input_id) {} @@ -157,14 +154,10 @@ V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( EGLDisplay egl_display, - EGLContext egl_context, - const base::WeakPtr<Client>& io_client, - const base::Callback<bool(void)>& make_context_current, - const scoped_refptr<V4L2Device>& device, - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const scoped_refptr<V4L2Device>& device) : child_task_runner_(base::ThreadTaskRunnerHandle::Get()), - io_task_runner_(io_task_runner), - io_client_(io_client), decoder_thread_("V4L2DecoderThread"), decoder_state_(kUninitialized), device_(device), @@ -184,9 +177,9 @@ V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( picture_clearing_count_(0), pictures_assigned_(false, false), device_poll_thread_("V4L2DevicePollThread"), - make_context_current_(make_context_current), egl_display_(egl_display), - egl_context_(egl_context), + get_gl_context_cb_(get_gl_context_cb), + make_context_current_cb_(make_context_current_cb), video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), output_format_fourcc_(0), weak_this_factory_(this) { @@ -212,6 +205,11 @@ bool V4L2VideoDecodeAccelerator::Initialize(const Config& config, DCHECK(child_task_runner_->BelongsToCurrentThread()); DCHECK_EQ(decoder_state_, kUninitialized); + if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { + NOTREACHED() << "GL callbacks are required for this VDA"; + return false; + } + if (config.is_encrypted) { NOTREACHED() << "Encrypted streams are not supported for this VDA"; return false; @@ -226,6 +224,14 @@ bool V4L2VideoDecodeAccelerator::Initialize(const Config& config, client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); client_ = client_ptr_factory_->GetWeakPtr(); + // If we haven't been set up to decode on separate thread via + // TryToSetupDecodeOnSeparateThread(), use the main thread/client for + // decode tasks. + if (!decode_task_runner_) { + decode_task_runner_ = child_task_runner_; + DCHECK(!decode_client_); + decode_client_ = client_; + } video_profile_ = config.profile; @@ -235,7 +241,7 @@ bool V4L2VideoDecodeAccelerator::Initialize(const Config& config, } // We need the context to be initialized to query extensions. - if (!make_context_current_.Run()) { + if (!make_context_current_cb_.Run()) { LOG(ERROR) << "Initialize(): could not make context current"; return false; } @@ -253,16 +259,9 @@ bool V4L2VideoDecodeAccelerator::Initialize(const Config& config, const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); if ((caps.capabilities & kCapsRequired) != kCapsRequired) { - // This cap combination is deprecated, but some older drivers may still be - // returning it. - const __u32 kCapsRequiredCompat = V4L2_CAP_VIDEO_CAPTURE_MPLANE | - V4L2_CAP_VIDEO_OUTPUT_MPLANE | - V4L2_CAP_STREAMING; - if ((caps.capabilities & kCapsRequiredCompat) != kCapsRequiredCompat) { - LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP" - ", caps check failed: 0x" << std::hex << caps.capabilities; - return false; - } + LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP" + ", caps check failed: 0x" << std::hex << caps.capabilities; + return false; } if (!SetupFormats()) @@ -303,7 +302,15 @@ void V4L2VideoDecodeAccelerator::Decode( const media::BitstreamBuffer& bitstream_buffer) { DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id() << ", size=" << bitstream_buffer.size(); - DCHECK(io_task_runner_->BelongsToCurrentThread()); + DCHECK(decode_task_runner_->BelongsToCurrentThread()); + + if (bitstream_buffer.id() < 0) { + LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id(); + if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle())) + base::SharedMemory::CloseHandle(bitstream_buffer.handle()); + NOTIFY_ERROR(INVALID_ARGUMENT); + return; + } // DecodeTask() will take care of running a DecodeBufferTask(). decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( @@ -327,7 +334,8 @@ void V4L2VideoDecodeAccelerator::AssignPictureBuffers( return; } - if (!make_context_current_.Run()) { + gfx::GLContext* gl_context = get_gl_context_cb_.Run(); + if (!gl_context || !make_context_current_cb_.Run()) { LOG(ERROR) << "AssignPictureBuffers(): could not make context current"; NOTIFY_ERROR(PLATFORM_FAILURE); return; @@ -365,14 +373,11 @@ void V4L2VideoDecodeAccelerator::AssignPictureBuffers( DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); DCHECK_EQ(output_record.picture_id, -1); DCHECK_EQ(output_record.cleared, false); + DCHECK_LE(1u, buffers[i].texture_ids().size()); - EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, - egl_context_, - buffers[i].texture_id(), - coded_size_, - i, - output_format_fourcc_, - output_planes_count_); + EGLImageKHR egl_image = device_->CreateEGLImage( + egl_display_, gl_context->GetHandle(), buffers[i].texture_ids()[0], + coded_size_, i, output_format_fourcc_, output_planes_count_); if (egl_image == EGL_NO_IMAGE_KHR) { LOG(ERROR) << "AssignPictureBuffers(): could not create EGLImageKHR"; // Ownership of EGLImages allocated in previous iterations of this loop @@ -397,7 +402,7 @@ void V4L2VideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_buffer_id) { // Must be run on child thread, as we'll insert a sync in the EGL context. DCHECK(child_task_runner_->BelongsToCurrentThread()); - if (!make_context_current_.Run()) { + if (!make_context_current_cb_.Run()) { LOG(ERROR) << "ReusePictureBuffer(): could not make context current"; NOTIFY_ERROR(PLATFORM_FAILURE); return; @@ -458,7 +463,13 @@ void V4L2VideoDecodeAccelerator::Destroy() { delete this; } -bool V4L2VideoDecodeAccelerator::CanDecodeOnIOThread() { return true; } +bool V4L2VideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { + decode_client_ = decode_client_; + decode_task_runner_ = decode_task_runner; + return true; +} // static media::VideoDecodeAccelerator::SupportedProfiles @@ -480,10 +491,11 @@ void V4L2VideoDecodeAccelerator::DecodeTask( bitstream_buffer.id()); scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef( - io_client_, io_task_runner_, - new base::SharedMemory(bitstream_buffer.handle(), true), - bitstream_buffer.size(), bitstream_buffer.id())); - if (!bitstream_record->shm->Map(bitstream_buffer.size())) { + decode_client_, decode_task_runner_, + scoped_ptr<SharedMemoryRegion>( + new SharedMemoryRegion(bitstream_buffer, true)), + bitstream_buffer.id())); + if (!bitstream_record->shm->Map()) { LOG(ERROR) << "Decode(): could not map bitstream_buffer"; NOTIFY_ERROR(UNREADABLE_INPUT); return; @@ -542,54 +554,51 @@ void V4L2VideoDecodeAccelerator::DecodeBufferTask() { // Setup to use the next buffer. decoder_current_bitstream_buffer_.reset(buffer_ref.release()); decoder_input_queue_.pop(); - DVLOG(3) << "DecodeBufferTask(): reading input_id=" - << decoder_current_bitstream_buffer_->input_id - << ", addr=" << (decoder_current_bitstream_buffer_->shm ? - decoder_current_bitstream_buffer_->shm->memory() : - NULL) - << ", size=" << decoder_current_bitstream_buffer_->size; + const auto& shm = decoder_current_bitstream_buffer_->shm; + if (shm) { + DVLOG(3) << "DecodeBufferTask(): reading input_id=" + << decoder_current_bitstream_buffer_->input_id + << ", addr=" << shm->memory() << ", size=" << shm->size(); + } else { + DCHECK_EQ(decoder_current_bitstream_buffer_->input_id, kFlushBufferId); + DVLOG(3) << "DecodeBufferTask(): reading input_id=kFlushBufferId"; + } } bool schedule_task = false; - const size_t size = decoder_current_bitstream_buffer_->size; size_t decoded_size = 0; - if (size == 0) { - const int32_t input_id = decoder_current_bitstream_buffer_->input_id; - if (input_id >= 0) { - // This is a buffer queued from the client that has zero size. Skip. + const auto& shm = decoder_current_bitstream_buffer_->shm; + if (!shm) { + // This is a dummy buffer, queued to flush the pipe. Flush. + DCHECK_EQ(decoder_current_bitstream_buffer_->input_id, kFlushBufferId); + // Enqueue a buffer guaranteed to be empty. To do that, we flush the + // current input, enqueue no data to the next frame, then flush that down. + schedule_task = true; + if (decoder_current_input_buffer_ != -1 && + input_buffer_map_[decoder_current_input_buffer_].input_id != + kFlushBufferId) + schedule_task = FlushInputFrame(); + + if (schedule_task && AppendToInputFrame(NULL, 0) && FlushInputFrame()) { + DVLOG(2) << "DecodeBufferTask(): enqueued flush buffer"; + decoder_partial_frame_pending_ = false; schedule_task = true; } else { - // This is a buffer of zero size, queued to flush the pipe. Flush. - DCHECK_EQ(decoder_current_bitstream_buffer_->shm.get(), - static_cast<base::SharedMemory*>(NULL)); - // Enqueue a buffer guaranteed to be empty. To do that, we flush the - // current input, enqueue no data to the next frame, then flush that down. - schedule_task = true; - if (decoder_current_input_buffer_ != -1 && - input_buffer_map_[decoder_current_input_buffer_].input_id != - kFlushBufferId) - schedule_task = FlushInputFrame(); - - if (schedule_task && AppendToInputFrame(NULL, 0) && FlushInputFrame()) { - DVLOG(2) << "DecodeBufferTask(): enqueued flush buffer"; - decoder_partial_frame_pending_ = false; - schedule_task = true; - } else { - // If we failed to enqueue the empty buffer (due to pipeline - // backpressure), don't advance the bitstream buffer queue, and don't - // schedule the next task. This bitstream buffer queue entry will get - // reprocessed when the pipeline frees up. - schedule_task = false; - } + // If we failed to enqueue the empty buffer (due to pipeline + // backpressure), don't advance the bitstream buffer queue, and don't + // schedule the next task. This bitstream buffer queue entry will get + // reprocessed when the pipeline frees up. + schedule_task = false; } + } else if (shm->size() == 0) { + // This is a buffer queued from the client that has zero size. Skip. + schedule_task = true; } else { // This is a buffer queued from the client, with actual contents. Decode. const uint8_t* const data = - reinterpret_cast<const uint8_t*>( - decoder_current_bitstream_buffer_->shm->memory()) + + reinterpret_cast<const uint8_t*>(shm->memory()) + decoder_current_bitstream_buffer_->bytes_used; const size_t data_size = - decoder_current_bitstream_buffer_->size - - decoder_current_bitstream_buffer_->bytes_used; + shm->size() - decoder_current_bitstream_buffer_->bytes_used; if (!AdvanceFrameFragment(data, data_size, &decoded_size)) { NOTIFY_ERROR(UNREADABLE_INPUT); return; @@ -618,8 +627,8 @@ void V4L2VideoDecodeAccelerator::DecodeBufferTask() { if (schedule_task) { decoder_current_bitstream_buffer_->bytes_used += decoded_size; - if (decoder_current_bitstream_buffer_->bytes_used == - decoder_current_bitstream_buffer_->size) { + if ((shm ? shm->size() : 0) == + decoder_current_bitstream_buffer_->bytes_used) { // Our current bitstream buffer is done; return it. int32_t input_id = decoder_current_bitstream_buffer_->input_id; DVLOG(3) << "DecodeBufferTask(): finished input_id=" << input_id; @@ -1023,14 +1032,7 @@ bool V4L2VideoDecodeAccelerator::DequeueResolutionChangeEvent() { while (device_->Ioctl(VIDIOC_DQEVENT, &ev) == 0) { if (ev.type == V4L2_EVENT_SOURCE_CHANGE) { - uint32_t changes = ev.u.src_change.changes; - // We used to define source change was always resolution change. The union - // |ev.u| is not used and it is zero by default. When using the upstream - // version of the resolution event change, we also need to check - // |ev.u.src_change.changes| to know what is changed. For API backward - // compatibility, event is treated as resolution change when all bits in - // |ev.u.src_change.changes| are cleared. - if (changes == 0 || (changes & V4L2_EVENT_SRC_CH_RESOLUTION)) { + if (ev.u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION) { DVLOG(3) << "DequeueResolutionChangeEvent(): got resolution change event."; return true; @@ -1282,7 +1284,7 @@ void V4L2VideoDecodeAccelerator::FlushTask() { // Queue up an empty buffer -- this triggers the flush. decoder_input_queue_.push( linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( - io_client_, io_task_runner_, NULL, 0, kFlushBufferId))); + decode_client_, decode_task_runner_, nullptr, kFlushBufferId))); decoder_flushing_ = true; SendPictureReady(); // Send all pending PictureReady. @@ -1886,9 +1888,9 @@ bool V4L2VideoDecodeAccelerator::CreateOutputBuffers() { << "buffer_count=" << buffer_count << ", coded_size=" << coded_size_.ToString(); child_task_runner_->PostTask( - FROM_HERE, base::Bind(&Client::ProvidePictureBuffers, client_, - buffer_count, coded_size_, - device_->GetTextureTarget())); + FROM_HERE, + base::Bind(&Client::ProvidePictureBuffers, client_, buffer_count, 1, + coded_size_, device_->GetTextureTarget())); // Wait for the client to call AssignPictureBuffers() on the Child thread. // We do this, because if we continue decoding without finishing buffer @@ -2005,10 +2007,12 @@ void V4L2VideoDecodeAccelerator::SendPictureReady() { bool cleared = pending_picture_ready_.front().cleared; const media::Picture& picture = pending_picture_ready_.front().picture; if (cleared && picture_clearing_count_ == 0) { - // This picture is cleared. Post it to IO thread to reduce latency. This - // should be the case after all pictures are cleared at the beginning. - io_task_runner_->PostTask( - FROM_HERE, base::Bind(&Client::PictureReady, io_client_, picture)); + // This picture is cleared. It can be posted to a thread different than + // the main GPU thread to reduce latency. This should be the case after + // all pictures are cleared at the beginning. + decode_task_runner_->PostTask( + FROM_HERE, + base::Bind(&Client::PictureReady, decode_client_, picture)); pending_picture_ready_.pop(); } else if (!cleared || resetting_or_flushing) { DVLOG(3) << "SendPictureReady()" diff --git a/chromium/content/common/gpu/media/v4l2_video_decode_accelerator.h b/chromium/content/common/gpu/media/v4l2_video_decode_accelerator.h index 3d06665e344..cb749569241 100644 --- a/chromium/content/common/gpu/media/v4l2_video_decode_accelerator.h +++ b/chromium/content/common/gpu/media/v4l2_video_decode_accelerator.h @@ -23,6 +23,7 @@ #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "content/common/content_export.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" #include "content/common/gpu/media/v4l2_device.h" #include "media/base/limits.h" #include "media/base/video_decoder_config.h" @@ -78,11 +79,9 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator public: V4L2VideoDecodeAccelerator( EGLDisplay egl_display, - EGLContext egl_context, - const base::WeakPtr<Client>& io_client_, - const base::Callback<bool(void)>& make_context_current, - const scoped_refptr<V4L2Device>& device, - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner); + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const scoped_refptr<V4L2Device>& device); ~V4L2VideoDecodeAccelerator() override; // media::VideoDecodeAccelerator implementation. @@ -95,7 +94,10 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator void Flush() override; void Reset() override; void Destroy() override; - bool CanDecodeOnIOThread() override; + bool TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) + override; static media::VideoDecodeAccelerator::SupportedProfiles GetSupportedProfiles(); @@ -316,8 +318,8 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator // Our original calling task runner for the child thread. scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_; - // Task runner of the IO thread. - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + // Task runner Decode() and PictureReady() run on. + scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner_; // WeakPtr<> pointing to |this| for use in posting tasks from the decoder or // device worker threads back to the child thread. Because the worker threads @@ -332,8 +334,8 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator // child_task_runner_. scoped_ptr<base::WeakPtrFactory<Client> > client_ptr_factory_; base::WeakPtr<Client> client_; - // Callbacks to |io_client_| must be executed on |io_task_runner_|. - base::WeakPtr<Client> io_client_; + // Callbacks to |decode_client_| must be executed on |decode_task_runner_|. + base::WeakPtr<Client> decode_client_; // // Decoder state, owned and operated by decoder_thread_. @@ -438,12 +440,13 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator // Other state, held by the child (main) thread. // - // Make our context current before running any EGL entry points. - base::Callback<bool(void)> make_context_current_; - // EGL state EGLDisplay egl_display_; - EGLContext egl_context_; + + // Callback to get current GLContext. + GetGLContextCallback get_gl_context_cb_; + // Callback to set the correct gl context. + MakeGLContextCurrentCallback make_context_current_cb_; // The codec we'll be decoding for. media::VideoCodecProfile video_profile_; diff --git a/chromium/content/common/gpu/media/v4l2_video_encode_accelerator.cc b/chromium/content/common/gpu/media/v4l2_video_encode_accelerator.cc index 98f4e48db35..d724d8dea40 100644 --- a/chromium/content/common/gpu/media/v4l2_video_encode_accelerator.cc +++ b/chromium/content/common/gpu/media/v4l2_video_encode_accelerator.cc @@ -17,8 +17,8 @@ #include "base/numerics/safe_conversions.h" #include "base/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" +#include "content/common/gpu/media/shared_memory_region.h" #include "content/common/gpu/media/v4l2_video_encode_accelerator.h" -#include "content/public/common/content_switches.h" #include "media/base/bitstream_buffer.h" #define NOTIFY_ERROR(x) \ @@ -51,13 +51,10 @@ namespace content { struct V4L2VideoEncodeAccelerator::BitstreamBufferRef { - BitstreamBufferRef(int32_t id, - scoped_ptr<base::SharedMemory> shm, - size_t size) - : id(id), shm(std::move(shm)), size(size) {} + BitstreamBufferRef(int32_t id, scoped_ptr<SharedMemoryRegion> shm) + : id(id), shm(std::move(shm)) {} const int32_t id; - const scoped_ptr<base::SharedMemory> shm; - const size_t size; + const scoped_ptr<SharedMemoryRegion> shm; }; V4L2VideoEncodeAccelerator::InputRecord::InputRecord() : at_device(false) { @@ -128,20 +125,13 @@ bool V4L2VideoEncodeAccelerator::Initialize( const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); if ((caps.capabilities & kCapsRequired) != kCapsRequired) { - // This cap combination is deprecated, but some older drivers may still be - // returning it. - const __u32 kCapsRequiredCompat = V4L2_CAP_VIDEO_CAPTURE_MPLANE | - V4L2_CAP_VIDEO_OUTPUT_MPLANE | - V4L2_CAP_STREAMING; - if ((caps.capabilities & kCapsRequiredCompat) != kCapsRequiredCompat) { - LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: " - "caps check failed: 0x" << std::hex << caps.capabilities; - return false; - } + LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: " + "caps check failed: 0x" << std::hex << caps.capabilities; + return false; } if (!SetFormats(input_format, output_profile)) { - LOG(ERROR) << "Failed setting up formats"; + DLOG(ERROR) << "Failed setting up formats"; return false; } @@ -231,15 +221,14 @@ void V4L2VideoEncodeAccelerator::UseOutputBitstreamBuffer( return; } - scoped_ptr<base::SharedMemory> shm( - new base::SharedMemory(buffer.handle(), false)); - if (!shm->Map(buffer.size())) { + scoped_ptr<SharedMemoryRegion> shm(new SharedMemoryRegion(buffer, false)); + if (!shm->Map()) { NOTIFY_ERROR(kPlatformFailureError); return; } scoped_ptr<BitstreamBufferRef> buffer_ref( - new BitstreamBufferRef(buffer.id(), std::move(shm), buffer.size())); + new BitstreamBufferRef(buffer.id(), std::move(shm))); encoder_thread_.message_loop()->PostTask( FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask, @@ -318,7 +307,13 @@ V4L2VideoEncodeAccelerator::GetSupportedProfiles() { profiles.push_back(profile); break; case V4L2_PIX_FMT_VP9: - profile.profile = media::VP9PROFILE_ANY; + profile.profile = media::VP9PROFILE_PROFILE0; + profiles.push_back(profile); + profile.profile = media::VP9PROFILE_PROFILE1; + profiles.push_back(profile); + profile.profile = media::VP9PROFILE_PROFILE2; + profiles.push_back(profile); + profile.profile = media::VP9PROFILE_PROFILE3; profiles.push_back(profile); break; } @@ -365,13 +360,21 @@ void V4L2VideoEncodeAccelerator::EncodeTask( std::vector<struct v4l2_ext_control> ctrls; struct v4l2_ext_control ctrl; memset(&ctrl, 0, sizeof(ctrl)); - ctrl.id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE; - ctrl.value = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME; + ctrl.id = V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME; ctrls.push_back(ctrl); if (!SetExtCtrls(ctrls)) { - LOG(ERROR) << "Failed requesting keyframe"; - NOTIFY_ERROR(kPlatformFailureError); - return; + // Some platforms still use the old control. Fallback before they are + // updated. + ctrls.clear(); + memset(&ctrl, 0, sizeof(ctrl)); + ctrl.id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE; + ctrl.value = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME; + ctrls.push_back(ctrl); + if (!SetExtCtrls(ctrls)) { + LOG(ERROR) << "Failed requesting keyframe"; + NOTIFY_ERROR(kPlatformFailureError); + return; + } } } } @@ -893,7 +896,7 @@ bool V4L2VideoEncodeAccelerator::NegotiateInputFormat( uint32_t input_format_fourcc = V4L2Device::VideoPixelFormatToV4L2PixFmt(input_format); if (!input_format_fourcc) { - LOG(ERROR) << "Unsupported input format"; + LOG(ERROR) << "Unsupported input format" << input_format_fourcc; return false; } @@ -913,8 +916,10 @@ bool V4L2VideoEncodeAccelerator::NegotiateInputFormat( input_format_fourcc = device_->PreferredInputFormat(); input_format = V4L2Device::V4L2PixFmtToVideoPixelFormat(input_format_fourcc); - if (input_format == media::PIXEL_FORMAT_UNKNOWN) + if (input_format == media::PIXEL_FORMAT_UNKNOWN) { + LOG(ERROR) << "Unsupported input format" << input_format_fourcc; return false; + } input_planes_count = media::VideoFrame::NumPlanes(input_format); DCHECK_LE(input_planes_count, static_cast<size_t>(VIDEO_MAX_PLANES)); @@ -930,9 +935,14 @@ bool V4L2VideoEncodeAccelerator::NegotiateInputFormat( DCHECK_EQ(format.fmt.pix_mp.num_planes, input_planes_count); } - // Take device-adjusted sizes for allocated size. + // Take device-adjusted sizes for allocated size. If the size is adjusted + // down, it means the input is too big and the hardware does not support it. input_allocated_size_ = V4L2Device::CodedSizeFromV4L2Format(format); - DCHECK(gfx::Rect(input_allocated_size_).Contains(gfx::Rect(visible_size_))); + if (!gfx::Rect(input_allocated_size_).Contains(gfx::Rect(visible_size_))) { + DVLOG(1) << "Input size too big " << visible_size_.ToString() + << ", adjusted to " << input_allocated_size_.ToString(); + return false; + } device_input_format_ = input_format; input_planes_count_ = input_planes_count; @@ -1031,30 +1041,35 @@ bool V4L2VideoEncodeAccelerator::InitControls() { ctrls.push_back(ctrl); } - // Enable "tight" bitrate mode. For this to work properly, frame- and mb-level - // bitrate controls have to be enabled as well. + // Enable macroblock-level bitrate control. memset(&ctrl, 0, sizeof(ctrl)); - ctrl.id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF; + ctrl.id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE; ctrl.value = 1; ctrls.push_back(ctrl); - // Force bitrate control to average over a GOP (for tight bitrate - // tolerance). + // Disable periodic key frames. memset(&ctrl, 0, sizeof(ctrl)); - ctrl.id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT; - ctrl.value = 1; + ctrl.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE; + ctrl.value = 0; ctrls.push_back(ctrl); - // Enable macroblock-level bitrate control. + // Ignore return value as these controls are optional. + SetExtCtrls(ctrls); + + // Optional Exynos specific controls. + ctrls.clear(); + // Enable "tight" bitrate mode. For this to work properly, frame- and mb-level + // bitrate controls have to be enabled as well. memset(&ctrl, 0, sizeof(ctrl)); - ctrl.id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE; + ctrl.id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF; ctrl.value = 1; ctrls.push_back(ctrl); - // Disable periodic key frames. + // Force bitrate control to average over a GOP (for tight bitrate + // tolerance). memset(&ctrl, 0, sizeof(ctrl)); - ctrl.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE; - ctrl.value = 0; + ctrl.id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT; + ctrl.value = 1; ctrls.push_back(ctrl); // Ignore return value as these controls are optional. diff --git a/chromium/content/common/gpu/media/vaapi_drm_picture.cc b/chromium/content/common/gpu/media/vaapi_drm_picture.cc index f20716426fd..ab5a4f28b1a 100644 --- a/chromium/content/common/gpu/media/vaapi_drm_picture.cc +++ b/chromium/content/common/gpu/media/vaapi_drm_picture.cc @@ -27,16 +27,16 @@ namespace content { VaapiDrmPicture::VaapiDrmPicture( const scoped_refptr<VaapiWrapper>& vaapi_wrapper, - const base::Callback<bool(void)>& make_context_current, + const MakeGLContextCurrentCallback& make_context_current_cb, int32_t picture_buffer_id, uint32_t texture_id, const gfx::Size& size) : VaapiPicture(picture_buffer_id, texture_id, size), vaapi_wrapper_(vaapi_wrapper), - make_context_current_(make_context_current) {} + make_context_current_cb_(make_context_current_cb) {} VaapiDrmPicture::~VaapiDrmPicture() { - if (gl_image_ && make_context_current_.Run()) { + if (gl_image_ && make_context_current_cb_.Run()) { gl_image_->ReleaseTexImage(GL_TEXTURE_EXTERNAL_OES); gl_image_->Destroy(true); @@ -67,7 +67,7 @@ bool VaapiDrmPicture::Initialize() { pixmap_->SetProcessingCallback( base::Bind(&VaapiWrapper::ProcessPixmap, vaapi_wrapper_)); - if (!make_context_current_.Run()) + if (!make_context_current_cb_.Run()) return false; gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_EXTERNAL_OES, diff --git a/chromium/content/common/gpu/media/vaapi_drm_picture.h b/chromium/content/common/gpu/media/vaapi_drm_picture.h index 066192b25ca..7f5fc8a1780 100644 --- a/chromium/content/common/gpu/media/vaapi_drm_picture.h +++ b/chromium/content/common/gpu/media/vaapi_drm_picture.h @@ -11,7 +11,6 @@ #include <stdint.h> -#include "base/callback.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" @@ -35,7 +34,7 @@ class VaapiWrapper; class VaapiDrmPicture : public VaapiPicture { public: VaapiDrmPicture(const scoped_refptr<VaapiWrapper>& vaapi_wrapper, - const base::Callback<bool(void)>& make_context_current, + const MakeGLContextCurrentCallback& make_context_current_cb, int32_t picture_buffer_id, uint32_t texture_id, const gfx::Size& size); @@ -52,7 +51,7 @@ class VaapiDrmPicture : public VaapiPicture { private: scoped_refptr<VaapiWrapper> vaapi_wrapper_; - base::Callback<bool(void)> make_context_current_; + MakeGLContextCurrentCallback make_context_current_cb_; // Ozone buffer, the storage of the EGLImage and the VASurface. scoped_refptr<ui::NativePixmap> pixmap_; diff --git a/chromium/content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc b/chromium/content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc index 8efb362180d..a0cbc6e059d 100644 --- a/chromium/content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc +++ b/chromium/content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc @@ -13,8 +13,9 @@ #include "base/metrics/histogram.h" #include "base/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" -#include "content/common/gpu/gpu_channel.h" +#include "content/common/gpu/media/shared_memory_region.h" #include "content/common/gpu/media/vaapi_picture.h" +#include "gpu/ipc/service/gpu_channel.h" #include "media/base/video_frame.h" #include "media/filters/jpeg_parser.h" #include "third_party/libyuv/include/libyuv.h" @@ -76,10 +77,10 @@ static unsigned int VaSurfaceFormatForJpeg( } // namespace VaapiJpegDecodeAccelerator::DecodeRequest::DecodeRequest( - const media::BitstreamBuffer& bitstream_buffer, - scoped_ptr<base::SharedMemory> shm, + int32_t bitstream_buffer_id, + scoped_ptr<SharedMemoryRegion> shm, const scoped_refptr<media::VideoFrame>& video_frame) - : bitstream_buffer(bitstream_buffer), + : bitstream_buffer_id(bitstream_buffer_id), shm(std::move(shm)), video_frame(video_frame) {} @@ -226,9 +227,9 @@ void VaapiJpegDecodeAccelerator::DecodeTask( media::JpegParseResult parse_result; if (!media::ParseJpegPicture( reinterpret_cast<const uint8_t*>(request->shm->memory()), - request->bitstream_buffer.size(), &parse_result)) { + request->shm->size(), &parse_result)) { DLOG(ERROR) << "ParseJpegPicture failed"; - NotifyErrorFromDecoderThread(request->bitstream_buffer.id(), + NotifyErrorFromDecoderThread(request->bitstream_buffer_id, PARSE_JPEG_FAILED); return; } @@ -237,7 +238,7 @@ void VaapiJpegDecodeAccelerator::DecodeTask( VaSurfaceFormatForJpeg(parse_result.frame_header); if (!new_va_rt_format) { DLOG(ERROR) << "Unsupported subsampling"; - NotifyErrorFromDecoderThread(request->bitstream_buffer.id(), + NotifyErrorFromDecoderThread(request->bitstream_buffer_id, UNSUPPORTED_JPEG); return; } @@ -255,7 +256,7 @@ void VaapiJpegDecodeAccelerator::DecodeTask( if (!vaapi_wrapper_->CreateSurfaces(va_rt_format_, new_coded_size, 1, &va_surfaces)) { LOG(ERROR) << "Create VA surface failed"; - NotifyErrorFromDecoderThread(request->bitstream_buffer.id(), + NotifyErrorFromDecoderThread(request->bitstream_buffer_id, PLATFORM_FAILURE); return; } @@ -266,15 +267,15 @@ void VaapiJpegDecodeAccelerator::DecodeTask( if (!VaapiJpegDecoder::Decode(vaapi_wrapper_.get(), parse_result, va_surface_id_)) { LOG(ERROR) << "Decode JPEG failed"; - NotifyErrorFromDecoderThread(request->bitstream_buffer.id(), + NotifyErrorFromDecoderThread(request->bitstream_buffer_id, PLATFORM_FAILURE); return; } - if (!OutputPicture(va_surface_id_, request->bitstream_buffer.id(), + if (!OutputPicture(va_surface_id_, request->bitstream_buffer_id, request->video_frame)) { LOG(ERROR) << "Output picture failed"; - NotifyErrorFromDecoderThread(request->bitstream_buffer.id(), + NotifyErrorFromDecoderThread(request->bitstream_buffer_id, PLATFORM_FAILURE); return; } @@ -289,17 +290,25 @@ void VaapiJpegDecodeAccelerator::Decode( DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id() << " size: " << bitstream_buffer.size(); - scoped_ptr<base::SharedMemory> shm( - new base::SharedMemory(bitstream_buffer.handle(), true)); - if (!shm->Map(bitstream_buffer.size())) { + // SharedMemoryRegion will take over the |bitstream_buffer.handle()|. + scoped_ptr<SharedMemoryRegion> shm( + new SharedMemoryRegion(bitstream_buffer, true)); + + if (bitstream_buffer.id() < 0) { + LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id(); + NotifyErrorFromDecoderThread(bitstream_buffer.id(), INVALID_ARGUMENT); + return; + } + + if (!shm->Map()) { LOG(ERROR) << "Failed to map input buffer"; NotifyErrorFromDecoderThread(bitstream_buffer.id(), UNREADABLE_INPUT); return; } scoped_ptr<DecodeRequest> request( - new DecodeRequest(bitstream_buffer, std::move(shm), video_frame)); + new DecodeRequest(bitstream_buffer.id(), std::move(shm), video_frame)); decoder_task_runner_->PostTask( FROM_HERE, base::Bind(&VaapiJpegDecodeAccelerator::DecodeTask, diff --git a/chromium/content/common/gpu/media/vaapi_jpeg_decode_accelerator.h b/chromium/content/common/gpu/media/vaapi_jpeg_decode_accelerator.h index 7d78a5503e9..232b04de829 100644 --- a/chromium/content/common/gpu/media/vaapi_jpeg_decode_accelerator.h +++ b/chromium/content/common/gpu/media/vaapi_jpeg_decode_accelerator.h @@ -15,6 +15,7 @@ #include "base/threading/non_thread_safe.h" #include "base/threading/thread.h" #include "content/common/content_export.h" +#include "content/common/gpu/media/shared_memory_region.h" #include "content/common/gpu/media/vaapi_jpeg_decoder.h" #include "content/common/gpu/media/vaapi_wrapper.h" #include "media/base/bitstream_buffer.h" @@ -47,13 +48,13 @@ class CONTENT_EXPORT VaapiJpegDecodeAccelerator // An input buffer and the corresponding output video frame awaiting // consumption, provided by the client. struct DecodeRequest { - DecodeRequest(const media::BitstreamBuffer& bitstream_buffer, - scoped_ptr<base::SharedMemory> shm, + DecodeRequest(int32_t bitstream_buffer_id, + scoped_ptr<SharedMemoryRegion> shm, const scoped_refptr<media::VideoFrame>& video_frame); ~DecodeRequest(); - media::BitstreamBuffer bitstream_buffer; - scoped_ptr<base::SharedMemory> shm; + int32_t bitstream_buffer_id; + scoped_ptr<SharedMemoryRegion> shm; scoped_refptr<media::VideoFrame> video_frame; }; diff --git a/chromium/content/common/gpu/media/vaapi_picture.cc b/chromium/content/common/gpu/media/vaapi_picture.cc index 5222bd23504..cdf8c355974 100644 --- a/chromium/content/common/gpu/media/vaapi_picture.cc +++ b/chromium/content/common/gpu/media/vaapi_picture.cc @@ -18,16 +18,16 @@ namespace content { // static linked_ptr<VaapiPicture> VaapiPicture::CreatePicture( const scoped_refptr<VaapiWrapper>& vaapi_wrapper, - const base::Callback<bool(void)> make_context_current, + const MakeGLContextCurrentCallback& make_context_current_cb, int32_t picture_buffer_id, uint32_t texture_id, const gfx::Size& size) { linked_ptr<VaapiPicture> picture; #if defined(USE_X11) - picture.reset(new VaapiTFPPicture(vaapi_wrapper, make_context_current, + picture.reset(new VaapiTFPPicture(vaapi_wrapper, make_context_current_cb, picture_buffer_id, texture_id, size)); #elif defined(USE_OZONE) - picture.reset(new VaapiDrmPicture(vaapi_wrapper, make_context_current, + picture.reset(new VaapiDrmPicture(vaapi_wrapper, make_context_current_cb, picture_buffer_id, texture_id, size)); #endif // USE_X11 diff --git a/chromium/content/common/gpu/media/vaapi_picture.h b/chromium/content/common/gpu/media/vaapi_picture.h index 921f80344ec..4bd51e11620 100644 --- a/chromium/content/common/gpu/media/vaapi_picture.h +++ b/chromium/content/common/gpu/media/vaapi_picture.h @@ -12,11 +12,11 @@ #include <stdint.h> -#include "base/callback.h" #include "base/macros.h" #include "base/memory/linked_ptr.h" #include "base/memory/ref_counted.h" #include "base/threading/non_thread_safe.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" #include "ui/gfx/geometry/size.h" namespace gl { @@ -52,10 +52,10 @@ class VaapiPicture : public base::NonThreadSafe { // Create a VaapiPicture of |size| to be associated with // |picture_buffer_id| and bound to |texture_id|. - // |make_context_current| is provided for the GL operations. + // |make_context_current_cb| is provided for the GL operations. static linked_ptr<VaapiPicture> CreatePicture( const scoped_refptr<VaapiWrapper>& vaapi_wrapper, - const base::Callback<bool(void)> make_context_current, + const MakeGLContextCurrentCallback& make_context_current_cb, int32_t picture_buffer_id, uint32_t texture_id, const gfx::Size& size); diff --git a/chromium/content/common/gpu/media/vaapi_tfp_picture.cc b/chromium/content/common/gpu/media/vaapi_tfp_picture.cc index 3de593b62fd..074ba98ed73 100644 --- a/chromium/content/common/gpu/media/vaapi_tfp_picture.cc +++ b/chromium/content/common/gpu/media/vaapi_tfp_picture.cc @@ -14,18 +14,18 @@ namespace content { VaapiTFPPicture::VaapiTFPPicture( const scoped_refptr<VaapiWrapper>& vaapi_wrapper, - const base::Callback<bool(void)> make_context_current, + const MakeGLContextCurrentCallback& make_context_current_cb, int32_t picture_buffer_id, uint32_t texture_id, const gfx::Size& size) : VaapiPicture(picture_buffer_id, texture_id, size), vaapi_wrapper_(vaapi_wrapper), - make_context_current_(make_context_current), + make_context_current_cb_(make_context_current_cb), x_display_(gfx::GetXDisplay()), x_pixmap_(0) {} VaapiTFPPicture::~VaapiTFPPicture() { - if (glx_image_.get() && make_context_current_.Run()) { + if (glx_image_.get() && make_context_current_cb_.Run()) { glx_image_->ReleaseTexImage(GL_TEXTURE_2D); glx_image_->Destroy(true); DCHECK_EQ(glGetError(), static_cast<GLenum>(GL_NO_ERROR)); @@ -36,7 +36,7 @@ VaapiTFPPicture::~VaapiTFPPicture() { } bool VaapiTFPPicture::Initialize() { - if (!make_context_current_.Run()) + if (!make_context_current_cb_.Run()) return false; XWindowAttributes win_attr; diff --git a/chromium/content/common/gpu/media/vaapi_tfp_picture.h b/chromium/content/common/gpu/media/vaapi_tfp_picture.h index 3b66e10800b..5ef35653202 100644 --- a/chromium/content/common/gpu/media/vaapi_tfp_picture.h +++ b/chromium/content/common/gpu/media/vaapi_tfp_picture.h @@ -11,7 +11,6 @@ #include <stdint.h> -#include "base/callback.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "content/common/gpu/media/vaapi_picture.h" @@ -34,7 +33,7 @@ class VaapiWrapper; class VaapiTFPPicture : public VaapiPicture { public: VaapiTFPPicture(const scoped_refptr<VaapiWrapper>& vaapi_wrapper, - const base::Callback<bool(void)> make_context_current, + const MakeGLContextCurrentCallback& make_context_current_cb, int32_t picture_buffer_id, uint32_t texture_id, const gfx::Size& size); @@ -50,7 +49,7 @@ class VaapiTFPPicture : public VaapiPicture { private: scoped_refptr<VaapiWrapper> vaapi_wrapper_; - base::Callback<bool(void)> make_context_current_; + MakeGLContextCurrentCallback make_context_current_cb_; Display* x_display_; Pixmap x_pixmap_; diff --git a/chromium/content/common/gpu/media/vaapi_video_decode_accelerator.cc b/chromium/content/common/gpu/media/vaapi_video_decode_accelerator.cc index 271a0f7a1c9..d8caeec94da 100644 --- a/chromium/content/common/gpu/media/vaapi_video_decode_accelerator.cc +++ b/chromium/content/common/gpu/media/vaapi_video_decode_accelerator.cc @@ -14,12 +14,12 @@ #include "base/strings/string_util.h" #include "base/synchronization/waitable_event.h" #include "base/trace_event/trace_event.h" -#include "content/common/gpu/gpu_channel.h" #include "content/common/gpu/media/accelerated_video_decoder.h" #include "content/common/gpu/media/h264_decoder.h" #include "content/common/gpu/media/vaapi_picture.h" #include "content/common/gpu/media/vp8_decoder.h" #include "content/common/gpu/media/vp9_decoder.h" +#include "gpu/ipc/service/gpu_channel.h" #include "media/base/bind_to_current_loop.h" #include "media/video/picture.h" #include "third_party/libva/va/va_dec_vp8.h" @@ -256,8 +256,7 @@ class VaapiVideoDecodeAccelerator::VaapiVP9Accelerator DISALLOW_COPY_AND_ASSIGN(VaapiVP9Accelerator); }; -VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() : id(0), size(0) { -} +VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() : id(0) {} VaapiVideoDecodeAccelerator::InputBuffer::~InputBuffer() { } @@ -293,11 +292,9 @@ VaapiPicture* VaapiVideoDecodeAccelerator::PictureById( } VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( - const base::Callback<bool(void)>& make_context_current, - const base::Callback<void(uint32_t, uint32_t, scoped_refptr<gl::GLImage>)>& - bind_image) - : make_context_current_(make_context_current), - state_(kUninitialized), + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb) + : state_(kUninitialized), input_ready_(&lock_), surfaces_available_(&lock_), message_loop_(base::MessageLoop::current()), @@ -307,7 +304,8 @@ VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( finish_flush_pending_(false), awaiting_va_surfaces_recycle_(false), requested_num_pics_(0), - bind_image_(bind_image), + make_context_current_cb_(make_context_current_cb), + bind_image_cb_(bind_image_cb), weak_this_factory_(this) { weak_this_ = weak_this_factory_.GetWeakPtr(); va_surface_release_cb_ = media::BindToCurrentLoop( @@ -322,6 +320,11 @@ bool VaapiVideoDecodeAccelerator::Initialize(const Config& config, Client* client) { DCHECK_EQ(message_loop_, base::MessageLoop::current()); + if (make_context_current_cb_.is_null() || bind_image_cb_.is_null()) { + NOTREACHED() << "GL callbacks are required for this VDA"; + return false; + } + if (config.is_encrypted) { NOTREACHED() << "Encrypted streams are not supported for this VDA"; return false; @@ -447,10 +450,10 @@ void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer( DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id() << " size: " << (int)bitstream_buffer.size(); - scoped_ptr<base::SharedMemory> shm( - new base::SharedMemory(bitstream_buffer.handle(), true)); - RETURN_AND_NOTIFY_ON_FAILURE(shm->Map(bitstream_buffer.size()), - "Failed to map input buffer", UNREADABLE_INPUT,); + scoped_ptr<SharedMemoryRegion> shm( + new SharedMemoryRegion(bitstream_buffer, true)); + RETURN_AND_NOTIFY_ON_FAILURE(shm->Map(), "Failed to map input buffer", + UNREADABLE_INPUT, ); base::AutoLock auto_lock(lock_); @@ -458,7 +461,6 @@ void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer( linked_ptr<InputBuffer> input_buffer(new InputBuffer()); input_buffer->shm.reset(shm.release()); input_buffer->id = bitstream_buffer.id(); - input_buffer->size = bitstream_buffer.size(); ++num_stream_bufs_at_decoder_; TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder", @@ -497,13 +499,12 @@ bool VaapiVideoDecodeAccelerator::GetInputBuffer_Locked() { curr_input_buffer_ = input_buffers_.front(); input_buffers_.pop(); - DVLOG(4) << "New current bitstream buffer, id: " - << curr_input_buffer_->id - << " size: " << curr_input_buffer_->size; + DVLOG(4) << "New current bitstream buffer, id: " << curr_input_buffer_->id + << " size: " << curr_input_buffer_->shm->size(); decoder_->SetStream( static_cast<uint8_t*>(curr_input_buffer_->shm->memory()), - curr_input_buffer_->size); + curr_input_buffer_->shm->size()); return true; default: @@ -663,7 +664,7 @@ void VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange() { message_loop_->PostTask( FROM_HERE, base::Bind(&Client::ProvidePictureBuffers, client_, requested_num_pics_, - requested_pic_size_, VaapiPicture::GetGLTextureTarget())); + 1, requested_pic_size_, VaapiPicture::GetGLTextureTarget())); } void VaapiVideoDecodeAccelerator::Decode( @@ -673,6 +674,12 @@ void VaapiVideoDecodeAccelerator::Decode( TRACE_EVENT1("Video Decoder", "VAVDA::Decode", "Buffer id", bitstream_buffer.id()); + RETURN_AND_NOTIFY_ON_FAILURE( + bitstream_buffer.id() >= 0 && + base::SharedMemory::IsHandleValid(bitstream_buffer.handle()), + "Invalid bitstream_buffer, id: " << bitstream_buffer.id(), + INVALID_ARGUMENT, ); + // We got a new input buffer from the client, map it and queue for later use. MapAndQueueNewInputBuffer(bitstream_buffer); @@ -734,18 +741,22 @@ void VaapiVideoDecodeAccelerator::AssignPictureBuffers( DCHECK_EQ(va_surface_ids.size(), buffers.size()); for (size_t i = 0; i < buffers.size(); ++i) { + DCHECK_LE(1u, buffers[i].texture_ids().size()); DVLOG(2) << "Assigning picture id: " << buffers[i].id() - << " to texture id: " << buffers[i].texture_id() + << " to texture id: " << buffers[i].texture_ids()[0] << " VASurfaceID: " << va_surface_ids[i]; linked_ptr<VaapiPicture> picture(VaapiPicture::CreatePicture( - vaapi_wrapper_, make_context_current_, buffers[i].id(), - buffers[i].texture_id(), requested_pic_size_)); + vaapi_wrapper_, make_context_current_cb_, buffers[i].id(), + buffers[i].texture_ids()[0], requested_pic_size_)); scoped_refptr<gl::GLImage> image = picture->GetImageToBind(); if (image) { - bind_image_.Run(buffers[i].internal_texture_id(), - VaapiPicture::GetGLTextureTarget(), image); + DCHECK_LE(1u, buffers[i].internal_texture_ids().size()); + RETURN_AND_NOTIFY_ON_FAILURE( + bind_image_cb_.Run(buffers[i].internal_texture_ids()[0], + VaapiPicture::GetGLTextureTarget(), image, true), + "Failed to bind image", PLATFORM_FAILURE, ); } RETURN_AND_NOTIFY_ON_FAILURE( @@ -960,7 +971,9 @@ void VaapiVideoDecodeAccelerator::Destroy() { delete this; } -bool VaapiVideoDecodeAccelerator::CanDecodeOnIOThread() { +bool VaapiVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { return false; } diff --git a/chromium/content/common/gpu/media/vaapi_video_decode_accelerator.h b/chromium/content/common/gpu/media/vaapi_video_decode_accelerator.h index 11cc082a627..f9cfb90376c 100644 --- a/chromium/content/common/gpu/media/vaapi_video_decode_accelerator.h +++ b/chromium/content/common/gpu/media/vaapi_video_decode_accelerator.h @@ -20,13 +20,14 @@ #include "base/logging.h" #include "base/macros.h" #include "base/memory/linked_ptr.h" -#include "base/memory/shared_memory.h" #include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop.h" #include "base/synchronization/condition_variable.h" #include "base/synchronization/lock.h" #include "base/threading/thread.h" #include "content/common/content_export.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" +#include "content/common/gpu/media/shared_memory_region.h" #include "content/common/gpu/media/vaapi_wrapper.h" #include "media/base/bitstream_buffer.h" #include "media/video/picture.h" @@ -55,9 +56,9 @@ class CONTENT_EXPORT VaapiVideoDecodeAccelerator class VaapiDecodeSurface; VaapiVideoDecodeAccelerator( - const base::Callback<bool(void)>& make_context_current, - const base::Callback< - void(uint32_t, uint32_t, scoped_refptr<gl::GLImage>)>& bind_image); + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb); + ~VaapiVideoDecodeAccelerator() override; // media::VideoDecodeAccelerator implementation. @@ -69,7 +70,10 @@ class CONTENT_EXPORT VaapiVideoDecodeAccelerator void Flush() override; void Reset() override; void Destroy() override; - bool CanDecodeOnIOThread() override; + bool TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) + override; static media::VideoDecodeAccelerator::SupportedProfiles GetSupportedProfiles(); @@ -180,10 +184,6 @@ class CONTENT_EXPORT VaapiVideoDecodeAccelerator // available. scoped_refptr<VaapiDecodeSurface> CreateSurface(); - - // Client-provided GL state. - base::Callback<bool(void)> make_context_current_; - // VAVDA state. enum State { // Initialize() not called yet or failed. @@ -210,8 +210,7 @@ class CONTENT_EXPORT VaapiVideoDecodeAccelerator ~InputBuffer(); int32_t id; - size_t size; - scoped_ptr<base::SharedMemory> shm; + scoped_ptr<SharedMemoryRegion> shm; }; // Queue for incoming input buffers. @@ -305,10 +304,11 @@ class CONTENT_EXPORT VaapiVideoDecodeAccelerator size_t requested_num_pics_; gfx::Size requested_pic_size_; - // Binds the provided GLImage to a givenr client texture ID & texture target - // combination in GLES. - base::Callback<void(uint32_t, uint32_t, scoped_refptr<gl::GLImage>)> - bind_image_; + // Callback to make GL context current. + MakeGLContextCurrentCallback make_context_current_cb_; + + // Callback to bind a GLImage to a given texture. + BindGLImageCallback bind_image_cb_; // The WeakPtrFactory for |weak_this_|. base::WeakPtrFactory<VaapiVideoDecodeAccelerator> weak_this_factory_; diff --git a/chromium/content/common/gpu/media/vaapi_video_encode_accelerator.cc b/chromium/content/common/gpu/media/vaapi_video_encode_accelerator.cc index 049cd7a5547..520d411e21b 100644 --- a/chromium/content/common/gpu/media/vaapi_video_encode_accelerator.cc +++ b/chromium/content/common/gpu/media/vaapi_video_encode_accelerator.cc @@ -13,6 +13,7 @@ #include "base/metrics/histogram.h" #include "base/numerics/safe_conversions.h" #include "content/common/gpu/media/h264_dpb.h" +#include "content/common/gpu/media/shared_memory_region.h" #include "media/base/bind_to_current_loop.h" #include "third_party/libva/va/va_enc_h264.h" @@ -100,13 +101,10 @@ struct VaapiVideoEncodeAccelerator::InputFrameRef { }; struct VaapiVideoEncodeAccelerator::BitstreamBufferRef { - BitstreamBufferRef(int32_t id, - scoped_ptr<base::SharedMemory> shm, - size_t size) - : id(id), shm(std::move(shm)), size(size) {} + BitstreamBufferRef(int32_t id, scoped_ptr<SharedMemoryRegion> shm) + : id(id), shm(std::move(shm)) {} const int32_t id; - const scoped_ptr<base::SharedMemory> shm; - const size_t size; + const scoped_ptr<SharedMemoryRegion> shm; }; media::VideoEncodeAccelerator::SupportedProfiles @@ -176,9 +174,19 @@ bool VaapiVideoEncodeAccelerator::Initialize( client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); client_ = client_ptr_factory_->GetWeakPtr(); - if (output_profile < media::H264PROFILE_BASELINE || - output_profile > media::H264PROFILE_MAIN) { - DVLOGF(1) << "Unsupported output profile: " << output_profile; + const SupportedProfiles& profiles = GetSupportedProfiles(); + auto profile = find_if(profiles.begin(), profiles.end(), + [output_profile](const SupportedProfile& profile) { + return profile.profile == output_profile; + }); + if (profile == profiles.end()) { + DVLOGF(1) << "Unsupported output profile " << output_profile; + return false; + } + if (input_visible_size.width() > profile->max_resolution.width() || + input_visible_size.height() > profile->max_resolution.height()) { + DVLOGF(1) << "Input size too big: " << input_visible_size.ToString() + << ", max supported size: " << profile->max_resolution.ToString(); return false; } @@ -546,11 +554,8 @@ void VaapiVideoEncodeAccelerator::TryToReturnBitstreamBuffer() { size_t data_size = 0; if (!vaapi_wrapper_->DownloadAndDestroyCodedBuffer( - encode_job->coded_buffer, - encode_job->input_surface->id(), - target_data, - buffer->size, - &data_size)) { + encode_job->coded_buffer, encode_job->input_surface->id(), + target_data, buffer->shm->size(), &data_size)) { NOTIFY_ERROR(kPlatformFailureError, "Failed downloading coded buffer"); return; } @@ -669,15 +674,14 @@ void VaapiVideoEncodeAccelerator::UseOutputBitstreamBuffer( return; } - scoped_ptr<base::SharedMemory> shm( - new base::SharedMemory(buffer.handle(), false)); - if (!shm->Map(buffer.size())) { + scoped_ptr<SharedMemoryRegion> shm(new SharedMemoryRegion(buffer, false)); + if (!shm->Map()) { NOTIFY_ERROR(kPlatformFailureError, "Failed mapping shared memory."); return; } scoped_ptr<BitstreamBufferRef> buffer_ref( - new BitstreamBufferRef(buffer.id(), std::move(shm), buffer.size())); + new BitstreamBufferRef(buffer.id(), std::move(shm))); encoder_thread_task_runner_->PostTask( FROM_HERE, diff --git a/chromium/content/common/gpu/media/vaapi_wrapper.cc b/chromium/content/common/gpu/media/vaapi_wrapper.cc index db38f32f7f8..19303e1e6d6 100644 --- a/chromium/content/common/gpu/media/vaapi_wrapper.cc +++ b/chromium/content/common/gpu/media/vaapi_wrapper.cc @@ -9,7 +9,6 @@ #include "base/bind.h" #include "base/callback_helpers.h" -#include "base/command_line.h" #include "base/logging.h" #include "base/macros.h" #include "base/numerics/safe_conversions.h" @@ -18,7 +17,6 @@ // Auto-generated for dlopen libva libraries #include "content/common/gpu/media/va_stubs.h" #include "content/common/gpu/media/vaapi_picture.h" -#include "content/public/common/content_switches.h" #include "third_party/libyuv/include/libyuv.h" #include "ui/gl/gl_bindings.h" #if defined(USE_X11) @@ -127,7 +125,9 @@ static const ProfileMap kProfileMap[] = { // media::H264PROFILE_HIGH*. {media::H264PROFILE_HIGH, VAProfileH264High}, {media::VP8PROFILE_ANY, VAProfileVP8Version0_3}, - {media::VP9PROFILE_ANY, VAProfileVP9Profile0}, + // TODO(servolk): Need to add VP9 profiles 1,2,3 here after rolling + // third_party/libva to 1.7. crbug.com/598118 + {media::VP9PROFILE_PROFILE0, VAProfileVP9Profile0}, }; static std::vector<VAConfigAttrib> GetRequiredAttribs( @@ -214,10 +214,6 @@ scoped_refptr<VaapiWrapper> VaapiWrapper::CreateForVideoCodec( media::VideoEncodeAccelerator::SupportedProfiles VaapiWrapper::GetSupportedEncodeProfiles() { media::VideoEncodeAccelerator::SupportedProfiles profiles; - const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); - if (cmd_line->HasSwitch(switches::kDisableVaapiAcceleratedVideoEncode)) - return profiles; - std::vector<ProfileInfo> encode_profile_infos = profile_infos_.Get().GetSupportedProfileInfosForCodecMode(kEncode); @@ -369,11 +365,8 @@ bool VaapiWrapper::VaInitialize(const base::Closure& report_error_to_uma_cb) { return false; } - VAStatus va_res = VA_STATUS_SUCCESS; - if (!va_display_state->Initialize(&va_res)) { - VA_LOG_ON_ERROR(va_res, "vaInitialize failed"); + if (!va_display_state->Initialize()) return false; - } va_display_ = va_display_state->va_display(); return true; @@ -1218,7 +1211,7 @@ VaapiWrapper::VADisplayState::VADisplayState() VaapiWrapper::VADisplayState::~VADisplayState() {} -bool VaapiWrapper::VADisplayState::Initialize(VAStatus* status) { +bool VaapiWrapper::VADisplayState::Initialize() { va_lock_.AssertAcquired(); if (refcount_++ == 0) { #if defined(USE_X11) @@ -1232,9 +1225,12 @@ bool VaapiWrapper::VADisplayState::Initialize(VAStatus* status) { return false; } - *status = vaInitialize(va_display_, &major_version_, &minor_version_); - if (*status != VA_STATUS_SUCCESS) + VAStatus va_res = + vaInitialize(va_display_, &major_version_, &minor_version_); + if (va_res != VA_STATUS_SUCCESS) { + LOG(WARNING) << "vaInitialize failed: " << vaErrorStr(va_res); return false; + } va_initialized_ = true; DVLOG(1) << "VAAPI version: " << major_version_ << "." << minor_version_; diff --git a/chromium/content/common/gpu/media/vaapi_wrapper.h b/chromium/content/common/gpu/media/vaapi_wrapper.h index 7f14b49be11..4394bc36b92 100644 --- a/chromium/content/common/gpu/media/vaapi_wrapper.h +++ b/chromium/content/common/gpu/media/vaapi_wrapper.h @@ -247,7 +247,7 @@ class CONTENT_EXPORT VaapiWrapper ~VADisplayState(); // |va_lock_| must be held on entry. - bool Initialize(VAStatus* status); + bool Initialize(); void Deinitialize(VAStatus* status); base::Lock* va_lock() { return &va_lock_; } diff --git a/chromium/content/common/gpu/media/video_decode_accelerator_unittest.cc b/chromium/content/common/gpu/media/video_decode_accelerator_unittest.cc index 36466304a3c..91339668867 100644 --- a/chromium/content/common/gpu/media/video_decode_accelerator_unittest.cc +++ b/chromium/content/common/gpu/media/video_decode_accelerator_unittest.cc @@ -47,9 +47,10 @@ #include "base/threading/thread.h" #include "build/build_config.h" #include "content/common/gpu/media/fake_video_decode_accelerator.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.h" #include "content/common/gpu/media/rendering_helper.h" #include "content/common/gpu/media/video_accelerator_unittest_helpers.h" -#include "content/public/common/content_switches.h" +#include "gpu/command_buffer/service/gpu_preferences.h" #include "media/filters/h264_parser.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/codec/png_codec.h" @@ -334,6 +335,7 @@ class GLRenderingVDAClient // VideoDecodeAccelerator::Client implementation. // The heart of the Client. void ProvidePictureBuffers(uint32_t requested_num_of_buffers, + uint32_t textures_per_buffer, const gfx::Size& dimensions, uint32_t texture_target) override; void DismissPictureBuffer(int32_t picture_buffer_id) override; @@ -359,16 +361,6 @@ class GLRenderingVDAClient private: typedef std::map<int32_t, scoped_refptr<TextureRef>> TextureRefMap; - scoped_ptr<media::VideoDecodeAccelerator> CreateFakeVDA(); - scoped_ptr<media::VideoDecodeAccelerator> CreateDXVAVDA(); - scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2VDA(); - scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2SliceVDA(); - scoped_ptr<media::VideoDecodeAccelerator> CreateVaapiVDA(); - - void BindImage(uint32_t client_texture_id, - uint32_t texture_target, - scoped_refptr<gl::GLImage> image); - void SetState(ClientState new_state); void FinishInitialization(); void ReturnPicture(int32_t picture_buffer_id); @@ -401,8 +393,10 @@ class GLRenderingVDAClient int next_bitstream_buffer_id_; ClientStateNotification<ClientState>* note_; scoped_ptr<VideoDecodeAccelerator> decoder_; - scoped_ptr<base::WeakPtrFactory<VideoDecodeAccelerator> > - weak_decoder_factory_; + base::WeakPtr<VideoDecodeAccelerator> weak_vda_; + scoped_ptr<base::WeakPtrFactory<VideoDecodeAccelerator>> + weak_vda_ptr_factory_; + scoped_ptr<GpuVideoDecodeAcceleratorFactoryImpl> vda_factory_; int remaining_play_throughs_; int reset_after_frame_num_; int delete_decoder_state_; @@ -440,9 +434,23 @@ class GLRenderingVDAClient int32_t next_picture_buffer_id_; + base::WeakPtr<GLRenderingVDAClient> weak_this_; + base::WeakPtrFactory<GLRenderingVDAClient> weak_this_factory_; + DISALLOW_IMPLICIT_CONSTRUCTORS(GLRenderingVDAClient); }; +static bool DoNothingReturnTrue() { + return true; +} + +static bool DummyBindImage(uint32_t client_texture_id, + uint32_t texture_target, + const scoped_refptr<gl::GLImage>& image, + bool can_bind_to_sampler) { + return true; +} + GLRenderingVDAClient::GLRenderingVDAClient( size_t window_id, RenderingHelper* rendering_helper, @@ -483,7 +491,8 @@ GLRenderingVDAClient::GLRenderingVDAClient( delay_reuse_after_frame_num_(delay_reuse_after_frame_num), decode_calls_per_second_(decode_calls_per_second), render_as_thumbnails_(render_as_thumbnails), - next_picture_buffer_id_(1) { + next_picture_buffer_id_(1), + weak_this_factory_(this) { LOG_ASSERT(num_in_flight_decodes > 0); LOG_ASSERT(num_play_throughs > 0); // |num_in_flight_decodes_| is unsupported if |decode_calls_per_second_| > 0. @@ -494,6 +503,8 @@ GLRenderingVDAClient::GLRenderingVDAClient( profile_ = (profile != media::VIDEO_CODEC_PROFILE_UNKNOWN ? profile : media::H264PROFILE_BASELINE); + + weak_this_ = weak_this_factory_.GetWeakPtr(); } GLRenderingVDAClient::~GLRenderingVDAClient() { @@ -502,119 +513,49 @@ GLRenderingVDAClient::~GLRenderingVDAClient() { SetState(CS_DESTROYED); } -static bool DoNothingReturnTrue() { return true; } +void GLRenderingVDAClient::CreateAndStartDecoder() { + LOG_ASSERT(decoder_deleted()); + LOG_ASSERT(!decoder_.get()); -scoped_ptr<media::VideoDecodeAccelerator> -GLRenderingVDAClient::CreateFakeVDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; if (fake_decoder_) { - decoder.reset(new FakeVideoDecodeAccelerator( - static_cast<gfx::GLContext*> (rendering_helper_->GetGLContextHandle()), - frame_size_, - base::Bind(&DoNothingReturnTrue))); - } - return decoder; -} - -scoped_ptr<media::VideoDecodeAccelerator> -GLRenderingVDAClient::CreateDXVAVDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; -#if defined(OS_WIN) - if (base::win::GetVersion() >= base::win::VERSION_WIN7) - decoder.reset( - new DXVAVideoDecodeAccelerator( - base::Bind(&DoNothingReturnTrue), - rendering_helper_->GetGLContext().get())); -#endif - return decoder; -} - -scoped_ptr<media::VideoDecodeAccelerator> -GLRenderingVDAClient::CreateV4L2VDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; -#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) - scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); - if (device.get()) { - base::WeakPtr<VideoDecodeAccelerator::Client> weak_client = AsWeakPtr(); - decoder.reset(new V4L2VideoDecodeAccelerator( - static_cast<EGLDisplay>(rendering_helper_->GetGLDisplay()), - static_cast<EGLContext>(rendering_helper_->GetGLContextHandle()), - weak_client, base::Bind(&DoNothingReturnTrue), device, - base::ThreadTaskRunnerHandle::Get())); - } -#endif - return decoder; -} + decoder_.reset(new FakeVideoDecodeAccelerator( + frame_size_, base::Bind(&DoNothingReturnTrue))); + LOG_ASSERT(decoder_->Initialize(profile_, this)); + } else { + if (!vda_factory_) { + vda_factory_ = GpuVideoDecodeAcceleratorFactoryImpl::Create( + base::Bind(&RenderingHelper::GetGLContext, + base::Unretained(rendering_helper_)), + base::Bind(&DoNothingReturnTrue), base::Bind(&DummyBindImage)); + LOG_ASSERT(vda_factory_); + } -scoped_ptr<media::VideoDecodeAccelerator> -GLRenderingVDAClient::CreateV4L2SliceVDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; -#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) - scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); - if (device.get()) { - base::WeakPtr<VideoDecodeAccelerator::Client> weak_client = AsWeakPtr(); - decoder.reset(new V4L2SliceVideoDecodeAccelerator( - device, static_cast<EGLDisplay>(rendering_helper_->GetGLDisplay()), - static_cast<EGLContext>(rendering_helper_->GetGLContextHandle()), - weak_client, base::Bind(&DoNothingReturnTrue), - base::ThreadTaskRunnerHandle::Get())); + VideoDecodeAccelerator::Config config(profile_); + gpu::GpuPreferences gpu_preferences; + decoder_ = vda_factory_->CreateVDA(this, config, gpu_preferences); } -#endif - return decoder; -} -scoped_ptr<media::VideoDecodeAccelerator> -GLRenderingVDAClient::CreateVaapiVDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; -#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) - decoder.reset(new VaapiVideoDecodeAccelerator( - base::Bind(&DoNothingReturnTrue), - base::Bind(&GLRenderingVDAClient::BindImage, base::Unretained(this)))); -#endif - return decoder; -} + LOG_ASSERT(decoder_) << "Failed creating a VDA"; -void GLRenderingVDAClient::BindImage(uint32_t client_texture_id, - uint32_t texture_target, - scoped_refptr<gl::GLImage> image) {} + decoder_->TryToSetupDecodeOnSeparateThread( + weak_this_, base::ThreadTaskRunnerHandle::Get()); -void GLRenderingVDAClient::CreateAndStartDecoder() { - LOG_ASSERT(decoder_deleted()); - LOG_ASSERT(!decoder_.get()); - - VideoDecodeAccelerator::Client* client = this; - - scoped_ptr<media::VideoDecodeAccelerator> decoders[] = { - CreateFakeVDA(), - CreateDXVAVDA(), - CreateV4L2VDA(), - CreateV4L2SliceVDA(), - CreateVaapiVDA(), - }; + weak_vda_ptr_factory_.reset( + new base::WeakPtrFactory<VideoDecodeAccelerator>(decoder_.get())); + weak_vda_ = weak_vda_ptr_factory_->GetWeakPtr(); - for (size_t i = 0; i < arraysize(decoders); ++i) { - if (!decoders[i]) - continue; - decoder_ = std::move(decoders[i]); - weak_decoder_factory_.reset( - new base::WeakPtrFactory<VideoDecodeAccelerator>(decoder_.get())); - if (decoder_->Initialize(profile_, client)) { - SetState(CS_DECODER_SET); - FinishInitialization(); - return; - } - } - // Decoders are all initialize failed. - LOG(ERROR) << "VideoDecodeAccelerator::Initialize() failed"; - LOG_ASSERT(false); + SetState(CS_DECODER_SET); + FinishInitialization(); } void GLRenderingVDAClient::ProvidePictureBuffers( uint32_t requested_num_of_buffers, + uint32_t textures_per_buffer, const gfx::Size& dimensions, uint32_t texture_target) { if (decoder_deleted()) return; + LOG_ASSERT(textures_per_buffer == 1u); std::vector<media::PictureBuffer> buffers; requested_num_of_buffers += kExtraPictureBuffers; @@ -637,8 +578,9 @@ void GLRenderingVDAClient::ProvidePictureBuffers( texture_id)))) .second); - buffers.push_back( - media::PictureBuffer(picture_buffer_id, dimensions, texture_id)); + media::PictureBuffer::TextureIds ids; + ids.push_back(texture_id); + buffers.push_back(media::PictureBuffer(picture_buffer_id, dimensions, ids)); } decoder_->AssignPictureBuffers(buffers); } @@ -710,10 +652,8 @@ void GLRenderingVDAClient::ReturnPicture(int32_t picture_buffer_id) { if (num_decoded_frames_ > delay_reuse_after_frame_num_) { base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&VideoDecodeAccelerator::ReusePictureBuffer, - weak_decoder_factory_->GetWeakPtr(), - picture_buffer_id), + FROM_HERE, base::Bind(&VideoDecodeAccelerator::ReusePictureBuffer, + weak_vda_, picture_buffer_id), kReuseDelay); } else { decoder_->ReusePictureBuffer(picture_buffer_id); @@ -835,7 +775,7 @@ void GLRenderingVDAClient::FinishInitialization() { void GLRenderingVDAClient::DeleteDecoder() { if (decoder_deleted()) return; - weak_decoder_factory_.reset(); + weak_vda_ptr_factory_->InvalidateWeakPtrs(); decoder_.reset(); STLClearObject(&encoded_data_); active_textures_.clear(); @@ -1196,17 +1136,6 @@ class VideoDecodeAcceleratorParamTest base::Tuple<int, int, int, ResetPoint, ClientState, bool, bool> > { }; -// Helper so that gtest failures emit a more readable version of the tuple than -// its byte representation. -::std::ostream& operator<<( - ::std::ostream& os, - const base::Tuple<int, int, int, ResetPoint, ClientState, bool, bool>& t) { - return os << base::get<0>(t) << ", " << base::get<1>(t) << ", " - << base::get<2>(t) << ", " << base::get<3>(t) << ", " - << base::get<4>(t) << ", " << base::get<5>(t) << ", " - << base::get<6>(t); -} - // Wait for |note| to report a state and if it's not |expected_state| then // assert |client| has deleted its decoder. static void AssertWaitForStateOrDeleted( diff --git a/chromium/content/common/gpu/media/video_encode_accelerator_unittest.cc b/chromium/content/common/gpu/media/video_encode_accelerator_unittest.cc index 9224e89c72f..09f1c63ed23 100644 --- a/chromium/content/common/gpu/media/video_encode_accelerator_unittest.cc +++ b/chromium/content/common/gpu/media/video_encode_accelerator_unittest.cc @@ -55,6 +55,8 @@ // Status has been defined as int in Xlib.h. #undef Status #endif // defined(ARCH_CPU_X86_FAMILY) +#elif defined(OS_MACOSX) +#include "content/common/gpu/media/vt_video_encode_accelerator_mac.h" #else #error The VideoEncodeAcceleratorUnittest is not supported on this platform. #endif @@ -126,7 +128,11 @@ const unsigned int kLoggedLatencyPercentiles[] = {50, 75, 95}; // of the stream. // Bitrate is only forced for tests that test bitrate. const char* g_default_in_filename = "bear_320x192_40frames.yuv"; +#if !defined(OS_MACOSX) const char* g_default_in_parameters = ":320:192:1:out.h264:200000"; +#else +const char* g_default_in_parameters = ":320:192:0:out.h264:200000"; +#endif // Enabled by including a --fake_encoder flag to the command line invoking the // test. @@ -623,8 +629,8 @@ class VideoFrameQualityValidator { private: void InitializeCB(bool success); - void DecodeDone(media::VideoDecoder::Status status); - void FlushDone(media::VideoDecoder::Status status); + void DecodeDone(media::DecodeStatus status); + void FlushDone(media::DecodeStatus status); void VerifyOutputFrame(const scoped_refptr<media::VideoFrame>& output_frame); void Decode(); @@ -670,16 +676,18 @@ void VideoFrameQualityValidator::Initialize(const gfx::Size& coded_size, if (IsVP8(profile_)) config.Initialize(media::kCodecVP8, media::VP8PROFILE_ANY, kInputFormat, media::COLOR_SPACE_UNSPECIFIED, coded_size, visible_size, - natural_size, media::EmptyExtraData(), false); + natural_size, media::EmptyExtraData(), + media::Unencrypted()); else if (IsH264(profile_)) config.Initialize(media::kCodecH264, media::H264PROFILE_MAIN, kInputFormat, media::COLOR_SPACE_UNSPECIFIED, coded_size, visible_size, - natural_size, media::EmptyExtraData(), false); + natural_size, media::EmptyExtraData(), + media::Unencrypted()); else LOG_ASSERT(0) << "Invalid profile " << profile_; decoder_->Initialize( - config, false, media::SetCdmReadyCB(), + config, false, nullptr, base::Bind(&VideoFrameQualityValidator::InitializeCB, base::Unretained(this)), base::Bind(&VideoFrameQualityValidator::VerifyOutputFrame, @@ -704,9 +712,8 @@ void VideoFrameQualityValidator::AddOriginalFrame( original_frames_.push(frame); } -void VideoFrameQualityValidator::DecodeDone( - media::VideoDecoder::Status status) { - if (status == media::VideoDecoder::kOk) { +void VideoFrameQualityValidator::DecodeDone(media::DecodeStatus status) { + if (status == media::DecodeStatus::OK) { decoder_state_ = INITIALIZED; Decode(); } else { @@ -716,7 +723,7 @@ void VideoFrameQualityValidator::DecodeDone( } } -void VideoFrameQualityValidator::FlushDone(media::VideoDecoder::Status status) { +void VideoFrameQualityValidator::FlushDone(media::DecodeStatus status) { flush_complete_cb_.Run(); } @@ -810,6 +817,7 @@ class VEAClient : public VideoEncodeAccelerator::Client { scoped_ptr<media::VideoEncodeAccelerator> CreateFakeVEA(); scoped_ptr<media::VideoEncodeAccelerator> CreateV4L2VEA(); scoped_ptr<media::VideoEncodeAccelerator> CreateVaapiVEA(); + scoped_ptr<media::VideoEncodeAccelerator> CreateVTVEA(); void SetState(ClientState new_state); @@ -1071,6 +1079,14 @@ scoped_ptr<media::VideoEncodeAccelerator> VEAClient::CreateVaapiVEA() { return encoder; } +scoped_ptr<media::VideoEncodeAccelerator> VEAClient::CreateVTVEA() { + scoped_ptr<media::VideoEncodeAccelerator> encoder; +#if defined(OS_MACOSX) + encoder.reset(new VTVideoEncodeAccelerator()); +#endif + return encoder; +} + void VEAClient::CreateEncoder() { DCHECK(thread_checker_.CalledOnValidThread()); LOG_ASSERT(!has_encoder()); @@ -1078,7 +1094,8 @@ void VEAClient::CreateEncoder() { scoped_ptr<media::VideoEncodeAccelerator> encoders[] = { CreateFakeVEA(), CreateV4L2VEA(), - CreateVaapiVEA() + CreateVaapiVEA(), + CreateVTVEA() }; DVLOG(1) << "Profile: " << test_stream_->requested_profile @@ -1649,6 +1666,7 @@ TEST_P(VideoEncodeAcceleratorTest, TestSimpleEncode) { encoder_thread.Stop(); } +#if !defined(OS_MACOSX) INSTANTIATE_TEST_CASE_P( SimpleEncode, VideoEncodeAcceleratorTest, @@ -1693,6 +1711,26 @@ INSTANTIATE_TEST_CASE_P( base::MakeTuple(3, false, 0, false, false, false, false, false), base::MakeTuple(3, false, 0, true, false, false, true, false), base::MakeTuple(3, false, 0, true, false, true, false, false))); +#else +INSTANTIATE_TEST_CASE_P( + SimpleEncode, + VideoEncodeAcceleratorTest, + ::testing::Values( + base::MakeTuple(1, true, 0, false, false, false, false, false), + base::MakeTuple(1, true, 0, false, false, false, false, true))); + +INSTANTIATE_TEST_CASE_P( + EncoderPerf, + VideoEncodeAcceleratorTest, + ::testing::Values( + base::MakeTuple(1, false, 0, false, true, false, false, false))); + +INSTANTIATE_TEST_CASE_P( + MultipleEncoders, + VideoEncodeAcceleratorTest, + ::testing::Values( + base::MakeTuple(3, false, 0, false, false, false, false, false))); +#endif // TODO(posciak): more tests: // - async FeedEncoderWithOutput diff --git a/chromium/content/common/gpu/media/vt_video_decode_accelerator_mac.cc b/chromium/content/common/gpu/media/vt_video_decode_accelerator_mac.cc index e74e6f64d55..1571e834620 100644 --- a/chromium/content/common/gpu/media/vt_video_decode_accelerator_mac.cc +++ b/chromium/content/common/gpu/media/vt_video_decode_accelerator_mac.cc @@ -10,7 +10,6 @@ #include <stddef.h> #include "base/bind.h" -#include "base/command_line.h" #include "base/logging.h" #include "base/mac/mac_logging.h" #include "base/macros.h" @@ -20,7 +19,6 @@ #include "base/thread_task_runner_handle.h" #include "base/version.h" #include "content/common/gpu/media/vt_video_decode_accelerator_mac.h" -#include "content/public/common/content_switches.h" #include "media/base/limits.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_image_io_surface.h" @@ -46,7 +44,11 @@ static const media::VideoCodecProfile kSupportedProfiles[] = { media::H264PROFILE_MAIN, media::H264PROFILE_EXTENDED, media::H264PROFILE_HIGH, - media::H264PROFILE_HIGH10PROFILE, + // TODO(hubbe): Try to re-enable this again somehow. Currently it seems + // that some codecs fail to check the profile during initialization and + // then fail on the first frame decode, which currently results in a + // pipeline failure. + // media::H264PROFILE_HIGH10PROFILE, media::H264PROFILE_SCALABLEBASELINE, media::H264PROFILE_SCALABLEHIGH, media::H264PROFILE_STEREOHIGH, @@ -72,9 +74,9 @@ static base::ScopedCFTypeRef<CFMutableDictionaryRef> BuildImageConfig(CMVideoDimensions coded_dimensions) { base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config; - // 4:2:2 is used over the native 4:2:0 because only 4:2:2 can be directly - // bound to a texture by CGLTexImageIOSurface2D(). - int32_t pixel_format = kCVPixelFormatType_422YpCbCr8; + // Note that 4:2:0 textures cannot be used directly as RGBA in OpenGL, but are + // lower power than 4:2:2 when composited directly by CoreAnimation. + int32_t pixel_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; #define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i) base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format)); base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_dimensions.width)); @@ -86,7 +88,7 @@ BuildImageConfig(CMVideoDimensions coded_dimensions) { image_config.reset( CFDictionaryCreateMutable( kCFAllocatorDefault, - 4, // capacity + 3, // capacity &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); if (!image_config.get()) @@ -96,8 +98,6 @@ BuildImageConfig(CMVideoDimensions coded_dimensions) { cf_pixel_format); CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width); CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height); - CFDictionarySetValue(image_config, kCVPixelBufferOpenGLCompatibilityKey, - kCFBooleanTrue); return image_config; } @@ -175,11 +175,6 @@ static bool CreateVideoToolboxSession(const uint8_t* sps, size_t sps_size, // session fails, hardware decoding will be disabled (Initialize() will always // return false). static bool InitializeVideoToolboxInternal() { - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableAcceleratedVideoDecode)) { - return false; - } - if (!IsVtInitialized()) { // CoreVideo is also required, but the loader stops after the first path is // loaded. Instead we rely on the transitive dependency from VideoToolbox to @@ -255,6 +250,8 @@ static void OutputThunk( VTVideoDecodeAccelerator::Task::Task(TaskType type) : type(type) { } +VTVideoDecodeAccelerator::Task::Task(const Task& other) = default; + VTVideoDecodeAccelerator::Task::~Task() { } @@ -291,11 +288,10 @@ bool VTVideoDecodeAccelerator::FrameOrder::operator()( } VTVideoDecodeAccelerator::VTVideoDecodeAccelerator( - const base::Callback<bool(void)>& make_context_current, - const base::Callback<void(uint32_t, uint32_t, scoped_refptr<gl::GLImage>)>& - bind_image) - : make_context_current_(make_context_current), - bind_image_(bind_image), + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb) + : make_context_current_cb_(make_context_current_cb), + bind_image_cb_(bind_image_cb), client_(nullptr), state_(STATE_DECODING), format_(nullptr), @@ -307,7 +303,6 @@ VTVideoDecodeAccelerator::VTVideoDecodeAccelerator( gpu_task_runner_(base::ThreadTaskRunnerHandle::Get()), decoder_thread_("VTDecoderThread"), weak_this_factory_(this) { - DCHECK(!make_context_current_.is_null()); callback_.decompressionOutputCallback = OutputThunk; callback_.decompressionOutputRefCon = this; weak_this_ = weak_this_factory_.GetWeakPtr(); @@ -321,6 +316,11 @@ bool VTVideoDecodeAccelerator::Initialize(const Config& config, Client* client) { DCHECK(gpu_thread_checker_.CalledOnValidThread()); + if (make_context_current_cb_.is_null() || bind_image_cb_.is_null()) { + NOTREACHED() << "GL callbacks are required for this VDA"; + return false; + } + if (config.is_encrypted) { NOTREACHED() << "Encrypted streams are not supported for this VDA"; return false; @@ -622,23 +622,21 @@ void VTVideoDecodeAccelerator::DecodeTask( config_changed_ = true; } if (config_changed_) { - if (last_sps_.empty()) { - config_changed_ = false; - DLOG(ERROR) << "Invalid configuration; no SPS"; - NotifyError(INVALID_ARGUMENT, SFT_INVALID_STREAM); - return; - } - if (last_pps_.empty()) { - config_changed_ = false; - DLOG(ERROR) << "Invalid configuration; no PPS"; - NotifyError(INVALID_ARGUMENT, SFT_INVALID_STREAM); - return; - } - // Only reconfigure at IDRs to avoid corruption. if (frame->is_idr) { config_changed_ = false; + if (last_sps_.empty()) { + DLOG(ERROR) << "Invalid configuration; no SPS"; + NotifyError(INVALID_ARGUMENT, SFT_INVALID_STREAM); + return; + } + if (last_pps_.empty()) { + DLOG(ERROR) << "Invalid configuration; no PPS"; + NotifyError(INVALID_ARGUMENT, SFT_INVALID_STREAM); + return; + } + // ConfigureDecoder() calls NotifyError() on failure. if (!ConfigureDecoder()) return; @@ -825,6 +823,13 @@ void VTVideoDecodeAccelerator::FlushDone(TaskType type) { void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) { DCHECK(gpu_thread_checker_.CalledOnValidThread()); + if (bitstream.id() < 0) { + DLOG(ERROR) << "Invalid bitstream, id: " << bitstream.id(); + if (base::SharedMemory::IsHandleValid(bitstream.handle())) + base::SharedMemory::CloseHandle(bitstream.handle()); + NotifyError(INVALID_ARGUMENT, SFT_INVALID_STREAM); + return; + } DCHECK_EQ(0u, assigned_bitstream_ids_.count(bitstream.id())); assigned_bitstream_ids_.insert(bitstream.id()); Frame* frame = new Frame(bitstream.id()); @@ -842,10 +847,12 @@ void VTVideoDecodeAccelerator::AssignPictureBuffers( DCHECK(!picture_info_map_.count(picture.id())); assigned_picture_ids_.insert(picture.id()); available_picture_ids_.push_back(picture.id()); + DCHECK_LE(1u, picture.internal_texture_ids().size()); + DCHECK_LE(1u, picture.texture_ids().size()); picture_info_map_.insert(std::make_pair( picture.id(), - make_scoped_ptr(new PictureInfo(picture.internal_texture_id(), - picture.texture_id())))); + make_scoped_ptr(new PictureInfo(picture.internal_texture_ids()[0], + picture.texture_ids()[0])))); } // Pictures are not marked as uncleared until after this method returns, and @@ -859,7 +866,7 @@ void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) { DCHECK(gpu_thread_checker_.CalledOnValidThread()); DCHECK(picture_info_map_.count(picture_id)); PictureInfo* picture_info = picture_info_map_.find(picture_id)->second.get(); - DCHECK_EQ(CFGetRetainCount(picture_info->cv_image), 1); + DCHECK_EQ(CFGetRetainCount(picture_info->cv_image), 2); picture_info->cv_image.reset(); picture_info->gl_image->Destroy(false); picture_info->gl_image = nullptr; @@ -1002,8 +1009,8 @@ bool VTVideoDecodeAccelerator::ProcessFrame(const Frame& frame) { // Request new pictures. picture_size_ = frame.coded_size; - client_->ProvidePictureBuffers( - kNumPictureBuffers, coded_size_, GL_TEXTURE_RECTANGLE_ARB); + client_->ProvidePictureBuffers(kNumPictureBuffers, 1, coded_size_, + GL_TEXTURE_RECTANGLE_ARB); return false; } if (!SendFrame(frame)) @@ -1026,47 +1033,27 @@ bool VTVideoDecodeAccelerator::SendFrame(const Frame& frame) { DCHECK(!picture_info->cv_image); DCHECK(!picture_info->gl_image); - if (!make_context_current_.Run()) { + if (!make_context_current_cb_.Run()) { DLOG(ERROR) << "Failed to make GL context current"; NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR); return false; } - IOSurfaceRef surface = CVPixelBufferGetIOSurface(frame.image.get()); - if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGLCoreProfile) - glEnable(GL_TEXTURE_RECTANGLE_ARB); - gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_RECTANGLE_ARB, - picture_info->service_texture_id); - CGLContextObj cgl_context = - static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle()); - CGLError status = CGLTexImageIOSurface2D( - cgl_context, // ctx - GL_TEXTURE_RECTANGLE_ARB, // target - GL_RGB, // internal_format - frame.coded_size.width(), // width - frame.coded_size.height(), // height - GL_YCBCR_422_APPLE, // format - GL_UNSIGNED_SHORT_8_8_APPLE, // type - surface, // io_surface - 0); // plane - if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGLCoreProfile) - glDisable(GL_TEXTURE_RECTANGLE_ARB); - if (status != kCGLNoError) { - NOTIFY_STATUS("CGLTexImageIOSurface2D()", status, SFT_PLATFORM_ERROR); - return false; - } - - bool allow_overlay = false; scoped_refptr<gl::GLImageIOSurface> gl_image( new gl::GLImageIOSurface(frame.coded_size, GL_BGRA_EXT)); - if (gl_image->Initialize(surface, gfx::GenericSharedMemoryId(), - gfx::BufferFormat::BGRA_8888)) { - allow_overlay = true; - } else { - gl_image = nullptr; + if (!gl_image->InitializeWithCVPixelBuffer( + frame.image.get(), gfx::GenericSharedMemoryId(), + gfx::BufferFormat::YUV_420_BIPLANAR)) { + NOTIFY_STATUS("Failed to initialize GLImageIOSurface", PLATFORM_FAILURE, + SFT_PLATFORM_ERROR); + } + + if (!bind_image_cb_.Run(picture_info->client_texture_id, + GL_TEXTURE_RECTANGLE_ARB, gl_image, false)) { + DLOG(ERROR) << "Failed to bind image"; + NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR); + return false; } - bind_image_.Run(picture_info->client_texture_id, GL_TEXTURE_RECTANGLE_ARB, - gl_image); // Assign the new image(s) to the the picture info. picture_info->gl_image = gl_image; @@ -1080,7 +1067,7 @@ bool VTVideoDecodeAccelerator::SendFrame(const Frame& frame) { // coded size and fix it. client_->PictureReady(media::Picture(picture_id, frame.bitstream_id, gfx::Rect(frame.coded_size), - allow_overlay)); + true)); return true; } @@ -1143,7 +1130,9 @@ void VTVideoDecodeAccelerator::Destroy() { QueueFlush(TASK_DESTROY); } -bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { +bool VTVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { return false; } diff --git a/chromium/content/common/gpu/media/vt_video_decode_accelerator_mac.h b/chromium/content/common/gpu/media/vt_video_decode_accelerator_mac.h index 2d222163823..22fc8b1d6ad 100644 --- a/chromium/content/common/gpu/media/vt_video_decode_accelerator_mac.h +++ b/chromium/content/common/gpu/media/vt_video_decode_accelerator_mac.h @@ -17,6 +17,7 @@ #include "base/message_loop/message_loop.h" #include "base/threading/thread.h" #include "base/threading/thread_checker.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" #include "content/common/gpu/media/vt_mac.h" #include "media/filters/h264_parser.h" #include "media/video/h264_poc.h" @@ -35,9 +36,9 @@ bool InitializeVideoToolbox(); class VTVideoDecodeAccelerator : public media::VideoDecodeAccelerator { public: explicit VTVideoDecodeAccelerator( - const base::Callback<bool(void)>& make_context_current, - const base::Callback< - void(uint32_t, uint32_t, scoped_refptr<gl::GLImage>)>& bind_image); + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb); + ~VTVideoDecodeAccelerator() override; // VideoDecodeAccelerator implementation. @@ -49,7 +50,10 @@ class VTVideoDecodeAccelerator : public media::VideoDecodeAccelerator { void Flush() override; void Reset() override; void Destroy() override; - bool CanDecodeOnIOThread() override; + bool TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) + override; // Called by OutputThunk() when VideoToolbox finishes decoding a frame. void Output( @@ -114,6 +118,7 @@ class VTVideoDecodeAccelerator : public media::VideoDecodeAccelerator { struct Task { Task(TaskType type); + Task(const Task& other); ~Task(); TaskType type; @@ -189,9 +194,9 @@ class VTVideoDecodeAccelerator : public media::VideoDecodeAccelerator { // // GPU thread state. // - base::Callback<bool(void)> make_context_current_; - base::Callback<void(uint32_t, uint32_t, scoped_refptr<gl::GLImage>)> - bind_image_; + MakeGLContextCurrentCallback make_context_current_cb_; + BindGLImageCallback bind_image_cb_; + media::VideoDecodeAccelerator::Client* client_; State state_; diff --git a/chromium/content/common/gpu/media/vt_video_encode_accelerator_mac.cc b/chromium/content/common/gpu/media/vt_video_encode_accelerator_mac.cc new file mode 100644 index 00000000000..71c80ef3a9f --- /dev/null +++ b/chromium/content/common/gpu/media/vt_video_encode_accelerator_mac.cc @@ -0,0 +1,552 @@ +// Copyright 2016 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 "content/common/gpu/media/vt_video_encode_accelerator_mac.h" + +#include "base/thread_task_runner_handle.h" +#include "media/base/mac/coremedia_glue.h" +#include "media/base/mac/corevideo_glue.h" +#include "media/base/mac/video_frame_mac.h" + +namespace content { + +namespace { + +// TODO(emircan): Check if we can find the actual system capabilities via +// creating VTCompressionSessions with varying requirements. +// See crbug.com/584784. +const size_t kBitsPerByte = 8; +const size_t kDefaultResolutionWidth = 640; +const size_t kDefaultResolutionHeight = 480; +const size_t kMaxFrameRateNumerator = 30; +const size_t kMaxFrameRateDenominator = 1; +const size_t kMaxResolutionWidth = 4096; +const size_t kMaxResolutionHeight = 2160; +const size_t kNumInputBuffers = 3; + +} // namespace + +struct VTVideoEncodeAccelerator::InProgressFrameEncode { + InProgressFrameEncode(base::TimeDelta rtp_timestamp, + base::TimeTicks ref_time) + : timestamp(rtp_timestamp), reference_time(ref_time) {} + const base::TimeDelta timestamp; + const base::TimeTicks reference_time; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(InProgressFrameEncode); +}; + +struct VTVideoEncodeAccelerator::EncodeOutput { + EncodeOutput(VTEncodeInfoFlags info_flags, CMSampleBufferRef sbuf) + : info(info_flags), sample_buffer(sbuf, base::scoped_policy::RETAIN) {} + const VTEncodeInfoFlags info; + const base::ScopedCFTypeRef<CMSampleBufferRef> sample_buffer; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(EncodeOutput); +}; + +struct VTVideoEncodeAccelerator::BitstreamBufferRef { + BitstreamBufferRef(int32_t id, + scoped_ptr<base::SharedMemory> shm, + size_t size) + : id(id), shm(std::move(shm)), size(size) {} + const int32_t id; + const scoped_ptr<base::SharedMemory> shm; + const size_t size; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(BitstreamBufferRef); +}; + +VTVideoEncodeAccelerator::VTVideoEncodeAccelerator() + : client_task_runner_(base::ThreadTaskRunnerHandle::Get()), + encoder_thread_("VTEncoderThread"), + encoder_task_weak_factory_(this) { + encoder_weak_ptr_ = encoder_task_weak_factory_.GetWeakPtr(); +} + +VTVideoEncodeAccelerator::~VTVideoEncodeAccelerator() { + DVLOG(3) << __FUNCTION__; + DCHECK(thread_checker_.CalledOnValidThread()); + + Destroy(); + DCHECK(!encoder_thread_.IsRunning()); + DCHECK(!encoder_task_weak_factory_.HasWeakPtrs()); +} + +media::VideoEncodeAccelerator::SupportedProfiles +VTVideoEncodeAccelerator::GetSupportedProfiles() { + DVLOG(3) << __FUNCTION__; + DCHECK(thread_checker_.CalledOnValidThread()); + + SupportedProfiles profiles; + // Check if HW encoder is supported initially. + videotoolbox_glue_ = VideoToolboxGlue::Get(); + if (!videotoolbox_glue_) { + DLOG(ERROR) << "Failed creating VideoToolbox glue."; + return profiles; + } + const bool rv = CreateCompressionSession( + media::video_toolbox::DictionaryWithKeysAndValues(nullptr, nullptr, 0), + gfx::Size(kDefaultResolutionWidth, kDefaultResolutionHeight), true); + DestroyCompressionSession(); + if (!rv) { + VLOG(1) + << "Hardware encode acceleration is not available on this platform."; + return profiles; + } + + SupportedProfile profile; + profile.profile = media::H264PROFILE_BASELINE; + profile.max_framerate_numerator = kMaxFrameRateNumerator; + profile.max_framerate_denominator = kMaxFrameRateDenominator; + profile.max_resolution = gfx::Size(kMaxResolutionWidth, kMaxResolutionHeight); + profiles.push_back(profile); + return profiles; +} + +bool VTVideoEncodeAccelerator::Initialize( + media::VideoPixelFormat format, + const gfx::Size& input_visible_size, + media::VideoCodecProfile output_profile, + uint32_t initial_bitrate, + Client* client) { + DVLOG(3) << __FUNCTION__ + << ": input_format=" << media::VideoPixelFormatToString(format) + << ", input_visible_size=" << input_visible_size.ToString() + << ", output_profile=" << output_profile + << ", initial_bitrate=" << initial_bitrate; + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(client); + + if (media::PIXEL_FORMAT_I420 != format) { + DLOG(ERROR) << "Input format not supported= " + << media::VideoPixelFormatToString(format); + return false; + } + if (media::H264PROFILE_BASELINE != output_profile) { + DLOG(ERROR) << "Output profile not supported= " + << output_profile; + return false; + } + + videotoolbox_glue_ = VideoToolboxGlue::Get(); + if (!videotoolbox_glue_) { + DLOG(ERROR) << "Failed creating VideoToolbox glue."; + return false; + } + + client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); + client_ = client_ptr_factory_->GetWeakPtr(); + input_visible_size_ = input_visible_size; + frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator; + target_bitrate_ = initial_bitrate; + bitstream_buffer_size_ = input_visible_size.GetArea(); + + if (!encoder_thread_.Start()) { + DLOG(ERROR) << "Failed spawning encoder thread."; + return false; + } + encoder_thread_task_runner_ = encoder_thread_.task_runner(); + + if (!ResetCompressionSession()) { + DLOG(ERROR) << "Failed creating compression session."; + return false; + } + + client_task_runner_->PostTask( + FROM_HERE, + base::Bind(&Client::RequireBitstreamBuffers, client_, kNumInputBuffers, + input_visible_size_, bitstream_buffer_size_)); + return true; +} + +void VTVideoEncodeAccelerator::Encode( + const scoped_refptr<media::VideoFrame>& frame, + bool force_keyframe) { + DVLOG(3) << __FUNCTION__; + DCHECK(thread_checker_.CalledOnValidThread()); + + encoder_thread_task_runner_->PostTask( + FROM_HERE, base::Bind(&VTVideoEncodeAccelerator::EncodeTask, + base::Unretained(this), frame, force_keyframe)); +} + +void VTVideoEncodeAccelerator::UseOutputBitstreamBuffer( + const media::BitstreamBuffer& buffer) { + DVLOG(3) << __FUNCTION__ << ": buffer size=" << buffer.size(); + DCHECK(thread_checker_.CalledOnValidThread()); + + if (buffer.size() < bitstream_buffer_size_) { + DLOG(ERROR) << "Output BitstreamBuffer isn't big enough: " << buffer.size() + << " vs. " << bitstream_buffer_size_; + client_->NotifyError(kInvalidArgumentError); + return; + } + + scoped_ptr<base::SharedMemory> shm( + new base::SharedMemory(buffer.handle(), false)); + if (!shm->Map(buffer.size())) { + DLOG(ERROR) << "Failed mapping shared memory."; + client_->NotifyError(kPlatformFailureError); + return; + } + + scoped_ptr<BitstreamBufferRef> buffer_ref( + new BitstreamBufferRef(buffer.id(), std::move(shm), buffer.size())); + + encoder_thread_task_runner_->PostTask( + FROM_HERE, + base::Bind(&VTVideoEncodeAccelerator::UseOutputBitstreamBufferTask, + base::Unretained(this), base::Passed(&buffer_ref))); +} + +void VTVideoEncodeAccelerator::RequestEncodingParametersChange( + uint32_t bitrate, + uint32_t framerate) { + DVLOG(3) << __FUNCTION__ << ": bitrate=" << bitrate + << ": framerate=" << framerate; + DCHECK(thread_checker_.CalledOnValidThread()); + + encoder_thread_task_runner_->PostTask( + FROM_HERE, + base::Bind(&VTVideoEncodeAccelerator::RequestEncodingParametersChangeTask, + base::Unretained(this), bitrate, framerate)); +} + +void VTVideoEncodeAccelerator::Destroy() { + DVLOG(3) << __FUNCTION__; + DCHECK(thread_checker_.CalledOnValidThread()); + + // Cancel all callbacks. + client_ptr_factory_.reset(); + + if (encoder_thread_.IsRunning()) { + encoder_thread_task_runner_->PostTask( + FROM_HERE, + base::Bind(&VTVideoEncodeAccelerator::DestroyTask, + base::Unretained(this))); + encoder_thread_.Stop(); + } else { + DestroyTask(); + } +} + +void VTVideoEncodeAccelerator::EncodeTask( + const scoped_refptr<media::VideoFrame>& frame, + bool force_keyframe) { + DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); + DCHECK(compression_session_); + DCHECK(frame); + + // TODO(emircan): See if we can eliminate a copy here by using + // CVPixelBufferPool for the allocation of incoming VideoFrames. + base::ScopedCFTypeRef<CVPixelBufferRef> pixel_buffer = + media::WrapVideoFrameInCVPixelBuffer(*frame); + base::ScopedCFTypeRef<CFDictionaryRef> frame_props = + media::video_toolbox::DictionaryWithKeyValue( + videotoolbox_glue_->kVTEncodeFrameOptionKey_ForceKeyFrame(), + force_keyframe ? kCFBooleanTrue : kCFBooleanFalse); + + base::TimeTicks ref_time; + if (!frame->metadata()->GetTimeTicks( + media::VideoFrameMetadata::REFERENCE_TIME, &ref_time)) { + ref_time = base::TimeTicks::Now(); + } + auto timestamp_cm = CoreMediaGlue::CMTimeMake( + frame->timestamp().InMicroseconds(), USEC_PER_SEC); + // Wrap information we'll need after the frame is encoded in a heap object. + // We'll get the pointer back from the VideoToolbox completion callback. + scoped_ptr<InProgressFrameEncode> request(new InProgressFrameEncode( + frame->timestamp(), ref_time)); + + // We can pass the ownership of |request| to the encode callback if + // successful. Otherwise let it fall out of scope. + OSStatus status = videotoolbox_glue_->VTCompressionSessionEncodeFrame( + compression_session_, pixel_buffer, timestamp_cm, + CoreMediaGlue::CMTime{0, 0, 0, 0}, frame_props, + reinterpret_cast<void*>(request.get()), nullptr); + if (status != noErr) { + DLOG(ERROR) << " VTCompressionSessionEncodeFrame failed: " << status; + NotifyError(kPlatformFailureError); + } else { + CHECK(request.release()); + } +} + +void VTVideoEncodeAccelerator::UseOutputBitstreamBufferTask( + scoped_ptr<BitstreamBufferRef> buffer_ref) { + DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); + + // If there is already EncodeOutput waiting, copy its output first. + if (!encoder_output_queue_.empty()) { + scoped_ptr<VTVideoEncodeAccelerator::EncodeOutput> encode_output = + std::move(encoder_output_queue_.front()); + encoder_output_queue_.pop_front(); + ReturnBitstreamBuffer(std::move(encode_output), std::move(buffer_ref)); + return; + } + + bitstream_buffer_queue_.push_back(std::move(buffer_ref)); +} + +void VTVideoEncodeAccelerator::RequestEncodingParametersChangeTask( + uint32_t bitrate, + uint32_t framerate) { + DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); + + frame_rate_ = framerate > 1 ? framerate : 1; + target_bitrate_ = bitrate > 1 ? bitrate : 1; + + if (!compression_session_) { + NotifyError(kPlatformFailureError); + return; + } + + media::video_toolbox::SessionPropertySetter session_property_setter( + compression_session_, videotoolbox_glue_); + // TODO(emircan): See crbug.com/425352. + bool rv = session_property_setter.Set( + videotoolbox_glue_->kVTCompressionPropertyKey_AverageBitRate(), + target_bitrate_); + rv &= session_property_setter.Set( + videotoolbox_glue_->kVTCompressionPropertyKey_ExpectedFrameRate(), + frame_rate_); + rv &= session_property_setter.Set( + videotoolbox_glue_->kVTCompressionPropertyKey_DataRateLimits(), + media::video_toolbox::ArrayWithIntegerAndFloat( + target_bitrate_ / kBitsPerByte, 1.0f)); + DLOG_IF(ERROR, !rv) << "Couldn't change session encoding parameters."; +} + +void VTVideoEncodeAccelerator::DestroyTask() { + DCHECK(thread_checker_.CalledOnValidThread() || + (encoder_thread_.IsRunning() && + encoder_thread_task_runner_->BelongsToCurrentThread())); + + // Cancel all encoder thread callbacks. + encoder_task_weak_factory_.InvalidateWeakPtrs(); + + // This call blocks until all pending frames are flushed out. + DestroyCompressionSession(); +} + +void VTVideoEncodeAccelerator::NotifyError( + media::VideoEncodeAccelerator::Error error) { + DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); + client_task_runner_->PostTask( + FROM_HERE, base::Bind(&Client::NotifyError, client_, error)); +} + +// static +void VTVideoEncodeAccelerator::CompressionCallback(void* encoder_opaque, + void* request_opaque, + OSStatus status, + VTEncodeInfoFlags info, + CMSampleBufferRef sbuf) { + // This function may be called asynchronously, on a different thread from the + // one that calls VTCompressionSessionEncodeFrame. + DVLOG(3) << __FUNCTION__; + + auto encoder = reinterpret_cast<VTVideoEncodeAccelerator*>(encoder_opaque); + DCHECK(encoder); + + // Release InProgressFrameEncode, since we don't have support to return + // timestamps at this point. + scoped_ptr<InProgressFrameEncode> request( + reinterpret_cast<InProgressFrameEncode*>(request_opaque)); + request.reset(); + + // EncodeOutput holds onto CMSampleBufferRef when posting task between + // threads. + scoped_ptr<EncodeOutput> encode_output(new EncodeOutput(info, sbuf)); + + // This method is NOT called on |encoder_thread_|, so we still need to + // post a task back to it to do work. + encoder->encoder_thread_task_runner_->PostTask( + FROM_HERE, base::Bind(&VTVideoEncodeAccelerator::CompressionCallbackTask, + encoder->encoder_weak_ptr_, status, + base::Passed(&encode_output))); +} + +void VTVideoEncodeAccelerator::CompressionCallbackTask( + OSStatus status, + scoped_ptr<EncodeOutput> encode_output) { + DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); + + if (status != noErr) { + DLOG(ERROR) << " encode failed: " << status; + NotifyError(kPlatformFailureError); + return; + } + + // If there isn't any BitstreamBuffer to copy into, add it to a queue for + // later use. + if (bitstream_buffer_queue_.empty()) { + encoder_output_queue_.push_back(std::move(encode_output)); + return; + } + + scoped_ptr<VTVideoEncodeAccelerator::BitstreamBufferRef> buffer_ref = + std::move(bitstream_buffer_queue_.front()); + bitstream_buffer_queue_.pop_front(); + ReturnBitstreamBuffer(std::move(encode_output), std::move(buffer_ref)); +} + +void VTVideoEncodeAccelerator::ReturnBitstreamBuffer( + scoped_ptr<EncodeOutput> encode_output, + scoped_ptr<VTVideoEncodeAccelerator::BitstreamBufferRef> buffer_ref) { + DVLOG(3) << __FUNCTION__; + DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); + + if (encode_output->info & VideoToolboxGlue::kVTEncodeInfo_FrameDropped) { + DVLOG(2) << " frame dropped"; + client_task_runner_->PostTask( + FROM_HERE, base::Bind(&Client::BitstreamBufferReady, client_, + buffer_ref->id, 0, false)); + return; + } + + auto sample_attachments = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex( + CoreMediaGlue::CMSampleBufferGetSampleAttachmentsArray( + encode_output->sample_buffer.get(), true), + 0)); + const bool keyframe = + !CFDictionaryContainsKey(sample_attachments, + CoreMediaGlue::kCMSampleAttachmentKey_NotSync()); + + size_t used_buffer_size = 0; + const bool copy_rv = media::video_toolbox::CopySampleBufferToAnnexBBuffer( + encode_output->sample_buffer.get(), keyframe, buffer_ref->size, + reinterpret_cast<char*>(buffer_ref->shm->memory()), &used_buffer_size); + if (!copy_rv) { + DLOG(ERROR) << "Cannot copy output from SampleBuffer to AnnexBBuffer."; + used_buffer_size = 0; + } + + client_task_runner_->PostTask( + FROM_HERE, base::Bind(&Client::BitstreamBufferReady, client_, + buffer_ref->id, used_buffer_size, keyframe)); +} + +bool VTVideoEncodeAccelerator::ResetCompressionSession() { + DCHECK(thread_checker_.CalledOnValidThread()); + + DestroyCompressionSession(); + + CFTypeRef attributes_keys[] = { + kCVPixelBufferOpenGLCompatibilityKey, + kCVPixelBufferIOSurfacePropertiesKey, + kCVPixelBufferPixelFormatTypeKey + }; + const int format[] = { + CoreVideoGlue::kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange}; + CFTypeRef attributes_values[] = { + kCFBooleanTrue, + media::video_toolbox::DictionaryWithKeysAndValues(nullptr, nullptr, 0) + .release(), + media::video_toolbox::ArrayWithIntegers(format, arraysize(format)) + .release()}; + const base::ScopedCFTypeRef<CFDictionaryRef> attributes = + media::video_toolbox::DictionaryWithKeysAndValues( + attributes_keys, attributes_values, arraysize(attributes_keys)); + for (auto& v : attributes_values) + CFRelease(v); + + bool session_rv = + CreateCompressionSession(attributes, input_visible_size_, false); + if (!session_rv) { + DestroyCompressionSession(); + return false; + } + + const bool configure_rv = ConfigureCompressionSession(); + if (configure_rv) + RequestEncodingParametersChange(target_bitrate_, frame_rate_); + return configure_rv; +} + +bool VTVideoEncodeAccelerator::CreateCompressionSession( + base::ScopedCFTypeRef<CFDictionaryRef> attributes, + const gfx::Size& input_size, + bool require_hw_encoding) { + DCHECK(thread_checker_.CalledOnValidThread()); + + std::vector<CFTypeRef> encoder_keys; + std::vector<CFTypeRef> encoder_values; + if (require_hw_encoding) { + encoder_keys.push_back(videotoolbox_glue_ + ->kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder()); + encoder_values.push_back(kCFBooleanTrue); + } else { + encoder_keys.push_back(videotoolbox_glue_ + ->kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder()); + encoder_values.push_back(kCFBooleanTrue); + } + base::ScopedCFTypeRef<CFDictionaryRef> encoder_spec = + media::video_toolbox::DictionaryWithKeysAndValues( + encoder_keys.data(), encoder_values.data(), encoder_keys.size()); + + // Create the compression session. + // Note that the encoder object is given to the compression session as the + // callback context using a raw pointer. The C API does not allow us to use a + // smart pointer, nor is this encoder ref counted. However, this is still + // safe, because we 1) we own the compression session and 2) we tear it down + // safely. When destructing the encoder, the compression session is flushed + // and invalidated. Internally, VideoToolbox will join all of its threads + // before returning to the client. Therefore, when control returns to us, we + // are guaranteed that the output callback will not execute again. + OSStatus status = videotoolbox_glue_->VTCompressionSessionCreate( + kCFAllocatorDefault, + input_size.width(), + input_size.height(), + CoreMediaGlue::kCMVideoCodecType_H264, + encoder_spec, + attributes, + nullptr /* compressedDataAllocator */, + &VTVideoEncodeAccelerator::CompressionCallback, + reinterpret_cast<void*>(this), + compression_session_.InitializeInto()); + if (status != noErr) { + DLOG(ERROR) << " VTCompressionSessionCreate failed: " << status; + return false; + } + DVLOG(3) << " VTCompressionSession created with HW encode: " + << require_hw_encoding << ", input size=" << input_size.ToString(); + return true; +} + +bool VTVideoEncodeAccelerator::ConfigureCompressionSession() { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(compression_session_); + + media::video_toolbox::SessionPropertySetter session_property_setter( + compression_session_, videotoolbox_glue_); + bool rv = true; + rv &= session_property_setter.Set( + videotoolbox_glue_->kVTCompressionPropertyKey_ProfileLevel(), + videotoolbox_glue_->kVTProfileLevel_H264_Baseline_AutoLevel()); + rv &= session_property_setter.Set( + videotoolbox_glue_->kVTCompressionPropertyKey_RealTime(), true); + rv &= session_property_setter.Set( + videotoolbox_glue_->kVTCompressionPropertyKey_AllowFrameReordering(), + false); + DLOG_IF(ERROR, !rv) << " Setting session property failed."; + return rv; +} + +void VTVideoEncodeAccelerator::DestroyCompressionSession() { + DCHECK(thread_checker_.CalledOnValidThread() || + (encoder_thread_.IsRunning() && + encoder_thread_task_runner_->BelongsToCurrentThread())); + + if (compression_session_) { + videotoolbox_glue_->VTCompressionSessionInvalidate(compression_session_); + compression_session_.reset(); + } +} + +} // namespace content diff --git a/chromium/content/common/gpu/media/vt_video_encode_accelerator_mac.h b/chromium/content/common/gpu/media/vt_video_encode_accelerator_mac.h new file mode 100644 index 00000000000..aa4b37ed22d --- /dev/null +++ b/chromium/content/common/gpu/media/vt_video_encode_accelerator_mac.h @@ -0,0 +1,142 @@ +// Copyright 2016 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 CONTENT_COMMON_GPU_MEDIA_VT_VIDEO_ENCODE_ACCELERATOR_MAC_H_ +#define CONTENT_COMMON_GPU_MEDIA_VT_VIDEO_ENCODE_ACCELERATOR_MAC_H_ + +#include "base/mac/scoped_cftyperef.h" +#include "content/common/content_export.h" +#include "media/base/mac/videotoolbox_glue.h" +#include "media/base/mac/videotoolbox_helpers.h" +#include "media/video/video_encode_accelerator.h" + +namespace content { + +// VideoToolbox.framework implementation of the VideoEncodeAccelerator +// interface for MacOSX. VideoToolbox makes no guarantees that it is thread +// safe, so this object is pinned to the thread on which it is constructed. +class CONTENT_EXPORT VTVideoEncodeAccelerator + : public media::VideoEncodeAccelerator { + public: + VTVideoEncodeAccelerator(); + ~VTVideoEncodeAccelerator() override; + + // media::VideoEncodeAccelerator implementation. + media::VideoEncodeAccelerator::SupportedProfiles GetSupportedProfiles() + override; + bool Initialize(media::VideoPixelFormat format, + const gfx::Size& input_visible_size, + media::VideoCodecProfile output_profile, + uint32_t initial_bitrate, + Client* client) override; + void Encode(const scoped_refptr<media::VideoFrame>& frame, + bool force_keyframe) override; + void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer) override; + void RequestEncodingParametersChange(uint32_t bitrate, + uint32_t framerate) override; + void Destroy() override; + + private: + using CMSampleBufferRef = CoreMediaGlue::CMSampleBufferRef; + using VTCompressionSessionRef = VideoToolboxGlue::VTCompressionSessionRef; + using VTEncodeInfoFlags = VideoToolboxGlue::VTEncodeInfoFlags; + + // Holds the associated data of a video frame being processed. + struct InProgressFrameEncode; + + // Holds output buffers coming from the encoder. + struct EncodeOutput; + + // Holds output buffers coming from the client ready to be filled. + struct BitstreamBufferRef; + + // Encoding tasks to be run on |encoder_thread_|. + void EncodeTask(const scoped_refptr<media::VideoFrame>& frame, + bool force_keyframe); + void UseOutputBitstreamBufferTask(scoped_ptr<BitstreamBufferRef> buffer_ref); + void RequestEncodingParametersChangeTask(uint32_t bitrate, + uint32_t framerate); + void DestroyTask(); + + // Helper function to notify the client of an error on |client_task_runner_|. + void NotifyError(media::VideoEncodeAccelerator::Error error); + + // Compression session callback function to handle compressed frames. + static void CompressionCallback(void* encoder_opaque, + void* request_opaque, + OSStatus status, + VTEncodeInfoFlags info, + CMSampleBufferRef sbuf); + void CompressionCallbackTask(OSStatus status, + scoped_ptr<EncodeOutput> encode_output); + + // Copy CMSampleBuffer into a BitstreamBuffer and return it to the |client_|. + void ReturnBitstreamBuffer( + scoped_ptr<EncodeOutput> encode_output, + scoped_ptr<VTVideoEncodeAccelerator::BitstreamBufferRef> buffer_ref); + + // Reset the encoder's compression session by destroying the existing one + // using DestroyCompressionSession() and creating a new one. The new session + // is configured using ConfigureCompressionSession(). + bool ResetCompressionSession(); + + // Create a compression session, with HW encoder enforced if + // |require_hw_encoding| is set. + bool CreateCompressionSession( + base::ScopedCFTypeRef<CFDictionaryRef> attributes, + const gfx::Size& input_size, + bool require_hw_encoding); + + // Configure the current compression session using current encoder settings. + bool ConfigureCompressionSession(); + + // Destroy the current compression session if any. Blocks until all pending + // frames have been flushed out (similar to EmitFrames without doing any + // encoding work). + void DestroyCompressionSession(); + + // VideoToolboxGlue provides access to VideoToolbox at runtime. + const VideoToolboxGlue* videotoolbox_glue_; + base::ScopedCFTypeRef<VTCompressionSessionRef> compression_session_; + + gfx::Size input_visible_size_; + size_t bitstream_buffer_size_; + int32_t frame_rate_; + int32_t target_bitrate_; + + // Bitstream buffers ready to be used to return encoded output as a FIFO. + std::deque<scoped_ptr<BitstreamBufferRef>> bitstream_buffer_queue_; + + // EncodeOutput needs to be copied into a BitstreamBufferRef as a FIFO. + std::deque<scoped_ptr<EncodeOutput>> encoder_output_queue_; + + // Our original calling task runner for the child thread. + const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner_; + + // To expose client callbacks from VideoEncodeAccelerator. + // NOTE: all calls to this object *MUST* be executed on + // |client_task_runner_|. + base::WeakPtr<Client> client_; + scoped_ptr<base::WeakPtrFactory<Client> > client_ptr_factory_; + + // Thread checker to enforce that this object is used on a specific thread. + // It is pinned on |client_task_runner_| thread. + base::ThreadChecker thread_checker_; + + // This thread services tasks posted from the VEA API entry points by the + // GPU child thread and CompressionCallback() posted from device thread. + base::Thread encoder_thread_; + scoped_refptr<base::SingleThreadTaskRunner> encoder_thread_task_runner_; + + // Declared last to ensure that all weak pointers are invalidated before + // other destructors run. + base::WeakPtr<VTVideoEncodeAccelerator> encoder_weak_ptr_; + base::WeakPtrFactory<VTVideoEncodeAccelerator> encoder_task_weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(VTVideoEncodeAccelerator); +}; + +} // namespace content + +#endif // CONTENT_COMMON_GPU_MEDIA_VT_VIDEO_ENCODE_ACCELERATOR_MAC_H_ diff --git a/chromium/content/common/gpu/stream_texture_android.cc b/chromium/content/common/gpu/stream_texture_android.cc deleted file mode 100644 index 17d841d8eb1..00000000000 --- a/chromium/content/common/gpu/stream_texture_android.cc +++ /dev/null @@ -1,386 +0,0 @@ -// Copyright (c) 2013 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 "content/common/gpu/stream_texture_android.h" - -#include <string.h> - -#include "base/bind.h" -#include "base/strings/stringize_macros.h" -#include "content/common/android/surface_texture_peer.h" -#include "content/common/gpu/gpu_channel.h" -#include "content/common/gpu/gpu_messages.h" -#include "gpu/command_buffer/service/context_group.h" -#include "gpu/command_buffer/service/context_state.h" -#include "gpu/command_buffer/service/gles2_cmd_decoder.h" -#include "gpu/command_buffer/service/texture_manager.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gl/gl_context.h" -#include "ui/gl/gl_helper.h" -#include "ui/gl/scoped_binders.h" -#include "ui/gl/scoped_make_current.h" - -namespace content { - -using gpu::gles2::ContextGroup; -using gpu::gles2::GLES2Decoder; -using gpu::gles2::TextureManager; -using gpu::gles2::TextureRef; - -// static -bool StreamTexture::Create(GpuCommandBufferStub* owner_stub, - uint32_t client_texture_id, - int stream_id) { - GLES2Decoder* decoder = owner_stub->decoder(); - TextureManager* texture_manager = - decoder->GetContextGroup()->texture_manager(); - TextureRef* texture = texture_manager->GetTexture(client_texture_id); - - if (texture && (!texture->texture()->target() || - texture->texture()->target() == GL_TEXTURE_EXTERNAL_OES)) { - - // TODO: Ideally a valid image id was returned to the client so that - // it could then call glBindTexImage2D() for doing the following. - scoped_refptr<gl::GLImage> gl_image( - new StreamTexture(owner_stub, stream_id, texture->service_id())); - gfx::Size size = gl_image->GetSize(); - texture_manager->SetTarget(texture, GL_TEXTURE_EXTERNAL_OES); - texture_manager->SetLevelInfo(texture, GL_TEXTURE_EXTERNAL_OES, 0, GL_RGBA, - size.width(), size.height(), 1, 0, GL_RGBA, - GL_UNSIGNED_BYTE, gfx::Rect(size)); - texture_manager->SetLevelImage(texture, GL_TEXTURE_EXTERNAL_OES, 0, - gl_image.get(), - gpu::gles2::Texture::UNBOUND); - return true; - } - - return false; -} - -StreamTexture::StreamTexture(GpuCommandBufferStub* owner_stub, - int32_t route_id, - uint32_t texture_id) - : surface_texture_(gfx::SurfaceTexture::Create(texture_id)), - size_(0, 0), - has_valid_frame_(false), - has_pending_frame_(false), - owner_stub_(owner_stub), - route_id_(route_id), - has_listener_(false), - texture_id_(texture_id), - framebuffer_(0), - vertex_shader_(0), - fragment_shader_(0), - program_(0), - vertex_buffer_(0), - u_xform_location_(-1), - weak_factory_(this) { - owner_stub->AddDestructionObserver(this); - memset(current_matrix_, 0, sizeof(current_matrix_)); - owner_stub->channel()->AddRoute(route_id, this); - surface_texture_->SetFrameAvailableCallback(base::Bind( - &StreamTexture::OnFrameAvailable, weak_factory_.GetWeakPtr())); -} - -StreamTexture::~StreamTexture() { - if (owner_stub_) { - owner_stub_->RemoveDestructionObserver(this); - owner_stub_->channel()->RemoveRoute(route_id_); - } -} - -void StreamTexture::OnWillDestroyStub() { - owner_stub_->RemoveDestructionObserver(this); - owner_stub_->channel()->RemoveRoute(route_id_); - - if (framebuffer_) { - scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current(MakeStubCurrent()); - - glDeleteProgram(program_); - glDeleteShader(vertex_shader_); - glDeleteShader(fragment_shader_); - glDeleteBuffersARB(1, &vertex_buffer_); - glDeleteFramebuffersEXT(1, &framebuffer_); - program_ = 0; - vertex_shader_ = 0; - fragment_shader_ = 0; - vertex_buffer_ = 0; - framebuffer_ = 0; - u_xform_location_ = -1; - } - - owner_stub_ = NULL; - - // If the owner goes away, there is no need to keep the SurfaceTexture around. - // The GL texture will keep working regardless with the currently bound frame. - surface_texture_ = NULL; -} - -void StreamTexture::Destroy(bool have_context) { - NOTREACHED(); -} - -scoped_ptr<ui::ScopedMakeCurrent> StreamTexture::MakeStubCurrent() { - scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current; - bool needs_make_current = - !owner_stub_->decoder()->GetGLContext()->IsCurrent(NULL); - // On Android we should not have to perform a real context switch here when - // using virtual contexts. - DCHECK(!needs_make_current || - !owner_stub_->decoder() - ->GetContextGroup() - ->feature_info() - ->workarounds() - .use_virtualized_gl_contexts); - if (needs_make_current) { - scoped_make_current.reset(new ui::ScopedMakeCurrent( - owner_stub_->decoder()->GetGLContext(), owner_stub_->surface())); - } - return scoped_make_current; -} - -void StreamTexture::UpdateTexImage() { - DCHECK(surface_texture_.get()); - DCHECK(owner_stub_); - - if (!has_pending_frame_) return; - - scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current(MakeStubCurrent()); - - surface_texture_->UpdateTexImage(); - - has_valid_frame_ = true; - has_pending_frame_ = false; - - float mtx[16]; - surface_texture_->GetTransformMatrix(mtx); - - if (memcmp(current_matrix_, mtx, sizeof(mtx)) != 0) { - memcpy(current_matrix_, mtx, sizeof(mtx)); - - if (has_listener_) { - GpuStreamTextureMsg_MatrixChanged_Params params; - memcpy(¶ms.m00, mtx, sizeof(mtx)); - owner_stub_->channel()->Send( - new GpuStreamTextureMsg_MatrixChanged(route_id_, params)); - } - } - - if (scoped_make_current.get()) { - // UpdateTexImage() implies glBindTexture(). - // The cmd decoder takes care of restoring the binding for this GLImage as - // far as the current context is concerned, but if we temporarily change - // it, we have to keep the state intact in *that* context also. - const gpu::gles2::ContextState* state = - owner_stub_->decoder()->GetContextState(); - const gpu::gles2::TextureUnit& active_unit = - state->texture_units[state->active_texture_unit]; - glBindTexture(GL_TEXTURE_EXTERNAL_OES, - active_unit.bound_texture_external_oes.get() - ? active_unit.bound_texture_external_oes->service_id() - : 0); - } -} - -bool StreamTexture::CopyTexImage(unsigned target) { - if (target == GL_TEXTURE_2D) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size_.width(), size_.height(), 0, - GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - return CopyTexSubImage(GL_TEXTURE_2D, gfx::Point(), gfx::Rect(size_)); - } - - if (target != GL_TEXTURE_EXTERNAL_OES) - return false; - - if (!owner_stub_ || !surface_texture_.get()) - return true; - - GLint texture_id; - glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texture_id); - DCHECK(texture_id); - - // The following code only works if we're being asked to copy into - // |texture_id_|. Copying into a different texture is not supported. - if (static_cast<unsigned>(texture_id) != texture_id_) - return false; - - UpdateTexImage(); - - TextureManager* texture_manager = - owner_stub_->decoder()->GetContextGroup()->texture_manager(); - gpu::gles2::Texture* texture = - texture_manager->GetTextureForServiceId(texture_id_); - if (texture) { - // By setting image state to UNBOUND instead of COPIED we ensure that - // CopyTexImage() is called each time the surface texture is used for - // drawing. - texture->SetLevelImage(GL_TEXTURE_EXTERNAL_OES, 0, this, - gpu::gles2::Texture::UNBOUND); - } - - return true; -} - -void StreamTexture::OnFrameAvailable() { - has_pending_frame_ = true; - if (has_listener_ && owner_stub_) { - owner_stub_->channel()->Send( - new GpuStreamTextureMsg_FrameAvailable(route_id_)); - } -} - -gfx::Size StreamTexture::GetSize() { - return size_; -} - -unsigned StreamTexture::GetInternalFormat() { - return GL_RGBA; -} - -bool StreamTexture::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(StreamTexture, message) - IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_StartListening, OnStartListening) - IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_EstablishPeer, OnEstablishPeer) - IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_SetSize, OnSetSize) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - - DCHECK(handled); - return handled; -} - -void StreamTexture::OnStartListening() { - DCHECK(!has_listener_); - has_listener_ = true; -} - -void StreamTexture::OnEstablishPeer(int32_t primary_id, int32_t secondary_id) { - if (!owner_stub_) - return; - - base::ProcessHandle process = owner_stub_->channel()->GetClientPID(); - - SurfaceTexturePeer::GetInstance()->EstablishSurfaceTexturePeer( - process, surface_texture_, primary_id, secondary_id); -} - -bool StreamTexture::BindTexImage(unsigned target) { - NOTREACHED(); - return false; -} - -void StreamTexture::ReleaseTexImage(unsigned target) { - NOTREACHED(); -} - -bool StreamTexture::CopyTexSubImage(unsigned target, - const gfx::Point& offset, - const gfx::Rect& rect) { - if (target != GL_TEXTURE_2D) - return false; - - if (!owner_stub_ || !surface_texture_.get()) - return true; - - if (!offset.IsOrigin()) { - LOG(ERROR) << "Non-origin offset is not supported"; - return false; - } - - if (rect != gfx::Rect(size_)) { - LOG(ERROR) << "Sub-rectangle is not supported"; - return false; - } - - GLint target_texture = 0; - glGetIntegerv(GL_TEXTURE_BINDING_2D, &target_texture); - DCHECK(target_texture); - - UpdateTexImage(); - - if (!framebuffer_) { - glGenFramebuffersEXT(1, &framebuffer_); - - // This vertex shader introduces a y flip before applying the stream - // texture matrix. This is required because the stream texture matrix - // Android provides is intended to be used in a y-up coordinate system, - // whereas Chromium expects y-down. - - // clang-format off - const char kVertexShader[] = STRINGIZE( - attribute vec2 a_position; - varying vec2 v_texCoord; - uniform mat4 u_xform; - void main() { - gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0); - vec2 uv_untransformed = a_position * vec2(0.5, -0.5) + vec2(0.5, 0.5); - v_texCoord = (u_xform * vec4(uv_untransformed, 0.0, 1.0)).xy; - } - ); - const char kFragmentShader[] = - "#extension GL_OES_EGL_image_external : require\n" STRINGIZE( - precision mediump float; - uniform samplerExternalOES a_texture; - varying vec2 v_texCoord; - void main() { - gl_FragColor = texture2D(a_texture, v_texCoord); - } - ); - // clang-format on - - vertex_buffer_ = gfx::GLHelper::SetupQuadVertexBuffer(); - vertex_shader_ = gfx::GLHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader); - fragment_shader_ = - gfx::GLHelper::LoadShader(GL_FRAGMENT_SHADER, kFragmentShader); - program_ = gfx::GLHelper::SetupProgram(vertex_shader_, fragment_shader_); - gfx::ScopedUseProgram use_program(program_); - int sampler_location = glGetUniformLocation(program_, "a_texture"); - DCHECK_NE(-1, sampler_location); - glUniform1i(sampler_location, 0); - u_xform_location_ = glGetUniformLocation(program_, "u_xform"); - DCHECK_NE(-1, u_xform_location_); - } - - gfx::ScopedActiveTexture active_texture(GL_TEXTURE0); - // UpdateTexImage() call below will bind the surface texture to - // TEXTURE_EXTERNAL_OES. This scoped texture binder will restore the current - // binding before this function returns. - gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_EXTERNAL_OES, texture_id_); - - { - gfx::ScopedFrameBufferBinder framebuffer_binder(framebuffer_); - gfx::ScopedViewport viewport(0, 0, size_.width(), size_.height()); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, target_texture, 0); - DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), - glCheckFramebufferStatusEXT(GL_FRAMEBUFFER)); - gfx::ScopedUseProgram use_program(program_); - - glUniformMatrix4fv(u_xform_location_, 1, false, current_matrix_); - gfx::GLHelper::DrawQuad(vertex_buffer_); - - // Detach the output texture from the fbo. - glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, 0, 0); - } - return true; -} - -bool StreamTexture::ScheduleOverlayPlane(gfx::AcceleratedWidget widget, - int z_order, - gfx::OverlayTransform transform, - const gfx::Rect& bounds_rect, - const gfx::RectF& crop_rect) { - NOTREACHED(); - return false; -} - -void StreamTexture::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, - uint64_t process_tracing_id, - const std::string& dump_name) { - // TODO(ericrk): Add OnMemoryDump for GLImages. crbug.com/514914 -} - -} // namespace content diff --git a/chromium/content/common/gpu/stream_texture_android.h b/chromium/content/common/gpu/stream_texture_android.h deleted file mode 100644 index e19fc1b321a..00000000000 --- a/chromium/content/common/gpu/stream_texture_android.h +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2013 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 CONTENT_COMMON_GPU_STREAM_TEXTURE_ANDROID_H_ -#define CONTENT_COMMON_GPU_STREAM_TEXTURE_ANDROID_H_ - -#include <stdint.h> - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "content/common/gpu/gpu_command_buffer_stub.h" -#include "ipc/ipc_listener.h" -#include "ui/gl/android/surface_texture.h" -#include "ui/gl/gl_image.h" - -namespace ui { -class ScopedMakeCurrent; -} - -namespace gfx { -class Size; -} - -namespace content { - -class StreamTexture : public gl::GLImage, - public IPC::Listener, - public GpuCommandBufferStub::DestructionObserver { - public: - static bool Create(GpuCommandBufferStub* owner_stub, - uint32_t client_texture_id, - int stream_id); - - private: - StreamTexture(GpuCommandBufferStub* owner_stub, - int32_t route_id, - uint32_t texture_id); - ~StreamTexture() override; - - // gl::GLImage implementation: - void Destroy(bool have_context) override; - gfx::Size GetSize() override; - unsigned GetInternalFormat() override; - bool BindTexImage(unsigned target) override; - void ReleaseTexImage(unsigned target) override; - bool CopyTexImage(unsigned target) override; - bool CopyTexSubImage(unsigned target, - const gfx::Point& offset, - const gfx::Rect& rect) override; - bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget, - int z_order, - gfx::OverlayTransform transform, - const gfx::Rect& bounds_rect, - const gfx::RectF& crop_rect) override; - void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, - uint64_t process_tracing_id, - const std::string& dump_name) override; - - // GpuCommandBufferStub::DestructionObserver implementation. - void OnWillDestroyStub() override; - - scoped_ptr<ui::ScopedMakeCurrent> MakeStubCurrent(); - - void UpdateTexImage(); - - // Called when a new frame is available for the SurfaceTexture. - void OnFrameAvailable(); - - // IPC::Listener implementation: - bool OnMessageReceived(const IPC::Message& message) override; - - // IPC message handlers: - void OnStartListening(); - void OnEstablishPeer(int32_t primary_id, int32_t secondary_id); - void OnSetSize(const gfx::Size& size) { size_ = size; } - - scoped_refptr<gfx::SurfaceTexture> surface_texture_; - - // Current transform matrix of the surface texture. - float current_matrix_[16]; - - // Current size of the surface texture. - gfx::Size size_; - - // Whether we ever bound a valid frame. - bool has_valid_frame_; - - // Whether a new frame is available that we should update to. - bool has_pending_frame_; - - GpuCommandBufferStub* owner_stub_; - int32_t route_id_; - bool has_listener_; - uint32_t texture_id_; - - unsigned framebuffer_; - unsigned vertex_shader_; - unsigned fragment_shader_; - unsigned program_; - unsigned vertex_buffer_; - int u_xform_location_; - - base::WeakPtrFactory<StreamTexture> weak_factory_; - DISALLOW_COPY_AND_ASSIGN(StreamTexture); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_STREAM_TEXTURE_ANDROID_H_ diff --git a/chromium/content/common/gpu/x_util.h b/chromium/content/common/gpu/x_util.h deleted file mode 100644 index 99687566356..00000000000 --- a/chromium/content/common/gpu/x_util.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_GPU_X_UTIL_H_ -#define CONTENT_COMMON_GPU_X_UTIL_H_ - -// Some X-Windows specific stuff. This can be included on any platform, and will -// be a NOP on non-Linux ones. - -#include "build/build_config.h" -#include "content/common/gpu/gpu_config.h" - -#if defined(USE_X11) - -namespace content { - -// Forward declares ------------------------------------------------------------ -// -// X Windows headers do a lot of evil stuff, like "#define Status int" which -// will cause many problems when combined with our other header files (like -// ones that define a class local enum called "Status." -// -// These definitions are not Kosher, but allow us to remove this dependency and -// actually compile X at all. - -typedef unsigned long XID; - -extern "C" { - -typedef struct _XDisplay Display; -typedef struct __GLXcontextRec *GLXContext; - -} // extern "C" - -} // namespace content - -#endif // USE_X11 - -#endif // CONTENT_COMMON_GPU_X_UTIL_H_ diff --git a/chromium/content/common/gpu_host_messages.h b/chromium/content/common/gpu_host_messages.h new file mode 100644 index 00000000000..0705be08955 --- /dev/null +++ b/chromium/content/common/gpu_host_messages.h @@ -0,0 +1,300 @@ +// Copyright 2016 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. + +// Multiply-included message file, hence no include guard here, but see below +// for a much smaller-than-usual include guard section. + +#include "build/build_config.h" +#include "content/common/content_export.h" +#include "content/common/establish_channel_params.h" +#include "gpu/command_buffer/common/sync_token.h" +#include "gpu/command_buffer/common/value_state.h" +#include "gpu/command_buffer/service/gpu_preferences.h" +#include "gpu/config/gpu_info.h" +#include "gpu/ipc/common/gpu_command_buffer_traits.h" +#include "gpu/ipc/common/gpu_memory_uma_stats.h" +#include "gpu/ipc/common/gpu_param_traits.h" +#include "gpu/ipc/common/memory_stats.h" +#include "gpu/ipc/common/surface_handle.h" +#include "ipc/ipc_channel_handle.h" +#include "ipc/ipc_message_macros.h" +#include "ipc/ipc_message_start.h" +#include "ui/events/ipc/latency_info_param_traits.h" +#include "ui/gfx/gpu_memory_buffer.h" +#include "ui/gfx/ipc/gfx_param_traits.h" +#include "ui/gfx/ipc/skia/gfx_skia_param_traits.h" +#include "url/gurl.h" +#include "url/ipc/url_param_traits.h" + +#if defined(OS_MACOSX) +#include "content/common/accelerated_surface_buffers_swapped_params_mac.h" +#include "content/common/buffer_presented_params_mac.h" +#include "ui/base/cocoa/remote_layer_api.h" +#include "ui/gfx/mac/io_surface.h" +#endif + +#undef IPC_MESSAGE_EXPORT +#define IPC_MESSAGE_EXPORT CONTENT_EXPORT + +#define IPC_MESSAGE_START GpuMsgStart + +IPC_STRUCT_TRAITS_BEGIN(gpu::GPUMemoryUmaStats) + IPC_STRUCT_TRAITS_MEMBER(bytes_allocated_current) + IPC_STRUCT_TRAITS_MEMBER(bytes_allocated_max) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(gpu::VideoMemoryUsageStats) + IPC_STRUCT_TRAITS_MEMBER(process_map) + IPC_STRUCT_TRAITS_MEMBER(bytes_allocated) + IPC_STRUCT_TRAITS_MEMBER(bytes_allocated_historical_max) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(gpu::VideoMemoryUsageStats::ProcessStats) + IPC_STRUCT_TRAITS_MEMBER(video_memory) + IPC_STRUCT_TRAITS_MEMBER(has_duplicates) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_BEGIN(GpuMsg_CreateGpuMemoryBuffer_Params) + IPC_STRUCT_MEMBER(gfx::GpuMemoryBufferId, id) + IPC_STRUCT_MEMBER(gfx::Size, size) + IPC_STRUCT_MEMBER(gfx::BufferFormat, format) + IPC_STRUCT_MEMBER(gfx::BufferUsage, usage) + IPC_STRUCT_MEMBER(int32_t, client_id) + IPC_STRUCT_MEMBER(gpu::SurfaceHandle, surface_handle) +IPC_STRUCT_END() + +IPC_STRUCT_BEGIN(GpuMsg_CreateGpuMemoryBufferFromHandle_Params) + IPC_STRUCT_MEMBER(gfx::GpuMemoryBufferHandle, handle) + IPC_STRUCT_MEMBER(gfx::GpuMemoryBufferId, id) + IPC_STRUCT_MEMBER(gfx::Size, size) + IPC_STRUCT_MEMBER(gfx::BufferFormat, format) + IPC_STRUCT_MEMBER(int32_t, client_id) +IPC_STRUCT_END() + +IPC_STRUCT_TRAITS_BEGIN(content::EstablishChannelParams) + IPC_STRUCT_TRAITS_MEMBER(client_id) + IPC_STRUCT_TRAITS_MEMBER(client_tracing_id) + IPC_STRUCT_TRAITS_MEMBER(preempts) + IPC_STRUCT_TRAITS_MEMBER(allow_view_command_buffers) + IPC_STRUCT_TRAITS_MEMBER(allow_real_time_streams) +IPC_STRUCT_TRAITS_END() + +#if defined(OS_MACOSX) +IPC_STRUCT_TRAITS_BEGIN(content::AcceleratedSurfaceBuffersSwappedParams) + IPC_STRUCT_TRAITS_MEMBER(surface_id) + // Only one of ca_context_id or io_surface may be non-0. + IPC_STRUCT_TRAITS_MEMBER(ca_context_id) + IPC_STRUCT_TRAITS_MEMBER(io_surface) + IPC_STRUCT_TRAITS_MEMBER(size) + IPC_STRUCT_TRAITS_MEMBER(scale_factor) + IPC_STRUCT_TRAITS_MEMBER(latency_info) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(content::BufferPresentedParams) + // The vsync parameters, to synchronize presentation with the display. + IPC_STRUCT_TRAITS_MEMBER(surface_id) + IPC_STRUCT_TRAITS_MEMBER(vsync_timebase) + IPC_STRUCT_TRAITS_MEMBER(vsync_interval) +IPC_STRUCT_TRAITS_END() +#endif + +IPC_STRUCT_TRAITS_BEGIN(gpu::GpuPreferences) + IPC_STRUCT_TRAITS_MEMBER(single_process) + IPC_STRUCT_TRAITS_MEMBER(in_process_gpu) + IPC_STRUCT_TRAITS_MEMBER(ui_prioritize_in_gpu_process) + IPC_STRUCT_TRAITS_MEMBER(disable_accelerated_video_decode) +#if defined(OS_CHROMEOS) + IPC_STRUCT_TRAITS_MEMBER(disable_vaapi_accelerated_video_encode) +#endif +#if defined(ENABLE_WEBRTC) + IPC_STRUCT_TRAITS_MEMBER(disable_web_rtc_hw_encoding) +#endif +#if defined(OS_WIN) + IPC_STRUCT_TRAITS_MEMBER(enable_accelerated_vpx_decode) +#endif + IPC_STRUCT_TRAITS_MEMBER(compile_shader_always_succeeds) + IPC_STRUCT_TRAITS_MEMBER(disable_gl_error_limit) + IPC_STRUCT_TRAITS_MEMBER(disable_glsl_translator) + IPC_STRUCT_TRAITS_MEMBER(disable_gpu_driver_bug_workarounds) + IPC_STRUCT_TRAITS_MEMBER(disable_shader_name_hashing) + IPC_STRUCT_TRAITS_MEMBER(enable_gpu_command_logging) + IPC_STRUCT_TRAITS_MEMBER(enable_gpu_debugging) + IPC_STRUCT_TRAITS_MEMBER(enable_gpu_service_logging_gpu) + IPC_STRUCT_TRAITS_MEMBER(disable_gpu_program_cache) + IPC_STRUCT_TRAITS_MEMBER(enforce_gl_minimums) + IPC_STRUCT_TRAITS_MEMBER(force_gpu_mem_available) + IPC_STRUCT_TRAITS_MEMBER(gpu_program_cache_size) + IPC_STRUCT_TRAITS_MEMBER(disable_gpu_shader_disk_cache) + IPC_STRUCT_TRAITS_MEMBER(enable_share_group_async_texture_upload) + IPC_STRUCT_TRAITS_MEMBER(enable_subscribe_uniform_extension) + IPC_STRUCT_TRAITS_MEMBER(enable_threaded_texture_mailboxes) + IPC_STRUCT_TRAITS_MEMBER(gl_shader_interm_output) + IPC_STRUCT_TRAITS_MEMBER(emulate_shader_precision) + IPC_STRUCT_TRAITS_MEMBER(enable_gpu_service_logging) + IPC_STRUCT_TRAITS_MEMBER(enable_gpu_service_tracing) + IPC_STRUCT_TRAITS_MEMBER(enable_unsafe_es3_apis) +IPC_STRUCT_TRAITS_END() + +//------------------------------------------------------------------------------ +// GPU Messages +// These are messages from the browser to the GPU process. + +// Tells the GPU process to initialize itself. The browser explicitly +// requests this be done so that we are guaranteed that the channel is set +// up between the browser and GPU process before doing any work that might +// potentially crash the GPU process. Detection of the child process +// exiting abruptly is predicated on having the IPC channel set up. +IPC_MESSAGE_CONTROL1(GpuMsg_Initialize, + gpu::GpuPreferences /* gpu_prefernces */) + +// Tells the GPU process to shutdown itself. +IPC_MESSAGE_CONTROL0(GpuMsg_Finalize) + +// Tells the GPU process to create a new channel for communication with a +// given client. The channel name is returned in a +// GpuHostMsg_ChannelEstablished message. The client ID is passed so +// that the GPU process reuses an existing channel to that process if it exists. +// This ID is a unique opaque identifier generated by the browser process. +// The client_tracing_id is a unique ID used for the purposes of tracing. +IPC_MESSAGE_CONTROL1(GpuMsg_EstablishChannel, + content::EstablishChannelParams /* params */) + +// Tells the GPU process to close the channel identified by |client_id|. +// If no channel can be identified, do nothing. +IPC_MESSAGE_CONTROL1(GpuMsg_CloseChannel, int32_t /* client_id */) + +// Tells the GPU process to create a new gpu memory buffer. +IPC_MESSAGE_CONTROL1(GpuMsg_CreateGpuMemoryBuffer, + GpuMsg_CreateGpuMemoryBuffer_Params) + +// Tells the GPU process to create a new gpu memory buffer from an existing +// handle. +IPC_MESSAGE_CONTROL1(GpuMsg_CreateGpuMemoryBufferFromHandle, + GpuMsg_CreateGpuMemoryBufferFromHandle_Params) + +// Tells the GPU process to destroy buffer. +IPC_MESSAGE_CONTROL3(GpuMsg_DestroyGpuMemoryBuffer, + gfx::GpuMemoryBufferId, /* id */ + int32_t, /* client_id */ + gpu::SyncToken /* sync_token */) + +// Tells the GPU process to create a context for collecting graphics card +// information. +IPC_MESSAGE_CONTROL0(GpuMsg_CollectGraphicsInfo) + +// Tells the GPU process to report video_memory information for the task manager +IPC_MESSAGE_CONTROL0(GpuMsg_GetVideoMemoryUsageStats) + +#if defined(OS_MACOSX) +// Tells the GPU process that the browser process has handled the swap +// buffers or post sub-buffer request. +IPC_MESSAGE_CONTROL1(AcceleratedSurfaceMsg_BufferPresented, + content::BufferPresentedParams) +#endif + +#if defined(OS_ANDROID) +// Tells the GPU process to wake up the GPU because we're about to draw. +IPC_MESSAGE_CONTROL0(GpuMsg_WakeUpGpu) +#endif + +// Tells the GPU process to remove all contexts. +IPC_MESSAGE_CONTROL0(GpuMsg_Clean) + +// Tells the GPU process to crash. +IPC_MESSAGE_CONTROL0(GpuMsg_Crash) + +// Tells the GPU process to hang. +IPC_MESSAGE_CONTROL0(GpuMsg_Hang) + +// Tells the GPU process to disable the watchdog thread. +IPC_MESSAGE_CONTROL0(GpuMsg_DisableWatchdog) + +// Tells the GPU process that the browser has seen a GPU switch. +IPC_MESSAGE_CONTROL0(GpuMsg_GpuSwitched) + +// Sends an input event to the gpu service. +IPC_MESSAGE_CONTROL3(GpuMsg_UpdateValueState, + int, /* client_id */ + unsigned int, /* target */ + gpu::ValueState /* valuestate */) + +//------------------------------------------------------------------------------ +// GPU Host Messages +// These are messages to the browser. + +// Response from GPU to a GputMsg_Initialize message. +IPC_MESSAGE_CONTROL2(GpuHostMsg_Initialized, + bool /* result */, + ::gpu::GPUInfo /* gpu_info */) + +// Response from GPU to a GpuHostMsg_EstablishChannel message. +IPC_MESSAGE_CONTROL1(GpuHostMsg_ChannelEstablished, + IPC::ChannelHandle /* channel_handle */) + +// Message from GPU to notify to destroy the channel. +IPC_MESSAGE_CONTROL1(GpuHostMsg_DestroyChannel, int32_t /* client_id */) + +// Message to cache the given shader information. +IPC_MESSAGE_CONTROL3(GpuHostMsg_CacheShader, + int32_t /* client_id */, + std::string /* key */, + std::string /* shader */) + +// Message to the GPU that a shader was loaded from disk. +IPC_MESSAGE_CONTROL1(GpuMsg_LoadedShader, std::string /* encoded shader */) + +// Response from GPU to a GpuMsg_CreateGpuMemoryBuffer message. +IPC_MESSAGE_CONTROL1(GpuHostMsg_GpuMemoryBufferCreated, + gfx::GpuMemoryBufferHandle /* handle */) + +// Response from GPU to a GpuMsg_CollectGraphicsInfo. +IPC_MESSAGE_CONTROL1(GpuHostMsg_GraphicsInfoCollected, + gpu::GPUInfo /* GPU logging stats */) + +// Response from GPU to a GpuMsg_GetVideoMemory. +IPC_MESSAGE_CONTROL1(GpuHostMsg_VideoMemoryUsageStats, + gpu::VideoMemoryUsageStats /* GPU memory stats */) + +#if defined(OS_MACOSX) +// Tells the browser that an accelerated surface has swapped. +IPC_MESSAGE_CONTROL1(GpuHostMsg_AcceleratedSurfaceBuffersSwapped, + content::AcceleratedSurfaceBuffersSwappedParams) +#endif + +#if defined(OS_WIN) +IPC_MESSAGE_CONTROL2(GpuHostMsg_AcceleratedSurfaceCreatedChildWindow, + gpu::SurfaceHandle /* parent_window */, + gpu::SurfaceHandle /* child_window */) +#endif + +IPC_MESSAGE_CONTROL1(GpuHostMsg_DidCreateOffscreenContext, GURL /* url */) + +IPC_MESSAGE_CONTROL3(GpuHostMsg_DidLoseContext, + bool /* offscreen */, + gpu::error::ContextLostReason /* reason */, + GURL /* url */) + +IPC_MESSAGE_CONTROL1(GpuHostMsg_DidDestroyOffscreenContext, GURL /* url */) + +// Tells the browser about GPU memory usage statistics for UMA logging. +IPC_MESSAGE_CONTROL1(GpuHostMsg_GpuMemoryUmaStats, + gpu::GPUMemoryUmaStats /* GPU memory UMA stats */) + +// Tells the browser that a context has subscribed to a new target and +// the browser should start sending the corresponding information +IPC_MESSAGE_CONTROL2(GpuHostMsg_AddSubscription, + int32_t /* client_id */, + unsigned int /* target */) + +// Tells the browser that no contexts are subscribed to the target anymore +// so the browser should stop sending the corresponding information +IPC_MESSAGE_CONTROL2(GpuHostMsg_RemoveSubscription, + int32_t /* client_id */, + unsigned int /* target */) + +// Message from GPU to add a GPU log message to the about:gpu page. +IPC_MESSAGE_CONTROL3(GpuHostMsg_OnLogMessage, + int /*severity*/, + std::string /* header */, + std::string /* message */) diff --git a/chromium/content/common/gpu/gpu_process_launch_causes.h b/chromium/content/common/gpu_process_launch_causes.h index 1c280761ef9..b7acd351152 100644 --- a/chromium/content/common/gpu/gpu_process_launch_causes.h +++ b/chromium/content/common/gpu_process_launch_causes.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_COMMON_GPU_GPU_PROCESS_LAUNCH_CAUSES_H_ -#define CONTENT_COMMON_GPU_GPU_PROCESS_LAUNCH_CAUSES_H_ +#ifndef CONTENT_COMMON_GPU_PROCESS_LAUNCH_CAUSES_H_ +#define CONTENT_COMMON_GPU_PROCESS_LAUNCH_CAUSES_H_ namespace content { @@ -23,7 +23,7 @@ enum CauseForGpuLaunch { CAUSE_FOR_GPU_LAUNCH_GPU_MEMORY_BUFFER_ALLOCATE, CAUSE_FOR_GPU_LAUNCH_JPEGDECODEACCELERATOR_INITIALIZE, CAUSE_FOR_GPU_LAUNCH_MOJO_SETUP, - CAUSE_FOR_GPU_LAUNCH_ARCVIDEOACCELERATOR, + CAUSE_FOR_GPU_LAUNCH_GET_GPU_SERVICE_REGISTRY, // All new values should be inserted above this point so that // existing values continue to match up with those in histograms.xml. @@ -32,4 +32,4 @@ enum CauseForGpuLaunch { } // namespace content -#endif // CONTENT_COMMON_GPU_GPU_PROCESS_LAUNCH_CAUSES_H_ +#endif // CONTENT_COMMON_GPU_PROCESS_LAUNCH_CAUSES_H_ diff --git a/chromium/content/common/host_discardable_shared_memory_manager.cc b/chromium/content/common/host_discardable_shared_memory_manager.cc index 7a6d480d295..d8d141cdaa8 100644 --- a/chromium/content/common/host_discardable_shared_memory_manager.cc +++ b/chromium/content/common/host_discardable_shared_memory_manager.cc @@ -15,6 +15,7 @@ #include "base/macros.h" #include "base/memory/discardable_memory.h" #include "base/numerics/safe_math.h" +#include "base/process/memory.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/sys_info.h" @@ -190,6 +191,9 @@ HostDiscardableSharedMemoryManager::current() { scoped_ptr<base::DiscardableMemory> HostDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory( size_t size) { + // TODO(reveman): Temporary diagnostics for http://crbug.com/577786. + CHECK_NE(size, 0u); + DiscardableSharedMemoryId new_id = g_next_discardable_shared_memory_id.GetNext(); base::ProcessHandle current_process_handle = base::GetCurrentProcessHandle(); @@ -200,10 +204,10 @@ HostDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory( AllocateLockedDiscardableSharedMemory(current_process_handle, ChildProcessHost::kInvalidUniqueID, size, new_id, &handle); - CHECK(base::SharedMemory::IsHandleValid(handle)); scoped_ptr<base::DiscardableSharedMemory> memory( new base::DiscardableSharedMemory(handle)); - CHECK(memory->Map(size)); + if (!memory->Map(size)) + base::TerminateBecauseOutOfMemory(size); // Close file descriptor to avoid running out. memory->Close(); return make_scoped_ptr(new DiscardableMemoryImpl( diff --git a/chromium/content/common/host_discardable_shared_memory_manager.h b/chromium/content/common/host_discardable_shared_memory_manager.h index 3965f1d4c5f..834afe75b3d 100644 --- a/chromium/content/common/host_discardable_shared_memory_manager.h +++ b/chromium/content/common/host_discardable_shared_memory_manager.h @@ -18,6 +18,7 @@ #include "base/memory/discardable_shared_memory.h" #include "base/memory/memory_pressure_listener.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/memory/shared_memory.h" #include "base/memory/weak_ptr.h" #include "base/process/process_handle.h" diff --git a/chromium/content/common/host_shared_bitmap_manager.cc b/chromium/content/common/host_shared_bitmap_manager.cc index d41ec392be5..e666f9b18c4 100644 --- a/chromium/content/common/host_shared_bitmap_manager.cc +++ b/chromium/content/common/host_shared_bitmap_manager.cc @@ -202,13 +202,8 @@ bool HostSharedBitmapManager::ChildAllocatedSharedBitmap( new BitmapData(process_handle, buffer_size)); handle_map_[id] = data; -#if defined(OS_WIN) - data->memory = make_scoped_ptr( - new base::SharedMemory(handle, false, data->process_handle)); -#else data->memory = make_scoped_ptr(new base::SharedMemory(handle, false)); -#endif data->memory->Map(data->buffer_size); data->memory->Close(); return true; diff --git a/chromium/content/common/id_type.h b/chromium/content/common/id_type.h deleted file mode 100644 index cc25fa5ac29..00000000000 --- a/chromium/content/common/id_type.h +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2016 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 CONTENT_COMMON_ID_TYPE_H_ -#define CONTENT_COMMON_ID_TYPE_H_ - -#include <stdint.h> -#include <ostream> -#include <type_traits> - -#include "base/containers/hash_tables.h" - -// IdType32<>, IdType64<>, etc. wrap an integer id in a custom, type-safe type. -// -// IdType32<Foo> is an alternative to int, for a class Foo with methods like: -// -// int GetId() { return id_; }; -// static Foo* FromId(int id) { return g_all_foos_by_id[id]; } -// -// Such methods are a standard means of safely referring to objects across -// thread and process boundaries. But if a nearby class Bar also represents -// its IDs as a bare int, horrific mixups are possible -- one example, of many, -// is http://crrev.com/365437. IdType<> offers compile-time protection against -// such mishaps, since IdType32<Foo> is incompatible with IdType32<Bar>, even -// though both just compile down to an int32_t. -// -// Templates in this file: -// IdType32<T> / IdTypeU32<T>: Signed / unsigned 32-bit IDs -// IdType64<T> / IdTypeU64<T>: Signed / unsigned 64-bit IDs -// IdType<>: For when you need a different underlying type or -// a default/invalid value other than zero. -// -// IdType32<Foo> behaves just like an int32_t in the following aspects: -// - it can be used as a key in std::map and/or base::hash_map; -// - it can be used as an argument to DCHECK_EQ or streamed to LOG(ERROR); -// - it has the same memory footprint and runtime overhead as int32_t; -// - it can be copied by memcpy. -// -// IdType32<Foo> has the following differences from a bare int32_t: -// - it forces coercions to go through GetUnsafeValue and FromUnsafeValue; -// - it restricts the set of available operations (i.e. no multiplication); -// - it ensures initialization to zero and allows checking against -// default-initialized values via is_null method. - -namespace content { - -template <typename TypeMarker, typename WrappedType, WrappedType kInvalidValue> -class IdType { - public: - IdType() : value_(kInvalidValue) {} - bool is_null() const { return value_ == kInvalidValue; } - - static IdType FromUnsafeValue(WrappedType value) { return IdType(value); } - WrappedType GetUnsafeValue() const { return value_; } - - IdType(const IdType& other) = default; - IdType& operator=(const IdType& other) = default; - - bool operator==(const IdType& other) const { return value_ == other.value_; } - bool operator!=(const IdType& other) const { return value_ != other.value_; } - bool operator<(const IdType& other) const { return value_ < other.value_; } - - protected: - explicit IdType(WrappedType val) : value_(val) {} - - private: - // In theory WrappedType could be any type that supports ==, <, <<, std::hash, - // etc., but to make things simpler (both for users and for maintainers) we - // explicitly restrict the design space to integers. This means the users - // can safely assume that IdType is relatively small and cheap to copy - // and the maintainers don't have to worry about WrappedType being a complex - // type (i.e. std::string or std::pair or a move-only type). - using IntegralWrappedType = - typename std::enable_if<std::is_integral<WrappedType>::value, - WrappedType>::type; - IntegralWrappedType value_; -}; - -// Type aliases for convenience: -template <typename TypeMarker> -using IdType32 = IdType<TypeMarker, int32_t, 0>; -template <typename TypeMarker> -using IdTypeU32 = IdType<TypeMarker, uint32_t, 0>; -template <typename TypeMarker> -using IdType64 = IdType<TypeMarker, int64_t, 0>; -template <typename TypeMarker> -using IdTypeU64 = IdType<TypeMarker, uint64_t, 0>; - -template <typename TypeMarker, typename WrappedType, WrappedType kInvalidValue> -std::ostream& operator<<( - std::ostream& stream, - const IdType<TypeMarker, WrappedType, kInvalidValue>& id) { - return stream << id.GetUnsafeValue(); -} - -} // namespace content - -namespace BASE_HASH_NAMESPACE { - -template <typename TypeMarker, typename WrappedType, WrappedType kInvalidValue> -struct hash<content::IdType<TypeMarker, WrappedType, kInvalidValue>> { - using argument_type = content::IdType<TypeMarker, WrappedType, kInvalidValue>; - using result_type = std::size_t; - result_type operator()(const argument_type& id) const { - return BASE_HASH_NAMESPACE::hash<WrappedType>()(id.GetUnsafeValue()); - } -}; - -} // namespace BASE_HASH_NAMESPACE - -#endif // CONTENT_COMMON_ID_TYPE_H_ diff --git a/chromium/content/common/id_type_unittest.cc b/chromium/content/common/id_type_unittest.cc deleted file mode 100644 index aa596d4cdc3..00000000000 --- a/chromium/content/common/id_type_unittest.cc +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2016 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 <limits> -#include <map> -#include <sstream> -#include <string> -#include <type_traits> - -#include "base/containers/hash_tables.h" -#include "content/common/id_type.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace content { - -namespace { - -class Foo; -using FooId = IdType<Foo, int, 0>; - -class Bar; -using BarId = IdType<Bar, int, 0>; - -class AnotherIdMarker; -class DerivedId : public IdType<AnotherIdMarker, int, 0> { - public: - explicit DerivedId(int unsafe_value) - : IdType<AnotherIdMarker, int, 0>(unsafe_value) {} -}; - -} // namespace - -TEST(IdType, DefaultValueIsInvalid) { - FooId foo_id; - EXPECT_TRUE(foo_id.is_null()); -} - -TEST(IdType, NormalValueIsValid) { - FooId foo_id = FooId::FromUnsafeValue(123); - EXPECT_FALSE(foo_id.is_null()); -} - -TEST(IdType, OutputStreamTest) { - FooId foo_id = FooId::FromUnsafeValue(123); - - std::ostringstream ss; - ss << foo_id; - EXPECT_EQ("123", ss.str()); -} - -TEST(IdType, IdType32) { - IdType32<Foo> id; - - EXPECT_EQ(0, id.GetUnsafeValue()); - static_assert(sizeof(int32_t) == sizeof(id), ""); -} - -TEST(IdType, IdTypeU32) { - IdTypeU32<Foo> id; - - EXPECT_EQ(0u, id.GetUnsafeValue()); - static_assert(sizeof(uint32_t) == sizeof(id), ""); -} - -TEST(IdType, IdType64) { - IdType64<Foo> id; - - EXPECT_EQ(0, id.GetUnsafeValue()); - static_assert(sizeof(int64_t) == sizeof(id), ""); -} - -TEST(IdType, IdTypeU64) { - IdTypeU64<Foo> id; - - EXPECT_EQ(0u, id.GetUnsafeValue()); - static_assert(sizeof(uint64_t) == sizeof(id), ""); -} - -TEST(IdType, DerivedClasses) { - DerivedId derived_id(456); - - std::ostringstream ss; - ss << derived_id; - EXPECT_EQ("456", ss.str()); - - std::map<DerivedId, std::string> ordered_map; - ordered_map[derived_id] = "blah"; - EXPECT_EQ(ordered_map[derived_id], "blah"); - - // TODO(lukasza): Enable std::unordered_map and base::hash_map for DerivedId. - // Ideally this should be possible without having to repeat std::hash<...> - // specialization for each derived class (but then SFINAE + std::enable_if + - // std::is_base_of doesn't seem to work for std::hash because std::hash only - // has a single template parameter?). - // std::unordered_map<DerivedId, std::string> unordered_map; - // unordered_map[derived_id] = "blah2"; - // EXPECT_EQ(unordered_map[derived_id], "blah2"); -} - -TEST(IdType, StaticAsserts) { - static_assert(!std::is_constructible<FooId, int>::value, - "Should be impossible to construct FooId from a raw integer."); - static_assert(!std::is_convertible<int, FooId>::value, - "Should be impossible to convert a raw integer into FooId."); - - static_assert(!std::is_constructible<FooId, BarId>::value, - "Should be impossible to construct FooId from a BarId."); - static_assert(!std::is_convertible<BarId, FooId>::value, - "Should be impossible to convert a BarId into FooId."); - - // The presence of a custom default constructor means that FooId is not a - // "trivial" class and therefore is not a POD type (unlike an int32_t). - // At the same time FooId has almost all of the properties of a POD type: - // - is "trivially copyable" (i.e. is memcpy-able), - // - has "standard layout" (i.e. interops with things expecting C layout). - // See http://stackoverflow.com/a/7189821 for more info about these - // concepts. - static_assert(std::is_standard_layout<FooId>::value, - "FooId should have standard layout. " - "See http://stackoverflow.com/a/7189821 for more info."); - static_assert(sizeof(FooId) == sizeof(int), - "FooId should be the same size as the raw integer it wraps."); - // TODO(lukasza): Enable these once <type_traits> supports all the standard - // C++11 equivalents (i.e. std::is_trivially_copyable instead of the - // non-standard std::has_trivial_copy_assign). - // static_assert(std::has_trivial_copy_constructor<FooId>::value, - // "FooId should have a trivial copy constructor."); - // static_assert(std::has_trivial_copy_assign<FooId>::value, - // "FooId should have a trivial copy assignment operator."); - // static_assert(std::has_trivial_destructor<FooId>::value, - // "FooId should have a trivial destructor."); -} - -class IdTypeSpecificValueTest : public ::testing::TestWithParam<int> { - protected: - FooId test_id() { return FooId::FromUnsafeValue(GetParam()); } - - FooId other_id() { - if (GetParam() != std::numeric_limits<int>::max()) - return FooId::FromUnsafeValue(GetParam() + 1); - else - return FooId::FromUnsafeValue(std::numeric_limits<int>::min()); - } -}; - -TEST_P(IdTypeSpecificValueTest, ComparisonToSelf) { - EXPECT_TRUE(test_id() == test_id()); - EXPECT_FALSE(test_id() != test_id()); - EXPECT_FALSE(test_id() < test_id()); -} - -TEST_P(IdTypeSpecificValueTest, ComparisonToOther) { - EXPECT_FALSE(test_id() == other_id()); - EXPECT_TRUE(test_id() != other_id()); -} - -TEST_P(IdTypeSpecificValueTest, UnsafeValueRoundtrips) { - int original_value = GetParam(); - FooId id = FooId::FromUnsafeValue(original_value); - int final_value = id.GetUnsafeValue(); - EXPECT_EQ(original_value, final_value); -} - -TEST_P(IdTypeSpecificValueTest, Copying) { - FooId original = test_id(); - - FooId copy_via_constructor(original); - EXPECT_EQ(original, copy_via_constructor); - - FooId copy_via_assignment; - copy_via_assignment = original; - EXPECT_EQ(original, copy_via_assignment); -} - -TEST_P(IdTypeSpecificValueTest, BaseHashmap) { - base::hash_map<FooId, std::string> map; - - map[test_id()] = "test_id"; - map[other_id()] = "other_id"; - - EXPECT_EQ(map[test_id()], "test_id"); - EXPECT_EQ(map[other_id()], "other_id"); -} - -TEST_P(IdTypeSpecificValueTest, StdMap) { - std::map<FooId, std::string> map; - - map[test_id()] = "test_id"; - map[other_id()] = "other_id"; - - EXPECT_EQ(map[test_id()], "test_id"); - EXPECT_EQ(map[other_id()], "other_id"); -} - -INSTANTIATE_TEST_CASE_P(, - IdTypeSpecificValueTest, - ::testing::Values(std::numeric_limits<int>::min(), - -1, - 0, - 1, - 123, - std::numeric_limits<int>::max())); - -} // namespace content diff --git a/chromium/content/common/image_downloader/image_downloader.mojom b/chromium/content/common/image_downloader/image_downloader.mojom index 7f3d289949d..b6ea34edd25 100644 --- a/chromium/content/common/image_downloader/image_downloader.mojom +++ b/chromium/content/common/image_downloader/image_downloader.mojom @@ -2,27 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -module image_downloader; +module content.mojom; import "skia/public/interfaces/bitmap.mojom"; import "ui/mojo/geometry/geometry.mojom"; -struct DownloadRequest { - string url; - bool is_favicon; - uint32 max_bitmap_size; - bool bypass_cache; -}; - -struct DownloadResult { - int32 http_status_code; - array<skia.Bitmap> images; - array<mojo.Size> original_image_sizes; -}; - interface ImageDownloader { // Fetch and decode an image from a given URL. // Returns the decoded images, or http_status_code to indicate error. // Each call is independent, overlapping calls are possible. - DownloadImage(DownloadRequest request) => (DownloadResult result); + DownloadImage(string url, + bool is_favicon, + uint32 max_bitmap_size, + bool bypass_cache) + => (int32 http_status_code, + array<skia.mojom.Bitmap> images, + array<mojo.Size> original_image_sizes); }; diff --git a/chromium/content/common/in_process_child_thread_params.cc b/chromium/content/common/in_process_child_thread_params.cc index 13e93902da6..84157997e06 100644 --- a/chromium/content/common/in_process_child_thread_params.cc +++ b/chromium/content/common/in_process_child_thread_params.cc @@ -8,9 +8,12 @@ namespace content { InProcessChildThreadParams::InProcessChildThreadParams( const std::string& channel_name, - scoped_refptr<base::SequencedTaskRunner> io_runner) - : channel_name_(channel_name), io_runner_(io_runner) { -} + scoped_refptr<base::SequencedTaskRunner> io_runner, + mojo::MessagePipeHandle handle) + : channel_name_(channel_name), io_runner_(io_runner), handle_(handle) {} + +InProcessChildThreadParams::InProcessChildThreadParams( + const InProcessChildThreadParams& other) = default; InProcessChildThreadParams::~InProcessChildThreadParams() { } diff --git a/chromium/content/common/in_process_child_thread_params.h b/chromium/content/common/in_process_child_thread_params.h index 938a6ef0806..73838db02d5 100644 --- a/chromium/content/common/in_process_child_thread_params.h +++ b/chromium/content/common/in_process_child_thread_params.h @@ -10,6 +10,7 @@ #include "base/memory/ref_counted.h" #include "base/sequenced_task_runner.h" #include "content/common/content_export.h" +#include "mojo/public/cpp/system/message_pipe.h" namespace content { @@ -20,17 +21,21 @@ class CONTENT_EXPORT InProcessChildThreadParams { public: InProcessChildThreadParams( const std::string& channel_name, - scoped_refptr<base::SequencedTaskRunner> io_runner); + scoped_refptr<base::SequencedTaskRunner> io_runner, + mojo::MessagePipeHandle handle = mojo::MessagePipeHandle()); + InProcessChildThreadParams(const InProcessChildThreadParams& other); ~InProcessChildThreadParams(); const std::string& channel_name() const { return channel_name_; } scoped_refptr<base::SequencedTaskRunner> io_runner() const { return io_runner_; } + mojo::MessagePipeHandle handle() const { return handle_; } private: std::string channel_name_; scoped_refptr<base::SequencedTaskRunner> io_runner_; + mojo::MessagePipeHandle handle_; }; } // namespace content diff --git a/chromium/content/common/indexed_db/indexed_db_messages.h b/chromium/content/common/indexed_db/indexed_db_messages.h index d360454f499..f0ec336ad9c 100644 --- a/chromium/content/common/indexed_db/indexed_db_messages.h +++ b/chromium/content/common/indexed_db/indexed_db_messages.h @@ -47,8 +47,8 @@ IPC_STRUCT_BEGIN(IndexedDBHostMsg_FactoryGetDatabaseNames_Params) // The response should have these ids. IPC_STRUCT_MEMBER(int32_t, ipc_thread_id) IPC_STRUCT_MEMBER(int32_t, ipc_callbacks_id) - // The string id of the origin doing the initiating. - IPC_STRUCT_MEMBER(std::string, database_identifier) + // The origin doing the initiating. + IPC_STRUCT_MEMBER(GURL, origin) IPC_STRUCT_END() // Used to open an indexed database. @@ -59,8 +59,8 @@ IPC_STRUCT_BEGIN(IndexedDBHostMsg_FactoryOpen_Params) IPC_STRUCT_MEMBER(int32_t, ipc_callbacks_id) // Identifier for database callbacks IPC_STRUCT_MEMBER(int32_t, ipc_database_callbacks_id) - // The string id of the origin doing the initiating. - IPC_STRUCT_MEMBER(std::string, database_identifier) + // The origin doing the initiating. + IPC_STRUCT_MEMBER(GURL, origin) // The name of the database. IPC_STRUCT_MEMBER(base::string16, name) // The transaction id used if a database upgrade is needed. @@ -74,8 +74,8 @@ IPC_STRUCT_BEGIN(IndexedDBHostMsg_FactoryDeleteDatabase_Params) // The response should have these ids. IPC_STRUCT_MEMBER(int32_t, ipc_thread_id) IPC_STRUCT_MEMBER(int32_t, ipc_callbacks_id) - // The string id of the origin doing the initiating. - IPC_STRUCT_MEMBER(std::string, database_identifier) + // The origin doing the initiating. + IPC_STRUCT_MEMBER(GURL, origin) // The name of the database. IPC_STRUCT_MEMBER(base::string16, name) IPC_STRUCT_END() @@ -341,8 +341,7 @@ IPC_STRUCT_END() IPC_STRUCT_BEGIN(IndexedDBDatabaseMetadata) IPC_STRUCT_MEMBER(int64_t, id) IPC_STRUCT_MEMBER(base::string16, name) - IPC_STRUCT_MEMBER(base::string16, version) - IPC_STRUCT_MEMBER(int64_t, int_version) + IPC_STRUCT_MEMBER(int64_t, version) IPC_STRUCT_MEMBER(int64_t, max_object_store_id) IPC_STRUCT_MEMBER(std::vector<IndexedDBObjectStoreMetadata>, object_stores) IPC_STRUCT_END() @@ -424,7 +423,7 @@ IPC_MESSAGE_CONTROL1(IndexedDBMsg_CallbacksUpgradeNeeded, IPC_MESSAGE_CONTROL2(IndexedDBMsg_DatabaseCallbacksForcedClose, int32_t, /* ipc_thread_id */ int32_t) /* ipc_database_callbacks_id */ -IPC_MESSAGE_CONTROL4(IndexedDBMsg_DatabaseCallbacksIntVersionChange, +IPC_MESSAGE_CONTROL4(IndexedDBMsg_DatabaseCallbacksVersionChange, int32_t, /* ipc_thread_id */ int32_t, /* ipc_database_callbacks_id */ int64_t, /* old_version */ diff --git a/chromium/content/common/indexed_db/indexed_db_param_traits.cc b/chromium/content/common/indexed_db/indexed_db_param_traits.cc index 9ca0ceceeac..c684e9f24d7 100644 --- a/chromium/content/common/indexed_db/indexed_db_param_traits.cc +++ b/chromium/content/common/indexed_db/indexed_db_param_traits.cc @@ -30,7 +30,7 @@ using blink::WebIDBKeyTypeString; namespace IPC { -void ParamTraits<IndexedDBKey>::Write(Message* m, const param_type& p) { +void ParamTraits<IndexedDBKey>::Write(base::Pickle* m, const param_type& p) { WriteParam(m, static_cast<int>(p.type())); switch (p.type()) { case WebIDBKeyTypeArray: @@ -58,7 +58,7 @@ void ParamTraits<IndexedDBKey>::Write(Message* m, const param_type& p) { } } -bool ParamTraits<IndexedDBKey>::Read(const Message* m, +bool ParamTraits<IndexedDBKey>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int type; @@ -153,7 +153,8 @@ void ParamTraits<IndexedDBKey>::Log(const param_type& p, std::string* l) { l->append(")"); } -void ParamTraits<IndexedDBKeyPath>::Write(Message* m, const param_type& p) { +void ParamTraits<IndexedDBKeyPath>::Write(base::Pickle* m, + const param_type& p) { WriteParam(m, static_cast<int>(p.type())); switch (p.type()) { case WebIDBKeyPathTypeArray: @@ -170,7 +171,7 @@ void ParamTraits<IndexedDBKeyPath>::Write(Message* m, const param_type& p) { } } -bool ParamTraits<IndexedDBKeyPath>::Read(const Message* m, +bool ParamTraits<IndexedDBKeyPath>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int type; @@ -230,14 +231,15 @@ void ParamTraits<IndexedDBKeyPath>::Log(const param_type& p, std::string* l) { l->append(")"); } -void ParamTraits<IndexedDBKeyRange>::Write(Message* m, const param_type& p) { +void ParamTraits<IndexedDBKeyRange>::Write(base::Pickle* m, + const param_type& p) { WriteParam(m, p.lower()); WriteParam(m, p.upper()); WriteParam(m, p.lower_open()); WriteParam(m, p.upper_open()); } -bool ParamTraits<IndexedDBKeyRange>::Read(const Message* m, +bool ParamTraits<IndexedDBKeyRange>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { IndexedDBKey lower; diff --git a/chromium/content/common/indexed_db/indexed_db_param_traits.h b/chromium/content/common/indexed_db/indexed_db_param_traits.h index 8f6eeb20bee..e11b2830743 100644 --- a/chromium/content/common/indexed_db/indexed_db_param_traits.h +++ b/chromium/content/common/indexed_db/indexed_db_param_traits.h @@ -21,24 +21,30 @@ namespace IPC { template <> struct ParamTraits<content::IndexedDBKey> { typedef content::IndexedDBKey param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct ParamTraits<content::IndexedDBKeyRange> { typedef content::IndexedDBKeyRange param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct ParamTraits<content::IndexedDBKeyPath> { typedef content::IndexedDBKeyPath param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; diff --git a/chromium/content/common/input/event_with_latency_info.h b/chromium/content/common/input/event_with_latency_info.h new file mode 100644 index 00000000000..24742a3baeb --- /dev/null +++ b/chromium/content/common/input/event_with_latency_info.h @@ -0,0 +1,63 @@ +// Copyright 2013 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 CONTENT_COMMON_INPUT_EVENT_WITH_LATENCY_INFO_H_ +#define CONTENT_COMMON_INPUT_EVENT_WITH_LATENCY_INFO_H_ + +#include "ui/events/latency_info.h" + +#include "content/common/input/web_input_event_traits.h" + +namespace blink { +class WebGestureEvent; +class WebMouseEvent; +class WebMouseWheelEvent; +class WebTouchEvent; +} + +namespace content { + +template <typename T> +class EventWithLatencyInfo { + public: + T event; + mutable ui::LatencyInfo latency; + + explicit EventWithLatencyInfo(const T& e) : event(e) {} + + EventWithLatencyInfo(const T& e, const ui::LatencyInfo& l) + : event(e), latency(l) {} + + EventWithLatencyInfo() {} + + bool CanCoalesceWith(const EventWithLatencyInfo& other) + const WARN_UNUSED_RESULT { + return WebInputEventTraits::CanCoalesce(other.event, event); + } + + void CoalesceWith(const EventWithLatencyInfo& other) { + // |other| should be a newer event than |this|. + if (other.latency.trace_id() >= 0 && latency.trace_id() >= 0) + DCHECK_GT(other.latency.trace_id(), latency.trace_id()); + WebInputEventTraits::Coalesce(other.event, &event); + // When coalescing two input events, we keep the oldest LatencyInfo + // for Telemetry latency tests, since it will represent the longest + // latency. + other.latency = latency; + other.latency.set_coalesced(); + } +}; + +typedef EventWithLatencyInfo<blink::WebGestureEvent> + GestureEventWithLatencyInfo; +typedef EventWithLatencyInfo<blink::WebMouseWheelEvent> + MouseWheelEventWithLatencyInfo; +typedef EventWithLatencyInfo<blink::WebMouseEvent> + MouseEventWithLatencyInfo; +typedef EventWithLatencyInfo<blink::WebTouchEvent> + TouchEventWithLatencyInfo; + +} // namespace content + +#endif // CONTENT_COMMON_INPUT_EVENT_WITH_LATENCY_INFO_H_ diff --git a/chromium/content/common/input/event_with_latency_info_unittest.cc b/chromium/content/common/input/event_with_latency_info_unittest.cc new file mode 100644 index 00000000000..8ae533dd605 --- /dev/null +++ b/chromium/content/common/input/event_with_latency_info_unittest.cc @@ -0,0 +1,122 @@ +// Copyright 2015 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 "content/common/input/event_with_latency_info.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/web/WebInputEvent.h" + +using blink::WebGestureEvent; +using blink::WebInputEvent; +using blink::WebMouseEvent; +using blink::WebMouseWheelEvent; +using blink::WebTouchEvent; + +namespace content { +namespace { + +class EventWithLatencyInfoTest : public testing::Test { + protected: + TouchEventWithLatencyInfo CreateTouchEvent(WebInputEvent::Type type, + double timestamp) { + TouchEventWithLatencyInfo touch; + touch.event.touchesLength = 1; + touch.event.type = type; + touch.event.timeStampSeconds = timestamp; + return touch; + } + + MouseEventWithLatencyInfo CreateMouseEvent(WebInputEvent::Type type, + double timestamp) { + MouseEventWithLatencyInfo mouse; + mouse.event.type = type; + mouse.event.timeStampSeconds = timestamp; + return mouse; + } + + MouseWheelEventWithLatencyInfo CreateMouseWheelEvent(double timestamp) { + MouseWheelEventWithLatencyInfo mouse_wheel; + mouse_wheel.event.type = WebInputEvent::MouseWheel; + mouse_wheel.event.timeStampSeconds = timestamp; + return mouse_wheel; + } + + GestureEventWithLatencyInfo CreateGestureEvent(WebInputEvent::Type type, + double timestamp) { + GestureEventWithLatencyInfo gesture; + gesture.event.type = type; + gesture.event.timeStampSeconds = timestamp; + return gesture; + } +}; + +TEST_F(EventWithLatencyInfoTest, TimestampCoalescingForMouseEvent) { + MouseEventWithLatencyInfo mouse_0 = CreateMouseEvent( + WebInputEvent::MouseMove, 5.0); + MouseEventWithLatencyInfo mouse_1 = CreateMouseEvent( + WebInputEvent::MouseMove, 10.0); + + ASSERT_TRUE(mouse_0.CanCoalesceWith(mouse_1)); + mouse_0.CoalesceWith(mouse_1); + // Coalescing WebMouseEvent preserves newer timestamp. + EXPECT_EQ(10.0, mouse_0.event.timeStampSeconds); +} + +TEST_F(EventWithLatencyInfoTest, TimestampCoalescingForMouseWheelEvent) { + MouseWheelEventWithLatencyInfo mouse_wheel_0 = CreateMouseWheelEvent(5.0); + MouseWheelEventWithLatencyInfo mouse_wheel_1 = CreateMouseWheelEvent(10.0); + + ASSERT_TRUE(mouse_wheel_0.CanCoalesceWith(mouse_wheel_1)); + mouse_wheel_0.CoalesceWith(mouse_wheel_1); + // Coalescing WebMouseWheelEvent preserves newer timestamp. + EXPECT_EQ(10.0, mouse_wheel_0.event.timeStampSeconds); +} + +TEST_F(EventWithLatencyInfoTest, TimestampCoalescingForTouchEvent) { + TouchEventWithLatencyInfo touch_0 = CreateTouchEvent( + WebInputEvent::TouchMove, 5.0); + TouchEventWithLatencyInfo touch_1 = CreateTouchEvent( + WebInputEvent::TouchMove, 10.0); + + ASSERT_TRUE(touch_0.CanCoalesceWith(touch_1)); + touch_0.CoalesceWith(touch_1); + // Coalescing WebTouchEvent preserves newer timestamp. + EXPECT_EQ(10.0, touch_0.event.timeStampSeconds); +} + +TEST_F(EventWithLatencyInfoTest, TimestampCoalescingForGestureEvent) { + GestureEventWithLatencyInfo scroll_0 = CreateGestureEvent( + WebInputEvent::GestureScrollUpdate, 5.0); + GestureEventWithLatencyInfo scroll_1 = CreateGestureEvent( + WebInputEvent::GestureScrollUpdate, 10.0); + + ASSERT_TRUE(scroll_0.CanCoalesceWith(scroll_1)); + scroll_0.CoalesceWith(scroll_1); + // Coalescing WebGestureEvent preserves newer timestamp. + EXPECT_EQ(10.0, scroll_0.event.timeStampSeconds); +} + +TEST_F(EventWithLatencyInfoTest, LatencyInfoCoalescing) { + MouseEventWithLatencyInfo mouse_0 = CreateMouseEvent( + WebInputEvent::MouseMove, 5.0); + mouse_0.latency.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0, base::TimeTicks(), 1); + MouseEventWithLatencyInfo mouse_1 = CreateMouseEvent( + WebInputEvent::MouseMove, 10.0); + + ASSERT_TRUE(mouse_0.CanCoalesceWith(mouse_1)); + + ui::LatencyInfo::LatencyComponent component; + EXPECT_FALSE(mouse_1.latency.FindLatency( + ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, &component)); + + mouse_0.CoalesceWith(mouse_1); + + // Coalescing WebMouseEvent preservers older LatencyInfo. + EXPECT_TRUE(mouse_1.latency.FindLatency( + ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, &component)); +} + +} // namespace +} // namespace content diff --git a/chromium/content/common/input/input_event_ack_state.h b/chromium/content/common/input/input_event_ack_state.h index 5b9c706e6b4..c8e8f833b86 100644 --- a/chromium/content/common/input/input_event_ack_state.h +++ b/chromium/content/common/input/input_event_ack_state.h @@ -14,7 +14,8 @@ enum InputEventAckState { INPUT_EVENT_ACK_STATE_NOT_CONSUMED, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, INPUT_EVENT_ACK_STATE_IGNORED, - INPUT_EVENT_ACK_STATE_MAX = INPUT_EVENT_ACK_STATE_IGNORED + INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING, + INPUT_EVENT_ACK_STATE_MAX = INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING }; } // namespace content diff --git a/chromium/content/common/input/input_event_dispatch_type.h b/chromium/content/common/input/input_event_dispatch_type.h new file mode 100644 index 00000000000..ea802ff2c81 --- /dev/null +++ b/chromium/content/common/input/input_event_dispatch_type.h @@ -0,0 +1,26 @@ +// Copyright 2016 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 CONTENT_COMMON_INPUT_INPUT_EVENT_DISPATCH_TYPE_H_ +#define CONTENT_COMMON_INPUT_INPUT_EVENT_DISPATCH_TYPE_H_ + +namespace content { + +enum InputEventDispatchType { + // Dispatch a blocking event. Sender is waiting on an ACK. + DISPATCH_TYPE_BLOCKING, + // Dispatch a blocking event and notify main thread as well. This type + // should only be sent from the compositor to main thread. + DISPATCH_TYPE_BLOCKING_NOTIFY_MAIN, + // Dispatch a non-blocking event. Sender will not receive an ACK. + DISPATCH_TYPE_NON_BLOCKING, + // Dispatch a non-blocking event and notify main thread as well. This type + // should only be sent from the compositor to main thread. + DISPATCH_TYPE_NON_BLOCKING_NOTIFY_MAIN, + DISPATCH_TYPE_MAX = DISPATCH_TYPE_NON_BLOCKING_NOTIFY_MAIN +}; + +} // namespace content + +#endif // CONTENT_COMMON_INPUT_INPUT_EVENT_DISPATCH_TYPE_H_ diff --git a/chromium/content/common/input/input_event_utils.cc b/chromium/content/common/input/input_event_utils.cc new file mode 100644 index 00000000000..31669ed3ca3 --- /dev/null +++ b/chromium/content/common/input/input_event_utils.cc @@ -0,0 +1,17 @@ +// Copyright 2016 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 "content/common/input/input_event_utils.h" + +#include "base/command_line.h" +#include "content/public/common/content_switches.h" + +namespace content { + +bool UseGestureBasedWheelScrolling() { + base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); + return !cmd->HasSwitch(switches::kDisableWheelGestures); +} + +} // namespace content diff --git a/chromium/content/common/input/input_event_utils.h b/chromium/content/common/input/input_event_utils.h new file mode 100644 index 00000000000..c1a61ce2444 --- /dev/null +++ b/chromium/content/common/input/input_event_utils.h @@ -0,0 +1,17 @@ +// Copyright 2016 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 CONTENT_RENDERER_INPUT_INPUT_EVENT_UTILS_H_ +#define CONTENT_RENDERER_INPUT_INPUT_EVENT_UTILS_H_ + +#include "content/common/content_export.h" +#include "content/public/common/content_switches.h" + +namespace content { + +CONTENT_EXPORT bool UseGestureBasedWheelScrolling(); + +}; // namespace content + +#endif // CONTENT_RENDERER_INPUT_INPUT_EVENT_UTILS_H_ diff --git a/chromium/content/common/input/input_param_traits.cc b/chromium/content/common/input/input_param_traits.cc index 0402f433c5e..076d54ace06 100644 --- a/chromium/content/common/input/input_param_traits.cc +++ b/chromium/content/common/input/input_param_traits.cc @@ -8,6 +8,7 @@ #include "content/common/content_param_traits.h" #include "content/common/input/synthetic_pinch_gesture_params.h" +#include "content/common/input/synthetic_pointer_action_params.h" #include "content/common/input/synthetic_smooth_drag_gesture_params.h" #include "content/common/input/synthetic_smooth_scroll_gesture_params.h" #include "content/common/input/web_input_event_traits.h" @@ -17,7 +18,7 @@ namespace IPC { namespace { template <typename GestureType> scoped_ptr<content::SyntheticGestureParams> ReadGestureParams( - const Message* m, + const base::Pickle* m, base::PickleIterator* iter) { scoped_ptr<GestureType> gesture_params(new GestureType); if (!ReadParam(m, iter, gesture_params.get())) @@ -27,7 +28,7 @@ scoped_ptr<content::SyntheticGestureParams> ReadGestureParams( } } // namespace -void ParamTraits<content::ScopedWebInputEvent>::Write(Message* m, +void ParamTraits<content::ScopedWebInputEvent>::Write(base::Pickle* m, const param_type& p) { bool valid_web_event = !!p; WriteParam(m, valid_web_event); @@ -35,7 +36,7 @@ void ParamTraits<content::ScopedWebInputEvent>::Write(Message* m, WriteParam(m, static_cast<WebInputEventPointer>(p.get())); } -bool ParamTraits<content::ScopedWebInputEvent>::Read(const Message* m, +bool ParamTraits<content::ScopedWebInputEvent>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* p) { bool valid_web_event = false; @@ -55,7 +56,7 @@ void ParamTraits<content::ScopedWebInputEvent>::Log(const param_type& p, LogParam(static_cast<WebInputEventPointer>(p.get()), l); } -void ParamTraits<content::SyntheticGesturePacket>::Write(Message* m, +void ParamTraits<content::SyntheticGesturePacket>::Write(base::Pickle* m, const param_type& p) { DCHECK(p.gesture_params()); WriteParam(m, p.gesture_params()->GetGestureType()); @@ -76,11 +77,15 @@ void ParamTraits<content::SyntheticGesturePacket>::Write(Message* m, WriteParam(m, *content::SyntheticTapGestureParams::Cast( p.gesture_params())); break; + case content::SyntheticGestureParams::POINTER_ACTION: + WriteParam( + m, *content::SyntheticPointerActionParams::Cast(p.gesture_params())); + break; } } bool ParamTraits<content::SyntheticGesturePacket>::Read( - const Message* m, + const base::Pickle* m, base::PickleIterator* iter, param_type* p) { content::SyntheticGestureParams::GestureType gesture_type; @@ -105,6 +110,11 @@ bool ParamTraits<content::SyntheticGesturePacket>::Read( gesture_params = ReadGestureParams<content::SyntheticTapGestureParams>(m, iter); break; + case content::SyntheticGestureParams::POINTER_ACTION: { + gesture_params = + ReadGestureParams<content::SyntheticPointerActionParams>(m, iter); + break; + } default: return false; } @@ -138,6 +148,10 @@ void ParamTraits<content::SyntheticGesturePacket>::Log(const param_type& p, *content::SyntheticTapGestureParams::Cast(p.gesture_params()), l); break; + case content::SyntheticGestureParams::POINTER_ACTION: + LogParam(*content::SyntheticPointerActionParams::Cast(p.gesture_params()), + l); + break; } } diff --git a/chromium/content/common/input/input_param_traits.h b/chromium/content/common/input/input_param_traits.h index 9f5b1cec36c..1c204c3bc31 100644 --- a/chromium/content/common/input/input_param_traits.h +++ b/chromium/content/common/input/input_param_traits.h @@ -18,16 +18,20 @@ namespace IPC { template <> struct CONTENT_EXPORT ParamTraits<content::ScopedWebInputEvent> { typedef content::ScopedWebInputEvent param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; template<> struct CONTENT_EXPORT ParamTraits<content::SyntheticGesturePacket> { typedef content::SyntheticGesturePacket param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; diff --git a/chromium/content/common/input/input_param_traits_unittest.cc b/chromium/content/common/input/input_param_traits_unittest.cc index 0dd2b3d1441..1935f9ca945 100644 --- a/chromium/content/common/input/input_param_traits_unittest.cc +++ b/chromium/content/common/input/input_param_traits_unittest.cc @@ -10,6 +10,7 @@ #include "content/common/input/input_event.h" #include "content/common/input/synthetic_gesture_params.h" #include "content/common/input/synthetic_pinch_gesture_params.h" +#include "content/common/input/synthetic_pointer_action_params.h" #include "content/common/input/synthetic_smooth_drag_gesture_params.h" #include "content/common/input/synthetic_smooth_scroll_gesture_params.h" #include "content/common/input_messages.h" @@ -77,6 +78,22 @@ class InputParamTraitsTest : public testing::Test { EXPECT_EQ(a->duration_ms, b->duration_ms); } + static void Compare(const SyntheticPointerActionParams* a, + const SyntheticPointerActionParams* b) { + EXPECT_EQ(a->gesture_source_type, b->gesture_source_type); + EXPECT_EQ(a->pointer_action_type(), b->pointer_action_type()); + if (a->pointer_action_type() == + SyntheticPointerActionParams::PointerActionType::PRESS || + a->pointer_action_type() == + SyntheticPointerActionParams::PointerActionType::MOVE) { + EXPECT_EQ(a->position(), b->position()); + } + if (a->pointer_action_type() != + SyntheticPointerActionParams::PointerActionType::PROCESS) { + EXPECT_EQ(a->index(), b->index()); + } + } + static void Compare(const SyntheticGesturePacket* a, const SyntheticGesturePacket* b) { ASSERT_EQ(!!a, !!b); @@ -102,6 +119,10 @@ class InputParamTraitsTest : public testing::Test { Compare(SyntheticTapGestureParams::Cast(a->gesture_params()), SyntheticTapGestureParams::Cast(b->gesture_params())); break; + case SyntheticGestureParams::POINTER_ACTION: + Compare(SyntheticPointerActionParams::Cast(a->gesture_params()), + SyntheticPointerActionParams::Cast(b->gesture_params())); + break; } } @@ -250,5 +271,44 @@ TEST_F(InputParamTraitsTest, SyntheticTapGestureParams) { Verify(packet_in); } +TEST_F(InputParamTraitsTest, SyntheticPointerActionParamsMove) { + scoped_ptr<SyntheticPointerActionParams> gesture_params( + new SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::MOVE)); + gesture_params->gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; + gesture_params->set_position(gfx::PointF(356, 287)); + gesture_params->set_index(0); + ASSERT_EQ(SyntheticGestureParams::POINTER_ACTION, + gesture_params->GetGestureType()); + SyntheticGesturePacket packet_in; + packet_in.set_gesture_params(std::move(gesture_params)); + Verify(packet_in); +} + +TEST_F(InputParamTraitsTest, SyntheticPointerActionParamsRelease) { + scoped_ptr<SyntheticPointerActionParams> gesture_params( + new SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::RELEASE)); + gesture_params->gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; + gesture_params->set_index(0); + ASSERT_EQ(SyntheticGestureParams::POINTER_ACTION, + gesture_params->GetGestureType()); + SyntheticGesturePacket packet_in; + packet_in.set_gesture_params(std::move(gesture_params)); + Verify(packet_in); +} + +TEST_F(InputParamTraitsTest, SyntheticPointerActionParamsProcess) { + scoped_ptr<SyntheticPointerActionParams> gesture_params( + new SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::PROCESS)); + gesture_params->gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; + ASSERT_EQ(SyntheticGestureParams::POINTER_ACTION, + gesture_params->GetGestureType()); + SyntheticGesturePacket packet_in; + packet_in.set_gesture_params(std::move(gesture_params)); + Verify(packet_in); +} + } // namespace } // namespace content diff --git a/chromium/content/common/input/synthetic_gesture_params.h b/chromium/content/common/input/synthetic_gesture_params.h index 1c40ca98fd2..5ece4db2996 100644 --- a/chromium/content/common/input/synthetic_gesture_params.h +++ b/chromium/content/common/input/synthetic_gesture_params.h @@ -48,8 +48,10 @@ struct CONTENT_EXPORT SyntheticGestureParams { SMOOTH_DRAG_GESTURE, PINCH_GESTURE, TAP_GESTURE, - SYNTHETIC_GESTURE_TYPE_MAX = TAP_GESTURE + POINTER_ACTION, + SYNTHETIC_GESTURE_TYPE_MAX = POINTER_ACTION }; + virtual GestureType GetGestureType() const = 0; // Returns true if the specific gesture source type is supported on this diff --git a/chromium/content/common/input/synthetic_pointer_action_params.cc b/chromium/content/common/input/synthetic_pointer_action_params.cc new file mode 100644 index 00000000000..593413b9822 --- /dev/null +++ b/chromium/content/common/input/synthetic_pointer_action_params.cc @@ -0,0 +1,48 @@ +// Copyright 2016 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 "content/common/input/synthetic_pointer_action_params.h" + +namespace content { + +SyntheticPointerActionParams::SyntheticPointerActionParams() + : pointer_action_type_(PointerActionType::NOT_INITIALIZED), index_(-1) {} + +SyntheticPointerActionParams::SyntheticPointerActionParams( + PointerActionType type) + : pointer_action_type_(type), index_(-1) {} + +SyntheticPointerActionParams::SyntheticPointerActionParams( + const SyntheticPointerActionParams& other) + : SyntheticGestureParams(other), + pointer_action_type_(other.pointer_action_type()) { + switch (other.pointer_action_type()) { + case PointerActionType::PRESS: + case PointerActionType::MOVE: + index_ = other.index(); + position_ = other.position(); + break; + case PointerActionType::RELEASE: + index_ = other.index(); + break; + default: + break; + } +} + +SyntheticPointerActionParams::~SyntheticPointerActionParams() {} + +SyntheticGestureParams::GestureType +SyntheticPointerActionParams::GetGestureType() const { + return POINTER_ACTION; +} + +const SyntheticPointerActionParams* SyntheticPointerActionParams::Cast( + const SyntheticGestureParams* gesture_params) { + DCHECK(gesture_params); + DCHECK_EQ(POINTER_ACTION, gesture_params->GetGestureType()); + return static_cast<const SyntheticPointerActionParams*>(gesture_params); +} + +} // namespace content diff --git a/chromium/content/common/input/synthetic_pointer_action_params.h b/chromium/content/common/input/synthetic_pointer_action_params.h new file mode 100644 index 00000000000..fe6c9f9b4a3 --- /dev/null +++ b/chromium/content/common/input/synthetic_pointer_action_params.h @@ -0,0 +1,86 @@ +// Copyright 2016 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 CONTENT_COMMON_INPUT_SYNTHETIC_POINTER_ACTION_PARAMS_H_ +#define CONTENT_COMMON_INPUT_SYNTHETIC_POINTER_ACTION_PARAMS_H_ + +#include "base/logging.h" +#include "content/common/content_export.h" +#include "content/common/input/input_param_traits.h" +#include "content/common/input/synthetic_gesture_params.h" +#include "ui/gfx/geometry/point_f.h" + +namespace ipc_fuzzer { +template <class T> +struct FuzzTraits; +} // namespace ipc_fuzzer + +namespace content { + +struct CONTENT_EXPORT SyntheticPointerActionParams + : public SyntheticGestureParams { + public: + // Actions are queued up until we receive a PROCESS action, at which point + // we'll dispatch all queued events. + enum class PointerActionType { + NOT_INITIALIZED, + PRESS, + MOVE, + RELEASE, + PROCESS, + POINTER_ACTION_TYPE_MAX = PROCESS + }; + + SyntheticPointerActionParams(); + explicit SyntheticPointerActionParams(PointerActionType type); + SyntheticPointerActionParams(const SyntheticPointerActionParams& other); + ~SyntheticPointerActionParams() override; + + GestureType GetGestureType() const override; + + static const SyntheticPointerActionParams* Cast( + const SyntheticGestureParams* gesture_params); + + void set_pointer_action_type(PointerActionType pointer_action_type) { + pointer_action_type_ = pointer_action_type; + } + + void set_index(int index) { + DCHECK(pointer_action_type_ != PointerActionType::PROCESS); + index_ = index; + } + + void set_position(const gfx::PointF& position) { + DCHECK(pointer_action_type_ == PointerActionType::PRESS || + pointer_action_type_ == PointerActionType::MOVE); + position_ = position; + } + + PointerActionType pointer_action_type() const { return pointer_action_type_; } + + int index() const { + DCHECK(pointer_action_type_ != PointerActionType::PROCESS); + return index_; + } + + gfx::PointF position() const { + DCHECK(pointer_action_type_ == PointerActionType::PRESS || + pointer_action_type_ == PointerActionType::MOVE); + return position_; + } + + private: + friend struct IPC::ParamTraits<content::SyntheticPointerActionParams>; + friend struct ipc_fuzzer::FuzzTraits<content::SyntheticPointerActionParams>; + + PointerActionType pointer_action_type_; + // Pass a position value when sending a press or move action. + gfx::PointF position_; + // Pass an index value except if the pointer_action_type_ is PROCESS. + int index_; +}; + +} // namespace content + +#endif // CONTENT_COMMON_INPUT_SYNTHETIC_POINTER_ACTION_PARAMS_H_ diff --git a/chromium/content/common/input/synthetic_web_input_event_builders.cc b/chromium/content/common/input/synthetic_web_input_event_builders.cc index e2e17febb95..c68c689c09b 100644 --- a/chromium/content/common/input/synthetic_web_input_event_builders.cc +++ b/chromium/content/common/input/synthetic_web_input_event_builders.cc @@ -61,8 +61,21 @@ WebMouseWheelEvent SyntheticWebMouseWheelEventBuilder::Build(float x, float dy, int modifiers, bool precise) { + return Build(x, y, 0, 0, dx, dy, modifiers, precise); +} + +WebMouseWheelEvent SyntheticWebMouseWheelEventBuilder::Build(float x, + float y, + float global_x, + float global_y, + float dx, + float dy, + int modifiers, + bool precise) { WebMouseWheelEvent result; result.type = WebInputEvent::MouseWheel; + result.globalX = global_x; + result.globalY = global_y; result.x = x; result.y = y; result.deltaX = dx; @@ -171,7 +184,7 @@ void SyntheticWebTouchEvent::ResetPoints() { } touchesLength = point; type = WebInputEvent::Undefined; - causesScrollingIfUncanceled = false; + movedBeyondSlopRegion = false; uniqueTouchEventId = ui::GetNextTouchEventId(); } @@ -198,7 +211,7 @@ void SyntheticWebTouchEvent::MovePoint(int index, float x, float y) { CHECK_LT(index, touchesLengthCap); // Always set this bit to avoid otherwise unexpected touchmove suppression. // The caller can opt-out explicitly, if necessary. - causesScrollingIfUncanceled = true; + movedBeyondSlopRegion = true; WebTouchPoint& point = touches[index]; point.position.x = point.screenPosition.x = x; point.position.y = point.screenPosition.y = y; diff --git a/chromium/content/common/input/synthetic_web_input_event_builders.h b/chromium/content/common/input/synthetic_web_input_event_builders.h index ef1a1694bb7..e865e9b23ce 100644 --- a/chromium/content/common/input/synthetic_web_input_event_builders.h +++ b/chromium/content/common/input/synthetic_web_input_event_builders.h @@ -32,6 +32,14 @@ class CONTENT_EXPORT SyntheticWebMouseWheelEventBuilder { float dy, int modifiers, bool precise); + static blink::WebMouseWheelEvent Build(float x, + float y, + float global_x, + float global_y, + float dx, + float dy, + int modifiers, + bool precise); }; class CONTENT_EXPORT SyntheticWebKeyboardEventBuilder { diff --git a/chromium/content/common/input/web_input_event_queue.h b/chromium/content/common/input/web_input_event_queue.h new file mode 100644 index 00000000000..fa85bd4f773 --- /dev/null +++ b/chromium/content/common/input/web_input_event_queue.h @@ -0,0 +1,79 @@ +// Copyright 2016 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 CONTENT_COMMON_INPUT_WEB_INPUT_EVENT_QUEUE_H_ +#define CONTENT_COMMON_INPUT_WEB_INPUT_EVENT_QUEUE_H_ + +#include <deque> + +#include "base/memory/scoped_ptr.h" + +namespace content { + +enum class WebInputEventQueueState { ITEM_PENDING, ITEM_NOT_PENDING }; + +// WebInputEventQueue is a coalescing queue with the addition of a state +// variable that represents whether an item is pending to be processed. +// The desired usage sending with this queue is: +// if (queue.state() == WebInputEventQueueState::ITEM_PENDING) { +// queue.Queue(T); +// } else { +// send T +// queue.set_state(WebInputEventQueueState::ITEM_PENDING); +// } +// +// Processing the event response: +// if (!queue.empty()) { +// T = queue.Pop(); +// send T now +// } else { +// queue.set_state(WebInputEventQueueState::ITEM_NOT_PENDING); +// } +// +template <typename T> +class WebInputEventQueue { + public: + WebInputEventQueue() : state_(WebInputEventQueueState::ITEM_NOT_PENDING) {} + + // Adds an event to the queue. The event may be coalesced with previously + // queued events. + void Queue(const T& event) { + if (!queue_.empty()) { + scoped_ptr<T>& last_event = queue_.back(); + if (last_event->CanCoalesceWith(event)) { + last_event->CoalesceWith(event); + return; + } + } + queue_.emplace_back(scoped_ptr<T>(new T(event))); + } + + scoped_ptr<T> Pop() { + scoped_ptr<T> result; + if (!queue_.empty()) { + result.reset(queue_.front().release()); + queue_.pop_front(); + } + return result; + } + + bool empty() const { return queue_.empty(); } + + size_t size() const { return queue_.size(); } + + void set_state(WebInputEventQueueState state) { state_ = state; } + + WebInputEventQueueState state() const WARN_UNUSED_RESULT { return state_; } + + private: + typedef std::deque<scoped_ptr<T>> EventQueue; + EventQueue queue_; + WebInputEventQueueState state_; + + DISALLOW_COPY_AND_ASSIGN(WebInputEventQueue); +}; + +} // namespace content + +#endif // CONTENT_COMMON_INPUT_WEB_INPUT_EVENT_QUEUE_H_ diff --git a/chromium/content/common/input/web_input_event_traits.cc b/chromium/content/common/input/web_input_event_traits.cc index 1008c549ef6..3aed966c5b6 100644 --- a/chromium/content/common/input/web_input_event_traits.cc +++ b/chromium/content/common/input/web_input_event_traits.cc @@ -111,10 +111,10 @@ void ApppendTouchPointDetails(const WebTouchPoint& point, std::string* result) { void ApppendEventDetails(const WebTouchEvent& event, std::string* result) { StringAppendF(result, - "{\n Touches: %u, Cancelable: %d, CausesScrolling: %d," + "{\n Touches: %u, DispatchType: %d, CausesScrolling: %d," " uniqueTouchEventId: %u\n[\n", - event.touchesLength, event.cancelable, - event.causesScrollingIfUncanceled, event.uniqueTouchEventId); + event.touchesLength, event.dispatchType, + event.movedBeyondSlopRegion, event.uniqueTouchEventId); for (unsigned i = 0; i < event.touchesLength; ++i) ApppendTouchPointDetails(event.touches[i], result); result->append(" ]\n}"); @@ -199,6 +199,23 @@ int GetIndexOfTouchID(const WebTouchEvent& event, int id) { return kInvalidTouchIndex; } +WebInputEvent::DispatchType MergeDispatchTypes( + WebInputEvent::DispatchType type_1, + WebInputEvent::DispatchType type_2) { + static_assert(WebInputEvent::DispatchType::Blocking < + WebInputEvent::DispatchType::EventNonBlocking, + "Enum not ordered correctly"); + static_assert(WebInputEvent::DispatchType::EventNonBlocking < + WebInputEvent::DispatchType::ListenersNonBlockingPassive, + "Enum not ordered correctly"); + static_assert( + WebInputEvent::DispatchType::ListenersNonBlockingPassive < + WebInputEvent::DispatchType::ListenersForcedNonBlockingPassive, + "Enum not ordered correctly"); + return static_cast<WebInputEvent::DispatchType>( + std::min(static_cast<int>(type_1), static_cast<int>(type_2))); +} + bool CanCoalesce(const WebTouchEvent& event_to_coalesce, const WebTouchEvent& event) { if (event.type != event_to_coalesce.type || @@ -240,7 +257,9 @@ void Coalesce(const WebTouchEvent& event_to_coalesce, WebTouchEvent* event) { if (old_event.touches[i_old].state == blink::WebTouchPoint::StateMoved) event->touches[i].state = blink::WebTouchPoint::StateMoved; } - event->causesScrollingIfUncanceled |= old_event.causesScrollingIfUncanceled; + event->movedBeyondSlopRegion |= old_event.movedBeyondSlopRegion; + event->dispatchType = MergeDispatchTypes(old_event.dispatchType, + event_to_coalesce.dispatchType); } bool CanCoalesce(const WebGestureEvent& event_to_coalesce, @@ -466,8 +485,7 @@ void WebInputEventTraits::Coalesce(const WebInputEvent& event_to_coalesce, Apply(WebInputEventCoalesce(), event->type, event_to_coalesce, event); } -bool WebInputEventTraits::WillReceiveAckFromRenderer( - const WebInputEvent& event) { +bool WebInputEventTraits::ShouldBlockEventStream(const WebInputEvent& event) { switch (event.type) { case WebInputEvent::MouseDown: case WebInputEvent::MouseUp: @@ -482,11 +500,24 @@ bool WebInputEventTraits::WillReceiveAckFromRenderer( case WebInputEvent::GestureTapCancel: case WebInputEvent::GesturePinchBegin: case WebInputEvent::GesturePinchEnd: + return false; + + // TouchCancel should always be non-blocking. case WebInputEvent::TouchCancel: + DCHECK_NE(WebInputEvent::Blocking, + static_cast<const WebTouchEvent&>(event).dispatchType); return false; + + // Touch start and touch end indicate whether they are non-blocking + // (aka uncancelable) on the event. case WebInputEvent::TouchStart: case WebInputEvent::TouchEnd: - return static_cast<const WebTouchEvent&>(event).cancelable; + return static_cast<const WebTouchEvent&>(event).dispatchType == + WebInputEvent::Blocking; + + // Touch move events may be non-blocking but are always explicitly + // acknowledge by the renderer so they block the event stream. + case WebInputEvent::TouchMove: default: return true; } diff --git a/chromium/content/common/input/web_input_event_traits.h b/chromium/content/common/input/web_input_event_traits.h index 008439c9e28..2f9ca8c5232 100644 --- a/chromium/content/common/input/web_input_event_traits.h +++ b/chromium/content/common/input/web_input_event_traits.h @@ -27,7 +27,7 @@ class CONTENT_EXPORT WebInputEventTraits { const blink::WebInputEvent& event); static void Coalesce(const blink::WebInputEvent& event_to_coalesce, blink::WebInputEvent* event); - static bool WillReceiveAckFromRenderer(const blink::WebInputEvent& event); + static bool ShouldBlockEventStream(const blink::WebInputEvent& event); // Return uniqueTouchEventId for WebTouchEvent, otherwise return 0. static uint32_t GetUniqueTouchEventId(const blink::WebInputEvent& event); diff --git a/chromium/content/common/input/web_input_event_traits_unittest.cc b/chromium/content/common/input/web_input_event_traits_unittest.cc index 6ae3d936616..1daf80dcf1a 100644 --- a/chromium/content/common/input/web_input_event_traits_unittest.cc +++ b/chromium/content/common/input/web_input_event_traits_unittest.cc @@ -124,6 +124,34 @@ TEST_F(WebInputEventTraitsTest, TouchEventCoalescing) { ASSERT_EQ(0, touch1.touches[1].id); EXPECT_EQ(WebTouchPoint::StateMoved, touch1.touches[0].state); EXPECT_EQ(WebTouchPoint::StateMoved, touch1.touches[1].state); + + // Touch moves with different dispatchTypes coalesce. + touch0 = CreateTouch(WebInputEvent::TouchMove, 2); + touch0.dispatchType = WebInputEvent::DispatchType::Blocking; + touch1 = CreateTouch(WebInputEvent::TouchMove, 2); + touch1.dispatchType = WebInputEvent::DispatchType::EventNonBlocking; + touch0.touches[0] = touch1.touches[1] = + CreateTouchPoint(WebTouchPoint::StateMoved, 1); + touch0.touches[1] = touch1.touches[0] = + CreateTouchPoint(WebTouchPoint::StateMoved, 0); + EXPECT_TRUE(WebInputEventTraits::CanCoalesce(touch0, touch1)); + WebInputEventTraits::Coalesce(touch0, &touch1); + ASSERT_EQ(WebInputEvent::DispatchType::Blocking, touch1.dispatchType); + + touch0 = CreateTouch(WebInputEvent::TouchMove, 2); + touch0.dispatchType = + WebInputEvent::DispatchType::ListenersForcedNonBlockingPassive; + touch1 = CreateTouch(WebInputEvent::TouchMove, 2); + touch1.dispatchType = + WebInputEvent::DispatchType::ListenersNonBlockingPassive; + touch0.touches[0] = touch1.touches[1] = + CreateTouchPoint(WebTouchPoint::StateMoved, 1); + touch0.touches[1] = touch1.touches[0] = + CreateTouchPoint(WebTouchPoint::StateMoved, 0); + EXPECT_TRUE(WebInputEventTraits::CanCoalesce(touch0, touch1)); + WebInputEventTraits::Coalesce(touch0, &touch1); + ASSERT_EQ(WebInputEvent::DispatchType::ListenersNonBlockingPassive, + touch1.dispatchType); } TEST_F(WebInputEventTraitsTest, PinchEventCoalescing) { diff --git a/chromium/content/common/input/web_touch_event_traits.cc b/chromium/content/common/input/web_touch_event_traits.cc index 175bf78ef41..77aa00f7069 100644 --- a/chromium/content/common/input/web_touch_event_traits.cc +++ b/chromium/content/common/input/web_touch_event_traits.cc @@ -52,7 +52,9 @@ void WebTouchEventTraits::ResetType(WebInputEvent::Type type, WebTouchEvent* event) { DCHECK(WebInputEvent::isTouchEventType(type)); event->type = type; - event->cancelable = (type != WebInputEvent::TouchCancel); + event->dispatchType = type == WebInputEvent::TouchCancel + ? WebInputEvent::EventNonBlocking + : WebInputEvent::Blocking; event->timeStampSeconds = timestamp_sec; } diff --git a/chromium/content/common/input_messages.h b/chromium/content/common/input_messages.h index a511d018458..e83a77bac4e 100644 --- a/chromium/content/common/input_messages.h +++ b/chromium/content/common/input_messages.h @@ -15,15 +15,16 @@ #include "content/common/input/input_event.h" #include "content/common/input/input_event_ack.h" #include "content/common/input/input_event_ack_state.h" +#include "content/common/input/input_event_dispatch_type.h" #include "content/common/input/input_param_traits.h" #include "content/common/input/synthetic_gesture_packet.h" #include "content/common/input/synthetic_gesture_params.h" #include "content/common/input/synthetic_pinch_gesture_params.h" +#include "content/common/input/synthetic_pointer_action_params.h" #include "content/common/input/synthetic_smooth_drag_gesture_params.h" #include "content/common/input/synthetic_smooth_scroll_gesture_params.h" #include "content/common/input/synthetic_tap_gesture_params.h" #include "content/common/input/touch_action.h" -#include "content/public/common/common_param_traits.h" #include "ipc/ipc_message_macros.h" #include "third_party/WebKit/public/web/WebInputEvent.h" #include "ui/events/ipc/latency_info_param_traits.h" @@ -31,6 +32,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/vector2d_f.h" #include "ui/gfx/ipc/gfx_param_traits.h" +#include "ui/gfx/ipc/skia/gfx_skia_param_traits.h" #include "ui/gfx/range/range.h" #undef IPC_MESSAGE_EXPORT @@ -48,6 +50,12 @@ IPC_ENUM_TRAITS_MAX_VALUE( IPC_ENUM_TRAITS_MAX_VALUE( content::SyntheticGestureParams::GestureType, content::SyntheticGestureParams::SYNTHETIC_GESTURE_TYPE_MAX) +IPC_ENUM_TRAITS_MAX_VALUE( + content::SyntheticPointerActionParams::PointerActionType, + content::SyntheticPointerActionParams::PointerActionType:: + POINTER_ACTION_TYPE_MAX) +IPC_ENUM_TRAITS_MAX_VALUE(content::InputEventDispatchType, + content::InputEventDispatchType::DISPATCH_TYPE_MAX) IPC_ENUM_TRAITS_VALIDATE(content::TouchAction, ( value >= 0 && value <= content::TOUCH_ACTION_MAX && @@ -105,6 +113,13 @@ IPC_STRUCT_TRAITS_BEGIN(content::SyntheticTapGestureParams) IPC_STRUCT_TRAITS_MEMBER(duration_ms) IPC_STRUCT_TRAITS_END() +IPC_STRUCT_TRAITS_BEGIN(content::SyntheticPointerActionParams) + IPC_STRUCT_TRAITS_PARENT(content::SyntheticGestureParams) + IPC_STRUCT_TRAITS_MEMBER(pointer_action_type_) + IPC_STRUCT_TRAITS_MEMBER(index_) + IPC_STRUCT_TRAITS_MEMBER(position_) +IPC_STRUCT_TRAITS_END() + IPC_STRUCT_TRAITS_BEGIN(content::InputEventAck) IPC_STRUCT_TRAITS_MEMBER(type) IPC_STRUCT_TRAITS_MEMBER(state) @@ -114,9 +129,10 @@ IPC_STRUCT_TRAITS_BEGIN(content::InputEventAck) IPC_STRUCT_TRAITS_END() // Sends an input event to the render widget. -IPC_MESSAGE_ROUTED2(InputMsg_HandleInputEvent, +IPC_MESSAGE_ROUTED3(InputMsg_HandleInputEvent, IPC::WebInputEventPointer /* event */, - ui::LatencyInfo /* latency_info */) + ui::LatencyInfo /* latency_info */, + content::InputEventDispatchType) // Sends the cursor visibility state to the render widget. IPC_MESSAGE_ROUTED1(InputMsg_CursorVisibilityChange, @@ -136,10 +152,11 @@ IPC_MESSAGE_ROUTED2(InputMsg_ExtendSelectionAndDelete, int /* after */) // This message sends a string being composed with an input method. -IPC_MESSAGE_ROUTED4( +IPC_MESSAGE_ROUTED5( InputMsg_ImeSetComposition, base::string16, /* text */ std::vector<blink::WebCompositionUnderline>, /* underlines */ + gfx::Range /* replacement_range */, int, /* selectiont_start */ int /* selection_end */) @@ -242,6 +259,8 @@ IPC_MESSAGE_ROUTED3(InputMsg_ActivateNearestFindResult, // otherwise a race condition can happen. IPC_MESSAGE_ROUTED0(InputMsg_ImeEventAck) +// Request from browser to update text input state. +IPC_MESSAGE_ROUTED0(InputMsg_RequestTextInputStateUpdate) #endif IPC_MESSAGE_ROUTED0(InputMsg_SyntheticGestureCompleted) diff --git a/chromium/content/common/leveldb_wrapper.mojom b/chromium/content/common/leveldb_wrapper.mojom new file mode 100644 index 00000000000..0035ebc5558 --- /dev/null +++ b/chromium/content/common/leveldb_wrapper.mojom @@ -0,0 +1,51 @@ +// Copyright 2016 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. + +module content.mojom; + +import "components/leveldb/public/interfaces/leveldb.mojom"; + +// Gives information about changes to a LevelDB database. +// Note that observer methods are called before the callbacks for the +// LevelDBWrapper methods are run. +interface LevelDBObserver { + KeyAdded(array<uint8> key, array<uint8> value, string source); + KeyChanged(array<uint8> key, array<uint8> new_value, array<uint8> old_value, + string source); + KeyDeleted(array<uint8> key, array<uint8> old_value, string source); + AllDeleted(string source); + + // Since the GetAll call is synchronous, observers need this asynchronously + // delivered notification to avoid applying changes to the returned array + // that it already contains. + GetAllComplete(string source); +}; + +struct KeyValue { + array<uint8> key; + array<uint8> value; +}; + +// A wrapper around leveldb that supports giving notifications when values +// change. +interface LevelDBWrapper { + // Sets the database entry for |key| to |value|. Returns OK on success. + Put(array<uint8> key, array<uint8> value, string source) => (bool success); + + // Remove the database entry (if any) for |key|. Returns OK on success, and a + // non-OK status on error. It is not an error if |key| did not exist in the + // database. + Delete(array<uint8> key, string source) => (bool success); + + // Removes all the entries. + DeleteAll(string source) => (bool success); + + // Returns the value of the |key|. + Get(array<uint8> key) => (bool success, array<uint8> value); + + // Only used with small databases. Returns all key/value pairs. + [Sync] + GetAll(string source) + => (leveldb.DatabaseError status, array<KeyValue> data); +}; diff --git a/chromium/content/common/mac/attributed_string_coder.h b/chromium/content/common/mac/attributed_string_coder.h index 971088e856f..6976d4e0a4d 100644 --- a/chromium/content/common/mac/attributed_string_coder.h +++ b/chromium/content/common/mac/attributed_string_coder.h @@ -21,6 +21,11 @@ class NSAttributedString; class NSDictionary; #endif +namespace base { +class Pickle; +class PickleIterator; +} + namespace mac { // This class will serialize the font information of an NSAttributedString so @@ -100,16 +105,20 @@ namespace IPC { template <> struct ParamTraits<mac::AttributedStringCoder::EncodedString> { typedef mac::AttributedStringCoder::EncodedString param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct ParamTraits<mac::AttributedStringCoder::FontAttribute> { typedef mac::AttributedStringCoder::FontAttribute param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; diff --git a/chromium/content/common/mac/attributed_string_coder.mm b/chromium/content/common/mac/attributed_string_coder.mm index 85ceeb3655e..f8fa6b05271 100644 --- a/chromium/content/common/mac/attributed_string_coder.mm +++ b/chromium/content/common/mac/attributed_string_coder.mm @@ -122,13 +122,14 @@ namespace IPC { using mac::AttributedStringCoder; void ParamTraits<AttributedStringCoder::EncodedString>::Write( - Message* m, const param_type& p) { + base::Pickle* m, + const param_type& p) { WriteParam(m, p.string()); WriteParam(m, p.attributes()); } bool ParamTraits<AttributedStringCoder::EncodedString>::Read( - const Message* m, + const base::Pickle* m, base::PickleIterator* iter, param_type* p) { bool success = true; @@ -147,13 +148,14 @@ void ParamTraits<AttributedStringCoder::EncodedString>::Log( } void ParamTraits<AttributedStringCoder::FontAttribute>::Write( - Message* m, const param_type& p) { + base::Pickle* m, + const param_type& p) { WriteParam(m, p.font_descriptor()); WriteParam(m, p.effective_range()); } bool ParamTraits<AttributedStringCoder::FontAttribute>::Read( - const Message* m, + const base::Pickle* m, base::PickleIterator* iter, param_type* p) { bool success = true; diff --git a/chromium/content/common/media/OWNERS b/chromium/content/common/media/OWNERS index 9d38af2734e..bd15b3e0625 100644 --- a/chromium/content/common/media/OWNERS +++ b/chromium/content/common/media/OWNERS @@ -1,9 +1,5 @@ -dalecurtis@chromium.org -ddorwin@chromium.org -jrummell@chromium.org -sandersd@chromium.org +file://media/OWNERS tommi@chromium.org -xhwang@chromium.org # For security review of IPC message files. per-file *_messages*.h=set noparent diff --git a/chromium/content/common/media/audio_messages.h b/chromium/content/common/media/audio_messages.h index 35e159c4f5e..7731dd6448a 100644 --- a/chromium/content/common/media/audio_messages.h +++ b/chromium/content/common/media/audio_messages.h @@ -17,6 +17,7 @@ #include "media/audio/audio_input_ipc.h" #include "media/audio/audio_output_ipc.h" #include "media/audio/audio_parameters.h" +#include "media/gpu/ipc/common/media_param_traits.h" #include "url/origin.h" #undef IPC_MESSAGE_EXPORT diff --git a/chromium/content/common/media/media_param_traits.cc b/chromium/content/common/media/media_param_traits.cc index 5d5020c9654..07d630b2779 100644 --- a/chromium/content/common/media/media_param_traits.cc +++ b/chromium/content/common/media/media_param_traits.cc @@ -12,6 +12,7 @@ #include "media/audio/point.h" #include "media/base/limits.h" #include "ui/gfx/ipc/gfx_param_traits.h" +#include "ui/gfx/ipc/skia/gfx_skia_param_traits.h" using media::AudioParameters; using media::ChannelLayout; @@ -19,7 +20,7 @@ using media::VideoCaptureFormat; namespace IPC { -void ParamTraits<AudioParameters>::Write(Message* m, +void ParamTraits<AudioParameters>::Write(base::Pickle* m, const AudioParameters& p) { WriteParam(m, p.format()); WriteParam(m, p.channel_layout()); @@ -31,7 +32,7 @@ void ParamTraits<AudioParameters>::Write(Message* m, WriteParam(m, p.mic_positions()); } -bool ParamTraits<AudioParameters>::Read(const Message* m, +bool ParamTraits<AudioParameters>::Read(const base::Pickle* m, base::PickleIterator* iter, AudioParameters* r) { AudioParameters::Format format; @@ -63,7 +64,7 @@ void ParamTraits<AudioParameters>::Log(const AudioParameters& p, l->append(base::StringPrintf("<AudioParameters>")); } -void ParamTraits<VideoCaptureFormat>::Write(Message* m, +void ParamTraits<VideoCaptureFormat>::Write(base::Pickle* m, const VideoCaptureFormat& p) { WriteParam(m, p.frame_size); WriteParam(m, p.frame_rate); @@ -71,7 +72,7 @@ void ParamTraits<VideoCaptureFormat>::Write(Message* m, WriteParam(m, p.pixel_storage); } -bool ParamTraits<VideoCaptureFormat>::Read(const Message* m, +bool ParamTraits<VideoCaptureFormat>::Read(const base::Pickle* m, base::PickleIterator* iter, VideoCaptureFormat* r) { if (!ReadParam(m, iter, &r->frame_size) || diff --git a/chromium/content/common/media/media_param_traits.h b/chromium/content/common/media/media_param_traits.h index f035b402c69..70675edba3e 100644 --- a/chromium/content/common/media/media_param_traits.h +++ b/chromium/content/common/media/media_param_traits.h @@ -19,16 +19,20 @@ namespace IPC { template <> struct CONTENT_EXPORT ParamTraits<media::AudioParameters> { typedef media::AudioParameters param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct CONTENT_EXPORT ParamTraits<media::VideoCaptureFormat> { typedef media::VideoCaptureFormat param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; diff --git a/chromium/content/common/media/media_player_delegate_messages.h b/chromium/content/common/media/media_player_delegate_messages.h new file mode 100644 index 00000000000..98d5d47ee94 --- /dev/null +++ b/chromium/content/common/media/media_player_delegate_messages.h @@ -0,0 +1,51 @@ +// Copyright 2016 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. + +// IPC messages for interactions between the WebMediaPlayerDelegate in the +// renderer process and MediaWebContentsObserver in the browser process. +// Multiply-included message file, hence no include guard. + +#include <stdint.h> + +#include "base/time/time.h" +#include "content/common/content_export.h" +#include "ipc/ipc_message_macros.h" + +#undef IPC_MESSAGE_EXPORT +#define IPC_MESSAGE_EXPORT CONTENT_EXPORT +#define IPC_MESSAGE_START MediaPlayerDelegateMsgStart + +// ---------------------------------------------------------------------------- +// Messages from the browser to the renderer requesting playback state changes. +// ---------------------------------------------------------------------------- + +IPC_MESSAGE_ROUTED1(MediaPlayerDelegateMsg_Pause, + int /* delegate_id, distinguishes instances */) + +IPC_MESSAGE_ROUTED1(MediaPlayerDelegateMsg_Play, + int /* delegate_id, distinguishes instances */) + +IPC_MESSAGE_ROUTED0(MediaPlayerDelegateMsg_SuspendAllMediaPlayers) + +IPC_MESSAGE_ROUTED2(MediaPlayerDelegateMsg_UpdateVolumeMultiplier, + int /* delegate_id, distinguishes instances */, + double /* multiplier */) + +// ---------------------------------------------------------------------------- +// Messages from the renderer notifying the browser of playback state changes. +// ---------------------------------------------------------------------------- + +IPC_MESSAGE_ROUTED1(MediaPlayerDelegateHostMsg_OnMediaDestroyed, + int /* delegate_id, distinguishes instances */) + +IPC_MESSAGE_ROUTED2(MediaPlayerDelegateHostMsg_OnMediaPaused, + int /* delegate_id, distinguishes instances */, + bool /* reached end of stream */) + +IPC_MESSAGE_ROUTED5(MediaPlayerDelegateHostMsg_OnMediaPlaying, + int /* delegate_id, distinguishes instances */, + bool /* has_video */, + bool /* has_audio */, + bool /* is_remote */, + base::TimeDelta /* duration */) diff --git a/chromium/content/common/media/media_player_messages_android.h b/chromium/content/common/media/media_player_messages_android.h index b4e0ba6ebd4..0aab6d85a5d 100644 --- a/chromium/content/common/media/media_player_messages_android.h +++ b/chromium/content/common/media/media_player_messages_android.h @@ -9,7 +9,9 @@ #include "content/common/content_export.h" #include "ipc/ipc_message_macros.h" #include "media/base/android/demuxer_stream_player_params.h" +#include "media/base/decrypt_config.h" #include "media/blink/renderer_media_player_interface.h" +#include "media/gpu/ipc/common/media_param_traits.h" #include "ui/gfx/geometry/rect_f.h" #include "url/gurl.h" @@ -68,6 +70,8 @@ IPC_STRUCT_BEGIN(MediaPlayerHostMsg_Initialize_Params) IPC_STRUCT_MEMBER(GURL, first_party_for_cookies) IPC_STRUCT_MEMBER(GURL, frame_url) IPC_STRUCT_MEMBER(bool, allow_credentials) + IPC_STRUCT_MEMBER(int, delegate_id) + IPC_STRUCT_MEMBER(int, media_session_id) IPC_STRUCT_END() // Chrome for Android seek message sequence is: @@ -193,6 +197,10 @@ IPC_MESSAGE_ROUTED2(MediaPlayerMsg_ConnectedToRemoteDevice, IPC_MESSAGE_ROUTED1(MediaPlayerMsg_DisconnectedFromRemoteDevice, int /* player_id */) +// The remote playback device selection has been cancelled. +IPC_MESSAGE_ROUTED1(MediaPlayerMsg_CancelledRemotePlaybackRequest, + int /* player_id */) + // The availability of remote devices has changed IPC_MESSAGE_ROUTED2(MediaPlayerMsg_RemoteRouteAvailabilityChanged, int /* player_id */, diff --git a/chromium/content/common/media/media_session_messages_android.h b/chromium/content/common/media/media_session_messages_android.h index 18a63844d70..266ee273bcf 100644 --- a/chromium/content/common/media/media_session_messages_android.h +++ b/chromium/content/common/media/media_session_messages_android.h @@ -7,12 +7,19 @@ #include "content/common/android/gin_java_bridge_errors.h" #include "content/common/content_export.h" +#include "content/public/common/media_metadata.h" #include "ipc/ipc_message_macros.h" #undef IPC_MESSAGE_EXPORT #define IPC_MESSAGE_EXPORT CONTENT_EXPORT #define IPC_MESSAGE_START MediaSessionMsgStart +IPC_STRUCT_TRAITS_BEGIN(content::MediaMetadata) + IPC_STRUCT_TRAITS_MEMBER(title) + IPC_STRUCT_TRAITS_MEMBER(artist) + IPC_STRUCT_TRAITS_MEMBER(album) +IPC_STRUCT_TRAITS_END() + // Messages for notifying the render process of media session status ------- IPC_MESSAGE_ROUTED2(MediaSessionMsg_DidActivate, @@ -30,3 +37,7 @@ IPC_MESSAGE_ROUTED2(MediaSessionHostMsg_Activate, IPC_MESSAGE_ROUTED2(MediaSessionHostMsg_Deactivate, int /* session_id */, int /* request_id */) + +IPC_MESSAGE_ROUTED2(MediaSessionHostMsg_SetMetadata, + int /* request_id*/, + content::MediaMetadata /* metadata */) diff --git a/chromium/content/common/media/media_stream_options.cc b/chromium/content/common/media/media_stream_options.cc index c942f460986..1b2b1e2750a 100644 --- a/chromium/content/common/media/media_stream_options.cc +++ b/chromium/content/common/media/media_stream_options.cc @@ -27,6 +27,8 @@ TrackControls::TrackControls() TrackControls::TrackControls(bool request) : requested(request) {} +TrackControls::TrackControls(const TrackControls& other) = default; + TrackControls::~TrackControls() {} StreamControls::StreamControls() diff --git a/chromium/content/common/media/media_stream_options.h b/chromium/content/common/media/media_stream_options.h index 4d61d579221..b815c602cdf 100644 --- a/chromium/content/common/media/media_stream_options.h +++ b/chromium/content/common/media/media_stream_options.h @@ -36,6 +36,7 @@ struct CONTENT_EXPORT TrackControls { public: TrackControls(); TrackControls(bool request); + TrackControls(const TrackControls& other); ~TrackControls(); bool requested; diff --git a/chromium/content/common/media/surface_view_manager_messages_android.h b/chromium/content/common/media/surface_view_manager_messages_android.h new file mode 100644 index 00000000000..72426c2539d --- /dev/null +++ b/chromium/content/common/media/surface_view_manager_messages_android.h @@ -0,0 +1,26 @@ +// Copyright 2016 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. + +// IPC messages for surface view manager. +// Multiply-included message file, hence no include guard. + +#include "content/common/content_export.h" +#include "ipc/ipc_message_macros.h" +#include "ui/gfx/geometry/size.h" + +#undef IPC_MESSAGE_EXPORT +#define IPC_MESSAGE_EXPORT CONTENT_EXPORT +#define IPC_MESSAGE_START SurfaceViewManagerMsgStart + +// Message sent from the renderer to the browser + +IPC_MESSAGE_ROUTED1(SurfaceViewManagerHostMsg_CreateFullscreenSurface, + gfx::Size /* video_natural_size */) +IPC_MESSAGE_ROUTED1(SurfaceViewManagerHostMsg_NaturalSizeChanged, + gfx::Size /* size */) + +// Message sent from the browser to the renderer + +IPC_MESSAGE_ROUTED1(SurfaceViewManagerMsg_FullscreenSurfaceCreated, + int /* surface_id */) diff --git a/chromium/content/common/media/video_capture_messages.h b/chromium/content/common/media/video_capture_messages.h index be1a179bda6..5241898beb2 100644 --- a/chromium/content/common/media/video_capture_messages.h +++ b/chromium/content/common/media/video_capture_messages.h @@ -19,7 +19,6 @@ IPC_ENUM_TRAITS_MAX_VALUE(content::VideoCaptureState, content::VIDEO_CAPTURE_STATE_LAST) IPC_ENUM_TRAITS_MAX_VALUE(media::ResolutionChangePolicy, media::RESOLUTION_POLICY_LAST) -IPC_ENUM_TRAITS_MAX_VALUE(media::VideoPixelFormat, media::PIXEL_FORMAT_MAX) IPC_ENUM_TRAITS_MAX_VALUE(media::VideoFrame::StorageType, media::VideoFrame::STORAGE_LAST) IPC_ENUM_TRAITS_MAX_VALUE(media::VideoPixelStorage, media::PIXEL_STORAGE_MAX) @@ -108,6 +107,11 @@ IPC_MESSAGE_CONTROL3(VideoCaptureHostMsg_Resume, media::VideoCaptureSessionId, /* session_id */ media::VideoCaptureParams /* params */) +// Requests that the video capturer send a frame "soon" (e.g., to resolve +// picture loss or quality issues). +IPC_MESSAGE_CONTROL1(VideoCaptureHostMsg_RequestRefreshFrame, + int /* device_id */) + // Close the video capture specified by |device_id|. IPC_MESSAGE_CONTROL1(VideoCaptureHostMsg_Stop, int /* device_id */) diff --git a/chromium/content/common/memory_benchmark_messages.h b/chromium/content/common/memory_benchmark_messages.h deleted file mode 100644 index 3955630496a..00000000000 --- a/chromium/content/common/memory_benchmark_messages.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2013 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. - -// IPC messages for memory benchmark. -// Multiply-included message file, hence no include guard. - -#include <string> - -#include "ipc/ipc_message_macros.h" - -#define IPC_MESSAGE_START MemoryBenchmarkMsgStart - -IPC_MESSAGE_CONTROL1(MemoryBenchmarkHostMsg_HeapProfilerDump, - std::string /* dump reason */) diff --git a/chromium/content/common/message_router.cc b/chromium/content/common/message_router.cc deleted file mode 100644 index ac6361e4fe6..00000000000 --- a/chromium/content/common/message_router.cc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2011 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 "content/common/message_router.h" - -#include "ipc/ipc_message.h" - -namespace content { - -MessageRouter::MessageRouter() { -} - -MessageRouter::~MessageRouter() { -} - -bool MessageRouter::OnControlMessageReceived(const IPC::Message& msg) { - NOTREACHED() << - "should override in subclass if you care about control messages"; - return false; -} - -bool MessageRouter::Send(IPC::Message* msg) { - NOTREACHED() << - "should override in subclass if you care about sending messages"; - return false; -} - -bool MessageRouter::AddRoute(int32_t routing_id, IPC::Listener* listener) { - if (routes_.Lookup(routing_id)) { - DLOG(ERROR) << "duplicate routing ID"; - return false; - } - routes_.AddWithID(listener, routing_id); - return true; -} - -void MessageRouter::RemoveRoute(int32_t routing_id) { - routes_.Remove(routing_id); -} - -bool MessageRouter::OnMessageReceived(const IPC::Message& msg) { - if (msg.routing_id() == MSG_ROUTING_CONTROL) - return OnControlMessageReceived(msg); - - return RouteMessage(msg); -} - -bool MessageRouter::RouteMessage(const IPC::Message& msg) { - IPC::Listener* listener = routes_.Lookup(msg.routing_id()); - if (!listener) - return false; - - return listener->OnMessageReceived(msg); -} - -} // namespace content diff --git a/chromium/content/common/message_router.h b/chromium/content/common/message_router.h deleted file mode 100644 index fea73252b35..00000000000 --- a/chromium/content/common/message_router.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_COMMON_MESSAGE_ROUTER_H_ -#define CONTENT_COMMON_MESSAGE_ROUTER_H_ - -#include <stdint.h> - -#include "base/id_map.h" -#include "base/macros.h" -#include "content/common/content_export.h" -#include "ipc/ipc_listener.h" -#include "ipc/ipc_sender.h" - -// The MessageRouter handles all incoming messages sent to it by routing them -// to the correct listener. Routing is based on the Message's routing ID. -// Since routing IDs are typically assigned asynchronously by the browser -// process, the MessageRouter has the notion of pending IDs for listeners that -// have not yet been assigned a routing ID. -// -// When a message arrives, the routing ID is used to index the set of routes to -// find a listener. If a listener is found, then the message is passed to it. -// Otherwise, the message is ignored if its routing ID is not equal to -// MSG_ROUTING_CONTROL. -// -// The MessageRouter supports the IPC::Sender interface for outgoing messages, -// but does not define a meaningful implementation of it. The subclass of -// MessageRouter is intended to provide that if appropriate. -// -// The MessageRouter can be used as a concrete class provided its Send method -// is not called and it does not receive any control messages. - -namespace content { - -class CONTENT_EXPORT MessageRouter : public IPC::Listener, public IPC::Sender { - public: - MessageRouter(); - ~MessageRouter() override; - - // Implemented by subclasses to handle control messages - virtual bool OnControlMessageReceived(const IPC::Message& msg); - - // IPC::Listener implementation: - bool OnMessageReceived(const IPC::Message& msg) override; - - // Like OnMessageReceived, except it only handles routed messages. Returns - // true if the message was dispatched, or false if there was no listener for - // that route id. - virtual bool RouteMessage(const IPC::Message& msg); - - // IPC::Sender implementation: - bool Send(IPC::Message* msg) override; - - // Called to add a listener for a particular message routing ID. - // Returns true if succeeded. - bool AddRoute(int32_t routing_id, IPC::Listener* listener); - - // Called to remove a listener for a particular message routing ID. - void RemoveRoute(int32_t routing_id); - - private: - // A list of all listeners with assigned routing IDs. - IDMap<IPC::Listener> routes_; - - DISALLOW_COPY_AND_ASSIGN(MessageRouter); -}; - -} // namespace content - -#endif // CONTENT_COMMON_MESSAGE_ROUTER_H_ diff --git a/chromium/content/common/mojo/DEPS b/chromium/content/common/mojo/DEPS index c70d064e525..0f2f39efd65 100644 --- a/chromium/content/common/mojo/DEPS +++ b/chromium/content/common/mojo/DEPS @@ -1,6 +1,5 @@ include_rules = [ - "+mojo/shell/public/cpp", - "+mojo/shell/public/interfaces", "+mojo/converters/network", - "+mojo/runner/child", + "+mojo/edk/embedder", + "+mojo/shell", ] diff --git a/chromium/content/common/mojo/channel_init.cc b/chromium/content/common/mojo/channel_init.cc index 967fb10be60..c8172ab2cd3 100644 --- a/chromium/content/common/mojo/channel_init.cc +++ b/chromium/content/common/mojo/channel_init.cc @@ -8,55 +8,25 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/command_line.h" #include "base/lazy_instance.h" +#include "base/memory/ref_counted.h" #include "base/message_loop/message_loop.h" +#include "base/task_runner.h" #include "base/thread_task_runner_handle.h" -#include "third_party/mojo/src/mojo/edk/embedder/embedder.h" +#include "mojo/edk/embedder/embedder.h" namespace content { -ChannelInit::ChannelInit() : channel_info_(nullptr), weak_factory_(this) {} +ChannelInit::ChannelInit() {} -ChannelInit::~ChannelInit() { - if (channel_info_) - mojo::embedder::DestroyChannel(channel_info_, - base::Bind(&base::DoNothing), nullptr); -} +ChannelInit::~ChannelInit() {} mojo::ScopedMessagePipeHandle ChannelInit::Init( base::PlatformFile file, scoped_refptr<base::TaskRunner> io_thread_task_runner) { - scoped_ptr<IPC::ScopedIPCSupport> ipc_support( - new IPC::ScopedIPCSupport(io_thread_task_runner)); - mojo::ScopedMessagePipeHandle message_pipe = mojo::embedder::CreateChannel( - mojo::embedder::ScopedPlatformHandle( - mojo::embedder::PlatformHandle(file)), - base::Bind(&ChannelInit::OnCreatedChannel, weak_factory_.GetWeakPtr(), - base::Passed(&ipc_support)), - base::ThreadTaskRunnerHandle::Get()); - return message_pipe; -} - -void ChannelInit::WillDestroySoon() { - if (channel_info_) - mojo::embedder::WillDestroyChannelSoon(channel_info_); -} - -// static -void ChannelInit::OnCreatedChannel( - base::WeakPtr<ChannelInit> self, - scoped_ptr<IPC::ScopedIPCSupport> ipc_support, - mojo::embedder::ChannelInfo* channel) { - // If |self| was already destroyed, shut the channel down. - if (!self) { - mojo::embedder::DestroyChannel(channel, - base::Bind(&base::DoNothing), nullptr); - return; - } - - DCHECK(!self->channel_info_); - self->channel_info_ = channel; - self->ipc_support_ = std::move(ipc_support); + return mojo::edk::CreateMessagePipe( + mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(file))); } } // namespace content diff --git a/chromium/content/common/mojo/channel_init.h b/chromium/content/common/mojo/channel_init.h index acdc5752c95..6b9daae2dd0 100644 --- a/chromium/content/common/mojo/channel_init.h +++ b/chromium/content/common/mojo/channel_init.h @@ -8,11 +8,8 @@ #include "base/files/file.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" #include "content/common/content_export.h" -#include "ipc/mojo/scoped_ipc_support.h" #include "mojo/public/cpp/system/message_pipe.h" -#include "third_party/mojo/src/mojo/edk/embedder/channel_info_forward.h" namespace base { class TaskRunner; @@ -22,35 +19,20 @@ namespace content { // ChannelInit handles creation and destruction of the Mojo channel. It is not // thread-safe, but may be used on any single thread with a MessageLoop. +// +// TODO(rockot): Get rid of this class ASAP (i.e. once the patch which includes +// this TODO has stuck for a bit) since it's no longer necessary. class CONTENT_EXPORT ChannelInit { public: ChannelInit(); ~ChannelInit(); - // Initializes the channel. This takes ownership of |file|. Returns the - // primordial MessagePipe for the channel. + // Initializes the channel. This takes ownership of |file|. mojo::ScopedMessagePipeHandle Init( base::PlatformFile file, scoped_refptr<base::TaskRunner> io_thread_task_runner); - // Notifies the channel that we (hence it) will soon be destroyed. - void WillDestroySoon(); - private: - // Invoked on the thread on which this object lives once the channel has been - // established. This is a static method that takes a weak pointer to self, - // since we want to destroy the channel if we were destroyed first. - static void OnCreatedChannel( - base::WeakPtr<ChannelInit> self, - scoped_ptr<IPC::ScopedIPCSupport> ipc_support, - mojo::embedder::ChannelInfo* channel); - - // If non-null the channel has been established. - mojo::embedder::ChannelInfo* channel_info_; - - scoped_ptr<IPC::ScopedIPCSupport> ipc_support_; - base::WeakPtrFactory<ChannelInit> weak_factory_; - DISALLOW_COPY_AND_ASSIGN(ChannelInit); }; diff --git a/chromium/content/common/mojo/current_thread_loader.cc b/chromium/content/common/mojo/current_thread_loader.cc new file mode 100644 index 00000000000..eb64b150863 --- /dev/null +++ b/chromium/content/common/mojo/current_thread_loader.cc @@ -0,0 +1,25 @@ +// Copyright 2016 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 "content/common/mojo/current_thread_loader.h" + +namespace content { + +CurrentThreadLoader::CurrentThreadLoader(const ApplicationFactory& factory) + : factory_(factory) {} + +CurrentThreadLoader::~CurrentThreadLoader() {} + +void CurrentThreadLoader::Load(const std::string& name, + mojo::shell::mojom::ShellClientRequest request) { + if (!shell_client_) { + shell_client_ = factory_.Run(); + factory_ = ApplicationFactory(); + } + + connections_.push_back(make_scoped_ptr( + new mojo::ShellConnection(shell_client_.get(), std::move(request)))); +} + +} // namespace content diff --git a/chromium/content/common/mojo/current_thread_loader.h b/chromium/content/common/mojo/current_thread_loader.h new file mode 100644 index 00000000000..e5e6e35de2c --- /dev/null +++ b/chromium/content/common/mojo/current_thread_loader.h @@ -0,0 +1,46 @@ +// Copyright 2016 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 CONTENT_COMMON_MOJO_CURRENT_THREAD_LOADER_H_ +#define CONTENT_COMMON_MOJO_CURRENT_THREAD_LOADER_H_ + +#include <vector> + +#include "base/callback.h" +#include "base/macros.h" +#include "mojo/shell/loader.h" +#include "mojo/shell/public/cpp/shell_client.h" +#include "mojo/shell/public/cpp/shell_connection.h" + +namespace content { + +// A Loader which loads a single type of app from a mojo::ShellClientFactory on +// the current thread. +class CurrentThreadLoader : public mojo::shell::Loader { + public: + using ApplicationFactory = base::Callback<scoped_ptr<mojo::ShellClient>()>; + + explicit CurrentThreadLoader(const ApplicationFactory& factory); + ~CurrentThreadLoader() override; + + // mojo::shell::Loader: + void Load(const std::string& name, + mojo::shell::mojom::ShellClientRequest request) override; + + private: + // The factory used to create new instances of the application delegate. This + // is called exactly once since all connections share a single client. + ApplicationFactory factory_; + + // Our shared shell client, passed to each connection. + scoped_ptr<mojo::ShellClient> shell_client_; + + std::vector<scoped_ptr<mojo::ShellConnection>> connections_; + + DISALLOW_COPY_AND_ASSIGN(CurrentThreadLoader); +}; + +} // namespace content + +#endif // CONTENT_COMMON_MOJO_CURRENT_THREAD_LOADER_H_ diff --git a/chromium/content/common/mojo/mojo_messages.h b/chromium/content/common/mojo/mojo_messages.h index 4ed553641ee..1232902be37 100644 --- a/chromium/content/common/mojo/mojo_messages.h +++ b/chromium/content/common/mojo/mojo_messages.h @@ -20,8 +20,3 @@ // Mojo IPC is bootstrapped over Chrome IPC via this message. IPC_MESSAGE_CONTROL1(MojoMsg_Activate, IPC::PlatformFileForTransit /* handle */) - -// Mojo IPC to an external shell is bootstrapped over Chrome IPC via this -// message. -IPC_MESSAGE_CONTROL1(MojoMsg_BindExternalMojoShellHandle, - IPC::PlatformFileForTransit /* handle */) diff --git a/chromium/content/common/mojo/mojo_shell_connection_impl.cc b/chromium/content/common/mojo/mojo_shell_connection_impl.cc index 34bf88a4766..5214096007a 100644 --- a/chromium/content/common/mojo/mojo_shell_connection_impl.cc +++ b/chromium/content/common/mojo/mojo_shell_connection_impl.cc @@ -8,15 +8,19 @@ #include "base/command_line.h" #include "base/lazy_instance.h" +#include "base/run_loop.h" #include "base/stl_util.h" #include "base/threading/thread_local.h" -#include "mojo/converters/network/network_type_converters.h" -#include "mojo/runner/child/runner_connection.h" -#include "mojo/shell/public/cpp/application_delegate.h" -#include "mojo/shell/public/cpp/application_impl.h" +#include "content/public/common/content_switches.h" +#include "mojo/edk/embedder/embedder.h" +#include "mojo/edk/embedder/platform_channel_pair.h" +#include "mojo/shell/public/cpp/shell_client.h" +#include "mojo/shell/public/cpp/shell_connection.h" +#include "mojo/shell/runner/common/client_util.h" namespace content { namespace { + using MojoShellConnectionPtr = base::ThreadLocalPointer<MojoShellConnectionImpl>; @@ -24,69 +28,115 @@ using MojoShellConnectionPtr = base::LazyInstance<MojoShellConnectionPtr>::Leaky lazy_tls_ptr = LAZY_INSTANCE_INITIALIZER; +MojoShellConnection::Factory* mojo_shell_connection_factory = nullptr; + } // namespace bool IsRunningInMojoShell() { - return base::CommandLine::ForCurrentProcess()->HasSwitch( - "mojo-platform-channel-handle"); + return mojo_shell_connection_factory || + base::CommandLine::ForCurrentProcess()->HasSwitch( + mojo::edk::PlatformChannelPair::kMojoPlatformChannelHandleSwitch); +} + +bool ShouldWaitForShell() { + return mojo_shell_connection_factory || + (IsRunningInMojoShell() && + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kWaitForMojoShell)); +} + +// static +bool MojoShellConnectionImpl::CreateUsingFactory() { + if (mojo_shell_connection_factory) { + DCHECK(!lazy_tls_ptr.Pointer()->Get()); + mojo_shell_connection_factory->Run(); + DCHECK(lazy_tls_ptr.Pointer()->Get()); + return true; + } + return false; } // static void MojoShellConnectionImpl::Create() { DCHECK(!lazy_tls_ptr.Pointer()->Get()); - MojoShellConnectionImpl* connection = new MojoShellConnectionImpl; + MojoShellConnectionImpl* connection = + new MojoShellConnectionImpl(true /* external */); lazy_tls_ptr.Pointer()->Set(connection); } // static +void MojoShellConnection::Create(mojo::shell::mojom::ShellClientRequest request, + bool is_external) { + DCHECK(!lazy_tls_ptr.Pointer()->Get()); + MojoShellConnectionImpl* connection = + new MojoShellConnectionImpl(is_external); + lazy_tls_ptr.Pointer()->Set(connection); + connection->shell_connection_.reset( + new mojo::ShellConnection(connection, std::move(request))); + if (is_external) + connection->WaitForShellIfNecessary(); +} + +// static +void MojoShellConnection::SetFactoryForTest(Factory* factory) { + DCHECK(!lazy_tls_ptr.Pointer()->Get()); + mojo_shell_connection_factory = factory; +} + +// static MojoShellConnectionImpl* MojoShellConnectionImpl::Get() { + // Assume that if a mojo_shell_connection_factory was set that it did not + // create a MojoShellConnectionImpl. return static_cast<MojoShellConnectionImpl*>(MojoShellConnection::Get()); } -void MojoShellConnectionImpl::BindToCommandLinePlatformChannel() { - DCHECK(IsRunningInMojoShell()); - if (initialized_) - return; - WaitForShell(mojo::ScopedMessagePipeHandle()); +void MojoShellConnectionImpl::BindToRequestFromCommandLine() { + DCHECK(!shell_connection_); + shell_connection_.reset(new mojo::ShellConnection( + this, mojo::shell::GetShellClientRequestFromCommandLine())); + WaitForShellIfNecessary(); } -void MojoShellConnectionImpl::BindToMessagePipe( - mojo::ScopedMessagePipeHandle handle) { - if (initialized_) - return; - WaitForShell(std::move(handle)); -} +MojoShellConnectionImpl::MojoShellConnectionImpl(bool external) + : external_(external) {} -MojoShellConnectionImpl::MojoShellConnectionImpl() : initialized_(false) {} MojoShellConnectionImpl::~MojoShellConnectionImpl() { STLDeleteElements(&listeners_); } -void MojoShellConnectionImpl::WaitForShell( - mojo::ScopedMessagePipeHandle handle) { - mojo::InterfaceRequest<mojo::Application> application_request; - runner_connection_.reset(mojo::runner::RunnerConnection::ConnectToRunner( - &application_request, std::move(handle))); - application_impl_.reset( - new mojo::ApplicationImpl(this, std::move(application_request))); - application_impl_->WaitForInitialize(); +void MojoShellConnectionImpl::WaitForShellIfNecessary() { + // TODO(rockot): Remove this. http://crbug.com/594852. + if (ShouldWaitForShell()) { + base::RunLoop wait_loop; + shell_connection_->set_initialize_handler(wait_loop.QuitClosure()); + wait_loop.Run(); + } } -void MojoShellConnectionImpl::Initialize(mojo::ApplicationImpl* application) { - initialized_ = true; +void MojoShellConnectionImpl::Initialize(mojo::Connector* connector, + const mojo::Identity& identity, + uint32_t id) { } -bool MojoShellConnectionImpl::ConfigureIncomingConnection( - mojo::ApplicationConnection* connection) { +bool MojoShellConnectionImpl::AcceptConnection(mojo::Connection* connection) { bool found = false; for (auto listener : listeners_) - found |= listener->ConfigureIncomingConnection(connection); + found |= listener->AcceptConnection(connection); return found; } -mojo::ApplicationImpl* MojoShellConnectionImpl::GetApplication() { - DCHECK(initialized_); - return application_impl_.get(); +mojo::Connector* MojoShellConnectionImpl::GetConnector() { + DCHECK(shell_connection_); + return shell_connection_->connector(); +} + +bool MojoShellConnectionImpl::UsingExternalShell() const { + return external_; +} + +void MojoShellConnectionImpl::SetConnectionLostClosure( + const base::Closure& closure) { + shell_connection_->set_connection_lost_closure(closure); } void MojoShellConnectionImpl::AddListener(Listener* listener) { diff --git a/chromium/content/common/mojo/mojo_shell_connection_impl.h b/chromium/content/common/mojo/mojo_shell_connection_impl.h index 3f7ecfa05fc..3f1a188eb55 100644 --- a/chromium/content/common/mojo/mojo_shell_connection_impl.h +++ b/chromium/content/common/mojo/mojo_shell_connection_impl.h @@ -11,13 +11,9 @@ #include "base/memory/scoped_ptr.h" #include "content/public/common/mojo_shell_connection.h" #include "mojo/public/cpp/system/message_pipe.h" -#include "mojo/shell/public/cpp/application_delegate.h" - -namespace mojo { -namespace runner { -class RunnerConnection; -} -} +#include "mojo/shell/public/cpp/shell.h" +#include "mojo/shell/public/cpp/shell_client.h" +#include "mojo/shell/public/cpp/shell_connection.h" namespace content { @@ -25,8 +21,12 @@ namespace content { bool IsRunningInMojoShell(); class MojoShellConnectionImpl : public MojoShellConnection, - public mojo::ApplicationDelegate { + public mojo::ShellClient { public: + // Creates the MojoShellConnection using MojoShellConnection::Factory. Returns + // true if a factory was set and the connection was created, false otherwise. + static bool CreateUsingFactory(); + // Creates an instance of this class and stuffs it in TLS on the calling // thread. Retrieve it using MojoShellConnection::Get(). static void Create(); @@ -36,37 +36,33 @@ class MojoShellConnectionImpl : public MojoShellConnection, // Mojo shell). static MojoShellConnectionImpl* Get(); - // Blocks the calling thread until calling GetApplication() will return an - // Initialized() application with a bound ShellPtr. This call is a no-op - // if the connection has already been initialized. - void BindToCommandLinePlatformChannel(); - - // Same as BindToCommandLinePlatformChannel(), but receives a |handle| instead - // of looking for one on the command line. - void BindToMessagePipe(mojo::ScopedMessagePipeHandle handle); + // Binds the shell connection to a ShellClientFactory request pipe from the + // command line. This must only be called once. + void BindToRequestFromCommandLine(); private: - MojoShellConnectionImpl(); + friend class MojoShellConnection; + + explicit MojoShellConnectionImpl(bool external); ~MojoShellConnectionImpl() override; - // mojo::ApplicationDelegate: - void Initialize(mojo::ApplicationImpl* application) override; - bool ConfigureIncomingConnection( - mojo::ApplicationConnection* connection) override; + void WaitForShellIfNecessary(); + + // mojo::ShellClient: + void Initialize(mojo::Connector* connector, + const mojo::Identity& identity, + uint32_t id) override; + bool AcceptConnection(mojo::Connection* connection) override; // MojoShellConnection: - mojo::ApplicationImpl* GetApplication() override; + mojo::Connector* GetConnector() override; + bool UsingExternalShell() const override; + void SetConnectionLostClosure(const base::Closure& closure) override; void AddListener(Listener* listener) override; void RemoveListener(Listener* listener) override; - // Blocks the calling thread until a connection to the spawning shell is - // established, an Application request from it is bound, and the Initialize() - // method on that application is called. - void WaitForShell(mojo::ScopedMessagePipeHandle handle); - - bool initialized_; - scoped_ptr<mojo::runner::RunnerConnection> runner_connection_; - scoped_ptr<mojo::ApplicationImpl> application_impl_; + const bool external_; + scoped_ptr<mojo::ShellConnection> shell_connection_; std::vector<Listener*> listeners_; DISALLOW_COPY_AND_ASSIGN(MojoShellConnectionImpl); diff --git a/chromium/content/common/mojo/service_registry_impl.cc b/chromium/content/common/mojo/service_registry_impl.cc index a55864f92ea..b26c60990be 100644 --- a/chromium/content/common/mojo/service_registry_impl.cc +++ b/chromium/content/common/mojo/service_registry_impl.cc @@ -21,27 +21,26 @@ ServiceRegistryImpl::~ServiceRegistryImpl() { } void ServiceRegistryImpl::Bind( - mojo::InterfaceRequest<mojo::ServiceProvider> request) { + mojo::shell::mojom::InterfaceProviderRequest request) { binding_.Bind(std::move(request)); binding_.set_connection_error_handler(base::Bind( &ServiceRegistryImpl::OnConnectionError, base::Unretained(this))); } void ServiceRegistryImpl::BindRemoteServiceProvider( - mojo::ServiceProviderPtr service_provider) { + mojo::shell::mojom::InterfaceProviderPtr service_provider) { CHECK(!remote_provider_); remote_provider_ = std::move(service_provider); while (!pending_connects_.empty()) { - remote_provider_->ConnectToService( + remote_provider_->GetInterface( mojo::String::From(pending_connects_.front().first), mojo::ScopedMessagePipeHandle(pending_connects_.front().second)); pending_connects_.pop(); } } -void ServiceRegistryImpl::AddService( - const std::string& service_name, - const base::Callback<void(mojo::ScopedMessagePipeHandle)> service_factory) { +void ServiceRegistryImpl::AddService(const std::string& service_name, + const ServiceFactory service_factory) { service_factories_[service_name] = service_factory; } @@ -52,15 +51,31 @@ void ServiceRegistryImpl::RemoveService(const std::string& service_name) { void ServiceRegistryImpl::ConnectToRemoteService( const base::StringPiece& service_name, mojo::ScopedMessagePipeHandle handle) { + auto override_it = service_overrides_.find(service_name.as_string()); + if (override_it != service_overrides_.end()) { + override_it->second.Run(std::move(handle)); + return; + } + if (!remote_provider_) { pending_connects_.push( std::make_pair(service_name.as_string(), handle.release())); return; } - remote_provider_->ConnectToService( + remote_provider_->GetInterface( mojo::String::From(service_name.as_string()), std::move(handle)); } +void ServiceRegistryImpl::AddServiceOverrideForTesting( + const std::string& service_name, + const ServiceFactory& factory) { + service_overrides_[service_name] = factory; +} + +void ServiceRegistryImpl::ClearServiceOverridesForTesting() { + service_overrides_.clear(); +} + bool ServiceRegistryImpl::IsBound() const { return binding_.is_bound(); } @@ -69,12 +84,10 @@ base::WeakPtr<ServiceRegistry> ServiceRegistryImpl::GetWeakPtr() { return weak_factory_.GetWeakPtr(); } -void ServiceRegistryImpl::ConnectToService( +void ServiceRegistryImpl::GetInterface( const mojo::String& name, mojo::ScopedMessagePipeHandle client_handle) { - std::map<std::string, - base::Callback<void(mojo::ScopedMessagePipeHandle)> >::iterator it = - service_factories_.find(name); + auto it = service_factories_.find(name); if (it == service_factories_.end()) return; diff --git a/chromium/content/common/mojo/service_registry_impl.h b/chromium/content/common/mojo/service_registry_impl.h index 5e4fd73fd91..807924cb1e3 100644 --- a/chromium/content/common/mojo/service_registry_impl.h +++ b/chromium/content/common/mojo/service_registry_impl.h @@ -16,53 +16,60 @@ #include "content/public/common/service_registry.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/system/core.h" -#include "mojo/shell/public/interfaces/service_provider.mojom.h" +#include "mojo/shell/public/interfaces/interface_provider.mojom.h" namespace content { class CONTENT_EXPORT ServiceRegistryImpl : public ServiceRegistry, - public NON_EXPORTED_BASE(mojo::ServiceProvider) { + public NON_EXPORTED_BASE(mojo::shell::mojom::InterfaceProvider) { public: + using ServiceFactory = base::Callback<void(mojo::ScopedMessagePipeHandle)>; + ServiceRegistryImpl(); ~ServiceRegistryImpl() override; // Binds this ServiceProvider implementation to a message pipe endpoint. - void Bind(mojo::InterfaceRequest<mojo::ServiceProvider> request); + void Bind(mojo::shell::mojom::InterfaceProviderRequest request); // Binds to a remote ServiceProvider. This will expose added services to the // remote ServiceProvider with the corresponding handle and enable // ConnectToRemoteService to provide access to services exposed by the remote // ServiceProvider. - void BindRemoteServiceProvider(mojo::ServiceProviderPtr service_provider); + void BindRemoteServiceProvider( + mojo::shell::mojom::InterfaceProviderPtr service_provider); // ServiceRegistry overrides. void AddService(const std::string& service_name, - const base::Callback<void(mojo::ScopedMessagePipeHandle)> - service_factory) override; + const ServiceFactory service_factory) override; void RemoveService(const std::string& service_name) override; void ConnectToRemoteService(const base::StringPiece& service_name, mojo::ScopedMessagePipeHandle handle) override; + void AddServiceOverrideForTesting( + const std::string& service_name, + const ServiceFactory& service_factory) override; + void ClearServiceOverridesForTesting() override; bool IsBound() const; base::WeakPtr<ServiceRegistry> GetWeakPtr(); private: - // mojo::ServiceProvider overrides. - void ConnectToService(const mojo::String& name, - mojo::ScopedMessagePipeHandle client_handle) override; + // mojo::InterfaceProvider overrides. + void GetInterface(const mojo::String& name, + mojo::ScopedMessagePipeHandle client_handle) override; void OnConnectionError(); - mojo::Binding<mojo::ServiceProvider> binding_; - mojo::ServiceProviderPtr remote_provider_; + mojo::Binding<mojo::shell::mojom::InterfaceProvider> binding_; + mojo::shell::mojom::InterfaceProviderPtr remote_provider_; - std::map<std::string, base::Callback<void(mojo::ScopedMessagePipeHandle)> > - service_factories_; + std::map<std::string, ServiceFactory> service_factories_; std::queue<std::pair<std::string, mojo::MessagePipeHandle> > pending_connects_; + std::map<std::string, ServiceFactory> service_overrides_; + base::WeakPtrFactory<ServiceRegistry> weak_factory_; }; diff --git a/chromium/content/common/mojo/static_loader.cc b/chromium/content/common/mojo/static_loader.cc new file mode 100644 index 00000000000..107c9135456 --- /dev/null +++ b/chromium/content/common/mojo/static_loader.cc @@ -0,0 +1,93 @@ +// Copyright 2015 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 "content/common/mojo/static_loader.h" + +#include <utility> + +#include "base/bind.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/task_runner.h" +#include "base/thread_task_runner_handle.h" +#include "base/threading/simple_thread.h" +#include "mojo/public/cpp/bindings/interface_request.h" +#include "mojo/shell/public/cpp/application_runner.h" +#include "mojo/shell/public/cpp/shell_client.h" +#include "mojo/shell/public/interfaces/shell_client.mojom.h" + +namespace content { + +namespace { + +class RunnerThread : public base::SimpleThread { + public: + RunnerThread(const std::string& name, + mojo::shell::mojom::ShellClientRequest request, + scoped_refptr<base::TaskRunner> exit_task_runner, + const base::Closure& exit_callback, + const StaticLoader::ApplicationFactory& factory) + : base::SimpleThread("Mojo Application: " + name), + request_(std::move(request)), + exit_task_runner_(exit_task_runner), + exit_callback_(exit_callback), + factory_(factory) {} + + void Run() override { + scoped_ptr<mojo::ApplicationRunner> runner( + new mojo::ApplicationRunner(factory_.Run().release())); + runner->Run(request_.PassMessagePipe().release().value(), + false /* init_base */); + exit_task_runner_->PostTask(FROM_HERE, exit_callback_); + } + + private: + mojo::shell::mojom::ShellClientRequest request_; + scoped_refptr<base::TaskRunner> exit_task_runner_; + base::Closure exit_callback_; + StaticLoader::ApplicationFactory factory_; + + DISALLOW_COPY_AND_ASSIGN(RunnerThread); +}; + +} // namespace + +StaticLoader::StaticLoader(const ApplicationFactory& factory) + : StaticLoader(factory, base::Closure()) { +} + +StaticLoader::StaticLoader(const ApplicationFactory& factory, + const base::Closure& quit_callback) + : factory_(factory), quit_callback_(quit_callback), weak_factory_(this) { +} + +StaticLoader::~StaticLoader() { + if (thread_) + StopAppThread(); +} + +void StaticLoader::Load(const std::string& name, + mojo::shell::mojom::ShellClientRequest request) { + if (thread_) + return; + + // If the application's thread quits on its own before this loader dies, we + // reset the Thread object, allowing future Load requests to be fulfilled + // with a new app instance. + auto exit_callback = base::Bind(&StaticLoader::StopAppThread, + weak_factory_.GetWeakPtr()); + thread_.reset(new RunnerThread(name, std::move(request), + base::ThreadTaskRunnerHandle::Get(), + exit_callback, factory_)); + thread_->Start(); +} + +void StaticLoader::StopAppThread() { + thread_->Join(); + thread_.reset(); + if (!quit_callback_.is_null()) + quit_callback_.Run(); +} + +} // namespace content diff --git a/chromium/content/common/mojo/static_loader.h b/chromium/content/common/mojo/static_loader.h new file mode 100644 index 00000000000..318366d805a --- /dev/null +++ b/chromium/content/common/mojo/static_loader.h @@ -0,0 +1,66 @@ +// Copyright 2015 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 CONTENT_COMMON_MOJO_STATIC_APPLICATION_LOADER_H_ +#define CONTENT_COMMON_MOJO_STATIC_APPLICATION_LOADER_H_ + +#include <list> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "mojo/shell/loader.h" + +namespace base { +class SimpleThread; +} + +namespace mojo { +class ShellClient; +} + +namespace content { + +// An Loader which loads a single type of app from a given +// mojo::ShellClientFactory. A Load() request is fulfilled by creating an +// instance of the app on a new thread. Only one instance of the app will run at +// a time. Any Load requests received while the app is running will be dropped. +class StaticLoader : public mojo::shell::Loader { + public: + using ApplicationFactory = base::Callback<scoped_ptr<mojo::ShellClient>()>; + + // Constructs a static loader for |factory|. + explicit StaticLoader(const ApplicationFactory& factory); + + // Constructs a static loader for |factory| with a closure that will be called + // when the loaded application quits. + StaticLoader(const ApplicationFactory& factory, + const base::Closure& quit_callback); + + ~StaticLoader() override; + + // mojo::shell::Loader: + void Load(const std::string& name, + mojo::shell::mojom::ShellClientRequest request) override; + + private: + void StopAppThread(); + + // The factory used t create new instances of the application delegate. + ApplicationFactory factory_; + + // If not null, this is run when the loaded application quits. + base::Closure quit_callback_; + + // Thread for the application if currently running. + scoped_ptr<base::SimpleThread> thread_; + + base::WeakPtrFactory<StaticLoader> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(StaticLoader); +}; + +} // namespace content + +#endif // CONTENT_COMMON_MOJO_STATIC_APPLICATION_LOADER_H_ diff --git a/chromium/content/common/navigation_params.cc b/chromium/content/common/navigation_params.cc index da6f5901f47..f09cccfebbf 100644 --- a/chromium/content/common/navigation_params.cc +++ b/chromium/content/common/navigation_params.cc @@ -7,6 +7,7 @@ #include "build/build_config.h" #include "content/common/service_worker/service_worker_types.h" #include "content/public/common/browser_side_navigation_policy.h" +#include "content/public/common/url_constants.h" namespace content { @@ -14,12 +15,13 @@ namespace content { bool ShouldMakeNetworkRequestForURL(const GURL& url) { CHECK(IsBrowserSideNavigationEnabled()); - // Data URLs, Javascript URLs and about:blank should not send a request to the - // network stack. + // Data URLs, Javascript URLs, about:blank, srcdoc should not send a request + // to the network stack. // TODO(clamy): same document navigations should not send requests to the // network stack. Neither should pushState/popState. return !url.SchemeIs(url::kDataScheme) && url != GURL(url::kAboutBlankURL) && - !url.SchemeIs(url::kJavaScriptScheme); + !url.SchemeIs(url::kJavaScriptScheme) && !url.is_empty() && + url != GURL(content::kAboutSrcDocURL); } CommonNavigationParams::CommonNavigationParams() @@ -29,8 +31,8 @@ CommonNavigationParams::CommonNavigationParams() should_replace_current_entry(false), report_type(FrameMsg_UILoadMetricsReportType::NO_REPORT), lofi_state(LOFI_UNSPECIFIED), - navigation_start(base::TimeTicks::Now()) { -} + navigation_start(base::TimeTicks::Now()), + method("GET") {} CommonNavigationParams::CommonNavigationParams( const GURL& url, @@ -44,7 +46,8 @@ CommonNavigationParams::CommonNavigationParams( const GURL& base_url_for_data_url, const GURL& history_url_for_data_url, LoFiState lofi_state, - const base::TimeTicks& navigation_start) + const base::TimeTicks& navigation_start, + std::string method) : url(url), referrer(referrer), transition(transition), @@ -56,8 +59,11 @@ CommonNavigationParams::CommonNavigationParams( base_url_for_data_url(base_url_for_data_url), history_url_for_data_url(history_url_for_data_url), lofi_state(lofi_state), - navigation_start(navigation_start) { -} + navigation_start(navigation_start), + method(method) {} + +CommonNavigationParams::CommonNavigationParams( + const CommonNavigationParams& other) = default; CommonNavigationParams::~CommonNavigationParams() { } @@ -69,21 +75,22 @@ BeginNavigationParams::BeginNavigationParams() request_context_type(REQUEST_CONTEXT_TYPE_LOCATION) {} BeginNavigationParams::BeginNavigationParams( - std::string method, std::string headers, int load_flags, bool has_user_gesture, bool skip_service_worker, RequestContextType request_context_type) - : method(method), - headers(headers), + : headers(headers), load_flags(load_flags), has_user_gesture(has_user_gesture), skip_service_worker(skip_service_worker), request_context_type(request_context_type) {} +BeginNavigationParams::BeginNavigationParams( + const BeginNavigationParams& other) = default; + StartNavigationParams::StartNavigationParams() - : is_post(false), + : #if defined(OS_ANDROID) has_user_gesture(false), #endif @@ -92,7 +99,6 @@ StartNavigationParams::StartNavigationParams() } StartNavigationParams::StartNavigationParams( - bool is_post, const std::string& extra_headers, const std::vector<unsigned char>& browser_initiated_post_data, #if defined(OS_ANDROID) @@ -100,8 +106,7 @@ StartNavigationParams::StartNavigationParams( #endif int transferred_request_child_id, int transferred_request_request_id) - : is_post(is_post), - extra_headers(extra_headers), + : extra_headers(extra_headers), browser_initiated_post_data(browser_initiated_post_data), #if defined(OS_ANDROID) has_user_gesture(has_user_gesture), @@ -110,6 +115,9 @@ StartNavigationParams::StartNavigationParams( transferred_request_request_id(transferred_request_request_id) { } +StartNavigationParams::StartNavigationParams( + const StartNavigationParams& other) = default; + StartNavigationParams::~StartNavigationParams() { } @@ -164,6 +172,9 @@ RequestNavigationParams::RequestNavigationParams( should_create_service_worker(false), service_worker_provider_id(kInvalidServiceWorkerProviderId) {} +RequestNavigationParams::RequestNavigationParams( + const RequestNavigationParams& other) = default; + RequestNavigationParams::~RequestNavigationParams() { } diff --git a/chromium/content/common/navigation_params.h b/chromium/content/common/navigation_params.h index 414319d73e3..d2f83e756c1 100644 --- a/chromium/content/common/navigation_params.h +++ b/chromium/content/common/navigation_params.h @@ -59,7 +59,9 @@ struct CONTENT_EXPORT CommonNavigationParams { const GURL& base_url_for_data_url, const GURL& history_url_for_data_url, LoFiState lofi_state, - const base::TimeTicks& navigation_start); + const base::TimeTicks& navigation_start, + std::string method); + CommonNavigationParams(const CommonNavigationParams& other); ~CommonNavigationParams(); // The URL to navigate to. @@ -113,6 +115,9 @@ struct CONTENT_EXPORT CommonNavigationParams { // PlzNavigate: For renderer initiated navigations, this will be set on the // renderer side and sent with FrameHostMsg_BeginNavigation. base::TimeTicks navigation_start; + + // The request method: GET, POST, etc. + std::string method; }; // Provided by the renderer ---------------------------------------------------- @@ -128,15 +133,12 @@ struct CONTENT_EXPORT BeginNavigationParams { // TODO(clamy): See if it is possible to reuse this in // ResourceMsg_Request_Params. BeginNavigationParams(); - BeginNavigationParams(std::string method, - std::string headers, + BeginNavigationParams(std::string headers, int load_flags, bool has_user_gesture, bool skip_service_worker, RequestContextType request_context_type); - - // The request method: GET, POST, etc. - std::string method; + BeginNavigationParams(const BeginNavigationParams& other); // Additional HTTP request headers. std::string headers; @@ -171,7 +173,6 @@ struct CONTENT_EXPORT BeginNavigationParams { struct CONTENT_EXPORT StartNavigationParams { StartNavigationParams(); StartNavigationParams( - bool is_post, const std::string& extra_headers, const std::vector<unsigned char>& browser_initiated_post_data, #if defined(OS_ANDROID) @@ -179,11 +180,9 @@ struct CONTENT_EXPORT StartNavigationParams { #endif int transferred_request_child_id, int transferred_request_request_id); + StartNavigationParams(const StartNavigationParams& other); ~StartNavigationParams(); - // Whether the navigation is a POST request (as opposed to a GET). - bool is_post; - // Extra headers (separated by \n) to send during the request. std::string extra_headers; @@ -224,6 +223,7 @@ struct CONTENT_EXPORT RequestNavigationParams { int current_history_list_length, bool is_view_source, bool should_clear_history_list); + RequestNavigationParams(const RequestNavigationParams& other); ~RequestNavigationParams(); // Whether or not the user agent override string should be used. diff --git a/chromium/content/common/net/url_request_service_worker_data.cc b/chromium/content/common/net/url_request_service_worker_data.cc new file mode 100644 index 00000000000..cbf2a875494 --- /dev/null +++ b/chromium/content/common/net/url_request_service_worker_data.cc @@ -0,0 +1,17 @@ +// Copyright 2016 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 "content/common/net/url_request_service_worker_data.h" + +namespace content { + +URLRequestServiceWorkerData::URLRequestServiceWorkerData() {} + +URLRequestServiceWorkerData::~URLRequestServiceWorkerData() {} + +// static +const void* URLRequestServiceWorkerData::kUserDataKey = + static_cast<const void*>(&URLRequestServiceWorkerData::kUserDataKey); + +} // namespace content diff --git a/chromium/content/common/net/url_request_service_worker_data.h b/chromium/content/common/net/url_request_service_worker_data.h new file mode 100644 index 00000000000..4d72321d0a6 --- /dev/null +++ b/chromium/content/common/net/url_request_service_worker_data.h @@ -0,0 +1,28 @@ +// Copyright 2016 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 CONTENT_COMMON_NET_URL_REQUEST_SERVICE_WORKER_DATA_H_ +#define CONTENT_COMMON_NET_URL_REQUEST_SERVICE_WORKER_DATA_H_ + +#include "base/supports_user_data.h" + +namespace content { + +// Used to annotate all URLRequests for which the request originated in the +// Service Worker and for initial Service Worker script loads. +// Summarized this includes requests due to: +// - fetching Service Worker script itself for installation, +// - importing other scripts from within a Service Worker script, +// - calling fetch() from within a Service Worker script. +class URLRequestServiceWorkerData : public base::SupportsUserData::Data { + public: + URLRequestServiceWorkerData(); + ~URLRequestServiceWorkerData() override; + + static const void* kUserDataKey; +}; + +} // namespace content + +#endif // CONTENT_COMMON_NET_URL_REQUEST_SERVICE_WORKER_DATA_H_ diff --git a/chromium/content/common/notification_constants.h b/chromium/content/common/notification_constants.h index 6ca8ad62e59..2573a6eb8f8 100644 --- a/chromium/content/common/notification_constants.h +++ b/chromium/content/common/notification_constants.h @@ -12,6 +12,18 @@ namespace content { // Maximum number of actions on a Platform Notification. static const size_t kPlatformNotificationMaxActions = 2; +// The maximum reasonable notification icon size, scaled from dip units to +// pixels using the largest supported scaling factor. +static const int kPlatformNotificationMaxIconSizePx = 320; // 80 dip * 4 + +// The maximum reasonable badge size, scaled from dip units to pixels using the +// largest supported scaling factor. +static const int kPlatformNotificationMaxBadgeSizePx = 96; // 24 dip * 4 + +// The maximum reasonable action icon size, scaled from dip units to +// pixels using the largest supported scaling factor. +static const int kPlatformNotificationMaxActionIconSizePx = 128; // 32 dip * 4 + } // namespace content #endif // CONTENT_COMMON_NOTIFICATION_CONSTANTS_H_ diff --git a/chromium/content/common/one_writer_seqlock_unittest.cc b/chromium/content/common/one_writer_seqlock_unittest.cc index 8e69812c9e2..84d5156a7bd 100644 --- a/chromium/content/common/one_writer_seqlock_unittest.cc +++ b/chromium/content/common/one_writer_seqlock_unittest.cc @@ -10,6 +10,7 @@ #include "base/macros.h" #include "base/third_party/dynamic_annotations/dynamic_annotations.h" #include "base/threading/platform_thread.h" +#include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" namespace base { @@ -60,7 +61,12 @@ class BasicSeqLockTestThread : public PlatformThread::Delegate { DISALLOW_COPY_AND_ASSIGN(BasicSeqLockTestThread); }; -TEST(OneWriterSeqLockTest, ManyThreads) { +#if defined(OS_ANDROID) +#define MAYBE_ManyThreads FLAKY_ManyThreads +#else +#define MAYBE_ManyThreads ManyThreads +#endif +TEST(OneWriterSeqLockTest, MAYBE_ManyThreads) { content::OneWriterSeqLock seqlock; TestData data = { 0, 0, 0 }; base::AtomicRefCount ready = 0; diff --git a/chromium/content/common/origin_trials/trial_token.cc b/chromium/content/common/origin_trials/trial_token.cc new file mode 100644 index 00000000000..0a137edc68b --- /dev/null +++ b/chromium/content/common/origin_trials/trial_token.cc @@ -0,0 +1,193 @@ +// Copyright 2015 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 "content/common/origin_trials/trial_token.h" + +#include <openssl/curve25519.h> + +#include <vector> + +#include "base/base64.h" +#include "base/big_endian.h" +#include "base/json/json_reader.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/strings/string_piece.h" +#include "base/time/time.h" +#include "base/values.h" +#include "url/gurl.h" +#include "url/origin.h" + +namespace content { + +namespace { + +// Version is a 1-byte field at offset 0. +const size_t kVersionOffset = 0; +const size_t kVersionSize = 1; + +// These constants define the Version 2 field sizes and offsets. +const size_t kSignatureOffset = kVersionOffset + kVersionSize; +const size_t kSignatureSize = 64; +const size_t kPayloadLengthOffset = kSignatureOffset + kSignatureSize; +const size_t kPayloadLengthSize = 4; +const size_t kPayloadOffset = kPayloadLengthOffset + kPayloadLengthSize; + +// Version 2 is the only token version currently supported. Version 1 was +// introduced in Chrome M50, and removed in M51. There were no experiments +// enabled in the stable M50 release which would have used those tokens. +const uint8_t kVersion2 = 2; + +} // namespace + +TrialToken::~TrialToken() {} + +// static +std::unique_ptr<TrialToken> TrialToken::From(const std::string& token_text, + base::StringPiece public_key) { + std::unique_ptr<std::string> token_payload = Extract(token_text, public_key); + if (!token_payload) { + return nullptr; + } + return Parse(*token_payload); +} + +bool TrialToken::IsValidForFeature(const url::Origin& origin, + base::StringPiece feature_name, + const base::Time& now) const { + return ValidateOrigin(origin) && ValidateFeatureName(feature_name) && + ValidateDate(now); +} + +std::unique_ptr<std::string> TrialToken::Extract( + const std::string& token_payload, + base::StringPiece public_key) { + if (token_payload.empty()) { + return nullptr; + } + + // Token is base64-encoded; decode first. + std::string token_contents; + if (!base::Base64Decode(token_payload, &token_contents)) { + return nullptr; + } + + // Only version 2 currently supported. + if (token_contents.length() < (kVersionOffset + kVersionSize)) { + return nullptr; + } + uint8_t version = token_contents[kVersionOffset]; + if (version != kVersion2) { + return nullptr; + } + + // Token must be large enough to contain a version, signature, and payload + // length. + if (token_contents.length() < (kPayloadLengthOffset + kPayloadLengthSize)) { + return nullptr; + } + + // Extract the length of the signed data (Big-endian). + uint32_t payload_length; + base::ReadBigEndian(&(token_contents[kPayloadLengthOffset]), &payload_length); + + // Validate that the stated length matches the actual payload length. + if (payload_length != token_contents.length() - kPayloadOffset) { + return nullptr; + } + + // Extract the version-specific contents of the token. + const char* token_bytes = token_contents.data(); + base::StringPiece version_piece(token_bytes + kVersionOffset, kVersionSize); + base::StringPiece signature(token_bytes + kSignatureOffset, kSignatureSize); + base::StringPiece payload_piece(token_bytes + kPayloadLengthOffset, + kPayloadLengthSize + payload_length); + + // The data which is covered by the signature is (version + length + payload). + std::string signed_data = + version_piece.as_string() + payload_piece.as_string(); + + // Validate the signature on the data before proceeding. + if (!TrialToken::ValidateSignature(signature, signed_data, public_key)) { + return nullptr; + } + + // Return just the payload, as a new string. + return base::WrapUnique( + new std::string(token_contents, kPayloadOffset, payload_length)); +} + +std::unique_ptr<TrialToken> TrialToken::Parse(const std::string& token_json) { + std::unique_ptr<base::DictionaryValue> datadict = + base::DictionaryValue::From(base::JSONReader::Read(token_json)); + if (!datadict) { + return nullptr; + } + + std::string origin_string; + std::string feature_name; + int expiry_timestamp = 0; + datadict->GetString("origin", &origin_string); + datadict->GetString("feature", &feature_name); + datadict->GetInteger("expiry", &expiry_timestamp); + + // Ensure that the origin is a valid (non-unique) origin URL. + url::Origin origin = url::Origin(GURL(origin_string)); + if (origin.unique()) { + return nullptr; + } + + // Ensure that the feature name is a valid string. + if (feature_name.empty()) { + return nullptr; + } + + // Ensure that the expiry timestamp is a valid (positive) integer. + if (expiry_timestamp <= 0) { + return nullptr; + } + + return base::WrapUnique( + new TrialToken(origin, feature_name, expiry_timestamp)); +} + +bool TrialToken::ValidateOrigin(const url::Origin& origin) const { + return origin == origin_; +} + +bool TrialToken::ValidateFeatureName(base::StringPiece feature_name) const { + return feature_name == feature_name_; +} + +bool TrialToken::ValidateDate(const base::Time& now) const { + return expiry_time_ > now; +} + +// static +bool TrialToken::ValidateSignature(base::StringPiece signature, + const std::string& data, + base::StringPiece public_key) { + // Public key must be 32 bytes long for Ed25519. + CHECK_EQ(public_key.length(), 32UL); + + // Signature must be 64 bytes long. + if (signature.length() != 64) { + return false; + } + + int result = ED25519_verify( + reinterpret_cast<const uint8_t*>(data.data()), data.length(), + reinterpret_cast<const uint8_t*>(signature.data()), + reinterpret_cast<const uint8_t*>(public_key.data())); + return (result != 0); +} + +TrialToken::TrialToken(const url::Origin& origin, + const std::string& feature_name, + uint64_t expiry_timestamp) + : origin_(origin), + feature_name_(feature_name), + expiry_time_(base::Time::FromDoubleT(expiry_timestamp)) {} + +} // namespace content diff --git a/chromium/content/common/origin_trials/trial_token.h b/chromium/content/common/origin_trials/trial_token.h new file mode 100644 index 00000000000..fa05e3713b5 --- /dev/null +++ b/chromium/content/common/origin_trials/trial_token.h @@ -0,0 +1,90 @@ +// Copyright 2015 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 CONTENT_COMMON_ORIGIN_TRIALS_TRIAL_TOKEN_H_ +#define CONTENT_COMMON_ORIGIN_TRIALS_TRIAL_TOKEN_H_ + +#include <memory> +#include <string> + +#include "base/strings/string_piece.h" +#include "base/time/time.h" +#include "content/common/content_export.h" +#include "url/origin.h" + +namespace content { + +// The Experimental Framework (EF) provides limited access to experimental +// features, on a per-origin basis (origin trials). This class defines the trial +// token data structure, used to securely provide access to an experimental +// feature. +// +// Features are defined by string names, provided by the implementers. The EF +// code does not maintain an enum or constant list for feature names. Instead, +// the EF validates the name provided by the feature implementation against any +// provided tokens. +// +// More documentation on the token format can be found at +// https://docs.google.com/document/d/1v5fi0EUV_QHckVHVF2K4P72iNywnrJtNhNZ6i2NPt0M + +class CONTENT_EXPORT TrialToken { + public: + ~TrialToken(); + + // Returns a token object if the string represents a signed well-formed token, + // or nullptr otherwise. (This does not mean that the token is currently + // valid, or appropriate for a given origin / feature, just that it is + // correctly formatted and signed by the supplied public key, and can be + // parsed.) + static std::unique_ptr<TrialToken> From(const std::string& token_text, + base::StringPiece public_key); + + // Returns true if this token is appropriate for use by the given origin, + // for the given feature name, and has not yet expired. + bool IsValidForFeature(const url::Origin& origin, + base::StringPiece feature_name, + const base::Time& now) const; + + url::Origin origin() { return origin_; } + std::string feature_name() { return feature_name_; } + base::Time expiry_time() { return expiry_time_; } + + protected: + friend class TrialTokenTest; + + // Returns the payload of a signed token, or nullptr if the token is not + // properly signed, or is not well-formed. + static std::unique_ptr<std::string> Extract(const std::string& token_text, + base::StringPiece public_key); + + // Returns a token object if the string represents a well-formed JSON token + // payload, or nullptr otherwise. + static std::unique_ptr<TrialToken> Parse(const std::string& token_json); + + bool ValidateOrigin(const url::Origin& origin) const; + bool ValidateFeatureName(base::StringPiece feature_name) const; + bool ValidateDate(const base::Time& now) const; + + static bool ValidateSignature(base::StringPiece signature_text, + const std::string& data, + base::StringPiece public_key); + + private: + TrialToken(const url::Origin& origin, + const std::string& feature_name, + uint64_t expiry_timestamp); + + // The origin for which this token is valid. Must be a secure origin. + url::Origin origin_; + + // The name of the experimental feature which this token enables. + std::string feature_name_; + + // The time until which this token should be considered valid. + base::Time expiry_time_; +}; + +} // namespace content + +#endif // CONTENT_COMMON_ORIGIN_TRIALS_TRIAL_TOKEN_H_ diff --git a/chromium/content/common/origin_trials/trial_token_unittest.cc b/chromium/content/common/origin_trials/trial_token_unittest.cc new file mode 100644 index 00000000000..ebb5b05a4cf --- /dev/null +++ b/chromium/content/common/origin_trials/trial_token_unittest.cc @@ -0,0 +1,300 @@ +// Copyright 2015 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 "content/common/origin_trials/trial_token.h" + +#include <memory> + +#include "base/macros.h" +#include "base/strings/string_piece.h" +#include "base/strings/string_util.h" +#include "base/test/simple_test_clock.h" +#include "base/time/time.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace content { + +namespace { + +// This is a sample public key for testing the API. The corresponding private +// key (use this to generate new samples for this test file) is: +// +// 0x83, 0x67, 0xf4, 0xcd, 0x2a, 0x1f, 0x0e, 0x04, 0x0d, 0x43, 0x13, +// 0x4c, 0x67, 0xc4, 0xf4, 0x28, 0xc9, 0x90, 0x15, 0x02, 0xe2, 0xba, +// 0xfd, 0xbb, 0xfa, 0xbc, 0x92, 0x76, 0x8a, 0x2c, 0x4b, 0xc7, 0x75, +// 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, 0x9a, +// 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, 0x64, +// 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0 +const uint8_t kTestPublicKey[] = { + 0x75, 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, + 0x9a, 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, + 0x64, 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0, +}; + +// This is a valid, but incorrect, public key for testing signatures against. +// The corresponding private key is: +// +// 0x21, 0xee, 0xfa, 0x81, 0x6a, 0xff, 0xdf, 0xb8, 0xc1, 0xdd, 0x75, +// 0x05, 0x04, 0x29, 0x68, 0x67, 0x60, 0x85, 0x91, 0xd0, 0x50, 0x16, +// 0x0a, 0xcf, 0xa2, 0x37, 0xa3, 0x2e, 0x11, 0x7a, 0x17, 0x96, 0x50, +// 0x07, 0x4d, 0x76, 0x55, 0x56, 0x42, 0x17, 0x2d, 0x8a, 0x9c, 0x47, +// 0x96, 0x25, 0xda, 0x70, 0xaa, 0xb9, 0xfd, 0x53, 0x5d, 0x51, 0x3e, +// 0x16, 0xab, 0xb4, 0x86, 0xea, 0xf3, 0x35, 0xc6, 0xca +const uint8_t kTestPublicKey2[] = { + 0x50, 0x07, 0x4d, 0x76, 0x55, 0x56, 0x42, 0x17, 0x2d, 0x8a, 0x9c, + 0x47, 0x96, 0x25, 0xda, 0x70, 0xaa, 0xb9, 0xfd, 0x53, 0x5d, 0x51, + 0x3e, 0x16, 0xab, 0xb4, 0x86, 0xea, 0xf3, 0x35, 0xc6, 0xca, +}; + +// This is a good trial token, signed with the above test private key. +// Generate this token with the command (in tools/origin_trials): +// generate_token.py valid.example.com Frobulate --expire-timestamp=1458766277 +const char* kSampleToken = + "Ap+Q/Qm0ELadZql+dlEGSwnAVsFZKgCEtUZg8idQC3uekkIeSZIY1tftoYdrwhqj" + "7FO5L22sNvkZZnacLvmfNwsAAABZeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l" + "eGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5" + "IjogMTQ1ODc2NjI3N30="; + +const char* kExpectedFeatureName = "Frobulate"; +const char* kExpectedOrigin = "https://valid.example.com"; +const uint64_t kExpectedExpiry = 1458766277; + +// The token should not be valid for this origin, or for this feature. +const char* kInvalidOrigin = "https://invalid.example.com"; +const char* kInsecureOrigin = "http://valid.example.com"; +const char* kInvalidFeatureName = "Grokalyze"; + +// The token should be valid if the current time is kValidTimestamp or earlier. +double kValidTimestamp = 1458766276.0; + +// The token should be invalid if the current time is kInvalidTimestamp or +// later. +double kInvalidTimestamp = 1458766278.0; + +// Well-formed trial token with an invalid signature. +const char* kInvalidSignatureToken = + "AYeNXSDktgG9p4ns5B1WKsLq2TytMxfR4whfbi+oyT0rXyzh+qXYfxbDMGmyjU2Z" + "lEJ16vQObMXJoOaYUqd8xwkAAABZeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l" + "eGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5" + "IjogMTQ1ODc2NjI3N30="; + +// Trial token truncated in the middle of the length field; too short to +// possibly be valid. +const char kTruncatedToken[] = + "Ap+Q/Qm0ELadZql+dlEGSwnAVsFZKgCEtUZg8idQC3uekkIeSZIY1tftoYdrwhqj" + "7FO5L22sNvkZZnacLvmfNwsA"; + +// Trial token with an incorrectly-declared length, but with a valid signature. +const char kIncorrectLengthToken[] = + "Ao06eNl/CZuM88qurWKX4RfoVEpHcVHWxdOTrEXZkaC1GUHyb/8L4sthADiVWdc9" + "kXFyF1BW5bbraqp6MBVr3wEAAABaeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l" + "eGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5" + "IjogMTQ1ODc2NjI3N30="; + +// Trial token with a misidentified version (42). +const char kIncorrectVersionToken[] = + "KlH8wVLT5o59uDvlJESorMDjzgWnvG1hmIn/GiT9Ng3f45ratVeiXCNTeaJheOaG" + "A6kX4ir4Amv8aHVC+OJHZQkAAABZeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l" + "eGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5" + "IjogMTQ1ODc2NjI3N30="; + +const char kSampleTokenJSON[] = + "{\"origin\": \"https://valid.example.com:443\", \"feature\": " + "\"Frobulate\", \"expiry\": 1458766277}"; + +// Various ill-formed trial tokens. These should all fail to parse. +const char* kInvalidTokens[] = { + // Invalid - Not JSON at all + "abcde", + // Invalid JSON + "{", + // Not an object + "\"abcde\"", + "123.4", + "[0, 1, 2]", + // Missing keys + "{}", + "{\"something\": 1}", + "{\"origin\": \"https://a.a\"}", + "{\"origin\": \"https://a.a\", \"feature\": \"a\"}" + "{\"origin\": \"https://a.a\", \"expiry\": 1458766277}", + "{\"feature\": \"FeatureName\", \"expiry\": 1458766277}", + // Incorrect types + "{\"origin\": 1, \"feature\": \"a\", \"expiry\": 1458766277}", + "{\"origin\": \"https://a.a\", \"feature\": 1, \"expiry\": 1458766277}", + "{\"origin\": \"https://a.a\", \"feature\": \"a\", \"expiry\": \"1\"}", + // Negative expiry timestamp + "{\"origin\": \"https://a.a\", \"feature\": \"a\", \"expiry\": -1}", + // Origin not a proper origin URL + "{\"origin\": \"abcdef\", \"feature\": \"a\", \"expiry\": 1458766277}", + "{\"origin\": \"data:text/plain,abcdef\", \"feature\": \"a\", \"expiry\": " + "1458766277}", + "{\"origin\": \"javascript:alert(1)\", \"feature\": \"a\", \"expiry\": " + "1458766277}"}; + +} // namespace + +class TrialTokenTest : public testing::TestWithParam<const char*> { + public: + TrialTokenTest() + : expected_origin_(GURL(kExpectedOrigin)), + invalid_origin_(GURL(kInvalidOrigin)), + insecure_origin_(GURL(kInsecureOrigin)), + expected_expiry_(base::Time::FromDoubleT(kExpectedExpiry)), + valid_timestamp_(base::Time::FromDoubleT(kValidTimestamp)), + invalid_timestamp_(base::Time::FromDoubleT(kInvalidTimestamp)), + correct_public_key_( + base::StringPiece(reinterpret_cast<const char*>(kTestPublicKey), + arraysize(kTestPublicKey))), + incorrect_public_key_( + base::StringPiece(reinterpret_cast<const char*>(kTestPublicKey2), + arraysize(kTestPublicKey2))) {} + + protected: + std::unique_ptr<std::string> Extract(const std::string& token_text, + base::StringPiece public_key) { + return TrialToken::Extract(token_text, public_key); + } + std::unique_ptr<TrialToken> Parse(const std::string& token_payload) { + return TrialToken::Parse(token_payload); + } + + bool ValidateOrigin(TrialToken* token, const url::Origin origin) { + return token->ValidateOrigin(origin); + } + + bool ValidateFeatureName(TrialToken* token, const char* feature_name) { + return token->ValidateFeatureName(feature_name); + } + + bool ValidateDate(TrialToken* token, const base::Time& now) { + return token->ValidateDate(now); + } + + base::StringPiece correct_public_key() { return correct_public_key_; } + base::StringPiece incorrect_public_key() { return incorrect_public_key_; } + + const url::Origin expected_origin_; + const url::Origin invalid_origin_; + const url::Origin insecure_origin_; + + const base::Time expected_expiry_; + const base::Time valid_timestamp_; + const base::Time invalid_timestamp_; + + private: + base::StringPiece correct_public_key_; + base::StringPiece incorrect_public_key_; +}; + +// Test the extraction of the signed payload from token strings. This includes +// checking the included version identifier, payload length, and cryptographic +// signature. + +// Test verification of signature and extraction of token JSON from signed +// token. +TEST_F(TrialTokenTest, ValidateValidSignature) { + std::unique_ptr<std::string> token_payload = + Extract(kSampleToken, correct_public_key()); + ASSERT_TRUE(token_payload); + EXPECT_STREQ(kSampleTokenJSON, token_payload.get()->c_str()); +} + +TEST_F(TrialTokenTest, ValidateInvalidSignature) { + std::unique_ptr<std::string> token_payload = + Extract(kInvalidSignatureToken, correct_public_key()); + ASSERT_FALSE(token_payload); +} + +TEST_F(TrialTokenTest, ValidateSignatureWithIncorrectKey) { + std::unique_ptr<std::string> token_payload = + Extract(kSampleToken, incorrect_public_key()); + ASSERT_FALSE(token_payload); +} + +TEST_F(TrialTokenTest, ValidateEmptyToken) { + std::unique_ptr<std::string> token_payload = + Extract("", correct_public_key()); + ASSERT_FALSE(token_payload); +} + +TEST_F(TrialTokenTest, ValidateShortToken) { + std::unique_ptr<std::string> token_payload = + Extract(kTruncatedToken, correct_public_key()); + ASSERT_FALSE(token_payload); +} + +TEST_F(TrialTokenTest, ValidateUnsupportedVersion) { + std::unique_ptr<std::string> token_payload = + Extract(kIncorrectVersionToken, correct_public_key()); + ASSERT_FALSE(token_payload); +} + +TEST_F(TrialTokenTest, ValidateSignatureWithIncorrectLength) { + std::unique_ptr<std::string> token_payload = + Extract(kIncorrectLengthToken, correct_public_key()); + ASSERT_FALSE(token_payload); +} + +// Test parsing of fields from JSON token. + +TEST_F(TrialTokenTest, ParseEmptyString) { + std::unique_ptr<TrialToken> empty_token = Parse(""); + EXPECT_FALSE(empty_token); +} + +TEST_P(TrialTokenTest, ParseInvalidString) { + std::unique_ptr<TrialToken> empty_token = Parse(GetParam()); + EXPECT_FALSE(empty_token) << "Invalid trial token should not parse."; +} + +INSTANTIATE_TEST_CASE_P(, TrialTokenTest, ::testing::ValuesIn(kInvalidTokens)); + +TEST_F(TrialTokenTest, ParseValidToken) { + std::unique_ptr<TrialToken> token = Parse(kSampleTokenJSON); + ASSERT_TRUE(token); + EXPECT_EQ(kExpectedFeatureName, token->feature_name()); + EXPECT_EQ(expected_origin_, token->origin()); + EXPECT_EQ(expected_expiry_, token->expiry_time()); +} + +TEST_F(TrialTokenTest, ValidateValidToken) { + std::unique_ptr<TrialToken> token = Parse(kSampleTokenJSON); + ASSERT_TRUE(token); + EXPECT_TRUE(ValidateOrigin(token.get(), expected_origin_)); + EXPECT_FALSE(ValidateOrigin(token.get(), invalid_origin_)); + EXPECT_FALSE(ValidateOrigin(token.get(), insecure_origin_)); + EXPECT_TRUE(ValidateFeatureName(token.get(), kExpectedFeatureName)); + EXPECT_FALSE(ValidateFeatureName(token.get(), kInvalidFeatureName)); + EXPECT_FALSE(ValidateFeatureName( + token.get(), base::ToUpperASCII(kExpectedFeatureName).c_str())); + EXPECT_FALSE(ValidateFeatureName( + token.get(), base::ToLowerASCII(kExpectedFeatureName).c_str())); + EXPECT_TRUE(ValidateDate(token.get(), valid_timestamp_)); + EXPECT_FALSE(ValidateDate(token.get(), invalid_timestamp_)); +} + +TEST_F(TrialTokenTest, TokenIsValidForFeature) { + std::unique_ptr<TrialToken> token = Parse(kSampleTokenJSON); + ASSERT_TRUE(token); + EXPECT_TRUE(token->IsValidForFeature(expected_origin_, kExpectedFeatureName, + valid_timestamp_)); + EXPECT_FALSE(token->IsValidForFeature( + expected_origin_, base::ToUpperASCII(kExpectedFeatureName), + valid_timestamp_)); + EXPECT_FALSE(token->IsValidForFeature( + expected_origin_, base::ToLowerASCII(kExpectedFeatureName), + valid_timestamp_)); + EXPECT_FALSE(token->IsValidForFeature(invalid_origin_, kExpectedFeatureName, + valid_timestamp_)); + EXPECT_FALSE(token->IsValidForFeature(insecure_origin_, kExpectedFeatureName, + valid_timestamp_)); + EXPECT_FALSE(token->IsValidForFeature(expected_origin_, kInvalidFeatureName, + valid_timestamp_)); + EXPECT_FALSE(token->IsValidForFeature(expected_origin_, kExpectedFeatureName, + invalid_timestamp_)); +} + +} // namespace content diff --git a/chromium/content/common/origin_trials/trial_token_validator.cc b/chromium/content/common/origin_trials/trial_token_validator.cc new file mode 100644 index 00000000000..6eef75a5e9a --- /dev/null +++ b/chromium/content/common/origin_trials/trial_token_validator.cc @@ -0,0 +1,30 @@ +// Copyright 2016 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 "content/common/origin_trials/trial_token_validator.h" + +#include "base/time/time.h" +#include "content/common/origin_trials/trial_token.h" +#include "content/public/common/content_client.h" + +namespace content { + +bool TrialTokenValidator::ValidateToken(const std::string& token, + const url::Origin& origin, + base::StringPiece feature_name) { + // TODO(iclelland): Allow for multiple signing keys, and iterate over all + // active keys here. https://crbug.com/543220 + ContentClient* content_client = GetContentClient(); + base::StringPiece public_key = content_client->GetOriginTrialPublicKey(); + if (public_key.empty()) { + return false; + } + std::unique_ptr<TrialToken> trial_token = TrialToken::From(token, public_key); + + return trial_token && + trial_token->IsValidForFeature(origin, feature_name, + base::Time::Now()); +} + +} // namespace content diff --git a/chromium/content/common/origin_trials/trial_token_validator.h b/chromium/content/common/origin_trials/trial_token_validator.h new file mode 100644 index 00000000000..a8406350d71 --- /dev/null +++ b/chromium/content/common/origin_trials/trial_token_validator.h @@ -0,0 +1,26 @@ +// Copyright 2016 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 CONTENT_COMMON_ORIGIN_TRIALS_TRIAL_TOKEN_VALIDATOR_H_ +#define CONTENT_COMMON_ORIGIN_TRIALS_TRIAL_TOKEN_VALIDATOR_H_ + +#include <string> +#include "base/strings/string_piece.h" +#include "content/common/content_export.h" +#include "url/origin.h" + +namespace content { + +namespace TrialTokenValidator { + +// This method is thread-safe. +CONTENT_EXPORT bool ValidateToken(const std::string& token, + const url::Origin& origin, + base::StringPiece feature_name); + +} // namespace TrialTokenValidator + +} // namespace content + +#endif // CONTENT_COMMON_ORIGIN_TRIALS_TRIAL_TOKEN_VALIDATOR_H_ diff --git a/chromium/content/common/origin_trials/trial_token_validator_unittest.cc b/chromium/content/common/origin_trials/trial_token_validator_unittest.cc new file mode 100644 index 00000000000..59011e785f2 --- /dev/null +++ b/chromium/content/common/origin_trials/trial_token_validator_unittest.cc @@ -0,0 +1,160 @@ +// Copyright 2016 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 "content/common/origin_trials/trial_token_validator.h" + +#include <memory> + +#include "base/macros.h" +#include "base/strings/string_util.h" +#include "base/test/simple_test_clock.h" +#include "base/time/time.h" +#include "content/public/common/content_client.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace content { + +namespace { + +// This is a sample public key for testing the API. The corresponding private +// key (use this to generate new samples for this test file) is: +// +// 0x83, 0x67, 0xf4, 0xcd, 0x2a, 0x1f, 0x0e, 0x04, 0x0d, 0x43, 0x13, +// 0x4c, 0x67, 0xc4, 0xf4, 0x28, 0xc9, 0x90, 0x15, 0x02, 0xe2, 0xba, +// 0xfd, 0xbb, 0xfa, 0xbc, 0x92, 0x76, 0x8a, 0x2c, 0x4b, 0xc7, 0x75, +// 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, 0x9a, +// 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, 0x64, +// 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0 +const uint8_t kTestPublicKey[] = { + 0x75, 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, + 0x9a, 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, + 0x64, 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0, +}; + +// 0x21, 0xee, 0xfa, 0x81, 0x6a, 0xff, 0xdf, 0xb8, 0xc1, 0xdd, 0x75, +// 0x05, 0x04, 0x29, 0x68, 0x67, 0x60, 0x85, 0x91, 0xd0, 0x50, 0x16, +// 0x0a, 0xcf, 0xa2, 0x37, 0xa3, 0x2e, 0x11, 0x7a, 0x17, 0x96, 0x50, +// 0x07, 0x4d, 0x76, 0x55, 0x56, 0x42, 0x17, 0x2d, 0x8a, 0x9c, 0x47, +// 0x96, 0x25, 0xda, 0x70, 0xaa, 0xb9, 0xfd, 0x53, 0x5d, 0x51, 0x3e, +// 0x16, 0xab, 0xb4, 0x86, 0xea, 0xf3, 0x35, 0xc6, 0xca +const uint8_t kTestPublicKey2[] = { + 0x50, 0x07, 0x4d, 0x76, 0x55, 0x56, 0x42, 0x17, 0x2d, 0x8a, 0x9c, + 0x47, 0x96, 0x25, 0xda, 0x70, 0xaa, 0xb9, 0xfd, 0x53, 0x5d, 0x51, + 0x3e, 0x16, 0xab, 0xb4, 0x86, 0xea, 0xf3, 0x35, 0xc6, 0xca, +}; + +// This is a good trial token, signed with the above test private key. +// TODO(iclelland): This token expires in 2033. Update it or find a way +// to autogenerate it before then. +// Generate this token with the command (in tools/origin_trials): +// generate_token.py valid.example.com Frobulate --expire-timestamp=2000000000 +const char kSampleToken[] = + "AuR/1mg+/w5ROLN54Ok20rApK3opgR7Tq9ZfzhATQmnCa+BtPA1RRw4Nigf336r+" + "O4fM3Sa+MEd+5JcIgSZafw8AAABZeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l" + "eGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5" + "IjogMjAwMDAwMDAwMH0="; + +// The token should be valid for this origin and for this feature. +const char kAppropriateOrigin[] = "https://valid.example.com"; +const char kAppropriateFeatureName[] = "Frobulate"; + +const char kInappropriateFeatureName[] = "Grokalyze"; +const char kInappropriateOrigin[] = "https://invalid.example.com"; +const char kInsecureOrigin[] = "http://valid.example.com"; + +// Well-formed trial token with an invalid signature. +// This token is a corruption of the above valid token. +const char kInvalidSignatureToken[] = + "AuR/1mg+/w5ROLN54Ok20rApK3opgR7Tq9ZfzhATQmnCa+BtPA1RRw4Nigf336r+" + "RrOtlAwa0gPqqn+A8GTD3AQAAABZeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l" + "eGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5" + "IjogMjAwMDAwMDAwMH0="; + +// Well-formed, but expired, trial token. (Expired in 2001) +// Generate this token with the command (in tools/origin_trials): +// generate_token.py valid.example.com Frobulate --expire-timestamp=1000000000 +const char kExpiredToken[] = + "AmHPUIXMaXe9jWW8kJeDFXolVjT93p4XMnK4+jMYd2pjqtFcYB1bUmdD8PunQKM+" + "RrOtlAwa0gPqqn+A8GTD3AQAAABZeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l" + "eGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5" + "IjogMTAwMDAwMDAwMH0="; + +const char kUnparsableToken[] = "abcde"; + +class TestContentClient : public ContentClient { + public: + base::StringPiece GetOriginTrialPublicKey() override { + return base::StringPiece(reinterpret_cast<const char*>(key_), + arraysize(kTestPublicKey)); + } + void SetOriginTrialPublicKey(const uint8_t* key) { key_ = key; } + const uint8_t* key_ = nullptr; +}; + +} // namespace + +class TrialTokenValidatorTest : public testing::Test { + public: + TrialTokenValidatorTest() + : appropriate_origin_(GURL(kAppropriateOrigin)), + inappropriate_origin_(GURL(kInappropriateOrigin)), + insecure_origin_(GURL(kInsecureOrigin)) { + SetPublicKey(kTestPublicKey); + SetContentClient(&test_content_client_); + } + + ~TrialTokenValidatorTest() override { SetContentClient(nullptr); } + + void SetPublicKey(const uint8_t* key) { + test_content_client_.SetOriginTrialPublicKey(key); + } + + const url::Origin appropriate_origin_; + const url::Origin inappropriate_origin_; + const url::Origin insecure_origin_; + + private: + TestContentClient test_content_client_; +}; + +TEST_F(TrialTokenValidatorTest, ValidateValidToken) { + EXPECT_TRUE(TrialTokenValidator::ValidateToken( + kSampleToken, appropriate_origin_, kAppropriateFeatureName)); +} + +TEST_F(TrialTokenValidatorTest, ValidateInappropriateOrigin) { + EXPECT_FALSE(TrialTokenValidator::ValidateToken( + kSampleToken, inappropriate_origin_, kAppropriateFeatureName)); + EXPECT_FALSE(TrialTokenValidator::ValidateToken( + kSampleToken, insecure_origin_, kAppropriateFeatureName)); +} + +TEST_F(TrialTokenValidatorTest, ValidateInappropriateFeature) { + EXPECT_FALSE(TrialTokenValidator::ValidateToken( + kSampleToken, appropriate_origin_, kInappropriateFeatureName)); +} + +TEST_F(TrialTokenValidatorTest, ValidateInvalidSignature) { + EXPECT_FALSE(TrialTokenValidator::ValidateToken( + kInvalidSignatureToken, appropriate_origin_, kAppropriateFeatureName)); +} + +TEST_F(TrialTokenValidatorTest, ValidateUnparsableToken) { + EXPECT_FALSE(TrialTokenValidator::ValidateToken( + kUnparsableToken, appropriate_origin_, kAppropriateFeatureName)); +} + +TEST_F(TrialTokenValidatorTest, ValidateExpiredToken) { + EXPECT_FALSE(TrialTokenValidator::ValidateToken( + kExpiredToken, appropriate_origin_, kAppropriateFeatureName)); +} + +TEST_F(TrialTokenValidatorTest, ValidateValidTokenWithIncorrectKey) { + SetPublicKey(kTestPublicKey2); + EXPECT_FALSE(TrialTokenValidator::ValidateToken( + kSampleToken, appropriate_origin_, kAppropriateFeatureName)); +} + +} // namespace content diff --git a/chromium/content/common/origin_util.cc b/chromium/content/common/origin_util.cc index 9c6b6310f22..4dfdc6ce8ca 100644 --- a/chromium/content/common/origin_util.cc +++ b/chromium/content/common/origin_util.cc @@ -8,7 +8,7 @@ #include "base/macros.h" #include "base/stl_util.h" #include "content/public/common/content_client.h" -#include "net/base/net_util.h" +#include "net/base/url_util.h" #include "url/gurl.h" namespace content { diff --git a/chromium/content/common/p2p_messages.h b/chromium/content/common/p2p_messages.h index 24daee51f07..9725b257cff 100644 --- a/chromium/content/common/p2p_messages.h +++ b/chromium/content/common/p2p_messages.h @@ -11,6 +11,7 @@ #include "content/common/content_export.h" #include "content/common/p2p_socket_type.h" #include "ipc/ipc_message_macros.h" +#include "net/base/ip_address.h" #include "net/base/network_interfaces.h" #include "third_party/webrtc/base/asyncpacketsocket.h" @@ -62,8 +63,8 @@ IPC_STRUCT_TRAITS_END() IPC_MESSAGE_CONTROL3(P2PMsg_NetworkListChanged, net::NetworkInterfaceList /* networks */, - net::IPAddressNumber /* default_ipv4_local_address */, - net::IPAddressNumber /* default_ipv6_local_address */) + net::IPAddress /* default_ipv4_local_address */, + net::IPAddress /* default_ipv6_local_address */) IPC_MESSAGE_CONTROL2(P2PMsg_GetHostAddressResult, int32_t /* request_id */, diff --git a/chromium/content/common/page_messages.h b/chromium/content/common/page_messages.h new file mode 100644 index 00000000000..284c134508b --- /dev/null +++ b/chromium/content/common/page_messages.h @@ -0,0 +1,25 @@ +// Copyright 2016 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 "ipc/ipc_message_macros.h" + +// IPC messages for page-level actions. +// Multiply-included message file, hence no include guard. + +#undef IPC_MESSAGE_EXPORT +#define IPC_MESSAGE_EXPORT CONTENT_EXPORT + +#define IPC_MESSAGE_START PageMsgStart + +// Messages sent from the browser to the renderer. + +IPC_MESSAGE_ROUTED1(PageMsg_UpdateWindowScreenRect, + gfx::Rect /* window_screen_rect */) + +// ----------------------------------------------------------------------------- +// Messages sent from the renderer to the browser. + +// Adding a new message? Stick to the sort order above: first platform +// independent PageMsg, then ifdefs for platform specific PageMsg, then platform +// independent PageHostMsg, then ifdefs for platform specific PageHostMsg. diff --git a/chromium/content/common/page_state_serialization.cc b/chromium/content/common/page_state_serialization.cc index 53ddf098d16..b9670c2f244 100644 --- a/chromium/content/common/page_state_serialization.cc +++ b/chromium/content/common/page_state_serialization.cc @@ -606,8 +606,7 @@ void ReadFrameState(SerializeObject* obj, bool is_top, float device_scale_factor = g_device_scale_factor_for_testing; if (!device_scale_factor) { device_scale_factor = - gfx::Screen::GetNativeScreen()->GetPrimaryDisplay(). - device_scale_factor(); + gfx::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor(); } state->scroll_offset = gfx::Point(state->scroll_offset.x() / state->page_scale_factor, @@ -672,6 +671,9 @@ ExplodedHttpBodyElement::ExplodedHttpBodyElement() file_modification_time(std::numeric_limits<double>::quiet_NaN()) { } +ExplodedHttpBodyElement::ExplodedHttpBodyElement( + const ExplodedHttpBodyElement& other) = default; + ExplodedHttpBodyElement::~ExplodedHttpBodyElement() { } diff --git a/chromium/content/common/page_state_serialization.h b/chromium/content/common/page_state_serialization.h index 9b6773c2303..24d81981ef8 100644 --- a/chromium/content/common/page_state_serialization.h +++ b/chromium/content/common/page_state_serialization.h @@ -32,6 +32,7 @@ struct CONTENT_EXPORT ExplodedHttpBodyElement { std::string blob_uuid; ExplodedHttpBodyElement(); + ExplodedHttpBodyElement(const ExplodedHttpBodyElement& other); ~ExplodedHttpBodyElement(); }; diff --git a/chromium/content/common/pepper_plugin_list.cc b/chromium/content/common/pepper_plugin_list.cc index ea24ff7eb97..610670e20b2 100644 --- a/chromium/content/common/pepper_plugin_list.cc +++ b/chromium/content/common/pepper_plugin_list.cc @@ -54,7 +54,8 @@ void ComputePluginsFromCommandLine(std::vector<PepperPluginInfo>* plugins) { // plugin-entry = // <file-path> + // ["#" + <name> + ["#" + <description> + ["#" + <version>]]] + - // *1( LWS + ";" + LWS + <mime-type> ) + // *1( LWS + ";" + LWS + <mime-type-data> ) + // mime-type-data = <mime-type> + [ LWS + "#" + LWS + <extension> ] std::vector<std::string> modules = base::SplitString( value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); @@ -105,8 +106,14 @@ void ComputePluginsFromCommandLine(std::vector<PepperPluginInfo>* plugins) { if (name_parts.size() > 3) plugin.version = name_parts[3]; for (size_t j = 1; j < parts.size(); ++j) { - WebPluginMimeType mime_type(parts[j], - std::string(), + std::vector<std::string> mime_parts = base::SplitString( + parts[j], "#", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + DCHECK_GE(mime_parts.size(), 1u); + std::string mime_extension; + if (mime_parts.size() > 1) + mime_extension = mime_parts[1]; + WebPluginMimeType mime_type(mime_parts[0], + mime_extension, plugin.description); plugin.mime_types.push_back(mime_type); } diff --git a/chromium/content/common/permission_service.mojom b/chromium/content/common/permission_service.mojom deleted file mode 100644 index 5a6178793c5..00000000000 --- a/chromium/content/common/permission_service.mojom +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2014 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. - -module content; - -import "content/public/common/permission_status.mojom"; - -enum PermissionName { - GEOLOCATION, - NOTIFICATIONS, - PUSH_NOTIFICATIONS, - MIDI, - MIDI_SYSEX, - PROTECTED_MEDIA_IDENTIFIER, - DURABLE_STORAGE, - AUDIO_CAPTURE, - VIDEO_CAPTURE, -}; - -// The Permission service provides permission handling capabilities by exposing -// methods to check, request, and revoke permissions. It also allows a client to -// start listening to permission changes. -interface PermissionService { - HasPermission(PermissionName permission, string origin) - => (PermissionStatus status); - RequestPermission(PermissionName permission, string origin, bool user_gesture) - => (PermissionStatus status); - RequestPermissions(array<PermissionName> permission, string origin, bool user_gesture) - => (array<PermissionStatus> statuses); - RevokePermission(PermissionName permission, string origin) - => (PermissionStatus status); - - // Runs the callback next time there is a permission status change for the - // given { permission, origin }. Callers of this method will have to call it - // again if they want to keep listening to the changes. To prevent race - // conditions, the caller must pass the last known value. - GetNextPermissionChange(PermissionName permission, - string origin, - PermissionStatus last_known_status) - => (PermissionStatus status); -}; diff --git a/chromium/content/common/platform_notification_messages.h b/chromium/content/common/platform_notification_messages.h index 8b8d7dad421..5e5d8bb65f7 100644 --- a/chromium/content/common/platform_notification_messages.h +++ b/chromium/content/common/platform_notification_messages.h @@ -10,6 +10,7 @@ #include <utility> #include <vector> +#include "content/public/common/notification_resources.h" #include "content/public/common/platform_notification_data.h" #include "ipc/ipc_message_macros.h" #include "third_party/WebKit/public/platform/modules/notifications/WebNotificationPermission.h" @@ -35,9 +36,15 @@ IPC_ENUM_TRAITS_MAX_VALUE( content::PlatformNotificationData::Direction, content::PlatformNotificationData::DIRECTION_LAST) +IPC_ENUM_TRAITS_MAX_VALUE(content::PlatformNotificationActionType, + content::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT) + IPC_STRUCT_TRAITS_BEGIN(content::PlatformNotificationAction) + IPC_STRUCT_TRAITS_MEMBER(type) IPC_STRUCT_TRAITS_MEMBER(action) IPC_STRUCT_TRAITS_MEMBER(title) + IPC_STRUCT_TRAITS_MEMBER(icon) + IPC_STRUCT_TRAITS_MEMBER(placeholder) IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_BEGIN(content::PlatformNotificationData) @@ -47,13 +54,22 @@ IPC_STRUCT_TRAITS_BEGIN(content::PlatformNotificationData) IPC_STRUCT_TRAITS_MEMBER(body) IPC_STRUCT_TRAITS_MEMBER(tag) IPC_STRUCT_TRAITS_MEMBER(icon) + IPC_STRUCT_TRAITS_MEMBER(badge) IPC_STRUCT_TRAITS_MEMBER(vibration_pattern) + IPC_STRUCT_TRAITS_MEMBER(timestamp) + IPC_STRUCT_TRAITS_MEMBER(renotify) IPC_STRUCT_TRAITS_MEMBER(silent) IPC_STRUCT_TRAITS_MEMBER(require_interaction) IPC_STRUCT_TRAITS_MEMBER(data) IPC_STRUCT_TRAITS_MEMBER(actions) IPC_STRUCT_TRAITS_END() +IPC_STRUCT_TRAITS_BEGIN(content::NotificationResources) + IPC_STRUCT_TRAITS_MEMBER(notification_icon) + IPC_STRUCT_TRAITS_MEMBER(badge) + IPC_STRUCT_TRAITS_MEMBER(action_icons) +IPC_STRUCT_TRAITS_END() + // Messages sent from the browser to the renderer. // Informs the renderer that the browser has displayed the notification. @@ -84,18 +100,20 @@ IPC_MESSAGE_CONTROL2(PlatformNotificationMsg_DidGetNotifications, // Messages sent from the renderer to the browser. -IPC_MESSAGE_CONTROL4(PlatformNotificationHostMsg_Show, - int /* notification_id */, - GURL /* origin */, - SkBitmap /* icon */, - content::PlatformNotificationData /* notification_data */) - -IPC_MESSAGE_CONTROL5(PlatformNotificationHostMsg_ShowPersistent, - int /* request_id */, - int64_t /* service_worker_registration_id */, - GURL /* origin */, - SkBitmap /* icon */, - content::PlatformNotificationData /* notification_data */) +IPC_MESSAGE_CONTROL4( + PlatformNotificationHostMsg_Show, + int /* notification_id */, + GURL /* origin */, + content::PlatformNotificationData /* notification_data */, + content::NotificationResources /* notification_resources */) + +IPC_MESSAGE_CONTROL5( + PlatformNotificationHostMsg_ShowPersistent, + int /* request_id */, + int64_t /* service_worker_registration_id */, + GURL /* origin */, + content::PlatformNotificationData /* notification_data */, + content::NotificationResources /* notification_resources */) IPC_MESSAGE_CONTROL4(PlatformNotificationHostMsg_GetNotifications, int /* request_id */, diff --git a/chromium/content/common/plugin_constants_win.cc b/chromium/content/common/plugin_constants_win.cc deleted file mode 100644 index 026885677e2..00000000000 --- a/chromium/content/common/plugin_constants_win.cc +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2011 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 "content/common/plugin_constants_win.h" - -namespace content { - -const base::char16 kNativeWindowClassName[] = L"NativeWindowClass"; -const base::char16 kWrapperNativeWindowClassName[] = - L"WrapperNativeWindowClass"; -const base::char16 kDummyActivationWindowName[] = L"DummyWindowForActivation"; -const base::char16 kPaintMessageName[] = L"Chrome_CustomPaintil"; -const base::char16 kRegistryMozillaPlugins[] = L"SOFTWARE\\MozillaPlugins"; -const base::char16 kMozillaActiveXPlugin[] = L"npmozax.dll"; -const base::char16 kNewWMPPlugin[] = L"np-mswmp.dll"; -const base::char16 kOldWMPPlugin[] = L"npdsplay.dll"; -const base::char16 kYahooApplicationStatePlugin[] = L"npystate.dll"; -const base::char16 kWanWangProtocolHandlerPlugin[] = L"npww.dll"; -const base::char16 kFlashPlugin[] = L"npswf32.dll"; -const base::char16 kAcrobatReaderPlugin[] = L"nppdf32.dll"; -const base::char16 kRealPlayerPlugin[] = L"nppl3260.dll"; -const base::char16 kSilverlightPlugin[] = L"npctrl.dll"; -const base::char16 kJavaPlugin1[] = L"npjp2.dll"; -const base::char16 kJavaPlugin2[] = L"npdeploytk.dll"; -const char kGPUPluginMimeType[] = "application/vnd.google.chrome.gpu-plugin"; -const base::char16 kPluginDummyParentProperty[] = L"NPAPIPluginDummyParent"; - -} // namespace content diff --git a/chromium/content/common/plugin_constants_win.h b/chromium/content/common/plugin_constants_win.h deleted file mode 100644 index 2269592d5ae..00000000000 --- a/chromium/content/common/plugin_constants_win.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2011 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 CONTENT_COMMON_PLUGIN_CONSTANTS_WIN_H_ -#define CONTENT_COMMON_PLUGIN_CONSTANTS_WIN_H_ - -#include "base/strings/string16.h" -#include "build/build_config.h" - -#if !defined(OS_WIN) -#error "Windows-only header" -#endif - -namespace content { - -// The window class name for a plugin window. -extern const base::char16 kNativeWindowClassName[]; - -// The name of the window class name for the wrapper HWND around the actual -// plugin window that's used when running in multi-process mode. This window -// is created on the browser UI thread. -extern const base::char16 kWrapperNativeWindowClassName[]; - -extern const base::char16 kDummyActivationWindowName[]; - -// The name of the custom window message that the browser uses to tell the -// plugin process to paint a window. -extern const base::char16 kPaintMessageName[]; - -// The name of the registry key which NPAPI plugins update on installation. -extern const base::char16 kRegistryMozillaPlugins[]; - -extern const base::char16 kMozillaActiveXPlugin[]; -extern const base::char16 kNewWMPPlugin[]; -extern const base::char16 kOldWMPPlugin[]; -extern const base::char16 kYahooApplicationStatePlugin[]; -extern const base::char16 kWanWangProtocolHandlerPlugin[]; -extern const base::char16 kFlashPlugin[]; -extern const base::char16 kAcrobatReaderPlugin[]; -extern const base::char16 kRealPlayerPlugin[]; -extern const base::char16 kSilverlightPlugin[]; -extern const base::char16 kJavaPlugin1[]; -extern const base::char16 kJavaPlugin2[]; - -extern const char kGPUPluginMimeType[]; - -extern const base::char16 kPluginDummyParentProperty[]; - -} // namespace content - -#endif // CONTENT_COMMON_PLUGIN_CONSTANTS_WIN_H_ diff --git a/chromium/content/common/plugin_list.cc b/chromium/content/common/plugin_list.cc index 80438818181..eff0f66b269 100644 --- a/chromium/content/common/plugin_list.cc +++ b/chromium/content/common/plugin_list.cc @@ -20,10 +20,6 @@ #include "net/base/mime_util.h" #include "url/gurl.h" -#if defined(OS_WIN) -#include "content/common/plugin_constants_win.h" -#endif - namespace content { namespace { @@ -37,42 +33,11 @@ PluginList* PluginList::Singleton() { return g_singleton.Pointer(); } -// static -bool PluginList::DebugPluginLoading() { - return base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDebugPluginLoading); -} - -void PluginList::DisablePluginsDiscovery() { - plugins_discovery_disabled_ = true; -} - void PluginList::RefreshPlugins() { base::AutoLock lock(lock_); loading_state_ = LOADING_STATE_NEEDS_REFRESH; } -void PluginList::AddExtraPluginPath(const base::FilePath& plugin_path) { - // Chrome OS only loads plugins from /opt/google/chrome/plugins. -#if !defined(OS_CHROMEOS) - base::AutoLock lock(lock_); - extra_plugin_paths_.push_back(plugin_path); -#endif -} - -void PluginList::RemoveExtraPluginPath(const base::FilePath& plugin_path) { - base::AutoLock lock(lock_); - RemoveExtraPluginPathLocked(plugin_path); -} - -void PluginList::AddExtraPluginDir(const base::FilePath& plugin_dir) { - // Chrome OS only loads plugins from /opt/google/chrome/plugins. -#if !defined(OS_CHROMEOS) - base::AutoLock lock(lock_); - extra_plugin_dirs_.push_back(plugin_dir); -#endif -} - void PluginList::RegisterInternalPlugin(const WebPluginInfo& info, bool add_at_beginning) { base::AutoLock lock(lock_); @@ -114,70 +79,18 @@ void PluginList::GetInternalPlugins( bool PluginList::ReadPluginInfo(const base::FilePath& filename, WebPluginInfo* info) { - { - base::AutoLock lock(lock_); - for (size_t i = 0; i < internal_plugins_.size(); ++i) { - if (filename == internal_plugins_[i].path) { - *info = internal_plugins_[i]; - return true; - } - } - } - - return PluginList::ReadWebPluginInfo(filename, info); -} - -// static -bool PluginList::ParseMimeTypes( - const std::string& mime_types_str, - const std::string& file_extensions_str, - const base::string16& mime_type_descriptions_str, - std::vector<WebPluginMimeType>* parsed_mime_types) { - std::vector<std::string> mime_types = base::SplitString( - mime_types_str, "|", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - std::vector<std::string> file_extensions = base::SplitString( - file_extensions_str, "|", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - std::vector<base::string16> descriptions = base::SplitString( - mime_type_descriptions_str, base::string16(1, '|'), base::TRIM_WHITESPACE, - base::SPLIT_WANT_ALL); - - parsed_mime_types->clear(); - - if (mime_types.empty()) - return false; - - for (size_t i = 0; i < mime_types.size(); ++i) { - WebPluginMimeType mime_type; - mime_type.mime_type = base::ToLowerASCII(mime_types[i]); - if (file_extensions.size() > i) { - mime_type.file_extensions = base::SplitString( - file_extensions[i], ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - } - - if (descriptions.size() > i) { - mime_type.description = descriptions[i]; - - // On Windows, the description likely has a list of file extensions - // embedded in it (e.g. "SurfWriter file (*.swr)"). Remove an extension - // list from the description if it is present. - size_t ext = mime_type.description.find(base::ASCIIToUTF16("(*")); - if (ext != base::string16::npos) { - if (ext > 1 && mime_type.description[ext - 1] == ' ') - ext--; - - mime_type.description.erase(ext); - } + base::AutoLock lock(lock_); + for (const auto& plugin : internal_plugins_) { + if (filename == plugin.path) { + *info = plugin; + return true; } - - parsed_mime_types->push_back(mime_type); } - - return true; + return false; } PluginList::PluginList() - : loading_state_(LOADING_STATE_NEEDS_REFRESH), - plugins_discovery_disabled_(false) { + : loading_state_(LOADING_STATE_NEEDS_REFRESH) { } bool PluginList::PrepareForPluginLoading() { @@ -189,7 +102,7 @@ bool PluginList::PrepareForPluginLoading() { return true; } -void PluginList::LoadPlugins(bool include_npapi) { +void PluginList::LoadPlugins() { if (!PrepareForPluginLoading()) return; @@ -203,7 +116,7 @@ void PluginList::LoadPlugins(bool include_npapi) { will_load_callback.Run(); std::vector<base::FilePath> plugin_paths; - GetPluginPathsToLoad(&plugin_paths, include_npapi); + GetPluginPathsToLoad(&plugin_paths); for (std::vector<base::FilePath>::const_iterator it = plugin_paths.begin(); it != plugin_paths.end(); @@ -219,41 +132,30 @@ bool PluginList::LoadPluginIntoPluginList( const base::FilePath& path, std::vector<WebPluginInfo>* plugins, WebPluginInfo* plugin_info) { - LOG_IF(ERROR, PluginList::DebugPluginLoading()) - << "Loading plugin " << path.value(); if (!ReadPluginInfo(path, plugin_info)) return false; - if (!ShouldLoadPluginUsingPluginList(*plugin_info, plugins)) - return false; - -#if defined(OS_WIN) && !defined(NDEBUG) - if (path.BaseName().value() != L"npspy.dll") // Make an exception for NPSPY -#endif - { - for (size_t i = 0; i < plugin_info->mime_types.size(); ++i) { - // TODO: don't load global handlers for now. - // WebKit hands to the Plugin before it tries - // to handle mimeTypes on its own. - const std::string &mime_type = plugin_info->mime_types[i].mime_type; - if (mime_type == "*") - return false; - } + // TODO(piman): Do we still need this after NPAPI removal? + for (size_t i = 0; i < plugin_info->mime_types.size(); ++i) { + // TODO: don't load global handlers for now. + // WebKit hands to the Plugin before it tries + // to handle mimeTypes on its own. + const std::string &mime_type = plugin_info->mime_types[i].mime_type; + if (mime_type == "*") + return false; } plugins->push_back(*plugin_info); return true; } -void PluginList::GetPluginPathsToLoad(std::vector<base::FilePath>* plugin_paths, - bool include_npapi) { +void PluginList::GetPluginPathsToLoad( + std::vector<base::FilePath>* plugin_paths) { // Don't want to hold the lock while loading new plugins, so we don't block // other methods if they're called on other threads. std::vector<base::FilePath> extra_plugin_paths; - std::vector<base::FilePath> extra_plugin_dirs; { base::AutoLock lock(lock_); extra_plugin_paths = extra_plugin_paths_; - extra_plugin_dirs = extra_plugin_dirs_; } for (size_t i = 0; i < extra_plugin_paths.size(); ++i) { @@ -264,22 +166,6 @@ void PluginList::GetPluginPathsToLoad(std::vector<base::FilePath>* plugin_paths, } plugin_paths->push_back(path); } - - if (include_npapi) { - // A bit confusingly, this function is used to load Pepper plugins as well. - // Those are all internal plugins so we have to use extra_plugin_paths. - for (size_t i = 0; i < extra_plugin_dirs.size(); ++i) - GetPluginsInDir(extra_plugin_dirs[i], plugin_paths); - - std::vector<base::FilePath> directories_to_scan; - GetPluginDirectories(&directories_to_scan); - for (size_t i = 0; i < directories_to_scan.size(); ++i) - GetPluginsInDir(directories_to_scan[i], plugin_paths); - -#if defined(OS_WIN) - GetPluginPathsFromRegistry(plugin_paths); -#endif - } } void PluginList::SetPlugins(const std::vector<WebPluginInfo>& plugins) { @@ -298,9 +184,8 @@ void PluginList::set_will_load_plugins_callback(const base::Closure& callback) { will_load_plugins_callback_ = callback; } -void PluginList::GetPlugins(std::vector<WebPluginInfo>* plugins, - bool include_npapi) { - LoadPlugins(include_npapi); +void PluginList::GetPlugins(std::vector<WebPluginInfo>* plugins) { + LoadPlugins(); base::AutoLock lock(lock_); plugins->insert(plugins->end(), plugins_list_.begin(), plugins_list_.end()); } @@ -317,14 +202,13 @@ void PluginList::GetPluginInfoArray( const std::string& mime_type, bool allow_wildcard, bool* use_stale, - bool include_npapi, std::vector<WebPluginInfo>* info, std::vector<std::string>* actual_mime_types) { DCHECK(mime_type == base::ToLowerASCII(mime_type)); DCHECK(info); if (!use_stale) - LoadPlugins(include_npapi); + LoadPlugins(); base::AutoLock lock(lock_); if (use_stale) *use_stale = (loading_state_ != LOADING_STATE_UP_TO_DATE); diff --git a/chromium/content/common/plugin_list.h b/chromium/content/common/plugin_list.h index 0b31ab0d7e1..b18b061043b 100644 --- a/chromium/content/common/plugin_list.h +++ b/chromium/content/common/plugin_list.h @@ -40,35 +40,16 @@ class CONTENT_EXPORT PluginList { // Gets the one instance of the PluginList. static PluginList* Singleton(); - // Returns true if we're in debug-plugin-loading mode. This is controlled - // by a command line switch. - static bool DebugPluginLoading(); - // Returns true if the plugin supports |mime_type|. |mime_type| should be all // lower case. static bool SupportsType(const WebPluginInfo& plugin, const std::string& mime_type, bool allow_wildcard); - // Disables discovery of third_party plugins in standard places next time - // plugins are loaded. - void DisablePluginsDiscovery(); - // Cause the plugin list to refresh next time they are accessed, regardless // of whether they are already loaded. void RefreshPlugins(); - // Add/Remove an extra plugin to load when we actually do the loading. Must - // be called before the plugins have been loaded. - void AddExtraPluginPath(const base::FilePath& plugin_path); - void RemoveExtraPluginPath(const base::FilePath& plugin_path); - - // Same as above, but specifies a directory in which to search for plugins. - void AddExtraPluginDir(const base::FilePath& plugin_dir); - - // Get the ordered list of directories from which to load plugins - void GetPluginDirectories(std::vector<base::FilePath>* plugin_dirs); - // Register an internal plugin with the specified plugin information. // An internal plugin must be registered before it can // be loaded using PluginList::LoadPlugin(). @@ -90,19 +71,8 @@ class CONTENT_EXPORT PluginList { bool ReadPluginInfo(const base::FilePath& filename, WebPluginInfo* info); - // In Windows plugins, the mime types are passed as a specially formatted list - // of strings. This function parses those strings into a WebPluginMimeType - // vector. - // TODO(evan): move this code into plugin_list_win. - static bool ParseMimeTypes( - const std::string& mime_types, - const std::string& file_extensions, - const base::string16& mime_type_descriptions, - std::vector<WebPluginMimeType>* parsed_mime_types); - // Get all the plugins synchronously, loading them if necessary. - void GetPlugins(std::vector<WebPluginInfo>* plugins, - bool include_npapi); + void GetPlugins(std::vector<WebPluginInfo>* plugins); // Copies the list of plugins into |plugins| without loading them. // Returns true if the list of plugins is up-to-date. @@ -124,7 +94,6 @@ class CONTENT_EXPORT PluginList { const std::string& mime_type, bool allow_wildcard, bool* use_stale, - bool include_npapi, std::vector<WebPluginInfo>* info, std::vector<std::string>* actual_mime_types); @@ -138,8 +107,7 @@ class CONTENT_EXPORT PluginList { // using a different instance of this class. // Computes a list of all plugins to potentially load from all sources. - void GetPluginPathsToLoad(std::vector<base::FilePath>* plugin_paths, - bool include_npapi); + void GetPluginPathsToLoad(std::vector<base::FilePath>* plugin_paths); // Signals that plugin loading will start. This method should be called before // loading plugins with a different instance of this class. Returns false if @@ -155,12 +123,6 @@ class CONTENT_EXPORT PluginList { virtual ~PluginList(); - // Creates a WebPluginInfo structure given a plugin's path. On success - // returns true, with the information being put into "info". - // Returns false if the library couldn't be found, or if it's not a plugin. - static bool ReadWebPluginInfo(const base::FilePath& filename, - WebPluginInfo* info); - private: enum LoadingState { LOADING_STATE_NEEDS_REFRESH, @@ -174,18 +136,7 @@ class CONTENT_EXPORT PluginList { PluginList(); // Load all plugins from the default plugins directory. - void LoadPlugins(bool include_npapi); - - // Walks a directory and produces a list of all the plugins to potentially - // load in that directory. - void GetPluginsInDir(const base::FilePath& path, - std::vector<base::FilePath>* plugins); - - // Returns true if we should load the given plugin, or false otherwise. - // |plugins| is the list of plugins we have crawled in the current plugin - // loading run. - bool ShouldLoadPluginUsingPluginList(const WebPluginInfo& info, - std::vector<WebPluginInfo>* plugins); + void LoadPlugins(); // Returns true if the given plugin supports a given file extension. // |extension| should be all lower case. If |mime_type| is not NULL, it will @@ -200,16 +151,6 @@ class CONTENT_EXPORT PluginList { void RemoveExtraPluginPathLocked(const base::FilePath& plugin_path); // - // Command-line switches - // - -#if defined(OS_WIN) - // Gets plugin paths registered under HKCU\Software\MozillaPlugins and - // HKLM\Software\MozillaPlugins. - void GetPluginPathsFromRegistry(std::vector<base::FilePath>* plugins); -#endif - - // // Internals // @@ -221,9 +162,6 @@ class CONTENT_EXPORT PluginList { // Extra plugin paths that we want to search when loading. std::vector<base::FilePath> extra_plugin_paths_; - // Extra plugin directories that we want to search when loading. - std::vector<base::FilePath> extra_plugin_dirs_; - // Holds information about internal plugins. std::vector<WebPluginInfo> internal_plugins_; @@ -237,10 +175,6 @@ class CONTENT_EXPORT PluginList { // accessed on multiple threads. base::Lock lock_; - // Flag indicating whether third_party plugins will be searched for - // in common places. - bool plugins_discovery_disabled_; - DISALLOW_COPY_AND_ASSIGN(PluginList); }; diff --git a/chromium/content/common/plugin_list_mac.mm b/chromium/content/common/plugin_list_mac.mm deleted file mode 100644 index b3d726c0d70..00000000000 --- a/chromium/content/common/plugin_list_mac.mm +++ /dev/null @@ -1,307 +0,0 @@ -// Copyright (c) 2012 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 "content/common/plugin_list.h" - -#import <Carbon/Carbon.h> -#import <Foundation/Foundation.h> - -#include "base/files/file_enumerator.h" -#include "base/files/file_util.h" -#include "base/mac/mac_util.h" -#include "base/mac/scoped_cftyperef.h" -#include "base/memory/scoped_ptr.h" -#include "base/native_library.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" - -using base::ScopedCFTypeRef; - -namespace content { - -namespace { - -void GetPluginCommonDirectory(std::vector<base::FilePath>* plugin_dirs, - bool user) { - // Note that there are no NSSearchPathDirectory constants for these - // directories so we can't use Cocoa's NSSearchPathForDirectoriesInDomains(). - // Interestingly, Safari hard-codes the location (see - // WebKit/WebKit/mac/Plugins/WebPluginDatabase.mm's +_defaultPlugInPaths). - FSRef ref; - OSErr err = FSFindFolder(user ? kUserDomain : kLocalDomain, - kInternetPlugInFolderType, false, &ref); - - if (err) - return; - - plugin_dirs->push_back(base::FilePath(base::mac::PathFromFSRef(ref))); -} - -// Returns true if the plugin should be prevented from loading. -bool IsBlacklistedPlugin(const WebPluginInfo& info) { - // We blacklist Gears by included MIME type, since that is more stable than - // its name. Be careful about adding any more plugins to this list though, - // since it's easy to accidentally blacklist plugins that support lots of - // MIME types. - for (const WebPluginMimeType& mime : info.mime_types) { - // The Gears plugin is Safari-specific, so don't load it. - if (mime.mime_type == "application/x-googlegears") - return true; - } - - // Versions of Flip4Mac 2.3 before 2.3.6 often hang the renderer, so don't - // load them. - if (base::StartsWith(info.name, - base::ASCIIToUTF16("Flip4Mac Windows Media"), - base::CompareCase::INSENSITIVE_ASCII) && - base::StartsWith(info.version, base::ASCIIToUTF16("2.3"), - base::CompareCase::SENSITIVE)) { - std::vector<base::StringPiece16> components = base::SplitStringPiece( - info.version, base::ASCIIToUTF16("."), base::TRIM_WHITESPACE, - base::SPLIT_WANT_ALL); - int bugfix_version = 0; - return (components.size() >= 3 && - base::StringToInt(components[2], &bugfix_version) && - bugfix_version < 6); - } - - return false; -} - -NSDictionary* GetMIMETypes(CFBundleRef bundle) { - NSString* mime_filename = - (NSString*)CFBundleGetValueForInfoDictionaryKey(bundle, - CFSTR("WebPluginMIMETypesFilename")); - - if (mime_filename) { - - // get the file - - NSString* mime_path = - [NSString stringWithFormat:@"%@/Library/Preferences/%@", - NSHomeDirectory(), mime_filename]; - NSDictionary* mime_file_dict = - [NSDictionary dictionaryWithContentsOfFile:mime_path]; - - // is it valid? - - bool valid_file = false; - if (mime_file_dict) { - NSString* l10n_name = - [mime_file_dict objectForKey:@"WebPluginLocalizationName"]; - NSString* preferred_l10n = [[NSLocale currentLocale] localeIdentifier]; - if ([l10n_name isEqualToString:preferred_l10n]) - valid_file = true; - } - - if (valid_file) - return [mime_file_dict objectForKey:@"WebPluginMIMETypes"]; - - // dammit, I didn't want to have to do this - - typedef void (*CreateMIMETypesPrefsPtr)(void); - CreateMIMETypesPrefsPtr create_prefs_file = - (CreateMIMETypesPrefsPtr)CFBundleGetFunctionPointerForName( - bundle, CFSTR("BP_CreatePluginMIMETypesPreferences")); - if (!create_prefs_file) - return nil; - create_prefs_file(); - - // one more time - - mime_file_dict = [NSDictionary dictionaryWithContentsOfFile:mime_path]; - if (mime_file_dict) - return [mime_file_dict objectForKey:@"WebPluginMIMETypes"]; - else - return nil; - - } else { - return (NSDictionary*)CFBundleGetValueForInfoDictionaryKey(bundle, - CFSTR("WebPluginMIMETypes")); - } -} - -bool ReadPlistPluginInfo(const base::FilePath& filename, CFBundleRef bundle, - WebPluginInfo* info) { - NSDictionary* mime_types = GetMIMETypes(bundle); - if (!mime_types) - return false; // no type info here; try elsewhere - - for (NSString* mime_type in [mime_types allKeys]) { - NSDictionary* mime_dict = [mime_types objectForKey:mime_type]; - NSNumber* type_enabled = [mime_dict objectForKey:@"WebPluginTypeEnabled"]; - NSString* mime_desc = [mime_dict objectForKey:@"WebPluginTypeDescription"]; - NSArray* mime_exts = [mime_dict objectForKey:@"WebPluginExtensions"]; - - // Skip any disabled types. - if (type_enabled && ![type_enabled boolValue]) - continue; - - WebPluginMimeType mime; - mime.mime_type = base::SysNSStringToUTF8([mime_type lowercaseString]); - // Remove PDF from the list of types handled by QuickTime, since it provides - // a worse experience than just downloading the PDF. - if (mime.mime_type == "application/pdf" && - base::StartsWith(filename.BaseName().value(), "QuickTime", - base::CompareCase::INSENSITIVE_ASCII)) { - continue; - } - - if (mime_desc) - mime.description = base::SysNSStringToUTF16(mime_desc); - for (NSString* ext in mime_exts) - mime.file_extensions.push_back( - base::SysNSStringToUTF8([ext lowercaseString])); - - info->mime_types.push_back(mime); - } - - NSString* plugin_name = - (NSString*)CFBundleGetValueForInfoDictionaryKey(bundle, - CFSTR("WebPluginName")); - NSString* plugin_vers = - (NSString*)CFBundleGetValueForInfoDictionaryKey(bundle, - CFSTR("CFBundleShortVersionString")); - NSString* plugin_desc = - (NSString*)CFBundleGetValueForInfoDictionaryKey(bundle, - CFSTR("WebPluginDescription")); - - if (plugin_name) - info->name = base::SysNSStringToUTF16(plugin_name); - else - info->name = base::UTF8ToUTF16(filename.BaseName().value()); - info->path = filename; - if (plugin_vers) - info->version = base::SysNSStringToUTF16(plugin_vers); - if (plugin_desc) - info->desc = base::SysNSStringToUTF16(plugin_desc); - else - info->desc = base::UTF8ToUTF16(filename.BaseName().value()); - - return true; -} - -} // namespace - -bool PluginList::ReadWebPluginInfo(const base::FilePath &filename, - WebPluginInfo* info) { - // There are three ways to get information about plugin capabilities: - // 1) a set of Info.plist keys, documented at - // http://developer.apple.com/documentation/InternetWeb/Conceptual/WebKit_PluginProgTopic/Concepts/AboutPlugins.html . - // 2) a set of STR# resources, documented at - // https://developer.mozilla.org/En/Gecko_Plugin_API_Reference/Plug-in_Development_Overview . - // 3) a NP_GetMIMEDescription() entry point, documented at - // https://developer.mozilla.org/en/NP_GetMIMEDescription - // - // Mozilla supported (3), but WebKit never has, so no plugins rely on it. Most - // browsers supported (2) and then added support for (1); Chromium originally - // supported (2) and (1), but now supports only (1) as (2) is deprecated. - // - // For the Info.plist version, the data is formatted as follows (in text plist - // format): - // { - // ... the usual plist keys ... - // WebPluginDescription = <<plugindescription>>; - // WebPluginMIMETypes = { - // <<type0mimetype>> = { - // WebPluginExtensions = ( - // <<type0fileextension0>>, - // ... - // <<type0fileextensionk>>, - // ); - // WebPluginTypeDescription = <<type0description>>; - // }; - // <<type1mimetype>> = { ... }; - // ... - // <<typenmimetype>> = { ... }; - // }; - // WebPluginName = <<pluginname>>; - // } - // - // Alternatively (and this is undocumented), rather than a WebPluginMIMETypes - // key, there may be a WebPluginMIMETypesFilename key. If it is present, then - // it is the name of a file in the user's preferences folder in which to find - // the WebPluginMIMETypes key. If the key is present but the file doesn't - // exist, we must load the plugin and call a specific function to have the - // plugin create the file. - - ScopedCFTypeRef<CFURLRef> bundle_url(CFURLCreateFromFileSystemRepresentation( - kCFAllocatorDefault, (const UInt8*)filename.value().c_str(), - filename.value().length(), true)); - if (!bundle_url) { - LOG_IF(ERROR, PluginList::DebugPluginLoading()) - << "PluginLib::ReadWebPluginInfo could not create bundle URL"; - return false; - } - ScopedCFTypeRef<CFBundleRef> bundle(CFBundleCreate(kCFAllocatorDefault, - bundle_url.get())); - if (!bundle) { - LOG_IF(ERROR, PluginList::DebugPluginLoading()) - << "PluginLib::ReadWebPluginInfo could not create CFBundleRef"; - return false; - } - - // preflight - - OSType type = 0; - CFBundleGetPackageInfo(bundle.get(), &type, NULL); - if (type != FOUR_CHAR_CODE('BRPL')) { - LOG_IF(ERROR, PluginList::DebugPluginLoading()) - << "PluginLib::ReadWebPluginInfo bundle is not BRPL, is " << type; - return false; - } - - CFErrorRef error; - Boolean would_load = CFBundlePreflightExecutable(bundle.get(), &error); - if (!would_load) { - ScopedCFTypeRef<CFStringRef> error_string(CFErrorCopyDescription(error)); - LOG_IF(ERROR, PluginList::DebugPluginLoading()) - << "PluginLib::ReadWebPluginInfo bundle failed preflight: " - << base::SysCFStringRefToUTF8(error_string); - return false; - } - - // get the info - - if (ReadPlistPluginInfo(filename, bundle.get(), info)) - return true; - - // ... or not - - return false; -} - -void PluginList::GetPluginDirectories( - std::vector<base::FilePath>* plugin_dirs) { - if (PluginList::plugins_discovery_disabled_) - return; - - // Load from the user's area - GetPluginCommonDirectory(plugin_dirs, true); - - // Load from the machine-wide area - GetPluginCommonDirectory(plugin_dirs, false); -} - -void PluginList::GetPluginsInDir( - const base::FilePath& path, std::vector<base::FilePath>* plugins) { - base::FileEnumerator enumerator(path, - false, // not recursive - base::FileEnumerator::DIRECTORIES); - for (base::FilePath path = enumerator.Next(); !path.value().empty(); - path = enumerator.Next()) { - plugins->push_back(path); - } -} - -bool PluginList::ShouldLoadPluginUsingPluginList( - const WebPluginInfo& info, - std::vector<WebPluginInfo>* plugins) { - return !IsBlacklistedPlugin(info); -} - -} // namespace content diff --git a/chromium/content/common/plugin_list_posix.cc b/chromium/content/common/plugin_list_posix.cc deleted file mode 100644 index 122fd59be42..00000000000 --- a/chromium/content/common/plugin_list_posix.cc +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2011 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 "content/common/plugin_list.h" - -namespace content { - -bool PluginList::ReadWebPluginInfo(const base::FilePath& filename, - WebPluginInfo* info) { - return false; -} - -void PluginList::GetPluginDirectories( - std::vector<base::FilePath>* plugin_dirs) { -} - -void PluginList::GetPluginsInDir(const base::FilePath& dir_path, - std::vector<base::FilePath>* plugins) { -} - -bool PluginList::ShouldLoadPluginUsingPluginList( - const WebPluginInfo& info, - std::vector<WebPluginInfo>* plugins) { - LOG_IF(ERROR, PluginList::DebugPluginLoading()) - << "Considering " << info.path.value() << " (" << info.name << ")"; - - if (info.type == WebPluginInfo::PLUGIN_TYPE_NPAPI) { - NOTREACHED() << "NPAPI plugins are not supported"; - return false; - } - - VLOG_IF(1, PluginList::DebugPluginLoading()) << "Using " << info.path.value(); - return true; -} - -} // namespace content diff --git a/chromium/content/common/plugin_list_unittest.cc b/chromium/content/common/plugin_list_unittest.cc index 4b8150b499b..d28c0eb589b 100644 --- a/chromium/content/common/plugin_list_unittest.cc +++ b/chromium/content/common/plugin_list_unittest.cc @@ -52,7 +52,6 @@ class PluginListTest : public testing::Test { } void SetUp() override { - plugin_list_.DisablePluginsDiscovery(); plugin_list_.RegisterInternalPlugin(bar_plugin_, false); foo_plugin_.mime_types.push_back( WebPluginMimeType(kFooMimeType, kFooFileType, std::string())); @@ -67,7 +66,7 @@ class PluginListTest : public testing::Test { TEST_F(PluginListTest, GetPlugins) { std::vector<WebPluginInfo> plugins; - plugin_list_.GetPlugins(&plugins, true); + plugin_list_.GetPlugins(&plugins); EXPECT_EQ(2u, plugins.size()); EXPECT_TRUE(Contains(plugins, foo_plugin_)); EXPECT_TRUE(Contains(plugins, bar_plugin_)); @@ -82,7 +81,7 @@ TEST_F(PluginListTest, BadPluginDescription) { // Now we should have them in the state we specified above. plugin_list_.RefreshPlugins(); std::vector<WebPluginInfo> plugins; - plugin_list_.GetPlugins(&plugins, true); + plugin_list_.GetPlugins(&plugins); ASSERT_TRUE(Contains(plugins, plugin_3043)); } @@ -99,7 +98,6 @@ TEST_F(PluginListTest, GetPluginInfoArray) { "application/octet-stream", false, // allow_wildcard NULL, // use_stale - false, // include_npapi &plugins, &actual_mime_types); EXPECT_EQ(0u, plugins.size()); @@ -112,7 +110,6 @@ TEST_F(PluginListTest, GetPluginInfoArray) { kFooMimeType, false, // allow_wildcard NULL, // use_stale - false, // include_npapi &plugins, &actual_mime_types); EXPECT_EQ(1u, plugins.size()); @@ -127,7 +124,6 @@ TEST_F(PluginListTest, GetPluginInfoArray) { "", false, // allow_wildcard NULL, // use_stale - false, // include_npapi &plugins, &actual_mime_types); EXPECT_EQ(1u, plugins.size()); diff --git a/chromium/content/common/plugin_list_win.cc b/chromium/content/common/plugin_list_win.cc deleted file mode 100644 index e96cc05698a..00000000000 --- a/chromium/content/common/plugin_list_win.cc +++ /dev/null @@ -1,493 +0,0 @@ -// Copyright (c) 2012 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 "content/common/plugin_list.h" - -#include <stddef.h> - -#include <set> - -#include "base/file_version_info.h" -#include "base/file_version_info_win.h" -#include "base/files/file_util.h" -#include "base/files/memory_mapped_file.h" -#include "base/memory/scoped_ptr.h" -#include "base/path_service.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/win/pe_image.h" -#include "base/win/registry.h" -#include "base/win/scoped_handle.h" -#include "base/win/windows_version.h" -#include "build/build_config.h" -#include "content/common/plugin_constants_win.h" - -namespace content { -namespace { - -const base::char16 kRegistryApps[] = - L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths"; -const base::char16 kRegistryAcrobat[] = L"Acrobat.exe"; -const base::char16 kRegistryAcrobatReader[] = L"AcroRd32.exe"; -const base::char16 kRegistryWindowsMedia[] = L"wmplayer.exe"; -const base::char16 kRegistryQuickTime[] = L"QuickTimePlayer.exe"; -const base::char16 kRegistryPath[] = L"Path"; -const base::char16 kRegistryFirefoxInstalled[] = - L"SOFTWARE\\Mozilla\\Mozilla Firefox"; -const base::char16 kRegistryJava[] = - L"Software\\JavaSoft\\Java Runtime Environment"; -const base::char16 kRegistryBrowserJavaVersion[] = L"BrowserJavaVersion"; -const base::char16 kRegistryCurrentJavaVersion[] = L"CurrentVersion"; -const base::char16 kRegistryJavaHome[] = L"JavaHome"; -const base::char16 kJavaDeploy1[] = L"npdeploytk.dll"; -const base::char16 kJavaDeploy2[] = L"npdeployjava1.dll"; - -base::FilePath AppendPluginsDir(const base::FilePath& path) { - return path.AppendASCII("plugins"); -} - -// Gets the directory where the application data and libraries exist. This -// may be a versioned subdirectory, or it may be the same directory as the -// GetExeDirectory(), depending on the embedder's implementation. -// Path is an output parameter to receive the path. -void GetAppDirectory(std::set<base::FilePath>* plugin_dirs) { - base::FilePath app_path; - if (!PathService::Get(base::DIR_MODULE, &app_path)) - return; - plugin_dirs->insert(AppendPluginsDir(app_path)); -} - -// Gets the directory where the launching executable resides on disk. -// Path is an output parameter to receive the path. -void GetExeDirectory(std::set<base::FilePath>* plugin_dirs) { - base::FilePath exe_path; - if (!PathService::Get(base::DIR_EXE, &exe_path)) - return; - plugin_dirs->insert(AppendPluginsDir(exe_path)); -} - -// Gets the installed path for a registered app. -bool GetInstalledPath(const base::char16* app, base::FilePath* out) { - base::string16 reg_path(kRegistryApps); - reg_path.append(L"\\"); - reg_path.append(app); - - base::win::RegKey hkcu_key(HKEY_CURRENT_USER, reg_path.c_str(), KEY_READ); - base::string16 path; - // As of Win7 AppPaths can also be registered in HKCU: http://goo.gl/UgFOf. - if (base::win::GetVersion() >= base::win::VERSION_WIN7 && - hkcu_key.ReadValue(kRegistryPath, &path) == ERROR_SUCCESS) { - *out = base::FilePath(path); - return true; - } else { - base::win::RegKey hklm_key(HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_READ); - if (hklm_key.ReadValue(kRegistryPath, &path) == ERROR_SUCCESS) { - *out = base::FilePath(path); - return true; - } - } - - return false; -} - -// Search the registry at the given path and detect plugin directories. -void GetPluginsInRegistryDirectory(HKEY root_key, - const base::string16& registry_folder, - REGSAM wow64_access, - std::set<base::FilePath>* plugin_dirs) { - for (base::win::RegistryKeyIterator iter( - root_key, registry_folder.c_str(), wow64_access); - iter.Valid(); - ++iter) { - // Use the registry to gather plugin across the file system. - base::string16 reg_path = registry_folder; - reg_path.append(L"\\"); - reg_path.append(iter.Name()); - base::win::RegKey key(root_key, reg_path.c_str(), KEY_READ | wow64_access); - - base::string16 path; - if (key.ReadValue(kRegistryPath, &path) == ERROR_SUCCESS) - plugin_dirs->insert(base::FilePath(path)); - } -} - -// Enumerate through the registry key to find all installed FireFox paths. -// FireFox 3 beta and version 2 can coexist. See bug: 1025003 -void GetFirefoxInstalledPaths(std::vector<base::FilePath>* out) { - base::win::RegistryKeyIterator it(HKEY_LOCAL_MACHINE, - kRegistryFirefoxInstalled, - KEY_WOW64_32KEY); - for (; it.Valid(); ++it) { - base::string16 full_path = base::string16(kRegistryFirefoxInstalled) + - L"\\" + it.Name() + L"\\Main"; - base::win::RegKey key(HKEY_LOCAL_MACHINE, full_path.c_str(), KEY_READ); - base::string16 install_dir; - if (key.ReadValue(L"Install Directory", &install_dir) != ERROR_SUCCESS) - continue; - out->push_back(base::FilePath(install_dir)); - } -} - -// Get plugin directory locations from the Firefox install path. This is kind -// of a kludge, but it helps us locate the flash player for users that -// already have it for firefox. Not having to download yet-another-plugin -// is a good thing. -void GetFirefoxDirectory(std::set<base::FilePath>* plugin_dirs) { - std::vector<base::FilePath> paths; - GetFirefoxInstalledPaths(&paths); - for (unsigned int i = 0; i < paths.size(); ++i) { - plugin_dirs->insert(AppendPluginsDir(paths[i])); - } - - base::FilePath firefox_app_data_plugin_path; - if (PathService::Get(base::DIR_APP_DATA, &firefox_app_data_plugin_path)) { - firefox_app_data_plugin_path = - firefox_app_data_plugin_path.AppendASCII("Mozilla"); - plugin_dirs->insert(AppendPluginsDir(firefox_app_data_plugin_path)); - } -} - -// Hardcoded logic to detect Acrobat plugins locations. -void GetAcrobatDirectory(std::set<base::FilePath>* plugin_dirs) { - base::FilePath path; - if (!GetInstalledPath(kRegistryAcrobatReader, &path) && - !GetInstalledPath(kRegistryAcrobat, &path)) { - return; - } - - plugin_dirs->insert(path.Append(L"Browser")); -} - -// Hardcoded logic to detect QuickTime plugin location. -void GetQuicktimeDirectory(std::set<base::FilePath>* plugin_dirs) { - base::FilePath path; - if (GetInstalledPath(kRegistryQuickTime, &path)) - plugin_dirs->insert(AppendPluginsDir(path)); -} - -// Hardcoded logic to detect Windows Media Player plugin location. -void GetWindowsMediaDirectory(std::set<base::FilePath>* plugin_dirs) { - base::FilePath path; - if (GetInstalledPath(kRegistryWindowsMedia, &path)) - plugin_dirs->insert(path); -} - -// Hardcoded logic to detect Java plugin location. -void GetJavaDirectory(std::set<base::FilePath>* plugin_dirs) { - // Load the new NPAPI Java plugin - // 1. Open the main JRE key under HKLM - base::win::RegKey java_key(HKEY_LOCAL_MACHINE, kRegistryJava, - KEY_QUERY_VALUE); - - // 2. Read the current Java version - base::string16 java_version; - if (java_key.ReadValue(kRegistryBrowserJavaVersion, &java_version) != - ERROR_SUCCESS) { - java_key.ReadValue(kRegistryCurrentJavaVersion, &java_version); - } - - if (!java_version.empty()) { - java_key.OpenKey(java_version.c_str(), KEY_QUERY_VALUE); - - // 3. Install path of the JRE binaries is specified in "JavaHome" - // value under the Java version key. - base::string16 java_plugin_directory; - if (java_key.ReadValue(kRegistryJavaHome, &java_plugin_directory) == - ERROR_SUCCESS) { - // 4. The new plugin resides under the 'bin/new_plugin' - // subdirectory. - DCHECK(!java_plugin_directory.empty()); - java_plugin_directory.append(L"\\bin\\new_plugin"); - - // 5. We don't know the exact name of the DLL but it's in the form - // NP*.dll so just invoke LoadPlugins on this path. - plugin_dirs->insert(base::FilePath(java_plugin_directory)); - } - } -} - -bool IsValid32BitImage(const base::FilePath& path) { - base::MemoryMappedFile plugin_image; - - if (!plugin_image.InitializeAsImageSection(path)) - return false; - - base::win::PEImage image(plugin_image.data()); - - PIMAGE_NT_HEADERS nt_headers = image.GetNTHeaders(); - return (nt_headers->FileHeader.Machine == IMAGE_FILE_MACHINE_I386); -} - -// Returns true if the given plugins share at least one mime type. This is used -// to differentiate newer versions of a plugin vs two plugins which happen to -// have the same filename. -bool HaveSharedMimeType(const WebPluginInfo& plugin1, - const WebPluginInfo& plugin2) { - for (size_t i = 0; i < plugin1.mime_types.size(); ++i) { - for (size_t j = 0; j < plugin2.mime_types.size(); ++j) { - if (plugin1.mime_types[i].mime_type == plugin2.mime_types[j].mime_type) - return true; - } - } - - return false; -} - -// Compares Windows style version strings (i.e. 1,2,3,4). Returns true if b's -// version is newer than a's, or false if it's equal or older. -bool IsNewerVersion(const base::string16& a, const base::string16& b) { - std::vector<base::string16> a_ver = base::SplitString( - a, base::string16(1, ','), base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - std::vector<base::string16> b_ver = base::SplitString( - b, base::string16(1, ','), base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - if (a_ver.size() == 1 && b_ver.size() == 1) { - a_ver = base::SplitString( - a, base::string16(1, '.'), base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - b_ver = base::SplitString( - b, base::string16(1, '.'), base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - } - if (a_ver.size() != b_ver.size()) - return false; - for (size_t i = 0; i < a_ver.size(); i++) { - int cur_a, cur_b; - base::StringToInt(a_ver[i], &cur_a); - base::StringToInt(b_ver[i], &cur_b); - - if (cur_a > cur_b) - return false; - if (cur_a < cur_b) - return true; - } - return false; -} - -} // namespace - -bool PluginList::ReadWebPluginInfo(const base::FilePath& filename, - WebPluginInfo* info) { - // On windows, the way we get the mime types for the library is - // to check the version information in the DLL itself. This - // will be a string of the format: <type1>|<type2>|<type3>|... - // For example: - // video/quicktime|audio/aiff|image/jpeg - scoped_ptr<FileVersionInfo> version_info( - FileVersionInfo::CreateFileVersionInfo(filename)); - if (!version_info) { - LOG_IF(ERROR, PluginList::DebugPluginLoading()) - << "Could not get version info for plugin " - << filename.value(); - return false; - } - - FileVersionInfoWin* version_info_win = - static_cast<FileVersionInfoWin*>(version_info.get()); - - info->name = version_info->product_name(); - info->desc = version_info->file_description(); - info->version = version_info->file_version(); - info->path = filename; - - // TODO(evan): Move the ParseMimeTypes code inline once Pepper is updated. - if (!PluginList::ParseMimeTypes( - base::UTF16ToASCII(version_info_win->GetStringValue(L"MIMEType")), - base::UTF16ToASCII(version_info_win->GetStringValue(L"FileExtents")), - version_info_win->GetStringValue(L"FileOpenName"), - &info->mime_types)) { - LOG_IF(ERROR, PluginList::DebugPluginLoading()) - << "Plugin " << info->name << " has bad MIME types, skipping"; - return false; - } - - return true; -} - -void PluginList::GetPluginDirectories( - std::vector<base::FilePath>* plugin_dirs) { - if (PluginList::plugins_discovery_disabled_) - return; - - // We use a set for uniqueness, which we require, over order, which we do not. - std::set<base::FilePath> dirs; - - // Load from the application-specific area - GetAppDirectory(&dirs); - - // Load from the executable area - GetExeDirectory(&dirs); - - // Load Java - GetJavaDirectory(&dirs); - - // Load firefox plugins too. This is mainly to try to locate - // a pre-installed Flash player. - GetFirefoxDirectory(&dirs); - - // Firefox hard-codes the paths of some popular plugins to ensure that - // the plugins are found. We are going to copy this as well. - GetAcrobatDirectory(&dirs); - GetQuicktimeDirectory(&dirs); - GetWindowsMediaDirectory(&dirs); - - for (std::set<base::FilePath>::iterator i = dirs.begin(); i != dirs.end(); ++i) - plugin_dirs->push_back(*i); -} - -void PluginList::GetPluginsInDir( - const base::FilePath& path, std::vector<base::FilePath>* plugins) { - WIN32_FIND_DATA find_file_data; - HANDLE find_handle; - - base::string16 dir = path.value(); - // FindFirstFile requires that you specify a wildcard for directories. - dir.append(L"\\NP*.DLL"); - - find_handle = FindFirstFile(dir.c_str(), &find_file_data); - if (find_handle == INVALID_HANDLE_VALUE) - return; - - do { - if (!(find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - base::FilePath filename = path.Append(find_file_data.cFileName); - plugins->push_back(filename); - } - } while (FindNextFile(find_handle, &find_file_data) != 0); - - DCHECK(GetLastError() == ERROR_NO_MORE_FILES); - FindClose(find_handle); -} - -void PluginList::GetPluginPathsFromRegistry( - std::vector<base::FilePath>* plugins) { - if (PluginList::plugins_discovery_disabled_) - return; - - std::set<base::FilePath> plugin_dirs; - - // Search for plugins from HKCU and HKLM. THis will only find plugins that - // are correctly registered in the correct WOW64 registry hive. - GetPluginsInRegistryDirectory(HKEY_CURRENT_USER, - kRegistryMozillaPlugins, - 0, - &plugin_dirs); - GetPluginsInRegistryDirectory(HKEY_LOCAL_MACHINE, - kRegistryMozillaPlugins, - 0, - &plugin_dirs); - - for (std::set<base::FilePath>::iterator i = plugin_dirs.begin(); - i != plugin_dirs.end(); ++i) { - plugins->push_back(*i); - } -} - -bool PluginList::ShouldLoadPluginUsingPluginList( - const WebPluginInfo& info, - std::vector<WebPluginInfo>* plugins) { - bool should_check_version = true; - { - base::AutoLock lock(lock_); - should_check_version = - std::find(extra_plugin_paths_.begin(), extra_plugin_paths_.end(), - info.path) == extra_plugin_paths_.end(); - } - // Version check for plugins that are not coming from |extra_plugin_paths_|. - if (should_check_version) { - for (size_t j = 0; j < plugins->size(); ++j) { - base::FilePath::StringType plugin1 = - base::ToLowerASCII((*plugins)[j].path.BaseName().value()); - base::FilePath::StringType plugin2 = - base::ToLowerASCII(info.path.BaseName().value()); - if ((plugin1 == plugin2 && HaveSharedMimeType((*plugins)[j], info)) || - (plugin1 == kJavaDeploy1 && plugin2 == kJavaDeploy2) || - (plugin1 == kJavaDeploy2 && plugin2 == kJavaDeploy1)) { - if (IsNewerVersion(info.version, (*plugins)[j].version)) - return false; // We have loaded a plugin whose version is newer. - plugins->erase(plugins->begin() + j); - break; - } - } - } - - // The checks below only apply to NPAPI plugins. - if (info.type != WebPluginInfo::PLUGIN_TYPE_NPAPI) - return true; - - { - base::AutoLock lock(lock_); - // If the plugin is in our internal list we should load it. - for (size_t i = 0; i < internal_plugins_.size(); ++i) { - if (info.path == internal_plugins_[i].path) - return true; - } - } - - // Troublemakers. - base::FilePath::StringType filename = - base::ToLowerASCII(info.path.BaseName().value()); - // Depends on XPCOM. - if (filename == kMozillaActiveXPlugin) - return false; - - // Disable the Yahoo Application State plugin as it crashes the plugin - // process on return from NPObjectStub::OnInvoke. Please refer to - // http://b/issue?id=1372124 for more information. - if (filename == kYahooApplicationStatePlugin) - return false; - - // Disable the WangWang protocol handler plugin (npww.dll) as it crashes - // chrome during shutdown. Firefox also disables this plugin. - // Please refer to http://code.google.com/p/chromium/issues/detail?id=3953 - // for more information. - if (filename == kWanWangProtocolHandlerPlugin) - return false; - - // We only work with newer versions of the Java plugin which use NPAPI only - // and don't depend on XPCOM. - if (filename == kJavaPlugin1 || filename == kJavaPlugin2) { - std::vector<base::FilePath::StringType> ver = base::SplitString( - info.version, base::FilePath::StringType(1, '.'), - base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - int major, minor, update; - if (ver.size() == 4 && - base::StringToInt(ver[0], &major) && - base::StringToInt(ver[1], &minor) && - base::StringToInt(ver[2], &update)) { - if (major == 6 && minor == 0 && update < 120) - return false; // Java SE6 Update 11 or older. - } - } - - // Special WMP handling: - // If both the new and old WMP plugins exist, only load the new one. - if (filename == kNewWMPPlugin) { - for (size_t j = 0; j < plugins->size(); ++j) { - if ((*plugins)[j].path.BaseName().value() == kOldWMPPlugin) { - plugins->erase(plugins->begin() + j); - break; - } - } - - } else if (filename == kOldWMPPlugin) { - for (size_t j = 0; j < plugins->size(); ++j) { - if ((*plugins)[j].path.BaseName().value() == kNewWMPPlugin) - return false; - } - } - - base::FilePath plugin_path(info.path); -#if defined(ARCH_CPU_X86_64) - // The plugin in question could be a 32 bit plugin which we cannot load. - if (IsValid32BitImage(base::MakeAbsoluteFilePath(plugin_path))) - return false; -#else - // The plugin in question could be a 64 bit plugin which we cannot load. - if (!IsValid32BitImage(base::MakeAbsoluteFilePath(plugin_path))) - return false; -#endif - return true; -} - -} // namespace content diff --git a/chromium/content/common/plugin_process_messages.h b/chromium/content/common/plugin_process_messages.h deleted file mode 100644 index a815b55ed30..00000000000 --- a/chromium/content/common/plugin_process_messages.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2012 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. -// -// Multiply-included message file, hence no include guard. - -#include <stdint.h> - -#include "build/build_config.h" -#include "content/common/content_export.h" -#include "content/common/content_param_traits.h" -#include "content/public/common/common_param_traits.h" -#include "ipc/ipc_channel_handle.h" -#include "ipc/ipc_message_macros.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/ipc/gfx_param_traits.h" -#include "ui/gfx/native_widget_types.h" - -#undef IPC_MESSAGE_EXPORT -#define IPC_MESSAGE_EXPORT CONTENT_EXPORT - -#define IPC_MESSAGE_START PluginProcessMsgStart - -//----------------------------------------------------------------------------- -// PluginProcess messages -// These are messages sent from the browser to the plugin process. -// Tells the plugin process to create a new channel for communication with a -// given renderer. The channel name is returned in a -// PluginProcessHostMsg_ChannelCreated message. The renderer ID is passed so -// that the plugin process reuses an existing channel to that process if it -// exists. This ID is a unique opaque identifier generated by the browser -// process. -IPC_MESSAGE_CONTROL2(PluginProcessMsg_CreateChannel, - int /* renderer_id */, - bool /* off_the_record */) - -// Tells the plugin process to notify every connected renderer of the pending -// shutdown, so we don't mistake it for a crash. -IPC_MESSAGE_CONTROL0(PluginProcessMsg_NotifyRenderersOfPendingShutdown) - -IPC_MESSAGE_CONTROL3(PluginProcessMsg_ClearSiteData, - std::string /* site */, - uint64_t /* flags */, - uint64_t /* max_age */) - -//----------------------------------------------------------------------------- -// PluginProcessHost messages -// These are messages sent from the plugin process to the browser process. -// Response to a PluginProcessMsg_CreateChannel message. -IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_ChannelCreated, - IPC::ChannelHandle /* channel_handle */) - -IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_ChannelDestroyed, - int /* renderer_id */) - -IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_ClearSiteDataResult, - bool /* success */) - -#if defined(OS_WIN) -// Destroys the given window's parent on the UI thread. -IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_PluginWindowDestroyed, - HWND /* window */, - HWND /* parent */) -#endif - -#if defined(OS_MACOSX) -// On Mac OS X, we need the browser to keep track of plugin windows so -// that it can add and remove them from stacking groups, hide and show the -// menu bar, etc. We pass the window rect for convenience so that the -// browser can easily tell if the window is fullscreen. - -// Notifies the browser that the plugin has shown a window. -IPC_MESSAGE_CONTROL3(PluginProcessHostMsg_PluginShowWindow, - uint32_t /* window ID */, - gfx::Rect /* window rect */, - bool /* modal */) - -// Notifies the browser that the plugin has hidden a window. -IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_PluginHideWindow, - uint32_t /* window ID */, - gfx::Rect /* window rect */) - -// Notifies the browser that a plugin instance has requested a cursor -// visibility change. -IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_PluginSetCursorVisibility, - bool /* cursor visibility */) -#endif diff --git a/chromium/content/common/presentation/presentation_service.mojom b/chromium/content/common/presentation/presentation_service.mojom index ae39815ccce..2c470a52ed3 100644 --- a/chromium/content/common/presentation/presentation_service.mojom +++ b/chromium/content/common/presentation/presentation_service.mojom @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -module presentation; +module content.mojom; struct PresentationSessionInfo { string url; @@ -16,6 +16,12 @@ enum PresentationConnectionState { TERMINATED }; +enum PresentationConnectionCloseReason { + CONNECTION_ERROR, + CLOSED, + WENT_AWAY +}; + enum PresentationErrorType { NO_AVAILABLE_SCREENS, SESSION_REQUEST_CANCELLED, @@ -119,6 +125,12 @@ interface PresentationServiceClient { OnConnectionStateChanged(PresentationSessionInfo connection, PresentationConnectionState newState); + // Caled when the state of |connection| started on this frame has changed to + // CLOSED. + OnConnectionClosed(PresentationSessionInfo connection, + PresentationConnectionCloseReason reason, + string message); + // See PresentationService::ListenForSessionMessages. OnSessionMessagesReceived(PresentationSessionInfo sessionInfo, array<SessionMessage> messages); diff --git a/chromium/content/common/process_control.mojom b/chromium/content/common/process_control.mojom index efd0adc51ce..0734a6cd264 100644 --- a/chromium/content/common/process_control.mojom +++ b/chromium/content/common/process_control.mojom @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -module content; +module content.mojom; -import "mojo/shell/public/interfaces/application.mojom"; +import "mojo/shell/public/interfaces/shell_client.mojom"; interface ProcessControl { - LoadApplication(string url, mojo.Application& request) => (bool success); + LoadApplication(string url, + mojo.shell.mojom.ShellClient& request) => (bool success); }; diff --git a/chromium/content/common/process_type.cc b/chromium/content/common/process_type.cc index 34019d453a6..ebce0e60141 100644 --- a/chromium/content/common/process_type.cc +++ b/chromium/content/common/process_type.cc @@ -15,8 +15,6 @@ std::string GetProcessTypeNameInEnglish(int type) { return "Browser"; case PROCESS_TYPE_RENDERER: return "Tab"; - case PROCESS_TYPE_PLUGIN: - return "Plugin"; case PROCESS_TYPE_UTILITY: return "Utility"; case PROCESS_TYPE_ZYGOTE: diff --git a/chromium/content/common/push_messaging_messages.h b/chromium/content/common/push_messaging_messages.h index 38a39e8cb11..df88b2f2a55 100644 --- a/chromium/content/common/push_messaging_messages.h +++ b/chromium/content/common/push_messaging_messages.h @@ -8,6 +8,7 @@ #include <stdint.h> #include "content/public/common/push_messaging_status.h" +#include "content/public/common/push_subscription_options.h" #include "ipc/ipc_message_macros.h" #include "third_party/WebKit/public/platform/modules/push_messaging/WebPushError.h" #include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h" @@ -29,6 +30,11 @@ IPC_ENUM_TRAITS_MAX_VALUE( blink::WebPushError::ErrorType, blink::WebPushError::ErrorType::ErrorTypeLast) +IPC_STRUCT_TRAITS_BEGIN(content::PushSubscriptionOptions) + IPC_STRUCT_TRAITS_MEMBER(user_visible_only) + IPC_STRUCT_TRAITS_MEMBER(sender_info) +IPC_STRUCT_TRAITS_END() + // Messages sent from the browser to the child process. IPC_MESSAGE_ROUTED4(PushMessagingMsg_SubscribeFromDocumentSuccess, @@ -80,17 +86,16 @@ IPC_MESSAGE_CONTROL2(PushMessagingMsg_GetPermissionStatusError, // Messages sent from the child process to the browser. -IPC_MESSAGE_CONTROL5(PushMessagingHostMsg_SubscribeFromDocument, +IPC_MESSAGE_CONTROL4(PushMessagingHostMsg_SubscribeFromDocument, int32_t /* render_frame_id */, int32_t /* request_id */, - std::string /* sender_id */, - bool /* user_visible */, + content::PushSubscriptionOptions /* options */, int64_t /* service_worker_registration_id */) IPC_MESSAGE_CONTROL3(PushMessagingHostMsg_SubscribeFromWorker, int32_t /* request_id */, int64_t /* service_worker_registration_id */, - bool /* user_visible */) + content::PushSubscriptionOptions /* options */) IPC_MESSAGE_CONTROL2(PushMessagingHostMsg_Unsubscribe, int32_t /* request_id */, diff --git a/chromium/content/common/render_frame_setup.mojom b/chromium/content/common/render_frame_setup.mojom index abe4f652f32..748f733096c 100644 --- a/chromium/content/common/render_frame_setup.mojom +++ b/chromium/content/common/render_frame_setup.mojom @@ -2,12 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -module content; +module content.mojom; -import "mojo/shell/public/interfaces/service_provider.mojom"; +import "mojo/shell/public/interfaces/interface_provider.mojom"; interface RenderFrameSetup { - ExchangeServiceProviders(int32 frame_routing_id, - mojo.ServiceProvider& services, - mojo.ServiceProvider exposed_services); + ExchangeInterfaceProviders( + int32 frame_routing_id, + mojo.shell.mojom.InterfaceProvider& remote_interfaces, + mojo.shell.mojom.InterfaceProvider local_interfaces); }; diff --git a/chromium/content/common/resize_params.cc b/chromium/content/common/resize_params.cc new file mode 100644 index 00000000000..ea9f18fb65b --- /dev/null +++ b/chromium/content/common/resize_params.cc @@ -0,0 +1,20 @@ +// Copyright 2015 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 "content/common/resize_params.h" + +namespace content { + +ResizeParams::ResizeParams() + : top_controls_shrink_blink_size(false), + top_controls_height(0.f), + is_fullscreen_granted(false), + display_mode(blink::WebDisplayModeUndefined), + needs_resize_ack(false) {} + +ResizeParams::ResizeParams(const ResizeParams& other) = default; + +ResizeParams::~ResizeParams() {} + +} // namespace content diff --git a/chromium/content/common/resize_params.h b/chromium/content/common/resize_params.h new file mode 100644 index 00000000000..f9eb07c247d --- /dev/null +++ b/chromium/content/common/resize_params.h @@ -0,0 +1,58 @@ +// Copyright 2015 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 CONTENT_COMMON_RESIZE_PARAMS_H_ +#define CONTENT_COMMON_RESIZE_PARAMS_H_ + +#include "content/common/content_export.h" +#include "third_party/WebKit/public/platform/WebDisplayMode.h" +#include "third_party/WebKit/public/platform/WebScreenInfo.h" +#include "ui/gfx/geometry/size.h" + +namespace content { + +struct CONTENT_EXPORT ResizeParams { + ResizeParams(); + ResizeParams(const ResizeParams& other); + ~ResizeParams(); + + // Information about the screen (dpi, depth, etc..). + blink::WebScreenInfo screen_info; + + // The size of the renderer. + gfx::Size new_size; + + // The size of the view's backing surface in non-DPI-adjusted pixels. + gfx::Size physical_backing_size; + + // Whether or not Blink's viewport size should be shrunk by the height of the + // URL-bar (always false on platforms where URL-bar hiding isn't supported). + bool top_controls_shrink_blink_size; + + // The height of the top controls (always 0 on platforms where URL-bar hiding + // isn't supported). + float top_controls_height; + + // The size of the visible viewport, which may be smaller than the view if the + // view is partially occluded (e.g. by a virtual keyboard). The size is in + // DPI-adjusted pixels. + gfx::Size visible_viewport_size; + + // The resizer rect. + gfx::Rect resizer_rect; + + // Indicates whether tab-initiated fullscreen was granted. + bool is_fullscreen_granted; + + // The display mode. + blink::WebDisplayMode display_mode; + + // If set, requests the renderer to reply with a ViewHostMsg_UpdateRect + // with the ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK bit set in flags. + bool needs_resize_ack; +}; + +} // namespace content + +#endif // CONTENT_COMMON_RESIZE_PARAMS_H_ diff --git a/chromium/content/common/resource_messages.cc b/chromium/content/common/resource_messages.cc index da92b97b09b..2c0cbe12b7b 100644 --- a/chromium/content/common/resource_messages.cc +++ b/chromium/content/common/resource_messages.cc @@ -9,8 +9,9 @@ namespace IPC { -void ParamTraits<scoped_refptr<net::HttpResponseHeaders> >::Write( - Message* m, const param_type& p) { +void ParamTraits<scoped_refptr<net::HttpResponseHeaders>>::Write( + base::Pickle* m, + const param_type& p) { WriteParam(m, p.get() != NULL); if (p.get()) { // Do not disclose Set-Cookie headers over IPC. @@ -19,7 +20,7 @@ void ParamTraits<scoped_refptr<net::HttpResponseHeaders> >::Write( } bool ParamTraits<scoped_refptr<net::HttpResponseHeaders>>::Read( - const Message* m, + const base::Pickle* m, base::PickleIterator* iter, param_type* r) { bool has_object; @@ -35,7 +36,8 @@ void ParamTraits<scoped_refptr<net::HttpResponseHeaders> >::Log( l->append("<HttpResponseHeaders>"); } -void ParamTraits<storage::DataElement>::Write(Message* m, const param_type& p) { +void ParamTraits<storage::DataElement>::Write(base::Pickle* m, + const param_type& p) { WriteParam(m, static_cast<int>(p.type())); switch (p.type()) { case storage::DataElement::TYPE_BYTES: { @@ -77,7 +79,7 @@ void ParamTraits<storage::DataElement>::Write(Message* m, const param_type& p) { } } -bool ParamTraits<storage::DataElement>::Read(const Message* m, +bool ParamTraits<storage::DataElement>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int type; @@ -160,8 +162,9 @@ void ParamTraits<storage::DataElement>::Log(const param_type& p, l->append("<storage::DataElement>"); } -void ParamTraits<scoped_refptr<content::ResourceDevToolsInfo> >::Write( - Message* m, const param_type& p) { +void ParamTraits<scoped_refptr<content::ResourceDevToolsInfo>>::Write( + base::Pickle* m, + const param_type& p) { WriteParam(m, p.get() != NULL); if (p.get()) { WriteParam(m, p->http_status_code); @@ -174,7 +177,7 @@ void ParamTraits<scoped_refptr<content::ResourceDevToolsInfo> >::Write( } bool ParamTraits<scoped_refptr<content::ResourceDevToolsInfo>>::Read( - const Message* m, + const base::Pickle* m, base::PickleIterator* iter, param_type* r) { bool has_object; @@ -203,8 +206,8 @@ void ParamTraits<scoped_refptr<content::ResourceDevToolsInfo> >::Log( l->append(")"); } -void ParamTraits<net::LoadTimingInfo>::Write( - Message* m, const param_type& p) { +void ParamTraits<net::LoadTimingInfo>::Write(base::Pickle* m, + const param_type& p) { WriteParam(m, p.socket_log_id); WriteParam(m, p.socket_reused); WriteParam(m, p.request_start_time.is_null()); @@ -225,7 +228,7 @@ void ParamTraits<net::LoadTimingInfo>::Write( WriteParam(m, p.receive_headers_end); } -bool ParamTraits<net::LoadTimingInfo>::Read(const Message* m, +bool ParamTraits<net::LoadTimingInfo>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { bool has_no_times; @@ -288,8 +291,8 @@ void ParamTraits<net::LoadTimingInfo>::Log(const param_type& p, l->append(")"); } -void ParamTraits<scoped_refptr<content::ResourceRequestBody> >::Write( - Message* m, +void ParamTraits<scoped_refptr<content::ResourceRequestBody>>::Write( + base::Pickle* m, const param_type& p) { WriteParam(m, p.get() != NULL); if (p.get()) { @@ -299,7 +302,7 @@ void ParamTraits<scoped_refptr<content::ResourceRequestBody> >::Write( } bool ParamTraits<scoped_refptr<content::ResourceRequestBody>>::Read( - const Message* m, + const base::Pickle* m, base::PickleIterator* iter, param_type* r) { bool has_object; diff --git a/chromium/content/common/resource_messages.h b/chromium/content/common/resource_messages.h index 44e4a611fc7..9c53b361a33 100644 --- a/chromium/content/common/resource_messages.h +++ b/chromium/content/common/resource_messages.h @@ -39,40 +39,50 @@ namespace IPC { template <> struct ParamTraits<scoped_refptr<net::HttpResponseHeaders> > { typedef scoped_refptr<net::HttpResponseHeaders> param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct CONTENT_EXPORT ParamTraits<storage::DataElement> { typedef storage::DataElement param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct ParamTraits<scoped_refptr<content::ResourceDevToolsInfo> > { typedef scoped_refptr<content::ResourceDevToolsInfo> param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct ParamTraits<net::LoadTimingInfo> { typedef net::LoadTimingInfo param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct ParamTraits<scoped_refptr<content::ResourceRequestBody> > { typedef scoped_refptr<content::ResourceRequestBody> param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; @@ -139,6 +149,8 @@ IPC_STRUCT_TRAITS_BEGIN(content::ResourceResponseInfo) IPC_STRUCT_TRAITS_MEMBER(response_type_via_service_worker) IPC_STRUCT_TRAITS_MEMBER(service_worker_start_time) IPC_STRUCT_TRAITS_MEMBER(service_worker_ready_time) + IPC_STRUCT_TRAITS_MEMBER(is_in_cache_storage) + IPC_STRUCT_TRAITS_MEMBER(cache_storage_cache_name) IPC_STRUCT_TRAITS_MEMBER(proxy_server) IPC_STRUCT_TRAITS_MEMBER(is_using_lofi) IPC_STRUCT_TRAITS_END() @@ -149,6 +161,7 @@ IPC_STRUCT_TRAITS_BEGIN(net::RedirectInfo) IPC_STRUCT_TRAITS_MEMBER(new_url) IPC_STRUCT_TRAITS_MEMBER(new_first_party_for_cookies) IPC_STRUCT_TRAITS_MEMBER(new_referrer) + IPC_STRUCT_TRAITS_MEMBER(referred_token_binding_host) IPC_STRUCT_TRAITS_END() // Parameters for a resource request. @@ -213,6 +226,10 @@ IPC_STRUCT_BEGIN(ResourceHostMsg_Request) // or kInvalidServiceWorkerProviderId. IPC_STRUCT_MEMBER(int, service_worker_provider_id) + // True if the request originated from a Service Worker, e.g. due to a + // fetch() in the Service Worker script. + IPC_STRUCT_MEMBER(bool, originated_from_service_worker) + // True if the request should not be handled by the ServiceWorker. IPC_STRUCT_MEMBER(bool, skip_service_worker) @@ -284,6 +301,11 @@ IPC_STRUCT_BEGIN(ResourceHostMsg_Request) // Whether or not to request a LoFi version of the resource or let the browser // decide. IPC_STRUCT_MEMBER(content::LoFiState, lofi_state) + + // PlzNavigate: the stream url associated with a navigation. Used to get + // access to the body of the response that has already been fetched by the + // browser. + IPC_STRUCT_MEMBER(GURL, resource_body_stream_url) IPC_STRUCT_END() // Parameters for a ResourceMsg_RequestComplete @@ -355,6 +377,19 @@ IPC_MESSAGE_CONTROL4(ResourceMsg_SetDataBuffer, IPC_MESSAGE_CONTROL2(ResourceMsg_DataReceivedDebug, int /* request_id */, int /* data_offset */) +IPC_MESSAGE_CONTROL4(ResourceMsg_DataReceivedDebug2, + int /* request_id */, + int /* data_offset */, + int /* data_length */, + int /* encoded_data_length */) + +// Sent when a chunk of data from a resource request is ready, and the resource +// is expected to be small enough to fit in the inlined buffer. +// The data is sent as a part of IPC message. +IPC_MESSAGE_CONTROL3(ResourceMsg_InlinedDataChunkReceived, + int /* request_id */, + std::vector<char> /* data */, + int /* encoded_data_length */) // Sent when some data from a resource request is ready. The data offset and // length specify a byte range into the shared memory buffer provided by the diff --git a/chromium/content/common/sandbox_init_mac.cc b/chromium/content/common/sandbox_init_mac.cc index c49aa80685e..36a4058c35e 100644 --- a/chromium/content/common/sandbox_init_mac.cc +++ b/chromium/content/common/sandbox_init_mac.cc @@ -53,8 +53,7 @@ bool GetSandboxTypeFromCommandLine(int* sandbox_type, if (command_line.HasSwitch(switches::kDisableGpuSandbox)) return false; *sandbox_type = SANDBOX_TYPE_GPU; - } else if ((process_type == switches::kPluginProcess) || - (process_type == switches::kPpapiBrokerProcess)) { + } else if (process_type == switches::kPpapiBrokerProcess) { return false; } else if (process_type == switches::kPpapiPluginProcess) { *sandbox_type = SANDBOX_TYPE_PPAPI; @@ -75,12 +74,4 @@ bool InitializeSandbox() { return InitializeSandbox(sandbox_type, allowed_dir); } -bool BrokerDuplicateSharedMemoryHandle( - const base::SharedMemoryHandle& source_handle, - base::ProcessId target_process_id, - base::SharedMemoryHandle* target_handle) { - *target_handle = base::SharedMemory::DuplicateHandle(source_handle); - return base::SharedMemory::IsHandleValid(*target_handle); -} - } // namespace content diff --git a/chromium/content/common/sandbox_init_win.cc b/chromium/content/common/sandbox_init_win.cc index 78c1fef251d..16e3e4afbd4 100644 --- a/chromium/content/common/sandbox_init_win.cc +++ b/chromium/content/common/sandbox_init_win.cc @@ -42,19 +42,4 @@ bool InitializeSandbox(sandbox::SandboxInterfaceInfo* sandbox_info) { return InitTargetServices(target_services); } -bool BrokerDuplicateSharedMemoryHandle( - const base::SharedMemoryHandle& source_handle, - base::ProcessId target_process_id, - base::SharedMemoryHandle* target_handle) { - HANDLE duped_handle; - if (!BrokerDuplicateHandle( - source_handle.GetHandle(), target_process_id, &duped_handle, - FILE_MAP_READ | FILE_MAP_WRITE | SECTION_QUERY, 0)) { - return false; - } - - *target_handle = base::SharedMemoryHandle(duped_handle, target_process_id); - return true; -} - } // namespace content diff --git a/chromium/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc b/chromium/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc index c3b1605fc7d..5f9813f5808 100644 --- a/chromium/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc +++ b/chromium/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc @@ -4,17 +4,51 @@ #include "content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.h" +#include <errno.h> +#include <fcntl.h> +#include <linux/net.h> +#include <sys/socket.h> #include <sys/syscall.h> #include <sys/types.h> #include "build/build_config.h" #include "sandbox/linux/bpf_dsl/bpf_dsl.h" +using sandbox::bpf_dsl::AllOf; using sandbox::bpf_dsl::Allow; +using sandbox::bpf_dsl::AnyOf; +using sandbox::bpf_dsl::Arg; +using sandbox::bpf_dsl::BoolExpr; +using sandbox::bpf_dsl::If; +using sandbox::bpf_dsl::Error; using sandbox::bpf_dsl::ResultExpr; namespace content { +#ifndef SOCK_CLOEXEC +#define SOCK_CLOEXEC O_CLOEXEC +#endif + +#ifndef SOCK_NONBLOCK +#define SOCK_NONBLOCK O_NONBLOCK +#endif + +namespace { + +// Restricts the arguments to sys_socket() to AF_UNIX. Returns a BoolExpr that +// evaluates to true if the syscall should be allowed. +BoolExpr RestrictSocketArguments(const Arg<int>& domain, + const Arg<int>& type, + const Arg<int>& protocol) { + const int kSockFlags = SOCK_CLOEXEC | SOCK_NONBLOCK; + return AllOf(domain == AF_UNIX, + AnyOf((type & ~kSockFlags) == SOCK_DGRAM, + (type & ~kSockFlags) == SOCK_STREAM), + protocol == 0); +} + +} // namespace + SandboxBPFBasePolicyAndroid::SandboxBPFBasePolicyAndroid() : SandboxBPFBasePolicy() {} @@ -27,11 +61,19 @@ ResultExpr SandboxBPFBasePolicyAndroid::EvaluateSyscall(int sysno) const { // TODO(rsesek): restrict clone parameters. case __NR_clone: case __NR_epoll_pwait: + case __NR_fdatasync: case __NR_flock: + case __NR_fsync: + case __NR_ftruncate: +#if defined(__i386__) || defined(__arm__) || defined(__mips__) + case __NR_ftruncate64: +#endif #if defined(__x86_64__) || defined(__aarch64__) case __NR_newfstatat: + case __NR_getdents64: #elif defined(__i386__) || defined(__arm__) || defined(__mips__) case __NR_fstatat64: + case __NR_getdents: #endif case __NR_getpriority: case __NR_ioctl: @@ -46,7 +88,11 @@ ResultExpr SandboxBPFBasePolicyAndroid::EvaluateSyscall(int sysno) const { #endif case __NR_openat: case __NR_pread64: + case __NR_pwrite64: case __NR_rt_sigtimedwait: + case __NR_sched_getparam: + case __NR_sched_getscheduler: + case __NR_sched_setscheduler: case __NR_setpriority: case __NR_set_tid_address: case __NR_sigaltstack: @@ -56,10 +102,49 @@ ResultExpr SandboxBPFBasePolicyAndroid::EvaluateSyscall(int sysno) const { case __NR_getrlimit: #endif case __NR_uname: + + // Permit socket operations so that renderers can connect to logd and + // debuggerd. The arguments to socket() are further restricted below. + // Note that on i386, both of these calls map to __NR_socketcall, which + // is demultiplexed below. +#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || \ + defined(__mips__) + case __NR_getsockopt: + case __NR_connect: + case __NR_socket: +#endif + + // Ptrace is allowed so the Breakpad Microdumper can fork in a renderer + // and then ptrace the parent. + case __NR_ptrace: override_and_allow = true; break; } +#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || \ + defined(__mips__) + if (sysno == __NR_socket) { + const Arg<int> domain(0); + const Arg<int> type(1); + const Arg<int> protocol(2); + return If(RestrictSocketArguments(domain, type, protocol), Allow()) + .Else(Error(EPERM)); + } +#elif defined(__i386__) + if (sysno == __NR_socketcall) { + const Arg<int> socketcall(0); + const Arg<int> domain(1); + const Arg<int> type(2); + const Arg<int> protocol(3); + return If(socketcall == SYS_CONNECT, Allow()) + .ElseIf(AllOf(socketcall == SYS_SOCKET, + RestrictSocketArguments(domain, type, protocol)), + Allow()) + .ElseIf(socketcall == SYS_GETSOCKOPT, Allow()) + .Else(Error(EPERM)); + } +#endif + if (override_and_allow) return Allow(); diff --git a/chromium/content/common/sandbox_linux/bpf_renderer_policy_linux.cc b/chromium/content/common/sandbox_linux/bpf_renderer_policy_linux.cc index e799273919a..b6a960ceef3 100644 --- a/chromium/content/common/sandbox_linux/bpf_renderer_policy_linux.cc +++ b/chromium/content/common/sandbox_linux/bpf_renderer_policy_linux.cc @@ -15,8 +15,17 @@ #include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h" #include "sandbox/linux/system_headers/linux_syscalls.h" -#if defined(USE_VGEM_MAP) -#include <libdrm/vgem_drm.h> +#if defined(OS_CHROMEOS) +// TODO(vignatti): replace the local definitions below with #include +// <linux/dma-buf.h> once kernel version 4.6 becomes widely used. +#include <linux/types.h> + +struct local_dma_buf_sync { + __u64 flags; +}; +#define LOCAL_DMA_BUF_BASE 'b' +#define LOCAL_DMA_BUF_IOCTL_SYNC \ + _IOW(LOCAL_DMA_BUF_BASE, 0, struct local_dma_buf_sync) #endif using sandbox::SyscallSets; @@ -34,12 +43,9 @@ ResultExpr RestrictIoctl() { return Switch(request) .SANDBOX_BPF_DSL_CASES((static_cast<unsigned long>(TCGETS), FIONREAD), Allow()) -#if defined(USE_VGEM_MAP) - // Type of DRM_IOCTL_XXX is unsigned long on IA and unsigned int on ARM. +#if defined(OS_CHROMEOS) .SANDBOX_BPF_DSL_CASES( - (static_cast<unsigned long>(DRM_IOCTL_GEM_CLOSE), - DRM_IOCTL_VGEM_MODE_MAP_DUMB, DRM_IOCTL_PRIME_FD_TO_HANDLE), - Allow()) + (static_cast<unsigned long>(LOCAL_DMA_BUF_IOCTL_SYNC)), Allow()) #endif .Default(sandbox::CrashSIGSYSIoctl()); } @@ -60,7 +66,8 @@ ResultExpr RendererProcessPolicy::EvaluateSyscall(int sysno) const { // Allow the system calls below. case __NR_fdatasync: case __NR_fsync: -#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) +#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \ + defined(__aarch64__) case __NR_getrlimit: #endif #if defined(__i386__) || defined(__arm__) diff --git a/chromium/content/common/sandbox_linux/bpf_utility_policy_linux.cc b/chromium/content/common/sandbox_linux/bpf_utility_policy_linux.cc index 3ead1c899d2..13367964e64 100644 --- a/chromium/content/common/sandbox_linux/bpf_utility_policy_linux.cc +++ b/chromium/content/common/sandbox_linux/bpf_utility_policy_linux.cc @@ -32,7 +32,8 @@ ResultExpr UtilityProcessPolicy::EvaluateSyscall(int sysno) const { // Allow the system calls below. case __NR_fdatasync: case __NR_fsync: -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \ + defined(__aarch64__) case __NR_getrlimit: #endif #if defined(__i386__) || defined(__arm__) diff --git a/chromium/content/common/sandbox_linux/sandbox_linux.h b/chromium/content/common/sandbox_linux/sandbox_linux.h index 0a80479799f..7ce723b3771 100644 --- a/chromium/content/common/sandbox_linux/sandbox_linux.h +++ b/chromium/content/common/sandbox_linux/sandbox_linux.h @@ -42,7 +42,7 @@ namespace content { class LinuxSandbox { public: // This is a list of sandbox IPC methods which the renderer may send to the - // sandbox host. See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC + // sandbox host. See https://chromium.googlesource.com/chromium/src/+/master/docs/linux_sandbox_ipc.md // This isn't the full list, values < 32 are reserved for methods called from // Skia. enum LinuxSandboxIPCMethods { diff --git a/chromium/content/common/sandbox_mac.h b/chromium/content/common/sandbox_mac.h index bac23f0df8c..afda387549f 100644 --- a/chromium/content/common/sandbox_mac.h +++ b/chromium/content/common/sandbox_mac.h @@ -50,9 +50,6 @@ class CONTENT_EXPORT SandboxCompiler { bool CompileAndApplyProfile(std::string* error); private: - // Frees all of the system resources allocated for the sandbox. - void FreeSandboxResources(void* profile, void* params, char* error); - // Storage of the key/value pairs of strings that are used in the sandbox // profile. std::map<std::string, std::string> params_map_; diff --git a/chromium/content/common/sandbox_mac.mm b/chromium/content/common/sandbox_mac.mm index ca915a739e8..6a7f2cfcc74 100644 --- a/chromium/content/common/sandbox_mac.mm +++ b/chromium/content/common/sandbox_mac.mm @@ -47,14 +47,10 @@ extern "C" { void CGSSetDenyWindowServerConnections(bool); void CGSShutdownServerConnections(); -void* sandbox_create_params(); -int sandbox_set_param(void* params, const char* key, const char* value); -void* sandbox_compile_string(const char* profile_str, - void* params, - char** error); -int sandbox_apply(void* profile); -void sandbox_free_params(void* params); -void sandbox_free_profile(void* profile); +int sandbox_init_with_parameters(const char* profile, + uint64_t flags, + const char* const parameters[], + char** errorbuf); }; namespace content { @@ -68,14 +64,6 @@ struct SandboxTypeToResourceIDMapping { int sandbox_profile_resource_id; }; -// This is the internal definition of the structure used by sandbox parameters -// on OS X 10.6. -struct SandboxParams { - void* buf; - size_t count; - size_t size; -}; - // Mapping from sandbox process types to resource IDs containing the sandbox // profile for all process types known to content. SandboxTypeToResourceIDMapping kDefaultSandboxTypeToResourceIDMapping[] = { @@ -153,58 +141,27 @@ bool SandboxCompiler::InsertStringParam(const std::string& key, return params_map_.insert(std::make_pair(key, value)).second; } -void SandboxCompiler::FreeSandboxResources(void* profile, - void* params, - char* error) { - if (error) - sandbox_free_error(error); - if (params) - sandbox_free_params(params); - if (profile) - sandbox_free_profile(profile); -} - bool SandboxCompiler::CompileAndApplyProfile(std::string* error) { char* error_internal = nullptr; - void* profile = nullptr; - void* params = nullptr; - - if (!params_map_.empty()) { - if (base::mac::IsOSSnowLeopard()) { - // This is a workaround for 10.6, see crbug.com/509114. - // Check that there is no integer overflow. - base::CheckedNumeric<size_t> checked_size = params_map_.size(); - checked_size *= 2; - if (!checked_size.IsValid()) - return false; - - SandboxParams* internal_params = - static_cast<SandboxParams*>(malloc(sizeof(SandboxParams))); - internal_params->buf = calloc(checked_size.ValueOrDie(), sizeof(void*)); - internal_params->count = 0; - internal_params->size = checked_size.ValueOrDie(); - params = internal_params; - } else { - params = sandbox_create_params(); - if (!params) - return false; - } + std::vector<const char*> params; - for (const auto& kv : params_map_) - sandbox_set_param(params, kv.first.c_str(), kv.second.c_str()); + for (const auto& kv : params_map_) { + params.push_back(kv.first.c_str()); + params.push_back(kv.second.c_str()); } + // The parameters array must be null terminated. + params.push_back(static_cast<const char*>(0)); - profile = - sandbox_compile_string(profile_str_.c_str(), params, &error_internal); - if (!profile) { + if (sandbox_init_with_parameters(profile_str_.c_str(), 0, params.data(), + &error_internal)) { error->assign(error_internal); - FreeSandboxResources(profile, params, error_internal); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + sandbox_free_error(error_internal); +#pragma clang diagnostic pop return false; } - - int result = sandbox_apply(profile); - FreeSandboxResources(profile, params, error_internal); - return result == 0; + return true; } // static @@ -534,16 +491,6 @@ bool Sandbox::EnableSandbox(int sandbox_type, if (!compiler.InsertBooleanParam("ELCAP_OR_LATER", elcap_or_later)) return false; -#if defined(COMPONENT_BUILD) - // dlopen() fails without file-read-metadata access if the executable image - // contains LC_RPATH load commands. The components build uses those. - // See http://crbug.com/127465 - if (base::mac::IsOSSnowLeopard()) { - if (!compiler.InsertBooleanParam("COMPONENT_BUILD_WORKAROUND", true)) - return false; - } -#endif - // Initialize sandbox. std::string error_str; bool success = compiler.CompileAndApplyProfile(&error_str); diff --git a/chromium/content/common/sandbox_mac_diraccess_unittest.mm b/chromium/content/common/sandbox_mac_diraccess_unittest.mm index 17be671801a..205e1cbc0b9 100644 --- a/chromium/content/common/sandbox_mac_diraccess_unittest.mm +++ b/chromium/content/common/sandbox_mac_diraccess_unittest.mm @@ -13,6 +13,7 @@ extern "C" { #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/macros.h" +#include "base/memory/scoped_ptr.h" #include "base/process/kill.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" diff --git a/chromium/content/common/sandbox_mac_system_access_unittest.mm b/chromium/content/common/sandbox_mac_system_access_unittest.mm index 02980715609..b37b967d2b9 100644 --- a/chromium/content/common/sandbox_mac_system_access_unittest.mm +++ b/chromium/content/common/sandbox_mac_system_access_unittest.mm @@ -9,11 +9,13 @@ #include "base/files/file_util.h" #include "base/files/scoped_file.h" #include "base/logging.h" +#include "base/memory/ref_counted.h" #include "base/strings/sys_string_conversions.h" #include "content/common/sandbox_mac.h" #include "content/common/sandbox_mac_unittest_helper.h" #include "crypto/openssl_util.h" #include "testing/gtest/include/gtest/gtest.h" +#import "ui/base/clipboard/clipboard_util_mac.h" namespace content { @@ -69,15 +71,16 @@ void MacSandboxedClipboardTestCase::SetTestData(const char* test_data) { } TEST_F(MacSandboxTest, ClipboardAccess) { - NSPasteboard* pb = [NSPasteboard pasteboardWithUniqueName]; - EXPECT_EQ([[pb types] count], 0U); + scoped_refptr<ui::UniquePasteboard> pb = new ui::UniquePasteboard; + ASSERT_TRUE(pb->get()); + EXPECT_EQ([[pb->get() types] count], 0U); - std::string pasteboard_name = base::SysNSStringToUTF8([pb name]); + std::string pasteboard_name = base::SysNSStringToUTF8([pb->get() name]); EXPECT_TRUE(RunTestInAllSandboxTypes("MacSandboxedClipboardTestCase", pasteboard_name.c_str())); // After executing the test, the clipboard should still be empty. - EXPECT_EQ([[pb types] count], 0U); + EXPECT_EQ([[pb->get() types] count], 0U); } //--------------------- File Access Sandboxing ---------------------- diff --git a/chromium/content/common/sandbox_util.cc b/chromium/content/common/sandbox_util.cc index 4b1dcef4a91..75b3977f4d6 100644 --- a/chromium/content/common/sandbox_util.cc +++ b/chromium/content/common/sandbox_util.cc @@ -6,6 +6,7 @@ #include "build/build_config.h" #include "content/public/common/sandbox_init.h" +#include "ipc/ipc_platform_file.h" #if defined(OS_POSIX) #include <unistd.h> @@ -17,30 +18,7 @@ IPC::PlatformFileForTransit BrokerGetFileHandleForProcess( base::PlatformFile handle, base::ProcessId target_process_id, bool should_close_source) { - IPC::PlatformFileForTransit out_handle; -#if defined(OS_WIN) - DWORD options = DUPLICATE_SAME_ACCESS; - if (should_close_source) - options |= DUPLICATE_CLOSE_SOURCE; - if (!content::BrokerDuplicateHandle(handle, target_process_id, &out_handle, - 0, options)) { - out_handle = IPC::InvalidPlatformFileForTransit(); - } -#elif defined(OS_POSIX) - // If asked to close the source, we can simply re-use the source fd instead of - // dup()ing and close()ing. - // When we're not closing the source, we need to duplicate the handle and take - // ownership of that. The reason is that this function is often used to - // generate IPC messages, and the handle must remain valid until it's sent to - // the other process from the I/O thread. Without the dup, calling code might - // close the source handle before the message is sent, creating a race - // condition. - int fd = should_close_source ? handle : ::dup(handle); - out_handle = base::FileDescriptor(fd, true); -#else - #error Not implemented. -#endif - return out_handle; + return IPC::GetPlatformFileForTransit(handle, should_close_source); } } // namespace content diff --git a/chromium/content/common/sandbox_win.cc b/chromium/content/common/sandbox_win.cc index 92a5a241f57..fe266227ad8 100644 --- a/chromium/content/common/sandbox_win.cc +++ b/chromium/content/common/sandbox_win.cc @@ -32,7 +32,6 @@ #include "content/common/content_switches_internal.h" #include "content/public/common/content_client.h" #include "content/public/common/content_switches.h" -#include "content/public/common/dwrite_font_platform_win.h" #include "content/public/common/sandbox_init.h" #include "content/public/common/sandboxed_process_launcher_delegate.h" #include "sandbox/win/src/process_mitigations.h" @@ -403,7 +402,6 @@ bool AddPolicyForSandboxedProcess(sandbox::TargetPolicy* policy) { if (result != sandbox::SBOX_ALL_OK) return false; - sandbox::TokenLevel initial_token = sandbox::USER_UNPROTECTED; if (base::win::GetVersion() > base::win::VERSION_XP) { // On 2003/Vista the initial token has to be restricted if the main @@ -415,6 +413,7 @@ bool AddPolicyForSandboxedProcess(sandbox::TargetPolicy* policy) { // Prevents the renderers from manipulating low-integrity processes. policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED); policy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); + policy->SetLockdownDefaultDacl(); if (sandbox::SBOX_ALL_OK != policy->SetAlternateDesktop(true)) { DLOG(WARNING) << "Failed to apply desktop security to the renderer"; @@ -665,7 +664,8 @@ bool InitTargetServices(sandbox::TargetServices* target_services) { base::Process StartSandboxedProcess( SandboxedProcessLauncherDelegate* delegate, - base::CommandLine* cmd_line) { + base::CommandLine* cmd_line, + const base::HandlesToInheritVector& handles_to_inherit) { DCHECK(delegate); const base::CommandLine& browser_command_line = *base::CommandLine::ForCurrentProcess(); @@ -684,20 +684,41 @@ base::Process StartSandboxedProcess( if ((!delegate->ShouldSandbox()) || browser_command_line.HasSwitch(switches::kNoSandbox) || cmd_line->HasSwitch(switches::kNoSandbox)) { - base::Process process = - base::LaunchProcess(*cmd_line, base::LaunchOptions()); + base::LaunchOptions options; + + base::HandlesToInheritVector handles = handles_to_inherit; + if (!handles_to_inherit.empty()) { + options.inherit_handles = true; + options.handles_to_inherit = &handles; + } + base::Process process = base::LaunchProcess(*cmd_line, options); + // TODO(rvargas) crbug.com/417532: Don't share a raw handle. g_broker_services->AddTargetPeer(process.Handle()); - return process.Pass(); + return process; } sandbox::TargetPolicy* policy = g_broker_services->CreatePolicy(); - sandbox::MitigationFlags mitigations = sandbox::MITIGATION_HEAP_TERMINATE | - sandbox::MITIGATION_BOTTOM_UP_ASLR | - sandbox::MITIGATION_DEP | - sandbox::MITIGATION_DEP_NO_ATL_THUNK | - sandbox::MITIGATION_SEHOP; + // Add any handles to be inherited to the policy. + for (HANDLE handle : handles_to_inherit) + policy->AddHandleToShare(handle); + + // Pre-startup mitigations. + sandbox::MitigationFlags mitigations = + sandbox::MITIGATION_HEAP_TERMINATE | + sandbox::MITIGATION_BOTTOM_UP_ASLR | + sandbox::MITIGATION_DEP | + sandbox::MITIGATION_DEP_NO_ATL_THUNK | + sandbox::MITIGATION_SEHOP | + sandbox::MITIGATION_NONSYSTEM_FONT_DISABLE | + sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE | + sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL; +#if !defined(NACL_WIN64) + // Don't block font loading with GDI. + if (!gfx::win::ShouldUseDirectWrite()) + mitigations ^= sandbox::MITIGATION_NONSYSTEM_FONT_DISABLE; +#endif if (policy->SetProcessMitigations(mitigations) != sandbox::SBOX_ALL_OK) return base::Process(); @@ -710,6 +731,7 @@ base::Process StartSandboxedProcess( } #endif + // Post-startup mitigations. mitigations = sandbox::MITIGATION_STRICT_HANDLE_CHECKS | sandbox::MITIGATION_DLL_SEARCH_ORDER; @@ -724,6 +746,9 @@ base::Process StartSandboxedProcess( } #if !defined(NACL_WIN64) + // NOTE: This is placed at function scope so that it stays alive through + // process launch. + base::SharedMemory direct_write_font_cache_section; if (type_str == switches::kRendererProcess || type_str == switches::kPpapiPluginProcess) { if (gfx::win::ShouldUseDirectWrite()) { @@ -732,25 +757,6 @@ base::Process StartSandboxedProcess( true, sandbox::TargetPolicy::FILES_ALLOW_READONLY, policy); - - if (!ShouldUseDirectWriteFontProxyFieldTrial()) { - // If DirectWrite is enabled for font rendering then open the font - // cache section which is created by the browser and pass the handle to - // the renderer process. This is needed because renderer processes on - // Windows 8+ may be running in an AppContainer sandbox and hence their - // kernel object namespace may be partitioned. - std::string name(content::kFontCacheSharedSectionName); - name.append(base::UintToString(base::GetCurrentProcId())); - - base::SharedMemory direct_write_font_cache_section; - if (direct_write_font_cache_section.Open(name, true)) { - void* shared_handle = policy->AddHandleToShare( - direct_write_font_cache_section.handle().GetHandle()); - cmd_line->AppendSwitchASCII( - switches::kFontCacheSharedHandle, - base::UintToString(base::win::HandleToUint32(shared_handle))); - } - } } } #endif diff --git a/chromium/content/common/service_port_service.mojom b/chromium/content/common/service_port_service.mojom deleted file mode 100644 index d5bbb58a497..00000000000 --- a/chromium/content/common/service_port_service.mojom +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015 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. - -module content; - -enum ServicePortConnectResult { - ACCEPT, - REJECT -}; - -struct MojoTransferredMessagePort { - int32 id; - bool send_messages_as_values; -}; - -interface ServicePortService { - SetClient(ServicePortServiceClient client); - - Connect(string target_url, string origin) - => (ServicePortConnectResult result, int32 port_id); - - PostMessageToPort(int32 port_id, string message, - array<MojoTransferredMessagePort> ports); - ClosePort(int32 port_id); -}; - -interface ServicePortServiceClient { - PostMessageToPort(int32 port_id, string message, - array<MojoTransferredMessagePort> ports, - array<int32> new_routing_ids); -}; - -interface ServicePortDispatcher { - Connect(string target_url, string origin, int32 port_id) - => (ServicePortConnectResult result, string name, string data); -}; diff --git a/chromium/content/common/service_port_type_converters.cc b/chromium/content/common/service_port_type_converters.cc deleted file mode 100644 index c07a946a972..00000000000 --- a/chromium/content/common/service_port_type_converters.cc +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015 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 "content/common/service_port_type_converters.h" - -namespace mojo { - -// static -content::TransferredMessagePort -TypeConverter<content::TransferredMessagePort, - content::MojoTransferredMessagePortPtr>:: - Convert(const content::MojoTransferredMessagePortPtr& input) { - content::TransferredMessagePort output; - output.id = input->id; - output.send_messages_as_values = input->send_messages_as_values; - return output; -} - -// static -content::MojoTransferredMessagePortPtr -TypeConverter<content::MojoTransferredMessagePortPtr, - content::TransferredMessagePort>:: - Convert(const content::TransferredMessagePort& input) { - content::MojoTransferredMessagePortPtr output( - content::MojoTransferredMessagePort::New()); - output->id = input.id; - output->send_messages_as_values = input.send_messages_as_values; - return output; -} - -} // namespace mojo diff --git a/chromium/content/common/service_port_type_converters.h b/chromium/content/common/service_port_type_converters.h deleted file mode 100644 index 70e01f9329c..00000000000 --- a/chromium/content/common/service_port_type_converters.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2015 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 CONTENT_COMMON_SERVICE_PORT_TYPE_CONVERTERS_H_ -#define CONTENT_COMMON_SERVICE_PORT_TYPE_CONVERTERS_H_ - -#include "content/common/content_export.h" -#include "content/common/service_port_service.mojom.h" -#include "content/public/common/message_port_types.h" -#include "mojo/public/cpp/bindings/type_converter.h" - -namespace mojo { - -template <> -struct CONTENT_EXPORT TypeConverter<content::TransferredMessagePort, - content::MojoTransferredMessagePortPtr> { - static content::TransferredMessagePort Convert( - const content::MojoTransferredMessagePortPtr& input); -}; - -template <> -struct CONTENT_EXPORT TypeConverter<content::MojoTransferredMessagePortPtr, - content::TransferredMessagePort> { - static content::MojoTransferredMessagePortPtr Convert( - const content::TransferredMessagePort& input); -}; - -} // namespace mojo - -#endif // CONTENT_COMMON_SERVICE_PORT_TYPE_CONVERTERS_H_ diff --git a/chromium/content/common/service_worker/embedded_worker_messages.h b/chromium/content/common/service_worker/embedded_worker_messages.h index fc9f02ea343..86fb48c8507 100644 --- a/chromium/content/common/service_worker/embedded_worker_messages.h +++ b/chromium/content/common/service_worker/embedded_worker_messages.h @@ -8,6 +8,7 @@ #include <string> +#include "content/common/service_worker/embedded_worker_settings.h" #include "content/public/common/web_preferences.h" #include "ipc/ipc_message.h" #include "ipc/ipc_message_macros.h" @@ -19,6 +20,11 @@ #define IPC_MESSAGE_START EmbeddedWorkerMsgStart +IPC_STRUCT_TRAITS_BEGIN(content::EmbeddedWorkerSettings) + IPC_STRUCT_TRAITS_MEMBER(v8_cache_options) + IPC_STRUCT_TRAITS_MEMBER(data_saver_enabled) +IPC_STRUCT_TRAITS_END() + // Parameters structure for EmbeddedWorkerMsg_StartWorker. IPC_STRUCT_BEGIN(EmbeddedWorkerMsg_StartWorker_Params) IPC_STRUCT_MEMBER(int, embedded_worker_id) @@ -26,8 +32,10 @@ IPC_STRUCT_BEGIN(EmbeddedWorkerMsg_StartWorker_Params) IPC_STRUCT_MEMBER(GURL, scope) IPC_STRUCT_MEMBER(GURL, script_url) IPC_STRUCT_MEMBER(int, worker_devtools_agent_route_id) + IPC_STRUCT_MEMBER(bool, pause_after_download) IPC_STRUCT_MEMBER(bool, wait_for_debugger) - IPC_STRUCT_MEMBER(content::V8CacheOptions, v8_cache_options) + IPC_STRUCT_MEMBER(bool, is_installed) + IPC_STRUCT_MEMBER(content::EmbeddedWorkerSettings, settings) IPC_STRUCT_END() // Parameters structure for EmbeddedWorkerHostMsg_ReportConsoleMessage. @@ -45,6 +53,11 @@ IPC_STRUCT_END() IPC_MESSAGE_CONTROL1(EmbeddedWorkerMsg_StartWorker, EmbeddedWorkerMsg_StartWorker_Params /* params */) +// Browser -> Renderer message to resume a worker that has been started +// with the pause_after_download option. +IPC_MESSAGE_CONTROL1(EmbeddedWorkerMsg_ResumeAfterDownload, + int /* embedded_worker_id */) + // Browser -> Renderer message to stop (terminate) the embedded worker. IPC_MESSAGE_CONTROL1(EmbeddedWorkerMsg_StopWorker, int /* embedded_worker_id */) diff --git a/chromium/content/common/service_worker/embedded_worker_settings.h b/chromium/content/common/service_worker/embedded_worker_settings.h new file mode 100644 index 00000000000..2014dae91c4 --- /dev/null +++ b/chromium/content/common/service_worker/embedded_worker_settings.h @@ -0,0 +1,19 @@ +// Copyright 2016 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 CONTENT_COMMON_SERVICE_WORKER_EMBEDDED_WORKER_SETTINGS_H_ +#define CONTENT_COMMON_SERVICE_WORKER_EMBEDDED_WORKER_SETTINGS_H_ + +#include "content/public/common/web_preferences.h" + +namespace content { + +struct EmbeddedWorkerSettings { + content::V8CacheOptions v8_cache_options; + bool data_saver_enabled; +}; + +} // namespace content + +#endif // CONTENT_COMMON_SERVICE_WORKER_EMBEDDED_WORKER_SETTINGS_H_ diff --git a/chromium/content/common/service_worker/embedded_worker_setup.mojom b/chromium/content/common/service_worker/embedded_worker_setup.mojom index 4a748541c1e..ad4583d1c64 100644 --- a/chromium/content/common/service_worker/embedded_worker_setup.mojom +++ b/chromium/content/common/service_worker/embedded_worker_setup.mojom @@ -2,12 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -module content; +module content.mojom; -import "mojo/shell/public/interfaces/service_provider.mojom"; +import "mojo/shell/public/interfaces/interface_provider.mojom"; interface EmbeddedWorkerSetup { - ExchangeServiceProviders(int32 thread_id, - mojo.ServiceProvider& services, - mojo.ServiceProvider exposed_services); + ExchangeInterfaceProviders( + int32 thread_id, + mojo.shell.mojom.InterfaceProvider& remote_interfaces, + mojo.shell.mojom.InterfaceProvider local_interfaces); }; diff --git a/chromium/content/common/service_worker/service_worker_client_info.cc b/chromium/content/common/service_worker/service_worker_client_info.cc index c864369c039..a412fa0b7de 100644 --- a/chromium/content/common/service_worker/service_worker_client_info.cc +++ b/chromium/content/common/service_worker/service_worker_client_info.cc @@ -10,25 +10,32 @@ namespace content { ServiceWorkerClientInfo::ServiceWorkerClientInfo() - : page_visibility_state(blink::WebPageVisibilityStateLast), - is_focused(false), - frame_type(REQUEST_CONTEXT_FRAME_TYPE_LAST), - client_type(blink::WebServiceWorkerClientTypeLast), - last_focus_time(base::TimeTicks()) {} + : ServiceWorkerClientInfo(std::string(), + blink::WebPageVisibilityStateLast, + false, + GURL(), + REQUEST_CONTEXT_FRAME_TYPE_LAST, + base::TimeTicks(), + blink::WebServiceWorkerClientTypeLast) {} ServiceWorkerClientInfo::ServiceWorkerClientInfo( + const std::string& client_uuid, blink::WebPageVisibilityState page_visibility_state, bool is_focused, const GURL& url, RequestContextFrameType frame_type, base::TimeTicks last_focus_time, blink::WebServiceWorkerClientType client_type) - : page_visibility_state(page_visibility_state), + : client_uuid(client_uuid), + page_visibility_state(page_visibility_state), is_focused(is_focused), url(url), frame_type(frame_type), - client_type(client_type), - last_focus_time(last_focus_time) {} + last_focus_time(last_focus_time), + client_type(client_type) {} + +ServiceWorkerClientInfo::ServiceWorkerClientInfo( + const ServiceWorkerClientInfo& other) = default; bool ServiceWorkerClientInfo::IsEmpty() const { return page_visibility_state == blink::WebPageVisibilityStateLast && diff --git a/chromium/content/common/service_worker/service_worker_client_info.h b/chromium/content/common/service_worker/service_worker_client_info.h index 1c81fe34816..93bfdf447a2 100644 --- a/chromium/content/common/service_worker/service_worker_client_info.h +++ b/chromium/content/common/service_worker/service_worker_client_info.h @@ -20,12 +20,14 @@ namespace content { // constructor to fill the properties. struct ServiceWorkerClientInfo { ServiceWorkerClientInfo(); - ServiceWorkerClientInfo(blink::WebPageVisibilityState page_visibility_state, + ServiceWorkerClientInfo(const std::string& client_uuid, + blink::WebPageVisibilityState page_visibility_state, bool is_focused, const GURL& url, RequestContextFrameType frame_type, base::TimeTicks last_focus_time, blink::WebServiceWorkerClientType client_type); + ServiceWorkerClientInfo(const ServiceWorkerClientInfo& other); // Returns whether the instance is empty. bool IsEmpty() const; @@ -39,8 +41,8 @@ struct ServiceWorkerClientInfo { bool is_focused; GURL url; RequestContextFrameType frame_type; - blink::WebServiceWorkerClientType client_type; base::TimeTicks last_focus_time; + blink::WebServiceWorkerClientType client_type; }; } // namespace content diff --git a/chromium/content/common/service_worker/service_worker_messages.h b/chromium/content/common/service_worker/service_worker_messages.h index 8ba0e58e7f0..41698cff41e 100644 --- a/chromium/content/common/service_worker/service_worker_messages.h +++ b/chromium/content/common/service_worker/service_worker_messages.h @@ -14,8 +14,8 @@ #include "content/common/service_worker/service_worker_status_code.h" #include "content/common/service_worker/service_worker_types.h" #include "content/public/common/message_port_types.h" -#include "content/public/common/navigator_connect_client.h" #include "content/public/common/platform_notification_data.h" +#include "content/public/common/push_event_payload.h" #include "ipc/ipc_message_macros.h" #include "ipc/ipc_param_traits.h" #include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h" @@ -23,6 +23,7 @@ #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerError.h" #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerEventResult.h" #include "url/gurl.h" +#include "url/origin.h" #undef IPC_MESSAGE_EXPORT #define IPC_MESSAGE_EXPORT CONTENT_EXPORT @@ -50,6 +51,14 @@ IPC_ENUM_TRAITS_MAX_VALUE(blink::WebServiceWorkerClientType, IPC_ENUM_TRAITS_MAX_VALUE(content::ServiceWorkerProviderType, content::SERVICE_WORKER_PROVIDER_TYPE_LAST) +IPC_ENUM_TRAITS_MAX_VALUE(content::ServiceWorkerFetchType, + content::ServiceWorkerFetchType::LAST) + +IPC_STRUCT_TRAITS_BEGIN(content::ExtendableMessageEventSource) + IPC_STRUCT_TRAITS_MEMBER(client_info) + IPC_STRUCT_TRAITS_MEMBER(service_worker_info) +IPC_STRUCT_TRAITS_END() + IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerFetchRequest) IPC_STRUCT_TRAITS_MEMBER(mode) IPC_STRUCT_TRAITS_MEMBER(is_main_resource_load) @@ -65,6 +74,7 @@ IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerFetchRequest) IPC_STRUCT_TRAITS_MEMBER(redirect_mode) IPC_STRUCT_TRAITS_MEMBER(client_id) IPC_STRUCT_TRAITS_MEMBER(is_reload) + IPC_STRUCT_TRAITS_MEMBER(fetch_type) IPC_STRUCT_TRAITS_END() IPC_ENUM_TRAITS_MAX_VALUE(content::ServiceWorkerFetchEventResult, @@ -80,6 +90,9 @@ IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerResponse) IPC_STRUCT_TRAITS_MEMBER(blob_size) IPC_STRUCT_TRAITS_MEMBER(stream_url) IPC_STRUCT_TRAITS_MEMBER(error) + IPC_STRUCT_TRAITS_MEMBER(response_time) + IPC_STRUCT_TRAITS_MEMBER(is_in_cache_storage) + IPC_STRUCT_TRAITS_MEMBER(cache_storage_cache_name) IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerObjectInfo) @@ -115,6 +128,14 @@ IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerClientQueryOptions) IPC_STRUCT_TRAITS_MEMBER(include_uncontrolled) IPC_STRUCT_TRAITS_END() +IPC_STRUCT_BEGIN(ServiceWorkerMsg_ExtendableMessageEvent_Params) + IPC_STRUCT_MEMBER(base::string16, message) + IPC_STRUCT_MEMBER(url::Origin, source_origin) + IPC_STRUCT_MEMBER(std::vector<content::TransferredMessagePort>, message_ports) + IPC_STRUCT_MEMBER(std::vector<int>, new_routing_ids) + IPC_STRUCT_MEMBER(content::ExtendableMessageEventSource, source) +IPC_STRUCT_END() + IPC_STRUCT_BEGIN(ServiceWorkerMsg_MessageToDocument_Params) IPC_STRUCT_MEMBER(int, thread_id) IPC_STRUCT_MEMBER(int, provider_id) @@ -127,10 +148,9 @@ IPC_STRUCT_END() IPC_ENUM_TRAITS_MAX_VALUE(blink::WebGeofencingEventType, blink::WebGeofencingEventTypeLast) -IPC_STRUCT_TRAITS_BEGIN(content::NavigatorConnectClient) - IPC_STRUCT_TRAITS_MEMBER(target_url) - IPC_STRUCT_TRAITS_MEMBER(origin) - IPC_STRUCT_TRAITS_MEMBER(message_port_id) +IPC_STRUCT_TRAITS_BEGIN(content::PushEventPayload) + IPC_STRUCT_TRAITS_MEMBER(data) + IPC_STRUCT_TRAITS_MEMBER(is_null) IPC_STRUCT_TRAITS_END() //--------------------------------------------------------------------------- @@ -171,10 +191,21 @@ IPC_MESSAGE_CONTROL3(ServiceWorkerHostMsg_GetRegistrationForReady, int /* request_id */, int /* provider_id */) -// Sends a 'message' event to a service worker (renderer->browser). -IPC_MESSAGE_CONTROL3( +// Sends ExtendableMessageEvent to a service worker (renderer->browser). +IPC_MESSAGE_CONTROL5( ServiceWorkerHostMsg_PostMessageToWorker, int /* handle_id */, + int /* provider_id */, + base::string16 /* message */, + url::Origin /* source_origin */, + std::vector<content::TransferredMessagePort> /* sent_message_ports */) + +// Sends MessageEvent to a service worker (renderer->browser). +// TODO(nhiroki): Remove this after ExtendableMessageEvent is enabled by +// default (crbug.com/543198). +IPC_MESSAGE_CONTROL3( + ServiceWorkerHostMsg_DeprecatedPostMessageToWorker, + int /* handle_id */, base::string16 /* message */, std::vector<content::TransferredMessagePort> /* sent_message_ports */) @@ -231,12 +262,19 @@ IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_InstallEventFinished, IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_ActivateEventFinished, int /* request_id */, blink::WebServiceWorkerEventResult) +IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_ExtendableMessageEventFinished, + int /* request_id */, + blink::WebServiceWorkerEventResult) IPC_MESSAGE_ROUTED3(ServiceWorkerHostMsg_FetchEventFinished, int /* request_id */, content::ServiceWorkerFetchEventResult, content::ServiceWorkerResponse) -IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_NotificationClickEventFinished, - int /* request_id */) +IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_NotificationClickEventFinished, + int /* request_id */, + blink::WebServiceWorkerEventResult) +IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_NotificationCloseEventFinished, + int /* request_id */, + blink::WebServiceWorkerEventResult) IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_PushEventFinished, int /* request_id */, blink::WebServiceWorkerEventResult) @@ -248,12 +286,17 @@ IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_GeofencingEventFinished, // Routed to the target ServiceWorkerVersion. IPC_MESSAGE_ROUTED0(ServiceWorkerHostMsg_Pong) +// Asks the browser to retrieve client of the sender ServiceWorker. +IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_GetClient, + int /* request_id */, + std::string /* client_uuid */) + // Asks the browser to retrieve clients of the sender ServiceWorker. IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_GetClients, int /* request_id */, content::ServiceWorkerClientQueryOptions) -// Sends a 'message' event to a client (renderer->browser). +// Sends MessageEvent to a client (renderer->browser). IPC_MESSAGE_ROUTED3( ServiceWorkerHostMsg_PostMessageToClient, std::string /* uuid */, @@ -297,8 +340,9 @@ IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_ClaimClients, // Informs the browser of new foreign fetch subscopes this worker wants to // handle. Should only be sent while an install event is being handled. -IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_RegisterForeignFetchScopes, - std::vector<GURL> /* sub_scopes */) +IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_RegisterForeignFetchScopes, + std::vector<GURL> /* sub_scopes */, + std::vector<url::Origin> /* origins */) //--------------------------------------------------------------------------- // Messages sent from the browser to the child process. @@ -425,7 +469,7 @@ IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_SetControllerServiceWorker, content::ServiceWorkerObjectInfo, bool /* should_notify_controllerchange */) -// Sends a 'message' event to a client document (browser->renderer). +// Sends MessageEvent to a client document (browser->renderer). IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_MessageToDocument, ServiceWorkerMsg_MessageToDocument_Params) @@ -434,6 +478,9 @@ IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_InstallEvent, int /* request_id */) IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_ActivateEvent, int /* request_id */) +IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_ExtendableMessageEvent, + int /* request_id */, + ServiceWorkerMsg_ExtendableMessageEvent_Params) IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_FetchEvent, int /* request_id */, content::ServiceWorkerFetchRequest) @@ -442,25 +489,27 @@ IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_NotificationClickEvent, int64_t /* persistent_notification_id */, content::PlatformNotificationData /* notification_data */, int /* action_index */) +IPC_MESSAGE_CONTROL3(ServiceWorkerMsg_NotificationCloseEvent, + int /* request_id */, + int64_t /* persistent_notification_id */, + content::PlatformNotificationData /* notification_data */) IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_PushEvent, int /* request_id */, - std::string /* data */) + content::PushEventPayload /* data */) IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_GeofencingEvent, int /* request_id */, blink::WebGeofencingEventType /* event_type */, std::string /* region_id */, blink::WebCircularGeofencingRegion /* region */) + +// TODO(nhiroki): Remove this after ExtendableMessageEvent is enabled by +// default (crbug.com/543198). IPC_MESSAGE_CONTROL3( ServiceWorkerMsg_MessageToWorker, base::string16 /* message */, std::vector<content::TransferredMessagePort> /* sent_message_ports */, std::vector<int> /* new_routing_ids */) -IPC_MESSAGE_CONTROL4( - ServiceWorkerMsg_CrossOriginMessageToWorker, - content::NavigatorConnectClient /* client */, - base::string16 /* message */, - std::vector<content::TransferredMessagePort> /* sent_message_ports */, - std::vector<int> /* new_routing_ids */) + IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_DidSkipWaiting, int /* request_id */) IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_DidClaimClients, @@ -473,6 +522,11 @@ IPC_MESSAGE_CONTROL3(ServiceWorkerMsg_ClaimClientsError, // Sent via EmbeddedWorker to Ping the worker, expecting a Pong in response. IPC_MESSAGE_CONTROL0(ServiceWorkerMsg_Ping) +// Sent via EmbeddedWorker as a response of GetClient. +IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_DidGetClient, + int /* request_id */, + content::ServiceWorkerClientInfo) + // Sent via EmbeddedWorker as a response of GetClients. IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_DidGetClients, int /* request_id */, diff --git a/chromium/content/common/service_worker/service_worker_status_code.h b/chromium/content/common/service_worker/service_worker_status_code.h index 3dff585c4b2..24be8167310 100644 --- a/chromium/content/common/service_worker/service_worker_status_code.h +++ b/chromium/content/common/service_worker/service_worker_status_code.h @@ -10,69 +10,74 @@ namespace content { // Generic service worker operation statuses. -// This enum is used in UMA histograms, so don't change the order or remove -// entries. +// This enum is used in UMA histograms. Append-only. enum ServiceWorkerStatusCode { // Operation succeeded. - SERVICE_WORKER_OK, + SERVICE_WORKER_OK = 0, // Generic operation error (more specific error code should be used in // general). - SERVICE_WORKER_ERROR_FAILED, + SERVICE_WORKER_ERROR_FAILED = 1, // Operation was aborted (e.g. due to context or child process shutdown). - SERVICE_WORKER_ERROR_ABORT, + SERVICE_WORKER_ERROR_ABORT = 2, // Starting a new service worker script context failed. - SERVICE_WORKER_ERROR_START_WORKER_FAILED, + SERVICE_WORKER_ERROR_START_WORKER_FAILED = 3, // Could not find a renderer process to run a service worker. - SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND, + SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND = 4, // Generic error code to indicate the specified item is not found. - SERVICE_WORKER_ERROR_NOT_FOUND, + SERVICE_WORKER_ERROR_NOT_FOUND = 5, // Generic error code to indicate the specified item already exists. - SERVICE_WORKER_ERROR_EXISTS, + SERVICE_WORKER_ERROR_EXISTS = 6, // Install event handling failed. - SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED, + SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED = 7, // Activate event handling failed. - SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED, + SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED = 8, // Sending an IPC to the worker failed (often due to child process is // terminated). - SERVICE_WORKER_ERROR_IPC_FAILED, + SERVICE_WORKER_ERROR_IPC_FAILED = 9, // Operation is failed by network issue. - SERVICE_WORKER_ERROR_NETWORK, + SERVICE_WORKER_ERROR_NETWORK = 10, // Operation is failed by security issue. - SERVICE_WORKER_ERROR_SECURITY, + SERVICE_WORKER_ERROR_SECURITY = 11, // Event handling failed (event.waitUntil Promise rejected). - SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED, + SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED = 12, // An error triggered by invalid worker state. - SERVICE_WORKER_ERROR_STATE, + SERVICE_WORKER_ERROR_STATE = 13, // The Service Worker took too long to finish a task. - SERVICE_WORKER_ERROR_TIMEOUT, + SERVICE_WORKER_ERROR_TIMEOUT = 14, // An error occurred during initial script evaluation. - SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED, + SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED = 15, // Generic error to indicate failure to read/write the disk cache. - SERVICE_WORKER_ERROR_DISK_CACHE, + SERVICE_WORKER_ERROR_DISK_CACHE = 16, // The worker is in REDUNDANT state. - SERVICE_WORKER_ERROR_REDUNDANT, + SERVICE_WORKER_ERROR_REDUNDANT = 17, - // The worker was disallowed. - SERVICE_WORKER_ERROR_DISALLOWED, + // The worker was disallowed (by ContentClient: e.g., due to + // browser settings). + SERVICE_WORKER_ERROR_DISALLOWED = 18, - SERVICE_WORKER_ERROR_MAX_VALUE + // Obsolete. + // SERVICE_WORKER_ERROR_DISABLED_WORKER = 19, + + // Add new status codes here. + + SERVICE_WORKER_ERROR_MAX_VALUE = 20 }; CONTENT_EXPORT const char* ServiceWorkerStatusToString( diff --git a/chromium/content/common/service_worker/service_worker_type_converters.cc b/chromium/content/common/service_worker/service_worker_type_converters.cc index 735f529a932..b752e142772 100644 --- a/chromium/content/common/service_worker/service_worker_type_converters.cc +++ b/chromium/content/common/service_worker/service_worker_type_converters.cc @@ -12,14 +12,14 @@ namespace mojo { // static cast. content::ServiceWorkerStatusCode TypeConverter<content::ServiceWorkerStatusCode, - content::ServiceWorkerEventStatus>:: - Convert(content::ServiceWorkerEventStatus status) { + content::mojom::ServiceWorkerEventStatus>:: + Convert(content::mojom::ServiceWorkerEventStatus status) { content::ServiceWorkerStatusCode status_code; - if (status == content::SERVICE_WORKER_EVENT_STATUS_COMPLETED) { + if (status == content::mojom::ServiceWorkerEventStatus::COMPLETED) { status_code = content::SERVICE_WORKER_OK; - } else if (status == content::SERVICE_WORKER_EVENT_STATUS_REJECTED) { + } else if (status == content::mojom::ServiceWorkerEventStatus::REJECTED) { status_code = content::SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED; - } else if (status == content::SERVICE_WORKER_EVENT_STATUS_ABORTED) { + } else if (status == content::mojom::ServiceWorkerEventStatus::ABORTED) { status_code = content::SERVICE_WORKER_ERROR_ABORT; } else { // We received an unexpected value back. This can theoretically happen as diff --git a/chromium/content/common/service_worker/service_worker_type_converters.h b/chromium/content/common/service_worker/service_worker_type_converters.h index 42606e34dc9..4c43fdaf8c0 100644 --- a/chromium/content/common/service_worker/service_worker_type_converters.h +++ b/chromium/content/common/service_worker/service_worker_type_converters.h @@ -12,9 +12,9 @@ namespace mojo { template <> struct CONTENT_EXPORT TypeConverter<content::ServiceWorkerStatusCode, - content::ServiceWorkerEventStatus> { + content::mojom::ServiceWorkerEventStatus> { static content::ServiceWorkerStatusCode Convert( - content::ServiceWorkerEventStatus status); + content::mojom::ServiceWorkerEventStatus status); }; } // namespace diff --git a/chromium/content/common/service_worker/service_worker_types.cc b/chromium/content/common/service_worker/service_worker_types.cc index e9ff0b96319..a320c29725a 100644 --- a/chromium/content/common/service_worker/service_worker_types.cc +++ b/chromium/content/common/service_worker/service_worker_types.cc @@ -27,7 +27,8 @@ ServiceWorkerFetchRequest::ServiceWorkerFetchRequest() blob_size(0), credentials_mode(FETCH_CREDENTIALS_MODE_OMIT), redirect_mode(FetchRedirectMode::FOLLOW_MODE), - is_reload(false) {} + is_reload(false), + fetch_type(ServiceWorkerFetchType::FETCH) {} ServiceWorkerFetchRequest::ServiceWorkerFetchRequest( const GURL& url, @@ -46,7 +47,11 @@ ServiceWorkerFetchRequest::ServiceWorkerFetchRequest( referrer(referrer), credentials_mode(FETCH_CREDENTIALS_MODE_OMIT), redirect_mode(FetchRedirectMode::FOLLOW_MODE), - is_reload(is_reload) {} + is_reload(is_reload), + fetch_type(ServiceWorkerFetchType::FETCH) {} + +ServiceWorkerFetchRequest::ServiceWorkerFetchRequest( + const ServiceWorkerFetchRequest& other) = default; ServiceWorkerFetchRequest::~ServiceWorkerFetchRequest() {} @@ -54,8 +59,7 @@ ServiceWorkerResponse::ServiceWorkerResponse() : status_code(0), response_type(blink::WebServiceWorkerResponseTypeOpaque), blob_size(0), - error(blink::WebServiceWorkerResponseErrorUnknown) { -} + error(blink::WebServiceWorkerResponseErrorUnknown) {} ServiceWorkerResponse::ServiceWorkerResponse( const GURL& url, @@ -66,7 +70,10 @@ ServiceWorkerResponse::ServiceWorkerResponse( const std::string& blob_uuid, uint64_t blob_size, const GURL& stream_url, - blink::WebServiceWorkerResponseError error) + blink::WebServiceWorkerResponseError error, + base::Time response_time, + bool is_in_cache_storage, + const std::string& cache_storage_cache_name) : url(url), status_code(status_code), status_text(status_text), @@ -75,7 +82,13 @@ ServiceWorkerResponse::ServiceWorkerResponse( blob_uuid(blob_uuid), blob_size(blob_size), stream_url(stream_url), - error(error) {} + error(error), + response_time(response_time), + is_in_cache_storage(is_in_cache_storage), + cache_storage_cache_name(cache_storage_cache_name) {} + +ServiceWorkerResponse::ServiceWorkerResponse( + const ServiceWorkerResponse& other) = default; ServiceWorkerResponse::~ServiceWorkerResponse() {} @@ -84,6 +97,11 @@ ServiceWorkerObjectInfo::ServiceWorkerObjectInfo() state(blink::WebServiceWorkerStateUnknown), version_id(kInvalidServiceWorkerVersionId) {} +bool ServiceWorkerObjectInfo::IsValid() const { + return handle_id != kInvalidServiceWorkerHandleId && + version_id != kInvalidServiceWorkerVersionId; +} + ServiceWorkerRegistrationObjectInfo::ServiceWorkerRegistrationObjectInfo() : handle_id(kInvalidServiceWorkerRegistrationHandleId), registration_id(kInvalidServiceWorkerRegistrationId) { @@ -94,4 +112,14 @@ ServiceWorkerClientQueryOptions::ServiceWorkerClientQueryOptions() include_uncontrolled(false) { } +ExtendableMessageEventSource::ExtendableMessageEventSource() {} + +ExtendableMessageEventSource::ExtendableMessageEventSource( + const ServiceWorkerClientInfo& client_info) + : client_info(client_info) {} + +ExtendableMessageEventSource::ExtendableMessageEventSource( + const ServiceWorkerObjectInfo& service_worker_info) + : service_worker_info(service_worker_info) {} + } // namespace content diff --git a/chromium/content/common/service_worker/service_worker_types.h b/chromium/content/common/service_worker/service_worker_types.h index d3a9f8f2a99..81f7d4f7d50 100644 --- a/chromium/content/common/service_worker/service_worker_types.h +++ b/chromium/content/common/service_worker/service_worker_types.h @@ -11,7 +11,9 @@ #include <string> #include "base/strings/string_util.h" +#include "base/time/time.h" #include "content/common/content_export.h" +#include "content/common/service_worker/service_worker_client_info.h" #include "content/public/common/referrer.h" #include "content/public/common/request_context_frame_type.h" #include "content/public/common/request_context_type.h" @@ -87,7 +89,8 @@ enum FetchCredentialsMode { FETCH_CREDENTIALS_MODE_OMIT, FETCH_CREDENTIALS_MODE_SAME_ORIGIN, FETCH_CREDENTIALS_MODE_INCLUDE, - FETCH_CREDENTIALS_MODE_LAST = FETCH_CREDENTIALS_MODE_INCLUDE + FETCH_CREDENTIALS_MODE_PASSWORD, + FETCH_CREDENTIALS_MODE_LAST = FETCH_CREDENTIALS_MODE_PASSWORD }; enum class FetchRedirectMode { @@ -106,6 +109,12 @@ enum ServiceWorkerFetchEventResult { SERVICE_WORKER_FETCH_EVENT_LAST = SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE }; +enum class ServiceWorkerFetchType { + FETCH, + FOREIGN_FETCH, + LAST = FOREIGN_FETCH +}; + struct ServiceWorkerCaseInsensitiveCompare { bool operator()(const std::string& lhs, const std::string& rhs) const { return base::CompareCaseInsensitiveASCII(lhs, rhs) < 0; @@ -123,6 +132,7 @@ struct CONTENT_EXPORT ServiceWorkerFetchRequest { const ServiceWorkerHeaderMap& headers, const Referrer& referrer, bool is_reload); + ServiceWorkerFetchRequest(const ServiceWorkerFetchRequest& other); ~ServiceWorkerFetchRequest(); FetchRequestMode mode; @@ -139,6 +149,7 @@ struct CONTENT_EXPORT ServiceWorkerFetchRequest { FetchRedirectMode redirect_mode; std::string client_id; bool is_reload; + ServiceWorkerFetchType fetch_type; }; // Represents a response to a fetch. @@ -152,7 +163,11 @@ struct CONTENT_EXPORT ServiceWorkerResponse { const std::string& blob_uuid, uint64_t blob_size, const GURL& stream_url, - blink::WebServiceWorkerResponseError error); + blink::WebServiceWorkerResponseError error, + base::Time response_time, + bool is_in_cache_storage, + const std::string& cache_storage_cache_name); + ServiceWorkerResponse(const ServiceWorkerResponse& other); ~ServiceWorkerResponse(); GURL url; @@ -164,11 +179,19 @@ struct CONTENT_EXPORT ServiceWorkerResponse { uint64_t blob_size; GURL stream_url; blink::WebServiceWorkerResponseError error; + base::Time response_time; + bool is_in_cache_storage = false; + std::string cache_storage_cache_name; }; // Represents initialization info for a WebServiceWorker object. struct CONTENT_EXPORT ServiceWorkerObjectInfo { ServiceWorkerObjectInfo(); + + // Returns whether the instance is valid. A valid instance has valid + // |handle_id| and |version_id|. + bool IsValid() const; + int handle_id; GURL url; blink::WebServiceWorkerState state; @@ -218,6 +241,18 @@ struct ServiceWorkerClientQueryOptions { bool include_uncontrolled; }; +struct ExtendableMessageEventSource { + ExtendableMessageEventSource(); + explicit ExtendableMessageEventSource( + const ServiceWorkerClientInfo& client_info); + explicit ExtendableMessageEventSource( + const ServiceWorkerObjectInfo& service_worker_info); + + // Exactly one of these infos should be valid. + ServiceWorkerClientInfo client_info; + ServiceWorkerObjectInfo service_worker_info; +}; + } // namespace content #endif // CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_TYPES_H_ diff --git a/chromium/content/common/service_worker/service_worker_utils.cc b/chromium/content/common/service_worker/service_worker_utils.cc index 62f197528f1..3a4971fc4ec 100644 --- a/chromium/content/common/service_worker/service_worker_utils.cc +++ b/chromium/content/common/service_worker/service_worker_utils.cc @@ -8,6 +8,7 @@ #include "base/logging.h" #include "base/strings/string_util.h" +#include "content/public/common/origin_util.h" namespace content { @@ -30,12 +31,16 @@ bool PathContainsDisallowedCharacter(const GURL& url) { return false; } +bool AllOriginsMatch(const GURL& url_a, const GURL& url_b, const GURL& url_c) { + return url_a.GetOrigin() == url_b.GetOrigin() && + url_a.GetOrigin() == url_c.GetOrigin(); +} + } // namespace // static bool ServiceWorkerUtils::ScopeMatches(const GURL& scope, const GURL& url) { DCHECK(!scope.has_ref()); - DCHECK(!url.has_ref()); return base::StartsWith(url.spec(), scope.spec(), base::CompareCase::SENSITIVE); } @@ -104,6 +109,19 @@ bool ServiceWorkerUtils::ContainsDisallowedCharacter( return false; } +// static +bool ServiceWorkerUtils::CanRegisterServiceWorker(const GURL& context_url, + const GURL& pattern, + const GURL& script_url) { + DCHECK(context_url.is_valid()); + DCHECK(pattern.is_valid()); + DCHECK(script_url.is_valid()); + return AllOriginsMatch(context_url, pattern, script_url) && + OriginCanAccessServiceWorkers(context_url) && + OriginCanAccessServiceWorkers(pattern) && + OriginCanAccessServiceWorkers(script_url); +} + bool LongestScopeMatcher::MatchLongest(const GURL& scope) { if (!ServiceWorkerUtils::ScopeMatches(scope, url_)) return false; diff --git a/chromium/content/common/service_worker/service_worker_utils.h b/chromium/content/common/service_worker/service_worker_utils.h index 8538b5ea304..5be59c0aa80 100644 --- a/chromium/content/common/service_worker/service_worker_utils.h +++ b/chromium/content/common/service_worker/service_worker_utils.h @@ -40,6 +40,10 @@ class ServiceWorkerUtils { const GURL& script_url, std::string* error_message); + static bool CanRegisterServiceWorker(const GURL& context_url, + const GURL& pattern, + const GURL& script_url); + // PlzNavigate // Returns true if the |provider_id| was assigned by the browser process. static bool IsBrowserAssignedProviderId(int provider_id) { diff --git a/chromium/content/common/service_worker/service_worker_utils_unittest.cc b/chromium/content/common/service_worker/service_worker_utils_unittest.cc index f8ab571682d..393c36ce158 100644 --- a/chromium/content/common/service_worker/service_worker_utils_unittest.cc +++ b/chromium/content/common/service_worker/service_worker_utils_unittest.cc @@ -38,6 +38,8 @@ TEST(ServiceWorkerUtilsTest, ScopeMatches) { ASSERT_FALSE(ServiceWorkerUtils::ScopeMatches( GURL("http://www.example.com/"), GURL("https://www.example.com/page.html"))); + ASSERT_TRUE(ServiceWorkerUtils::ScopeMatches( + GURL("http://www.example.com/"), GURL("http://www.example.com/#a"))); ASSERT_FALSE(ServiceWorkerUtils::ScopeMatches(GURL("http://www.example.com/"), GURL("http://www.foo.com/"))); diff --git a/chromium/content/common/site_isolation_policy.cc b/chromium/content/common/site_isolation_policy.cc index 60288700ca7..b25741b3b39 100644 --- a/chromium/content/common/site_isolation_policy.cc +++ b/chromium/content/common/site_isolation_policy.cc @@ -6,6 +6,7 @@ #include "base/command_line.h" #include "base/lazy_instance.h" +#include "content/public/common/browser_plugin_guest_mode.h" #include "content/public/common/browser_side_navigation_policy.h" #include "content/public/common/content_client.h" #include "content/public/common/content_switches.h" @@ -14,9 +15,10 @@ namespace content { // static bool SiteIsolationPolicy::AreCrossProcessFramesPossible() { - return base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kSitePerProcess) || - GetContentClient()->IsSupplementarySiteIsolationModeEnabled(); + return UseDedicatedProcessesForAllSites() || + IsTopDocumentIsolationEnabled() || + GetContentClient()->IsSupplementarySiteIsolationModeEnabled() || + BrowserPluginGuestMode::UseCrossProcessFramesForGuests(); } // static @@ -26,6 +28,16 @@ bool SiteIsolationPolicy::UseDedicatedProcessesForAllSites() { } // static +bool SiteIsolationPolicy::IsTopDocumentIsolationEnabled() { + // --site-per-process trumps --top-document-isolation. + if (UseDedicatedProcessesForAllSites()) + return false; + + return base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kTopDocumentIsolation); +} + +// static bool SiteIsolationPolicy::UseSubframeNavigationEntries() { // Enable the new navigation history behavior if any manner of site isolation // is active. @@ -33,9 +45,4 @@ bool SiteIsolationPolicy::UseSubframeNavigationEntries() { return AreCrossProcessFramesPossible() || IsBrowserSideNavigationEnabled(); } -// static -bool SiteIsolationPolicy::IsSwappedOutStateForbidden() { - return true; -} - } // namespace content diff --git a/chromium/content/common/site_isolation_policy.h b/chromium/content/common/site_isolation_policy.h index 69b6c5e4cf4..c6d6e6132aa 100644 --- a/chromium/content/common/site_isolation_policy.h +++ b/chromium/content/common/site_isolation_policy.h @@ -37,23 +37,16 @@ class CONTENT_EXPORT SiteIsolationPolicy { // Returns true if every site should be placed in a dedicated process. static bool UseDedicatedProcessesForAllSites(); + // Returns true if third-party subframes of a page should be kept in a + // different process from the main frame. + static bool IsTopDocumentIsolationEnabled(); + // Returns true if navigation and history code should maintain per-frame // navigation entries. This is an in-progress feature related to site // isolation, so the return value is currently tied to --site-per-process. // TODO(creis, avi): Make this the default, and eliminate this. static bool UseSubframeNavigationEntries(); - // Returns true if we are currently in a mode where the swapped out state - // should not be used. Currently (as an implementation strategy) swapped out - // is forbidden under --site-per-process, but our goal is to eliminate the - // mode entirely. In code that deals with the swapped out state, prefer calls - // to this function over consulting the switches directly. It will be easier - // to grep, and easier to rip out. - // - // TODO(nasko): When swappedout:// is eliminated entirely, this function - // should be removed and its callers cleaned up. - static bool IsSwappedOutStateForbidden(); - private: SiteIsolationPolicy(); // Not instantiable. diff --git a/chromium/content/common/storage_partition_service.mojom b/chromium/content/common/storage_partition_service.mojom new file mode 100644 index 00000000000..3338658618d --- /dev/null +++ b/chromium/content/common/storage_partition_service.mojom @@ -0,0 +1,15 @@ +// Copyright 2016 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. + +module content.mojom; + +import "content/common/leveldb_wrapper.mojom"; +import "url/mojo/origin.mojom"; + +// Returns services related to the current storage partition. +interface StoragePartitionService { + OpenLocalStorage(url.mojom.Origin origin, + LevelDBObserver observer, + LevelDBWrapper& database); +}; diff --git a/chromium/content/common/swapped_out_messages.cc b/chromium/content/common/swapped_out_messages.cc index 7980014711d..718dd08e49a 100644 --- a/chromium/content/common/swapped_out_messages.cc +++ b/chromium/content/common/swapped_out_messages.cc @@ -9,7 +9,6 @@ #include "content/common/input_messages.h" #include "content/common/view_messages.h" #include "content/public/common/content_client.h" -#include "content/shell/common/shell_messages.h" namespace content { @@ -40,8 +39,6 @@ bool SwappedOutMessages::CanSendWhileSwappedOut(const IPC::Message* msg) { // Frame detach must occur after the RenderView has swapped out. case FrameHostMsg_Detach::ID: case FrameHostMsg_DomOperationResponse::ID: - case FrameHostMsg_CompositorFrameSwappedACK::ID: - case FrameHostMsg_ReclaimCompositorResources::ID: // Input events propagate from parent to child. case FrameHostMsg_ForwardInputEvent::ID: case FrameHostMsg_InitializeChildFrame::ID: @@ -50,8 +47,8 @@ bool SwappedOutMessages::CanSendWhileSwappedOut(const IPC::Message* msg) { case FrameHostMsg_DidAssignPageId::ID: // A swapped-out frame's opener might be updated with window.open. case FrameHostMsg_DidChangeOpener::ID: - // Used in layout tests; handled in BlinkTestController. - case ShellViewHostMsg_PrintMessage::ID: + // For handling pop-ups from cross-site frames. + case ViewHostMsg_CreateWidget::ID: return true; default: break; diff --git a/chromium/content/common/text_input_client_messages.h b/chromium/content/common/text_input_client_messages.h index 70da1d8916e..f66196cc6c5 100644 --- a/chromium/content/common/text_input_client_messages.h +++ b/chromium/content/common/text_input_client_messages.h @@ -48,7 +48,7 @@ IPC_MESSAGE_ROUTED1(TextInputClientMsg_StringAtPoint, gfx::Point) // Reply message for TextInputClientMsg_CharacterIndexForPoint. IPC_MESSAGE_ROUTED1(TextInputClientReplyMsg_GotCharacterIndexForPoint, - size_t /* character index */) + uint32_t /* character index */) // Reply message for TextInputClientMsg_FirstRectForCharacterRange. IPC_MESSAGE_ROUTED1(TextInputClientReplyMsg_GotFirstRectForRange, diff --git a/chromium/content/common/url_schemes.cc b/chromium/content/common/url_schemes.cc index 6d4c58c699f..c985e854ae1 100644 --- a/chromium/content/common/url_schemes.cc +++ b/chromium/content/common/url_schemes.cc @@ -18,35 +18,37 @@ namespace { -void AddStandardSchemeHelper(const url::SchemeWithType& scheme) { - url::AddStandardScheme(scheme.scheme, scheme.type); -} - } // namespace namespace content { -void RegisterContentSchemes(bool lock_standard_schemes) { +void RegisterContentSchemes(bool lock_schemes) { std::vector<url::SchemeWithType> additional_standard_schemes; + std::vector<url::SchemeWithType> additional_referrer_schemes; std::vector<std::string> additional_savable_schemes; + GetContentClient()->AddAdditionalSchemes(&additional_standard_schemes, + &additional_referrer_schemes, &additional_savable_schemes); url::AddStandardScheme(kChromeDevToolsScheme, url::SCHEME_WITHOUT_PORT); url::AddStandardScheme(kChromeUIScheme, url::SCHEME_WITHOUT_PORT); url::AddStandardScheme(kGuestScheme, url::SCHEME_WITHOUT_PORT); url::AddStandardScheme(kMetadataScheme, url::SCHEME_WITHOUT_AUTHORITY); - std::for_each(additional_standard_schemes.begin(), - additional_standard_schemes.end(), - AddStandardSchemeHelper); - - // Prevent future modification of the standard schemes list. This is to - // prevent accidental creation of data races in the program. AddStandardScheme - // isn't threadsafe so must be called when GURL isn't used on any other - // thread. This is really easy to mess up, so we say that all calls to - // AddStandardScheme in Chrome must be inside this function. - if (lock_standard_schemes) - url::LockStandardSchemes(); + + for (const url::SchemeWithType& scheme : additional_standard_schemes) + url::AddStandardScheme(scheme.scheme, scheme.type); + + for (const url::SchemeWithType& scheme : additional_referrer_schemes) + url::AddReferrerScheme(scheme.scheme, scheme.type); + + // Prevent future modification of the scheme lists. This is to prevent + // accidental creation of data races in the program. Add*Scheme aren't + // threadsafe so must be called when GURL isn't used on any other thread. This + // is really easy to mess up, so we say that all calls to Add*Scheme in Chrome + // must be inside this function. + if (lock_schemes) + url::LockSchemeRegistries(); // We rely on the above lock to protect this part from being invoked twice. if (!additional_savable_schemes.empty()) { diff --git a/chromium/content/common/url_schemes.h b/chromium/content/common/url_schemes.h index 571c660f217..1441c9c9ab0 100644 --- a/chromium/content/common/url_schemes.h +++ b/chromium/content/common/url_schemes.h @@ -10,16 +10,16 @@ namespace content { // Note: ContentMainRunner calls this method internally as part of main -// initialziation, so this function generally should not be called by +// initialization, so this function generally should not be called by // embedders. It's exported to facilitate test harnesses that do not // utilize ContentMainRunner and that do not wish to lock the set // of standard schemes at init time. // -// Called near the beginning of startup to register URL schemes that should -// be parsed as "standard" with the src/url/ library. Optionally, the set -// of standard schemes is locked down. The embedder can add additional -// schemes by overriding the ContentClient::AddAdditionalSchemes method. -CONTENT_EXPORT void RegisterContentSchemes(bool lock_standard_schemes); +// Called near the beginning of startup to register URL schemes that should be +// parsed as "standard" or "referrer" with the src/url/ library. Optionally, the +// sets of schemes are locked down. The embedder can add additional schemes by +// overriding the ContentClient::AddAdditionalSchemes method. +CONTENT_EXPORT void RegisterContentSchemes(bool lock_schemes); } // namespace content diff --git a/chromium/content/common/utility_messages.h b/chromium/content/common/utility_messages.h index a76986ede7c..6a43e5a1f2d 100644 --- a/chromium/content/common/utility_messages.h +++ b/chromium/content/common/utility_messages.h @@ -4,15 +4,7 @@ // Multiply-included message file, so no include guard. -#include <stdint.h> - -#include <string> -#include <vector> - -#include "build/build_config.h" #include "content/common/content_export.h" -#include "content/public/common/common_param_traits.h" -#include "content/public/common/webplugininfo.h" #include "ipc/ipc_message_macros.h" #undef IPC_MESSAGE_EXPORT @@ -28,27 +20,3 @@ IPC_MESSAGE_CONTROL0(UtilityMsg_BatchMode_Started) // Tells the utility process that it can shutdown. IPC_MESSAGE_CONTROL0(UtilityMsg_BatchMode_Finished) - -#if defined(OS_POSIX) && defined(ENABLE_PLUGINS) -// Tells the utility process to load each plugin in the order specified by the -// vector. It will respond after each load with the WebPluginInfo. -IPC_MESSAGE_CONTROL1(UtilityMsg_LoadPlugins, - std::vector<base::FilePath> /* plugin paths */) -#endif - -//------------------------------------------------------------------------------ -// Utility process host messages: -// These are messages from the utility process to the browser. - -#if defined(OS_POSIX) && defined(ENABLE_PLUGINS) -// Notifies the browser when a plugin failed to load so the two processes can -// keep the canonical list in sync. -IPC_SYNC_MESSAGE_CONTROL2_0(UtilityHostMsg_LoadPluginFailed, - uint32_t /* index in the vector */, - base::FilePath /* path of plugin */) - -// Notifies the browser that a plugin in the vector sent by it has been loaded. -IPC_SYNC_MESSAGE_CONTROL2_0(UtilityHostMsg_LoadedPlugin, - uint32_t /* index in the vector */, - content::WebPluginInfo /* plugin info */) -#endif diff --git a/chromium/content/common/view_messages.h b/chromium/content/common/view_messages.h index 5b5e578b7dd..324bdef3c51 100644 --- a/chromium/content/common/view_messages.h +++ b/chromium/content/common/view_messages.h @@ -22,8 +22,8 @@ #include "content/common/frame_replication_state.h" #include "content/common/media/media_param_traits.h" #include "content/common/navigation_gesture.h" +#include "content/common/resize_params.h" #include "content/common/view_message_enums.h" -#include "content/common/webplugin_geometry.h" #include "content/public/common/common_param_traits.h" #include "content/public/common/favicon_url.h" #include "content/public/common/file_chooser_file_info.h" @@ -34,7 +34,6 @@ #include "content/public/common/page_zoom.h" #include "content/public/common/referrer.h" #include "content/public/common/renderer_preferences.h" -#include "content/public/common/stop_find_action.h" #include "content/public/common/three_d_api_types.h" #include "content/public/common/window_container_type.h" #include "ipc/ipc_channel_handle.h" @@ -49,7 +48,6 @@ #include "third_party/WebKit/public/platform/WebScreenInfo.h" #include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h" #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h" -#include "third_party/WebKit/public/web/WebFindOptions.h" #include "third_party/WebKit/public/web/WebMediaPlayerAction.h" #include "third_party/WebKit/public/web/WebPluginAction.h" #include "third_party/WebKit/public/web/WebPopupType.h" @@ -66,6 +64,7 @@ #include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/geometry/vector2d_f.h" #include "ui/gfx/ipc/gfx_param_traits.h" +#include "ui/gfx/ipc/skia/gfx_skia_param_traits.h" #include "ui/gfx/range/range.h" #if defined(OS_MACOSX) @@ -111,8 +110,6 @@ IPC_ENUM_TRAITS_MAX_VALUE(gfx::FontRenderParams::SubpixelRendering, gfx::FontRenderParams::SUBPIXEL_RENDERING_MAX) IPC_ENUM_TRAITS_MAX_VALUE(content::TapMultipleTargetsStrategy, content::TAP_MULTIPLE_TARGETS_STRATEGY_MAX) -IPC_ENUM_TRAITS_MAX_VALUE(content::StopFindAction, - content::STOP_FIND_ACTION_LAST) IPC_ENUM_TRAITS_MAX_VALUE(content::ThreeDAPIType, content::THREE_D_API_TYPE_LAST) IPC_ENUM_TRAITS_MAX_VALUE(media::MediaLogEvent::Type, @@ -128,12 +125,6 @@ IPC_ENUM_TRAITS_MAX_VALUE( IPC_ENUM_TRAITS_MAX_VALUE(blink::ScrollerStyle, blink::ScrollerStyleOverlay) #endif -IPC_STRUCT_TRAITS_BEGIN(blink::WebFindOptions) - IPC_STRUCT_TRAITS_MEMBER(forward) - IPC_STRUCT_TRAITS_MEMBER(matchCase) - IPC_STRUCT_TRAITS_MEMBER(findNext) -IPC_STRUCT_TRAITS_END() - IPC_STRUCT_TRAITS_BEGIN(blink::WebMediaPlayerAction) IPC_STRUCT_TRAITS_MEMBER(type) IPC_STRUCT_TRAITS_MEMBER(enable) @@ -170,6 +161,8 @@ IPC_STRUCT_TRAITS_BEGIN(blink::WebDeviceEmulationParams) IPC_STRUCT_TRAITS_MEMBER(fitToView) IPC_STRUCT_TRAITS_MEMBER(offset) IPC_STRUCT_TRAITS_MEMBER(scale) + IPC_STRUCT_TRAITS_MEMBER(screenOrientationAngle) + IPC_STRUCT_TRAITS_MEMBER(screenOrientationType) IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_BEGIN(blink::WebScreenInfo) @@ -183,6 +176,19 @@ IPC_STRUCT_TRAITS_BEGIN(blink::WebScreenInfo) IPC_STRUCT_TRAITS_MEMBER(orientationAngle) IPC_STRUCT_TRAITS_END() +IPC_STRUCT_TRAITS_BEGIN(content::ResizeParams) + IPC_STRUCT_TRAITS_MEMBER(screen_info) + IPC_STRUCT_TRAITS_MEMBER(new_size) + IPC_STRUCT_TRAITS_MEMBER(physical_backing_size) + IPC_STRUCT_TRAITS_MEMBER(top_controls_shrink_blink_size) + IPC_STRUCT_TRAITS_MEMBER(top_controls_height) + IPC_STRUCT_TRAITS_MEMBER(visible_viewport_size) + IPC_STRUCT_TRAITS_MEMBER(resizer_rect) + IPC_STRUCT_TRAITS_MEMBER(is_fullscreen_granted) + IPC_STRUCT_TRAITS_MEMBER(display_mode) + IPC_STRUCT_TRAITS_MEMBER(needs_resize_ack) +IPC_STRUCT_TRAITS_END() + IPC_STRUCT_TRAITS_BEGIN(content::MenuItem) IPC_STRUCT_TRAITS_MEMBER(label) IPC_STRUCT_TRAITS_MEMBER(tool_tip) @@ -279,15 +285,6 @@ IPC_STRUCT_TRAITS_BEGIN(content::RendererPreferences) IPC_STRUCT_TRAITS_MEMBER(default_font_size) IPC_STRUCT_TRAITS_END() -IPC_STRUCT_TRAITS_BEGIN(content::WebPluginGeometry) - IPC_STRUCT_TRAITS_MEMBER(window) - IPC_STRUCT_TRAITS_MEMBER(window_rect) - IPC_STRUCT_TRAITS_MEMBER(clip_rect) - IPC_STRUCT_TRAITS_MEMBER(cutout_rects) - IPC_STRUCT_TRAITS_MEMBER(rects_valid) - IPC_STRUCT_TRAITS_MEMBER(visible) -IPC_STRUCT_TRAITS_END() - IPC_STRUCT_TRAITS_BEGIN(media::MediaLogEvent) IPC_STRUCT_TRAITS_MEMBER(id) IPC_STRUCT_TRAITS_MEMBER(type) @@ -382,6 +379,9 @@ IPC_STRUCT_BEGIN(ViewHostMsg_CreateWorker_Params) // RenderFrame routing id used to send messages back to the parent. IPC_STRUCT_MEMBER(int, render_frame_route_id) + // Address space of the context that created the worker. + IPC_STRUCT_MEMBER(blink::WebAddressSpace, creation_address_space) + // The type (secure or nonsecure) of the context that created the worker. IPC_STRUCT_MEMBER(blink::WebSharedWorkerCreationContextType, creation_context_type) @@ -460,10 +460,6 @@ IPC_STRUCT_BEGIN(ViewHostMsg_UpdateRect_Params) // view size. IPC_STRUCT_MEMBER(gfx::Size, view_size) - // New window locations for plugin child windows. - IPC_STRUCT_MEMBER(std::vector<content::WebPluginGeometry>, - plugin_window_moves) - // The following describes the various bits that may be set in flags: // // ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK @@ -479,34 +475,6 @@ IPC_STRUCT_BEGIN(ViewHostMsg_UpdateRect_Params) IPC_STRUCT_MEMBER(int, flags) IPC_STRUCT_END() -IPC_STRUCT_BEGIN(ViewMsg_Resize_Params) - // Information about the screen (dpi, depth, etc..). - IPC_STRUCT_MEMBER(blink::WebScreenInfo, screen_info) - // The size of the renderer. - IPC_STRUCT_MEMBER(gfx::Size, new_size) - // The size of the view's backing surface in non-DPI-adjusted pixels. - IPC_STRUCT_MEMBER(gfx::Size, physical_backing_size) - // Whether or not Blink's viewport size should be shrunk by the height of the - // URL-bar (always false on platforms where URL-bar hiding isn't supported). - IPC_STRUCT_MEMBER(bool, top_controls_shrink_blink_size) - // The height of the top controls (always 0 on platforms where URL-bar hiding - // isn't supported). - IPC_STRUCT_MEMBER(float, top_controls_height) - // The size of the visible viewport, which may be smaller than the view if the - // view is partially occluded (e.g. by a virtual keyboard). The size is in - // DPI-adjusted pixels. - IPC_STRUCT_MEMBER(gfx::Size, visible_viewport_size) - // The resizer rect. - IPC_STRUCT_MEMBER(gfx::Rect, resizer_rect) - // Indicates whether tab-initiated fullscreen was granted. - IPC_STRUCT_MEMBER(bool, is_fullscreen_granted) - // The display mode. - IPC_STRUCT_MEMBER(blink::WebDisplayMode, display_mode) - // If set, requests the renderer to reply with a ViewHostMsg_UpdateRect - // with the ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK bit set in flags. - IPC_STRUCT_MEMBER(bool, needs_resize_ack) -IPC_STRUCT_END() - IPC_STRUCT_BEGIN(ViewMsg_New_Params) // Renderer-wide preferences. IPC_STRUCT_MEMBER(content::RendererPreferences, renderer_preferences) @@ -558,7 +526,7 @@ IPC_STRUCT_BEGIN(ViewMsg_New_Params) IPC_STRUCT_MEMBER(int32_t, next_page_id) // The initial renderer size. - IPC_STRUCT_MEMBER(ViewMsg_Resize_Params, initial_size) + IPC_STRUCT_MEMBER(content::ResizeParams, initial_size) // Whether to enable auto-resize. IPC_STRUCT_MEMBER(bool, enable_auto_resize) @@ -577,7 +545,6 @@ IPC_STRUCT_BEGIN(ViewMsg_UpdateScrollbarTheme_Params) IPC_STRUCT_MEMBER(bool, jump_on_track_click) IPC_STRUCT_MEMBER(blink::ScrollerStyle, preferred_scroller_style) IPC_STRUCT_MEMBER(bool, redraw) - IPC_STRUCT_MEMBER(bool, scroll_animation_enabled) IPC_STRUCT_MEMBER(blink::WebScrollbarButtonsPlacement, button_placement) IPC_STRUCT_END() #endif @@ -642,8 +609,7 @@ IPC_MESSAGE_ROUTED0(ViewMsg_Close) // the view's current size. The generated ViewHostMsg_UpdateRect message will // have the IS_RESIZE_ACK flag set. It also receives the resizer rect so that // we don't have to fetch it every time WebKit asks for it. -IPC_MESSAGE_ROUTED1(ViewMsg_Resize, - ViewMsg_Resize_Params /* params */) +IPC_MESSAGE_ROUTED1(ViewMsg_Resize, content::ResizeParams /* params */) // Enables device emulation. See WebDeviceEmulationParams for description. IPC_MESSAGE_ROUTED1(ViewMsg_EnableDeviceEmulation, @@ -684,17 +650,6 @@ IPC_MESSAGE_ROUTED2(ViewMsg_ShowContextMenu, ui::MenuSourceType, gfx::Point /* location where menu should be shown */) -// Sent when the user wants to search for a word on the page (find in page). -IPC_MESSAGE_ROUTED3(ViewMsg_Find, - int /* request_id */, - base::string16 /* search_text */, - blink::WebFindOptions) - -// This message notifies the renderer that the user has closed the FindInPage -// window (and what action to take regarding the selection). -IPC_MESSAGE_ROUTED1(ViewMsg_StopFinding, - content::StopFindAction /* action */) - // Copies the image at location x, y to the clipboard (if there indeed is an // image at that location). IPC_MESSAGE_ROUTED2(ViewMsg_CopyImageAt, @@ -779,11 +734,6 @@ IPC_MESSAGE_ROUTED2(ViewMsg_EnumerateDirectoryResponse, int /* request_id */, std::vector<base::FilePath> /* files_in_directory */) -// Tells the renderer to suppress any further modal dialogs until it receives a -// corresponding ViewMsg_SwapOut message. This ensures that no -// PageGroupLoadDeferrer is on the stack for SwapOut. -IPC_MESSAGE_ROUTED0(ViewMsg_SuppressDialogsUntilSwapOut) - // Instructs the renderer to close the current page, including running the // onunload event handler. // @@ -867,6 +817,10 @@ IPC_MESSAGE_CONTROL2(ViewMsg_NetworkConnectionChanged, net::NetworkChangeNotifier::ConnectionType /* type */, double /* max bandwidth mbps */) +// Sent by the browser to synchronize with the next compositor frame. Used only +// for tests. +IPC_MESSAGE_ROUTED1(ViewMsg_WaitForNextFrameForTests, int /* routing_id */) + #if defined(ENABLE_PLUGINS) // Reply to ViewHostMsg_OpenChannelToPpapiBroker // Tells the renderer that the channel to the broker has been created. @@ -886,9 +840,6 @@ IPC_MESSAGE_CONTROL1(ViewMsg_PurgePluginListCache, bool /* reload_pages */) #endif -// Used to instruct the RenderView to go into "view source" mode. -IPC_MESSAGE_ROUTED0(ViewMsg_EnableViewSourceMode) - // An acknowledge to ViewHostMsg_MultipleTargetsTouched to notify the renderer // process to release the magnified image. IPC_MESSAGE_ROUTED1(ViewMsg_ReleaseDisambiguationPopupBitmap, @@ -914,19 +865,6 @@ IPC_MESSAGE_CONTROL3(ViewMsg_SystemColorsChanged, IPC_MESSAGE_CONTROL1(ViewMsg_SetWebKitSharedTimersSuspended, bool /* suspend */) -// Sent when the browser wants the bounding boxes of the current find matches. -// -// If match rects are already cached on the browser side, |current_version| -// should be the version number from the ViewHostMsg_FindMatchRects_Reply -// they came in, so the renderer can tell if it needs to send updated rects. -// Otherwise just pass -1 to always receive the list of rects. -// -// There must be an active search string (it is probably most useful to call -// this immediately after a ViewHostMsg_Find_Reply message arrives with -// final_update set to true). -IPC_MESSAGE_ROUTED1(ViewMsg_FindMatchRects, - int /* current_version */) - // Notifies the renderer whether hiding/showing the top controls is enabled // and whether or not to animate to the proper state. IPC_MESSAGE_ROUTED3(ViewMsg_UpdateTopControlsState, @@ -940,26 +878,6 @@ IPC_MESSAGE_ROUTED0(ViewMsg_ShowImeIfNeeded) // ViewHostMsg_SmartClipDataExtracted IPC. IPC_MESSAGE_ROUTED1(ViewMsg_ExtractSmartClipData, gfx::Rect /* rect */) - -#elif defined(OS_MACOSX) -// Let the RenderView know its window has changed visibility. -IPC_MESSAGE_ROUTED1(ViewMsg_SetWindowVisibility, - bool /* visibile */) - -// Let the RenderView know its window's frame has changed. -IPC_MESSAGE_ROUTED2(ViewMsg_WindowFrameChanged, - gfx::Rect /* window frame */, - gfx::Rect /* content view frame */) - -// Message sent from the browser to the renderer when the user starts or stops -// resizing the view. -IPC_MESSAGE_ROUTED1(ViewMsg_SetInLiveResize, - bool /* enable */) - -// Tell the renderer that plugin IME has completed. -IPC_MESSAGE_ROUTED2(ViewMsg_PluginImeCompositionCompleted, - base::string16 /* text */, - int /* plugin_id */) #endif // Sent by the browser as a reply to ViewHostMsg_SwapCompositorFrame. @@ -1071,19 +989,6 @@ IPC_MESSAGE_ROUTED0(ViewHostMsg_UpdateScreenRects_ACK) IPC_MESSAGE_ROUTED1(ViewHostMsg_RequestMove, gfx::Rect /* position */) -// Result of string search in the page. -// Response to ViewMsg_Find with the results of the requested find-in-page -// search, the number of matches found and the selection rect (in screen -// coordinates) for the string found. If |final_update| is false, it signals -// that this is not the last Find_Reply message - more will be sent as the -// scoping effort continues. -IPC_MESSAGE_ROUTED5(ViewHostMsg_Find_Reply, - int /* request_id */, - int /* number of matches */, - gfx::Rect /* selection_rect */, - int /* active_match_ordinal */, - bool /* final_update */) - // Indicates that the render view has been closed in respose to a // Close message. IPC_MESSAGE_CONTROL1(ViewHostMsg_Close_ACK, @@ -1127,14 +1032,6 @@ IPC_MESSAGE_ROUTED2(ViewHostMsg_FocusedNodeChanged, IPC_MESSAGE_ROUTED1(ViewHostMsg_SetCursor, content::WebCursor) -#if defined(OS_WIN) -IPC_MESSAGE_ROUTED1(ViewHostMsg_WindowlessPluginDummyWindowCreated, - gfx::NativeViewId /* dummy_activation_window */) - -IPC_MESSAGE_ROUTED1(ViewHostMsg_WindowlessPluginDummyWindowDestroyed, - gfx::NativeViewId /* dummy_activation_window */) -#endif - // Get the list of proxies to use for |url|, as a semicolon delimited list // of "<TYPE> <HOST>:<PORT>" | "DIRECT". IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_ResolveProxy, @@ -1221,7 +1118,7 @@ IPC_MESSAGE_ROUTED2(ViewHostMsg_SetTooltipText, // text in the document. IPC_MESSAGE_ROUTED3(ViewHostMsg_SelectionChanged, base::string16 /* text covers the selection range */, - size_t /* the offset of the text in the document */, + uint32_t /* the offset of the text in the document */, gfx::Range /* selection range in the document */) // Notification that the selection bounds have changed. @@ -1363,27 +1260,10 @@ IPC_MESSAGE_ROUTED0(ViewHostMsg_DidFirstPaintAfterLoad) IPC_MESSAGE_ROUTED1(ViewHostMsg_ForwardCompositorProto, std::vector<uint8_t> /* proto */) -#if defined(OS_ANDROID) -// Response to ViewMsg_FindMatchRects. -// -// |version| will contain the current version number of the renderer's find -// match list (incremented whenever they change), which should be passed in the -// next call to ViewMsg_FindMatchRects. -// -// |rects| will either contain a list of the enclosing rects of all matches -// found by the most recent Find operation, or will be empty if |version| is not -// greater than the |current_version| passed to ViewMsg_FindMatchRects (hence -// your locally cached rects should still be valid). The rect coords will be -// custom normalized fractions of the document size. The rects will be sorted by -// frame traversal order starting in the main frame, then by dom order. -// -// |active_rect| will contain the bounding box of the active find-in-page match -// marker, in similarly normalized coords (or an empty rect if there isn't one). -IPC_MESSAGE_ROUTED3(ViewHostMsg_FindMatchRects_Reply, - int /* version */, - std::vector<gfx::RectF> /* rects */, - gfx::RectF /* active_rect */) +// Sent in reply to ViewMsg_WaitForNextFrameForTests. +IPC_MESSAGE_ROUTED0(ViewHostMsg_WaitForNextFrameForTests_ACK) +#if defined(OS_ANDROID) // Start an android intent with the given URI. IPC_MESSAGE_ROUTED2(ViewHostMsg_StartContentIntent, GURL /* content_url */, @@ -1402,14 +1282,6 @@ IPC_MESSAGE_ROUTED2(ViewHostMsg_ShowUnhandledTapUIIfNeeded, int /* y */) #elif defined(OS_MACOSX) -// Informs the browser that a plugin has gained or lost focus. -IPC_MESSAGE_ROUTED2(ViewHostMsg_PluginFocusChanged, - bool, /* focused */ - int /* plugin_id */) - -// Instructs the browser to start plugin IME. -IPC_MESSAGE_ROUTED0(ViewHostMsg_StartPluginIme) - // Receives content of a web page as plain text. IPC_MESSAGE_ROUTED1(ViewMsg_GetRenderedTextCompleted, std::string) #endif diff --git a/chromium/content/common/vr_service.mojom b/chromium/content/common/vr_service.mojom index 2d81ec70a11..5e90880a519 100644 --- a/chromium/content/common/vr_service.mojom +++ b/chromium/content/common/vr_service.mojom @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -module content; +module content.mojom; struct VRVector3 { float x; diff --git a/chromium/content/common/wake_lock_service.mojom b/chromium/content/common/wake_lock_service.mojom index 3d6e6d896c9..452d9342cda 100644 --- a/chromium/content/common/wake_lock_service.mojom +++ b/chromium/content/common/wake_lock_service.mojom @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -module content; +module content.mojom; // WebLockService receives per-frame wake lock preference from its client. interface WakeLockService { diff --git a/chromium/content/common/webplugin_geometry.cc b/chromium/content/common/webplugin_geometry.cc deleted file mode 100644 index ff290d20001..00000000000 --- a/chromium/content/common/webplugin_geometry.cc +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2012 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 "content/common/webplugin_geometry.h" - -namespace content { - -WebPluginGeometry::WebPluginGeometry() - : window(gfx::kNullPluginWindow), - rects_valid(false), - visible(false) { -} - -WebPluginGeometry::~WebPluginGeometry() { -} - -bool WebPluginGeometry::Equals(const WebPluginGeometry& rhs) const { - return window == rhs.window && - window_rect == rhs.window_rect && - clip_rect == rhs.clip_rect && - cutout_rects == rhs.cutout_rects && - rects_valid == rhs.rects_valid && - visible == rhs.visible; -} - -} // namespace content diff --git a/chromium/content/common/webplugin_geometry.h b/chromium/content/common/webplugin_geometry.h deleted file mode 100644 index 7f727a1317e..00000000000 --- a/chromium/content/common/webplugin_geometry.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2013 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 CONTENT_COMMON_WEBPLUGIN_GEOMETRY_H_ -#define CONTENT_COMMON_WEBPLUGIN_GEOMETRY_H_ - -#include <vector> - -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/native_widget_types.h" - -namespace content { - -// Describes the new location for a plugin window. -struct WebPluginGeometry { - WebPluginGeometry(); - ~WebPluginGeometry(); - - bool Equals(const WebPluginGeometry& rhs) const; - - // On Windows, this is the plugin window in the plugin process. - // On X11, this is the XID of the plugin-side GtkPlug containing the - // GtkSocket hosting the actual plugin window. - // - // On Mac OS X, all of the plugin types are currently "windowless" - // (window == 0) except for the special case of the GPU plugin, - // which currently performs rendering on behalf of the Pepper 3D API - // and WebGL. The GPU plugin uses a simple integer for the - // PluginWindowHandle which is used to map to a side data structure - // containing information about the plugin. Soon this plugin will be - // generalized, at which point this mechanism will be rethought or - // removed. - gfx::PluginWindowHandle window; - gfx::Rect window_rect; - // Clip rect (include) and cutouts (excludes), relative to - // window_rect origin. - gfx::Rect clip_rect; - std::vector<gfx::Rect> cutout_rects; - bool rects_valid; - bool visible; -}; - -} // namespace content - -#endif // CONTENT_COMMON_WEBPLUGIN_GEOMETRY_H_ diff --git a/chromium/content/common/websocket_messages.h b/chromium/content/common/websocket_messages.h index e0af254960e..383eb5a1f4a 100644 --- a/chromium/content/common/websocket_messages.h +++ b/chromium/content/common/websocket_messages.h @@ -73,6 +73,23 @@ IPC_MESSAGE_ROUTED4(WebSocketHostMsg_AddChannelRequest, url::Origin /* origin */, int /* render_frame_id */) +// Send a complete binary WebSocket message consisting of the Blob identified by +// |uuid|. The message will be split into frames as necessary. |expected_size| +// must match the browser's idea of the size of the Blob to prevent flow control +// from becoming desynchronised. If it does not match the connection will be +// terminated with a WebSocketMsg_NotifyFailure message. On success, the browser +// will have consumed |expected_size| bytes of flow control send quota and the +// renderer needs to subtract that from its running total of flow control send +// quota. See the design doc at +// https://docs.google.com/document/d/1CDiXB9pBumhFVVfmIn1CRI6v6byxyqWu2urEE9xp714/edit +// SendFrame or SendBlob IPCs must not be sent by the renderer until the +// BlobSendComplete message has been received from the browser. The renderer +// should retain a reference to the Blob until either a BlobSendComplete or +// NotifyFailure IPC is received. +IPC_MESSAGE_ROUTED2(WebSocketHostMsg_SendBlob, + std::string /* uuid */, + uint64_t /* expected_size */) + // WebSocket messages sent from the browser to the renderer. // Respond to an AddChannelRequest. |selected_protocol| is the sub-protocol the @@ -111,6 +128,11 @@ IPC_MESSAGE_ROUTED1(WebSocketMsg_NotifyFinishOpeningHandshake, IPC_MESSAGE_ROUTED1(WebSocketMsg_NotifyFailure, std::string /* message */) +// Indicates tbat the current Blob has finished sending. The renderer can +// release its reference on the Blob, and may now use SendFrame or SendBlob to +// send more messages. +IPC_MESSAGE_ROUTED0(WebSocketMsg_BlobSendComplete) + // WebSocket messages that can be sent in either direction. // Send a non-control frame to the channel. @@ -136,6 +158,14 @@ IPC_MESSAGE_ROUTED3(WebSocketMsg_SendFrame, // Both sides start a new channel with a quota of 0, and must wait for a // FlowControl message before calling SendFrame. The total available quota on // one side must never exceed 0x7FFFFFFFFFFFFFFF tokens. +// +// During "blob sending mode", ie. between the renderer sending a +// WebSocketHostMsg_SendBlob IPC and receiving a WebSocketMsg_BlobSendComplete +// IPC, quota is used up in the browser process to send the blob, but +// FlowControl IPCs for that quota are still sent to the renderer. The render +// process needs to take into account that quota equal to the size of the Blob +// has already been used when calculating how much send quota it has left after +// receiving BlobSendComplete. IPC_MESSAGE_ROUTED1(WebSocketMsg_FlowControl, int64_t /* quota */) // Drop the channel. diff --git a/chromium/content/common/worker_messages.h b/chromium/content/common/worker_messages.h index 60f1a4a9d10..e49ce80e525 100644 --- a/chromium/content/common/worker_messages.h +++ b/chromium/content/common/worker_messages.h @@ -41,6 +41,7 @@ IPC_STRUCT_BEGIN(WorkerProcessMsg_CreateWorker_Params) IPC_STRUCT_MEMBER(base::string16, name) IPC_STRUCT_MEMBER(base::string16, content_security_policy) IPC_STRUCT_MEMBER(blink::WebContentSecurityPolicyType, security_policy_type) + IPC_STRUCT_MEMBER(blink::WebAddressSpace, creation_address_space) IPC_STRUCT_MEMBER(bool, pause_on_start) IPC_STRUCT_MEMBER(int, route_id) IPC_STRUCT_END() @@ -55,16 +56,6 @@ IPC_MESSAGE_CONTROL1(WorkerProcessMsg_CreateWorker, // WorkerProcessHost messages // These are messages sent from the worker process to the browser process. -// Sent by the worker process to check whether access to web databases is -// allowed. -IPC_SYNC_MESSAGE_CONTROL5_1(WorkerProcessHostMsg_AllowDatabase, - int /* worker_route_id */, - GURL /* origin url */, - base::string16 /* database name */, - base::string16 /* database display name */, - unsigned long /* estimated size */, - bool /* result */) - // Sent by the worker process to check whether access to file system is allowed. IPC_SYNC_MESSAGE_CONTROL2_1(WorkerProcessHostMsg_RequestFileSystemAccessSync, int /* worker_route_id */, |