Chromium Code Reviews| Index: blimp/client/android/compositor/blimp_compositor.cc |
| diff --git a/blimp/client/android/compositor/blimp_compositor.cc b/blimp/client/android/compositor/blimp_compositor.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..22f470f30c40952aaf111020b94907045fc515ac |
| --- /dev/null |
| +++ b/blimp/client/android/compositor/blimp_compositor.cc |
| @@ -0,0 +1,533 @@ |
| +// 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 "blimp/client/android/compositor/blimp_compositor.h" |
| + |
| +#include <android/native_window_jni.h> |
| + |
| +#include "base/bind_helpers.h" |
| +#include "base/command_line.h" |
| +#include "base/lazy_instance.h" |
| +#include "base/single_thread_task_runner.h" |
| +#include "base/strings/string_number_conversions.h" |
| +#include "base/strings/string_split.h" |
| +#include "base/sys_info.h" |
| +#include "base/thread_task_runner_handle.h" |
| +#include "base/threading/simple_thread.h" |
| +#include "base/threading/thread.h" |
| +#include "base/threading/thread_local.h" |
| +#include "base/threading/thread_restrictions.h" |
| +#include "blimp/client/android/compositor/blimp_context_provider.h" |
| +#include "blimp/client/android/compositor/blimp_output_surface.h" |
| +#include "cc/base/switches.h" |
| +#include "cc/layers/layer.h" |
| +#include "cc/layers/solid_color_layer.h" |
| +#include "cc/output/output_surface.h" |
| +#include "cc/raster/task_graph_runner.h" |
| +#include "cc/trees/layer_tree_host.h" |
| +#include "content/public/common/content_switches.h" |
| +#include "ui/gl/gl_surface.h" |
| + |
| +namespace { |
| + |
| +class SingleThreadTaskGraphRunner |
| + : public cc::TaskGraphRunner, |
| + public base::DelegateSimpleThread::Delegate { |
| + public: |
| + SingleThreadTaskGraphRunner() |
| + : worker_thread_( |
| + this, |
| + "CompositorTileWorker1", |
| + base::SimpleThread::Options(base::ThreadPriority::BACKGROUND)) { |
| + worker_thread_.Start(); |
| + } |
| + |
| + ~SingleThreadTaskGraphRunner() override { |
| + Shutdown(); |
| + worker_thread_.Join(); |
| + } |
| + |
| + private: |
| + // Overridden from base::DelegateSimpleThread::Delegate: |
| + void Run() override { cc::TaskGraphRunner::Run(); } |
| + |
| + base::DelegateSimpleThread worker_thread_; |
| +}; |
| + |
| +base::LazyInstance<SingleThreadTaskGraphRunner> g_task_graph_runner = |
| + LAZY_INSTANCE_INITIALIZER; |
| + |
| +bool GetSwitchValueAsInt(const base::CommandLine& command_line, |
| + const std::string& switch_string, |
| + int min_value, |
| + int max_value, |
| + int* result) { |
| + std::string string_value = command_line.GetSwitchValueASCII(switch_string); |
| + int int_value; |
| + if (base::StringToInt(string_value, &int_value) && int_value >= min_value && |
| + int_value <= max_value) { |
| + *result = int_value; |
| + return true; |
| + } else { |
| + return false; |
| + } |
| +} |
| + |
| +void StringToUintVector(const std::string& str, std::vector<unsigned>* vector) { |
| + DCHECK(vector->empty()); |
| + std::vector<std::string> pieces = |
| + base::SplitString(str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
| + DCHECK_EQ(pieces.size(), static_cast<size_t>(gfx::BufferFormat::LAST) + 1); |
| + for (size_t i = 0; i < pieces.size(); ++i) { |
| + unsigned number = 0; |
| + bool succeed = base::StringToUint(pieces[i], &number); |
| + DCHECK(succeed); |
| + vector->push_back(number); |
| + } |
| +} |
| + |
| +bool GetSwitchValueAsUInt(const base::CommandLine& command_line, |
| + const std::string& switch_string, |
| + unsigned min_value, |
| + unsigned max_value, |
| + unsigned* result) { |
| + std::string string_value = command_line.GetSwitchValueASCII(switch_string); |
| + unsigned uint_value; |
| + if (base::StringToUint(string_value, &uint_value) && |
| + uint_value >= min_value && uint_value <= max_value) { |
| + *result = uint_value; |
| + return true; |
| + } else { |
| + return false; |
| + } |
| +} |
| + |
| +gfx::Size CalculateDefaultTileSize(const gfx::Size& physical_size, |
| + const gfx::Size& display_size) { |
| + int default_tile_size = 256; |
| + bool real_size_supported = true; |
| + int display_width = physical_size.width(); |
| + int display_height = physical_size.height(); |
| + if (display_width == 0 || display_height == 0) { |
| + real_size_supported = false; |
| + display_width = display_size.width(); |
| + display_height = display_size.height(); |
| + } |
| + |
| + int portrait_width = std::min(display_width, display_height); |
| + int landscape_width = std::max(display_width, display_height); |
| + |
| + if (real_size_supported) { |
| + // Maximum HD dimensions should be 768x1280 |
| + // Maximum FHD dimensions should be 1200x1920 |
| + if (portrait_width > 768 || landscape_width > 1280) |
| + default_tile_size = 384; |
| + if (portrait_width > 1200 || landscape_width > 1920) |
| + default_tile_size = 512; |
| + |
| + // Adjust for some resolutions that barely straddle an extra |
| + // tile when in portrait mode. This helps worst case scroll/raster |
| + // by not needing a full extra tile for each row. |
| + if (default_tile_size == 256 && portrait_width == 768) |
| + default_tile_size += 32; |
| + if (default_tile_size == 384 && portrait_width == 1200) |
| + default_tile_size += 32; |
| + } else { |
| + // We don't know the exact resolution due to screen controls etc. |
|
nyquist
2015/08/19 07:48:06
Optional nit: Add comma at end of line, and lowerc
David Trainor- moved to gerrit
2015/08/21 00:49:46
Done.
|
| + // So this just estimates the values above using tile counts. |
| + int numTiles = (display_width * display_height) / (256 * 256); |
| + if (numTiles > 16) |
| + default_tile_size = 384; |
| + if (numTiles >= 40) |
| + default_tile_size = 512; |
| + } |
| + |
| + return gfx::Size(default_tile_size, default_tile_size); |
| +} |
| + |
| +void PopulateLayerTreeSettings(cc::LayerTreeSettings& settings, |
| + const gfx::Size& physical_size, |
| + const gfx::Size& display_size) { |
| + base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); |
| + |
| + // For web contents, layer transforms should scale up the contents of layers |
| + // to keep content always crisp when possible. |
| + settings.layer_transforms_should_scale_layer_contents = true; |
| + |
| + if (cmd->HasSwitch(switches::kDisableGpuVsync)) { |
| + std::string display_vsync_string = |
| + cmd->GetSwitchValueASCII(switches::kDisableGpuVsync); |
| + if (display_vsync_string == "gpu") { |
| + settings.renderer_settings.disable_display_vsync = true; |
| + } else if (display_vsync_string == "beginframe") { |
| + settings.wait_for_beginframe_interval = false; |
| + } else { |
| + settings.renderer_settings.disable_display_vsync = true; |
| + settings.wait_for_beginframe_interval = false; |
| + } |
| + } |
| + settings.main_frame_before_activation_enabled = |
| + cmd->HasSwitch(cc::switches::kEnableMainFrameBeforeActivation) && |
| + !cmd->HasSwitch(cc::switches::kDisableMainFrameBeforeActivation); |
| + settings.accelerated_animation_enabled = |
| + !cmd->HasSwitch(cc::switches::kDisableThreadedAnimation); |
| + settings.use_display_lists = cmd->HasSwitch(switches::kEnableSlimmingPaint); |
| + // if (cmd->HasSwitch(switches::kEnableCompositorAnimationTimelines)) { |
| + // settings.use_compositor_animation_timelines = true; |
| + // blink::WebRuntimeFeatures::enableCompositorAnimationTimelines(true); |
| + //} |
| + |
| + settings.default_tile_size = |
| + CalculateDefaultTileSize(physical_size, display_size); |
| + if (cmd->HasSwitch(switches::kDefaultTileWidth)) { |
| + int tile_width = 0; |
| + GetSwitchValueAsInt(*cmd, switches::kDefaultTileWidth, 1, |
| + std::numeric_limits<int>::max(), &tile_width); |
| + settings.default_tile_size.set_width(tile_width); |
| + } |
| + if (cmd->HasSwitch(switches::kDefaultTileHeight)) { |
| + int tile_height = 0; |
| + GetSwitchValueAsInt(*cmd, switches::kDefaultTileHeight, 1, |
| + std::numeric_limits<int>::max(), &tile_height); |
| + settings.default_tile_size.set_height(tile_height); |
| + } |
| + |
| + int max_untiled_layer_width = settings.max_untiled_layer_size.width(); |
| + if (cmd->HasSwitch(switches::kMaxUntiledLayerWidth)) { |
| + GetSwitchValueAsInt(*cmd, switches::kMaxUntiledLayerWidth, 1, |
| + std::numeric_limits<int>::max(), |
| + &max_untiled_layer_width); |
| + } |
| + int max_untiled_layer_height = settings.max_untiled_layer_size.height(); |
| + if (cmd->HasSwitch(switches::kMaxUntiledLayerHeight)) { |
| + GetSwitchValueAsInt(*cmd, switches::kMaxUntiledLayerHeight, 1, |
| + std::numeric_limits<int>::max(), |
| + &max_untiled_layer_height); |
| + } |
| + |
| + settings.max_untiled_layer_size = |
| + gfx::Size(max_untiled_layer_width, max_untiled_layer_height); |
| + |
| + settings.gpu_rasterization_msaa_sample_count = 0; |
| + if (cmd->HasSwitch(switches::kGpuRasterizationMSAASampleCount)) { |
| + GetSwitchValueAsInt(*cmd, switches::kGpuRasterizationMSAASampleCount, 0, |
| + std::numeric_limits<int>::max(), |
| + &settings.gpu_rasterization_msaa_sample_count); |
| + } |
| + |
| + settings.gpu_rasterization_forced = |
| + cmd->HasSwitch(switches::kForceGpuRasterization); |
| + settings.gpu_rasterization_enabled = |
| + cmd->HasSwitch(switches::kEnableGpuRasterization); |
| + |
| + settings.can_use_lcd_text = false; |
| + settings.use_distance_field_text = |
| + cmd->HasSwitch(switches::kEnableDistanceFieldText); |
| + |
| + settings.use_zero_copy = cmd->HasSwitch(switches::kEnableZeroCopy); |
| + settings.use_one_copy = !cmd->HasSwitch(switches::kDisableOneCopy); |
| + settings.enable_elastic_overscroll = false; |
| + |
| + if (cmd->HasSwitch(switches::kContentImageTextureTarget)) { |
| + settings.use_image_texture_targets.clear(); |
| + StringToUintVector( |
| + cmd->GetSwitchValueASCII(switches::kContentImageTextureTarget), |
| + &settings.use_image_texture_targets); |
| + } |
| + |
| + settings.gather_pixel_refs = false; |
| + if (cmd->HasSwitch(switches::kNumRasterThreads)) { |
| + int num_raster_threads = 0; |
| + GetSwitchValueAsInt(*cmd, switches::kNumRasterThreads, 0, |
| + std::numeric_limits<int>::max(), &num_raster_threads); |
| + settings.gather_pixel_refs = num_raster_threads > 1; |
| + } |
| + |
| + if (cmd->HasSwitch(cc::switches::kTopControlsShowThreshold)) { |
| + std::string top_threshold_str = |
| + cmd->GetSwitchValueASCII(cc::switches::kTopControlsShowThreshold); |
| + double show_threshold; |
| + if (base::StringToDouble(top_threshold_str, &show_threshold) && |
| + show_threshold >= 0.f && show_threshold <= 1.f) |
| + settings.top_controls_show_threshold = show_threshold; |
| + } |
| + |
| + if (cmd->HasSwitch(cc::switches::kTopControlsHideThreshold)) { |
| + std::string top_threshold_str = |
| + cmd->GetSwitchValueASCII(cc::switches::kTopControlsHideThreshold); |
| + double hide_threshold; |
| + if (base::StringToDouble(top_threshold_str, &hide_threshold) && |
| + hide_threshold >= 0.f && hide_threshold <= 1.f) |
| + settings.top_controls_hide_threshold = hide_threshold; |
| + } |
| + |
| + settings.verify_property_trees = |
| + cmd->HasSwitch(cc::switches::kEnablePropertyTreeVerification); |
| + settings.renderer_settings.allow_antialiasing &= |
| + !cmd->HasSwitch(cc::switches::kDisableCompositedAntialiasing); |
| + // The means the renderer compositor has 2 possible modes: |
| + // - Threaded compositing with a scheduler. |
| + // - Single threaded compositing without a scheduler (for layout tests only). |
| + // Using the scheduler in layout tests introduces additional composite steps |
| + // that create flakiness. |
| + settings.single_thread_proxy_scheduler = false; |
| + |
| + // These flags should be mirrored by UI versions in ui/compositor/. |
| + settings.initial_debug_state.show_debug_borders = |
| + cmd->HasSwitch(cc::switches::kShowCompositedLayerBorders); |
| + settings.initial_debug_state.show_fps_counter = |
| + cmd->HasSwitch(cc::switches::kShowFPSCounter); |
| + settings.initial_debug_state.show_layer_animation_bounds_rects = |
| + cmd->HasSwitch(cc::switches::kShowLayerAnimationBounds); |
| + settings.initial_debug_state.show_paint_rects = |
| + cmd->HasSwitch(switches::kShowPaintRects); |
| + settings.initial_debug_state.show_property_changed_rects = |
| + cmd->HasSwitch(cc::switches::kShowPropertyChangedRects); |
| + settings.initial_debug_state.show_surface_damage_rects = |
| + cmd->HasSwitch(cc::switches::kShowSurfaceDamageRects); |
| + settings.initial_debug_state.show_screen_space_rects = |
| + cmd->HasSwitch(cc::switches::kShowScreenSpaceRects); |
| + settings.initial_debug_state.show_replica_screen_space_rects = |
| + cmd->HasSwitch(cc::switches::kShowReplicaScreenSpaceRects); |
| + |
| + settings.initial_debug_state.SetRecordRenderingStats( |
| + cmd->HasSwitch(cc::switches::kEnableGpuBenchmarking)); |
| + |
| + if (cmd->HasSwitch(cc::switches::kSlowDownRasterScaleFactor)) { |
| + const int kMinSlowDownScaleFactor = 0; |
| + const int kMaxSlowDownScaleFactor = INT_MAX; |
| + GetSwitchValueAsInt( |
| + *cmd, cc::switches::kSlowDownRasterScaleFactor, kMinSlowDownScaleFactor, |
| + kMaxSlowDownScaleFactor, |
| + &settings.initial_debug_state.slow_down_raster_scale_factor); |
| + } |
| + |
| + settings.invert_viewport_scroll_order = |
| + cmd->HasSwitch(switches::kInvertViewportScrollOrder); |
| + |
| + if (cmd->HasSwitch(cc::switches::kMaxUnusedResourceMemoryUsagePercentage)) { |
| + int max_unused_resource_memory_percentage; |
| + if (GetSwitchValueAsInt( |
| + *cmd, cc::switches::kMaxUnusedResourceMemoryUsagePercentage, 0, 100, |
| + &max_unused_resource_memory_percentage)) { |
| + settings.max_unused_resource_memory_percentage = |
| + max_unused_resource_memory_percentage; |
| + } |
| + } |
| + |
| + settings.strict_layer_property_change_checking = |
| + cmd->HasSwitch(cc::switches::kStrictLayerPropertyChangeChecking); |
| + |
| +#if defined(OS_ANDROID) |
| + bool has_synchronous_compositor_factory = false; |
| + // SynchronousCompositorFactory* synchronous_compositor_factory = |
| + // SynchronousCompositorFactory::GetInstance(); |
| + |
| + // We can't use GPU rasterization on low-end devices, because the Ganesh |
| + // cache would consume too much memory. |
| + if (base::SysInfo::IsLowEndDevice()) |
| + settings.gpu_rasterization_enabled = false; |
| + settings.using_synchronous_renderer_compositor = |
| + has_synchronous_compositor_factory; |
| + settings.record_full_layer = false; // widget_->DoesRecordFullLayer(); |
| + settings.max_partial_texture_updates = 0; |
| + if (has_synchronous_compositor_factory) { |
|
nyquist
2015/08/19 07:48:06
Would we be certain to get one of these blocks alw
|
| + // Android WebView uses system scrollbars, so make ours invisible. |
| + settings.scrollbar_animator = cc::LayerTreeSettings::NO_ANIMATOR; |
| + settings.solid_color_scrollbar_color = SK_ColorTRANSPARENT; |
| + } else { |
| + settings.scrollbar_animator = cc::LayerTreeSettings::LINEAR_FADE; |
| + settings.scrollbar_fade_delay_ms = 300; |
| + settings.scrollbar_fade_resize_delay_ms = 2000; |
| + settings.scrollbar_fade_duration_ms = 300; |
| + settings.solid_color_scrollbar_color = SkColorSetARGB(128, 128, 128, 128); |
| + } |
| + settings.renderer_settings.highp_threshold_min = 2048; |
| + // Android WebView handles root layer flings itself. |
| + settings.ignore_root_layer_flings = has_synchronous_compositor_factory; |
| + // Memory policy on Android WebView does not depend on whether device is |
| + // low end, so always use default policy. |
| + bool use_low_memory_policy = |
| + base::SysInfo::IsLowEndDevice() && !has_synchronous_compositor_factory; |
| + // RGBA_4444 textures are only enabled for low end devices |
| + // and are disabled for Android WebView as it doesn't support the format. |
| + settings.renderer_settings.use_rgba_4444_textures = use_low_memory_policy; |
| + if (use_low_memory_policy) { |
| + // On low-end we want to be very carefull about killing other |
| + // apps. So initially we use 50% more memory to avoid flickering |
| + // or raster-on-demand. |
| + settings.max_memory_for_prepaint_percentage = 67; |
| + } else { |
| + // On other devices we have increased memory excessively to avoid |
| + // raster-on-demand already, so now we reserve 50% _only_ to avoid |
| + // raster-on-demand, and use 50% of the memory otherwise. |
| + settings.max_memory_for_prepaint_percentage = 50; |
| + } |
| + // Webview does not own the surface so should not clear it. |
| + settings.renderer_settings.should_clear_root_render_pass = |
| + !has_synchronous_compositor_factory; |
| + |
| + // TODO(danakj): Only do this on low end devices. |
| + settings.create_low_res_tiling = true; |
| + |
| +// settings.use_external_begin_frame_source = true; |
| + |
| +#elif !defined(OS_MACOSX) |
| + if (ui::IsOverlayScrollbarEnabled()) { |
| + settings.scrollbar_animator = cc::LayerTreeSettings::THINNING; |
| + settings.solid_color_scrollbar_color = SkColorSetARGB(128, 128, 128, 128); |
| + } else { |
| + settings.scrollbar_animator = cc::LayerTreeSettings::LINEAR_FADE; |
| + settings.solid_color_scrollbar_color = SkColorSetARGB(128, 128, 128, 128); |
| + } |
| + settings.scrollbar_fade_delay_ms = 500; |
| + settings.scrollbar_fade_resize_delay_ms = 500; |
| + settings.scrollbar_fade_duration_ms = 300; |
| + |
| + // When pinching in, only show the pinch-viewport overlay scrollbars if the |
| + // page scale is at least some threshold away from the minimum. i.e. don't |
| + // show the pinch scrollbars when at minimum scale. |
| + settings.scrollbar_show_scale_threshold = 1.05f; |
| +#endif |
| + |
| + if (cmd->HasSwitch(switches::kEnableLowResTiling)) |
| + settings.create_low_res_tiling = true; |
| + if (cmd->HasSwitch(switches::kDisableLowResTiling)) |
| + settings.create_low_res_tiling = false; |
| + if (cmd->HasSwitch(cc::switches::kEnableBeginFrameScheduling)) |
| + settings.use_external_begin_frame_source = true; |
| +} |
| + |
| +} // namespace |
| + |
| +namespace blimp { |
| + |
| +scoped_ptr<BlimpCompositor> BlimpCompositor::Create( |
| + const gfx::Size& physical_size, |
| + const gfx::Size& display_size, |
| + float device_scale_factor) { |
| + return make_scoped_ptr( |
| + new BlimpCompositor(physical_size, display_size, device_scale_factor)); |
| +} |
| + |
| +BlimpCompositor::BlimpCompositor(const gfx::Size& physical_size, |
| + const gfx::Size& display_size, |
| + float device_scale_factor) |
| + : device_scale_factor_(device_scale_factor), |
| + window_(nullptr), |
| + weak_factory_(this) { |
| + PopulateLayerTreeSettings(settings_, physical_size, display_size); |
| +} |
| + |
| +BlimpCompositor::~BlimpCompositor() {} |
| + |
| +void BlimpCompositor::SetSurface(JNIEnv* env, jobject jsurface) { |
| + if (window_) { |
| + ANativeWindow_release(window_); |
| + window_ = nullptr; |
| + SetVisible(false); |
| + } |
| + |
| + if (!jsurface) |
| + return; |
| + |
| + base::android::ScopedJavaLocalFrame scoped_local_reference_frame(env); |
| + window_ = ANativeWindow_fromSurface(env, jsurface); |
| + // TODO(dtrainor): Investigate ref counts! |
| + // ANativeWindow_acquire(window_); |
| + // ANativeWindow_release(window_); |
| + |
| + SetVisible(true); |
| +} |
| + |
| +void BlimpCompositor::SetVisible(bool visible) { |
| + if (visible && !host_) { |
| + // Create the LayerTreeHost |
| + cc::LayerTreeHost::InitParams params; |
| + params.client = this; |
| + params.shared_bitmap_manager = nullptr; |
| + params.gpu_memory_buffer_manager = nullptr; |
| + params.task_graph_runner = g_task_graph_runner.Pointer(); |
| + params.main_task_runner = base::ThreadTaskRunnerHandle::Get(); |
| + params.settings = &settings_; |
| + host_ = |
| + cc::LayerTreeHost::CreateThreaded(GetCompositorTaskRunner(), ¶ms); |
| + |
| + host_->SetVisible(true); |
| + host_->SetLayerTreeHostClientReady(); |
| + host_->SetViewportSize(viewport_size_); |
| + host_->SetDeviceScaleFactor(device_scale_factor_); |
| + |
| + // Dummy Layers |
| + scoped_refptr<cc::Layer> root( |
| + cc::SolidColorLayer::Create(cc::LayerSettings())); |
| + root->SetBounds(gfx::Size(300, 300)); |
| + root->SetBackgroundColor(SK_ColorRED); |
| + root->SetIsDrawable(true); |
| + host_->SetRootLayer(root); |
| + |
| + } else if (!visible && host_) { |
| + // Destroy the LayerTreeHost |
| + host_.reset(); |
| + } |
| +} |
| + |
| +void BlimpCompositor::SetSize(const gfx::Size& size) { |
| + viewport_size_ = size; |
| + if (host_) |
| + host_->SetViewportSize(viewport_size_); |
| +} |
| + |
| +void BlimpCompositor::Layout() {} |
| + |
| +void BlimpCompositor::RequestNewOutputSurface() { |
| + scoped_refptr<BlimpContextProvider> context_provider = |
| + BlimpContextProvider::Create(window_); |
| + |
| + scoped_ptr<cc::OutputSurface> output_surface( |
| + new BlimpOutputSurface(context_provider)); |
| + |
| + host_->SetOutputSurface(output_surface.Pass()); |
| +} |
| + |
| +void BlimpCompositor::DidInitializeOutputSurface() {} |
| + |
| +void BlimpCompositor::DidFailToInitializeOutputSurface() {} |
| + |
| +void BlimpCompositor::DidCommit() {} |
| + |
| +void BlimpCompositor::DidCompleteSwapBuffers() {} |
| + |
| +void BlimpCompositor::ScheduleComposite() {} |
| + |
| +void BlimpCompositor::ScheduleAnimation() {} |
| + |
| +void BlimpCompositor::DidPostSwapBuffers() {} |
| + |
| +void BlimpCompositor::DidAbortSwapBuffers() {} |
| + |
| +scoped_refptr<base::SingleThreadTaskRunner> |
| +BlimpCompositor::GetCompositorTaskRunner() { |
| + if (!compositor_thread_) { |
| + base::Thread::Options thread_options; |
| +#if defined(OS_ANDROID) |
| + thread_options.priority = base::ThreadPriority::DISPLAY; |
| +#endif |
| + compositor_thread_.reset(new base::Thread("Compositor")); |
| + compositor_thread_->StartWithOptions(thread_options); |
| + |
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner = |
| + compositor_thread_->task_runner(); |
| + task_runner->PostTask( |
| + FROM_HERE, |
| + base::Bind(base::IgnoreResult(&base::ThreadRestrictions::SetIOAllowed), |
| + false)); |
| + |
| + return task_runner; |
| + } else { |
| + return compositor_thread_->task_runner(); |
| + } |
| +} |
| + |
| +} // namespace blimp |