0

Delay screenshot SendResult and compression

SendResult and compression are expensive operations that can cause
contention with loading operations during navigation.

We don't need a screenshot immediately, but after the user reacts to a
page load, they might decide to do a history navigation gesture.
In other words, we can't wait that long. This CL uses a delay of
400ms, configurable via trial fields.

Screenshot compression can be delayed until the browser reaches
quiescence.

This CL replaces the previous approach of using lower priorities, which
proved not to be enough.

Bug: 393558258
Change-Id: Ibf4092ceb9d7adc5ff265fe1beec3819509924cb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6502812
Reviewed-by: Bo Liu <boliu@chromium.org>
Reviewed-by: Giovanni Ortuno Urquidi <ortuno@chromium.org>
Commit-Queue: Aldo Culquicondor <acondor@chromium.org>
Reviewed-by: Jonathan Ross <jonross@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1455899}
This commit is contained in:
Aldo Culquicondor
2025-05-05 13:03:11 -07:00
committed by Chromium LUCI CQ
parent 0b796753bd
commit aee41bb06a
17 changed files with 178 additions and 158 deletions

@ -10,6 +10,7 @@
#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/trace_event/trace_event.h"
@ -18,6 +19,8 @@
namespace {
constexpr int kMaxPendingSendResult = 4;
const char* ResultFormatToShortString(
viz::CopyOutputRequest::ResultFormat result_format) {
switch (result_format) {
@ -40,6 +43,13 @@ const char* ResultDestinationToShortString(
}
}
int g_pending_send_result_count = 0;
base::Lock& GetPendingSendResultLock() {
static base::NoDestructor<base::Lock> lock;
return *lock;
}
} // namespace
namespace viz {
@ -128,9 +138,28 @@ void CopyOutputRequest::SendResult(std::unique_ptr<CopyOutputResult> result) {
"viz", "CopyOutputRequest", this, "success", !result->IsEmpty(),
"has_provided_task_runner", !!result_task_runner_);
CHECK(result_task_runner_);
result_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(std::move(result_callback_), std::move(result)));
auto task = base::BindOnce(std::move(result_callback_), std::move(result));
if (send_result_delay_.is_zero()) {
result_task_runner_->PostTask(FROM_HERE, std::move(task));
} else {
base::AutoLock locked_counter(GetPendingSendResultLock());
if (g_pending_send_result_count >= kMaxPendingSendResult) {
result_task_runner_->PostTask(FROM_HERE, std::move(task));
} else {
g_pending_send_result_count++;
result_task_runner_->PostDelayedTask(
FROM_HERE,
base::BindOnce(
[](base::OnceClosure callback) {
std::move(callback).Run();
base::AutoLock locked_counter(GetPendingSendResultLock());
g_pending_send_result_count--;
},
std::move(task)),
send_result_delay_);
}
}
// Remove the reference to the task runner (no-op if we didn't have one).
result_task_runner_ = nullptr;
}

@ -12,6 +12,7 @@
#include "base/functional/callback.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/unguessable_token.h"
#include "components/viz/common/frame_sinks/blit_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
@ -52,15 +53,6 @@ class VIZ_COMMON_EXPORT CopyOutputRequest {
// results will still be returned via ResultDestination::kSystemMemory.
using ResultDestination = CopyOutputResult::Destination;
// This setting might influence the thread priority to use when sending the
// result over IPC. Currently only implemented for Android.
enum class IpcPriority {
// Use existing priority.
kDefault,
// Reduce the priority to background.
kBackground
};
using CopyOutputRequestCallback =
base::OnceCallback<void(std::unique_ptr<CopyOutputResult> result)>;
@ -80,10 +72,22 @@ class VIZ_COMMON_EXPORT CopyOutputRequest {
// Returns the requested result destination.
ResultDestination result_destination() const { return result_destination_; }
IpcPriority ipc_priority() const { return ipc_priority_; }
// Optionally set the thread priority to use when sending the result over IPC.
// Currently only affects Android.
void set_ipc_priority(IpcPriority p) { ipc_priority_ = p; }
base::TimeDelta send_result_delay() const { return send_result_delay_; }
// Optionally set a delay for sending the result.
// You can use this when you know that the CPU will be busy at the time of
// requesting the output and the result can wait.
// Because holding tasks can be expensive, we limit the number of pending
// tasks to kMaxPendingSendResult. When the limit is reached, results are sent
// immediately.
// There are no guarantees as to the order in which the SendResults are
// called.
//
// To provide ordering guarantees, we would have to include some form of
// queueing and track it across multiple threads. This complexity was not
// worth it when this was first introduced with only one usage with minimal
// delays.
void set_send_result_delay(base::TimeDelta d) { send_result_delay_ = d; }
// Requests that the result callback be run as a task posted to the given
// |task_runner|. If this is not set, the result callback will be run on the
@ -181,7 +185,7 @@ class VIZ_COMMON_EXPORT CopyOutputRequest {
const ResultFormat result_format_;
const ResultDestination result_destination_;
IpcPriority ipc_priority_ = IpcPriority::kDefault;
base::TimeDelta send_result_delay_;
CopyOutputRequestCallback result_callback_;
scoped_refptr<base::SequencedTaskRunner> result_task_runner_;
gfx::Vector2d scale_from_;

@ -5,14 +5,16 @@
#include "content/browser/renderer_host/navigation_transitions/navigation_entry_screenshot.h"
#include "base/feature_list.h"
#include "base/functional/callback.h"
#include "base/metrics/histogram_macros.h"
#include "base/task/bind_post_task.h"
#include "base/task/thread_pool.h"
#include "components/performance_manager/scenario_api/performance_scenario_observer.h"
#include "components/performance_manager/scenario_api/performance_scenarios.h"
#include "content/browser/renderer_host/navigation_transitions/navigation_entry_screenshot_cache.h"
#include "content/browser/renderer_host/navigation_transitions/navigation_transition_config.h"
#if BUILDFLAG(IS_ANDROID)
#include "base/functional/callback.h"
#include "base/task/bind_post_task.h"
#include "base/task/thread_pool.h"
#include "ui/android/resources/etc1_utils.h"
#endif
@ -69,19 +71,42 @@ NavigationEntryScreenshot::NavigationEntryScreenshot(
const SkBitmap& bitmap,
NavigationTransitionData::UniqueId unique_id,
bool supports_etc_non_power_of_two)
: bitmap_(cc::UIResourceBitmap(bitmap)),
: performance_scenarios::MatchingScenarioObserver(
performance_scenarios::kDefaultIdleScenarios),
bitmap_(cc::UIResourceBitmap(bitmap)),
unique_id_(unique_id),
dimensions_without_compression_(bitmap_->GetSize()) {
CHECK(NavigationTransitionConfig::AreBackForwardTransitionsEnabled());
DCHECK_CURRENTLY_ON(BrowserThread::UI);
StartCompression(bitmap, supports_etc_non_power_of_two);
compression_task_ = CompressionTask(bitmap, supports_etc_non_power_of_two);
if (!compression_task_) {
return;
}
if (NavigationTransitionConfig::ShouldCompressScreenshotWhenQuiet()) {
auto observer_list =
performance_scenarios::PerformanceScenarioObserverList::GetForScope(
performance_scenarios::ScenarioScope::kGlobal);
if (observer_list) {
observer_list->AddMatchingObserver(this);
return;
}
}
StartCompression();
}
NavigationEntryScreenshot::~NavigationEntryScreenshot() {
if (cache_) {
cache_->OnNavigationEntryGone(unique_id_);
}
if (compression_task_) {
auto observer_list =
performance_scenarios::PerformanceScenarioObserverList::GetForScope(
performance_scenarios::ScenarioScope::kGlobal);
if (observer_list) {
observer_list->RemoveMatchingObserver(this);
}
}
}
cc::UIResourceBitmap NavigationEntryScreenshot::GetBitmap(cc::UIResourceId uid,
@ -103,6 +128,17 @@ size_t NavigationEntryScreenshot::SetCache(
return GetBitmap().SizeInBytes();
}
void NavigationEntryScreenshot::OnScenarioMatchChanged(
performance_scenarios::ScenarioScope scope,
bool matches_pattern) {
if (matches_pattern && compression_task_) {
StartCompression();
performance_scenarios::PerformanceScenarioObserverList::GetForScope(
performance_scenarios::ScenarioScope::kGlobal)
->RemoveMatchingObserver(this);
}
}
SkBitmap NavigationEntryScreenshot::GetBitmapForTesting() const {
return GetBitmap().GetBitmapForTesting(); // IN-TEST
}
@ -111,13 +147,13 @@ size_t NavigationEntryScreenshot::CompressedSizeForTesting() const {
return !bitmap_ ? compressed_bitmap_->SizeInBytes() : 0u;
}
void NavigationEntryScreenshot::StartCompression(
base::OnceClosure NavigationEntryScreenshot::CompressionTask(
const SkBitmap& bitmap,
bool supports_etc_non_power_of_two) {
#if BUILDFLAG(IS_ANDROID)
if (!base::FeatureList::IsEnabled(kNavigationEntryScreenshotCompression) ||
g_disable_compression_for_testing) {
return;
return base::OnceClosure();
}
CompressionDoneCallback done_callback = base::BindPostTask(
@ -125,15 +161,21 @@ void NavigationEntryScreenshot::StartCompression(
base::BindOnce(&NavigationEntryScreenshot::OnCompressionFinished,
weak_factory_.GetWeakPtr()));
base::ThreadPool::PostTask(
FROM_HERE,
{base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
base::BindOnce(&CompressNavigationScreenshotOnWorkerThread, bitmap,
supports_etc_non_power_of_two, std::move(done_callback)));
return base::BindOnce(&CompressNavigationScreenshotOnWorkerThread, bitmap,
supports_etc_non_power_of_two,
std::move(done_callback));
#else
return base::OnceClosure();
#endif
}
void NavigationEntryScreenshot::StartCompression() {
base::ThreadPool::PostTask(FROM_HERE,
{base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
std::move(compression_task_));
}
void NavigationEntryScreenshot::OnCompressionFinished(
sk_sp<SkPixelRef> compressed_bitmap) {
CHECK(!compressed_bitmap_);

@ -5,9 +5,11 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_TRANSITIONS_NAVIGATION_ENTRY_SCREENSHOT_H_
#define CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_TRANSITIONS_NAVIGATION_ENTRY_SCREENSHOT_H_
#include "base/functional/callback_forward.h"
#include "base/supports_user_data.h"
#include "cc/resources/ui_resource_bitmap.h"
#include "cc/resources/ui_resource_client.h"
#include "components/performance_manager/scenario_api/performance_scenario_observer.h"
#include "content/browser/renderer_host/navigation_transitions/navigation_transition_data.h"
#include "content/common/content_export.h"
@ -45,7 +47,8 @@ class NavigationEntryScreenshotCache;
// `NavigationEntryScreenshot`.
class CONTENT_EXPORT NavigationEntryScreenshot
: public cc::UIResourceClient,
public base::SupportsUserData::Data {
public base::SupportsUserData::Data,
public performance_scenarios::MatchingScenarioObserver {
public:
const static void* const kUserDataKey;
@ -70,6 +73,9 @@ class CONTENT_EXPORT NavigationEntryScreenshot
// Returns the memory occupied by the bitmap in bytes.
size_t SetCache(NavigationEntryScreenshotCache* cache);
void OnScenarioMatchChanged(performance_scenarios::ScenarioScope scope,
bool matches_pattern) override;
// Returns true if the screenshot is being managed by a cache. This is not the
// case when it's being displayed in the UI.
bool is_cached() const { return cache_ != nullptr; }
@ -87,8 +93,10 @@ class CONTENT_EXPORT NavigationEntryScreenshot
private:
void OnCompressionFinished(sk_sp<SkPixelRef> compressed_bitmap);
void StartCompression(const SkBitmap& bitmap,
bool supports_etc_non_power_of_two);
base::OnceClosure CompressionTask(const SkBitmap& bitmap,
bool supports_etc_non_power_of_two);
void StartCompression();
const cc::UIResourceBitmap& GetBitmap() const;
// The uncompressed bitmap cached when navigating away from this navigation
@ -114,6 +122,8 @@ class CONTENT_EXPORT NavigationEntryScreenshot
const gfx::Size dimensions_without_compression_;
base::OnceClosure compression_task_;
base::WeakPtrFactory<NavigationEntryScreenshot> weak_factory_{this};
};

@ -5,6 +5,7 @@
#include "content/browser/renderer_host/navigation_transitions/navigation_transition_config.h"
#include "base/system/sys_info.h"
#include "base/time/time.h"
#include "content/public/common/content_features.h"
#include "third_party/blink/public/common/features.h"
#include "ui/display/screen.h"
@ -29,9 +30,21 @@ const base::FeatureParam<base::TimeDelta> kInvisibleCacheCleanupDelay{
&blink::features::kBackForwardTransitions, "invisible-cache-cleanup-delay",
base::Minutes(7)};
const base::FeatureParam<bool> kTransferScreenshotInBackgroundPriority{
// Compression can be done in a best-effort basis to reduce contention.
// Quiescence is defined as no visible page loading and no input being
// processed.
const base::FeatureParam<bool> kCompressScreenshotWhenQuiet{
&blink::features::kBackForwardTransitions, "compress-screenshot-when-quiet",
false};
// SendResult is an expensive operation and the start of a navigation is a busy
// time. Delaying SendResult reduces chances of contention.
// The value can be based on human reaction times and LCP latencies and it can
// be adjusted based on the incidence of the value SentScreenshotRequest in
// Navigation.GestureTransition.CacheHitOrMissReason.
const base::FeatureParam<int> kScreenshotSendResultDelayMs{
&blink::features::kBackForwardTransitions,
"transfer-screenshot-in-background-priority", false};
"screenshot-send-result-delay-ms", 0};
size_t GetMaxCacheSizeInBytes() {
constexpr int kLowEndMax = 32 * 1024 * 1024; // 32MB
@ -94,9 +107,13 @@ NavigationTransitionConfig::GetCleanupDelayForInvisibleCaches() {
}
// static
bool NavigationTransitionConfig::
ShouldTransferScreenshotInBackgroundPriority() {
return kTransferScreenshotInBackgroundPriority.Get();
bool NavigationTransitionConfig::ShouldCompressScreenshotWhenQuiet() {
return kCompressScreenshotWhenQuiet.Get();
}
// static
base::TimeDelta NavigationTransitionConfig::ScreenshotSendResultDelay() {
return base::Milliseconds(kScreenshotSendResultDelayMs.Get());
}
} // namespace content

@ -26,9 +26,12 @@ class NavigationTransitionConfig {
// Provides the duration for a cache to be invisible before its evicted.
static base::TimeDelta GetCleanupDelayForInvisibleCaches();
// Whether to use background priority to transfer the navigation screenshot
// between processes.
static bool ShouldTransferScreenshotInBackgroundPriority();
// Whether to wait for quiescence to start compressing a screenshot.
static bool ShouldCompressScreenshotWhenQuiet();
// How long to wait after obtaining a copy of the contents in the GPU process
// before sending it to the browser process.
static base::TimeDelta ScreenshotSendResultDelay();
};
} // namespace content

@ -4,6 +4,7 @@
#include "content/browser/renderer_host/navigation_transitions/navigation_transition_utils.h"
#include "base/time/time.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "content/browser/compositor/surface_utils.h"
@ -446,12 +447,8 @@ bool NavigationTransitionUtils::
const gfx::Size output_size = g_output_size_for_test;
#if BUILDFLAG(IS_ANDROID)
CopyOutputIpcPriority ipc_priority =
NavigationTransitionConfig::ShouldTransferScreenshotInBackgroundPriority()
? CopyOutputIpcPriority::kBackground
: CopyOutputIpcPriority::kDefault;
static_cast<RenderWidgetHostViewBase*>(rwhv)
->CopyFromExactSurfaceWithIpcPriority(
->CopyFromExactSurfaceWithIpcDelay(
/*src_rect=*/gfx::Rect(), output_size,
base::BindOnce(
&CacheScreenshotImpl, navigation_controller.GetWeakPtr(),
@ -459,7 +456,7 @@ bool NavigationTransitionUtils::
last_committed_entry->navigation_transition_data().unique_id(),
/*is_copied_from_embedder=*/false, request_sequence,
SupportsETC1NonPowerOfTwo(navigation_request)),
ipc_priority);
NavigationTransitionConfig::ScreenshotSendResultDelay());
#else
static_cast<RenderWidgetHostViewBase*>(rwhv)->CopyFromExactSurface(
/*src_rect=*/gfx::Rect(), output_size,

@ -1763,23 +1763,22 @@ void RenderWidgetHostViewAndroid::CopyFromSurface(
},
std::move(callback)),
/*capture_exact_surface_id=*/false,
viz::CopyOutputRequest::IpcPriority::kDefault);
/*ipc_delay=*/base::TimeDelta());
}
void RenderWidgetHostViewAndroid::CopyFromExactSurface(
const gfx::Rect& src_rect,
const gfx::Size& output_size,
base::OnceCallback<void(const SkBitmap&)> callback) {
CopyFromExactSurfaceWithIpcPriority(
src_rect, output_size, std::move(callback),
viz::CopyOutputRequest::IpcPriority::kDefault);
CopyFromExactSurfaceWithIpcDelay(src_rect, output_size, std::move(callback),
/*ipc_delay=*/base::TimeDelta());
}
void RenderWidgetHostViewAndroid::CopyFromExactSurfaceWithIpcPriority(
void RenderWidgetHostViewAndroid::CopyFromExactSurfaceWithIpcDelay(
const gfx::Rect& src_rect,
const gfx::Size& output_size,
base::OnceCallback<void(const SkBitmap&)> callback,
CopyOutputIpcPriority ipc_priority) {
base::TimeDelta ipc_delay) {
CHECK(IsSurfaceAvailableForCopy())
<< "To copy the exact surface, it must be available for copy (embedded "
"via the browser).";
@ -1792,7 +1791,7 @@ void RenderWidgetHostViewAndroid::CopyFromExactSurfaceWithIpcPriority(
[](base::OnceCallback<void(const SkBitmap&)> callback,
const SkBitmap& bitmap) { std::move(callback).Run(bitmap); },
std::move(callback)),
/*capture_exact_surface_id=*/true, ipc_priority);
/*capture_exact_surface_id=*/true, ipc_delay);
}
void RenderWidgetHostViewAndroid::EnsureSurfaceSynchronizedForWebTest() {

@ -166,11 +166,11 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
const gfx::Rect& src_rect,
const gfx::Size& output_size,
base::OnceCallback<void(const SkBitmap&)> callback) override;
void CopyFromExactSurfaceWithIpcPriority(
void CopyFromExactSurfaceWithIpcDelay(
const gfx::Rect& src_rect,
const gfx::Size& output_size,
base::OnceCallback<void(const SkBitmap&)> callback,
CopyOutputIpcPriority ipc_priority) override;
base::TimeDelta ipc_delay) override;
void CopyFromExactSurface(
const gfx::Rect& src_rect,
const gfx::Size& output_size,

@ -12,6 +12,7 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "base/unguessable_token.h"
#include "build/build_config.h"
#include "components/input/event_with_latency_info.h"
@ -256,11 +257,11 @@ void RenderWidgetHostViewBase::CopyFromExactSurface(
}
#if BUILDFLAG(IS_ANDROID)
void RenderWidgetHostViewBase::CopyFromExactSurfaceWithIpcPriority(
void RenderWidgetHostViewBase::CopyFromExactSurfaceWithIpcDelay(
const gfx::Rect& src_rect,
const gfx::Size& output_size,
base::OnceCallback<void(const SkBitmap&)> callback,
CopyOutputIpcPriority ipc_priority) {
base::TimeDelta ipc_delay) {
NOTIMPLEMENTED_LOG_ONCE();
std::move(callback).Run(SkBitmap());
}

@ -81,8 +81,6 @@ class WebContentsAccessibility;
class DelegatedFrameHost;
class SyntheticGestureTarget;
using CopyOutputIpcPriority = viz::CopyOutputRequest::IpcPriority;
// Basic implementation shared by concrete RenderWidgetHostView subclasses.
class CONTENT_EXPORT RenderWidgetHostViewBase
: public RenderWidgetHostView,
@ -175,11 +173,11 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
base::OnceCallback<void(const SkBitmap&)> callback);
#if BUILDFLAG(IS_ANDROID)
virtual void CopyFromExactSurfaceWithIpcPriority(
virtual void CopyFromExactSurfaceWithIpcDelay(
const gfx::Rect& src_rect,
const gfx::Size& output_size,
base::OnceCallback<void(const SkBitmap&)> callback,
CopyOutputIpcPriority ipc_priority);
base::TimeDelta ipc_delay);
#endif
// For HiDPI capture mode, allow applying a render scale multiplier

@ -12,7 +12,9 @@
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "services/viz/public/cpp/compositing/copy_output_result_mojom_traits.h"
@ -75,71 +77,10 @@ void SendResult(
remote->SendResult(std::move(result));
}
#if BUILDFLAG(IS_ANDROID)
class ScopedThreadType {
public:
explicit ScopedThreadType(base::ThreadType thread_type) {
former_thread_type_ = base::PlatformThread::GetCurrentThreadType();
base::PlatformThread::SetCurrentThreadType(thread_type);
}
~ScopedThreadType() {
base::PlatformThread::SetCurrentThreadType(former_thread_type_);
}
private:
base::ThreadType former_thread_type_;
};
// On Android, we don't currently have threadpools with background priority.
// This function momentarily reduces the priority of the thread where the task
// is running.
// https://crbug.com/384902323
void SendResultBackgroundPriority(
mojo::PendingRemote<viz::mojom::CopyOutputResultSender> pending_remote,
std::unique_ptr<viz::CopyOutputResult> result) {
TRACE_EVENT0(
"viz",
"viz::mojom::CopyOutputResultSender::SendResultBackgroundPriority");
ScopedThreadType scoped_thread_type(base::ThreadType::kBackground);
SendResult(std::move(pending_remote), std::move(result));
}
#endif // BUILDFLAG(IS_ANDROID)
} // namespace
namespace mojo {
// static
viz::mojom::CopyOutputRequestIpcPriority
EnumTraits<viz::mojom::CopyOutputRequestIpcPriority,
viz::CopyOutputRequest::IpcPriority>::
ToMojom(viz::CopyOutputRequest::IpcPriority priority) {
switch (priority) {
case viz::CopyOutputRequest::IpcPriority::kDefault:
return viz::mojom::CopyOutputRequestIpcPriority::kDefault;
case viz::CopyOutputRequest::IpcPriority::kBackground:
return viz::mojom::CopyOutputRequestIpcPriority::kBackground;
}
NOTREACHED();
}
// static
bool EnumTraits<viz::mojom::CopyOutputRequestIpcPriority,
viz::CopyOutputRequest::IpcPriority>::
FromMojom(viz::mojom::CopyOutputRequestIpcPriority input,
viz::CopyOutputRequest::IpcPriority* out) {
switch (input) {
case viz::mojom::CopyOutputRequestIpcPriority::kDefault:
*out = viz::CopyOutputRequest::IpcPriority::kDefault;
return true;
case viz::mojom::CopyOutputRequestIpcPriority::kBackground:
*out = viz::CopyOutputRequest::IpcPriority::kBackground;
return true;
}
return false;
}
// static
mojo::PendingRemote<viz::mojom::CopyOutputResultSender>
StructTraits<viz::mojom::CopyOutputRequestDataView,
@ -180,22 +121,16 @@ bool StructTraits<viz::mojom::CopyOutputRequestDataView,
auto result_sender = data.TakeResultSender<
mojo::PendingRemote<viz::mojom::CopyOutputResultSender>>();
viz::CopyOutputRequest::IpcPriority ipc_priority;
if (!data.ReadIpcPriority(&ipc_priority)) {
base::TimeDelta send_result_delay;
if (!data.ReadSendResultDelay(&send_result_delay)) {
return false;
}
auto callback = SendResult;
#if BUILDFLAG(IS_ANDROID)
if (ipc_priority == viz::CopyOutputRequest::IpcPriority::kBackground) {
callback = SendResultBackgroundPriority;
}
#endif
auto request = std::make_unique<viz::CopyOutputRequest>(
result_format, result_destination,
base::BindOnce(callback, std::move(result_sender)));
base::BindOnce(&SendResult, std::move(result_sender)));
request->set_ipc_priority(ipc_priority);
request->set_send_result_delay(send_result_delay);
// Serializing the result requires an expensive copy, so to not block the
// any important thread we PostTask onto the threadpool.
request->set_result_task_runner(

@ -17,16 +17,6 @@
namespace mojo {
template <>
struct EnumTraits<viz::mojom::CopyOutputRequestIpcPriority,
viz::CopyOutputRequest::IpcPriority> {
static viz::mojom::CopyOutputRequestIpcPriority ToMojom(
viz::CopyOutputRequest::IpcPriority priority);
static bool FromMojom(viz::mojom::CopyOutputRequestIpcPriority input,
viz::CopyOutputRequest::IpcPriority* out);
};
template <>
struct StructTraits<viz::mojom::CopyOutputRequestDataView,
std::unique_ptr<viz::CopyOutputRequest>> {
@ -40,9 +30,9 @@ struct StructTraits<viz::mojom::CopyOutputRequestDataView,
return request->result_destination();
}
static viz::CopyOutputRequest::IpcPriority ipc_priority(
static base::TimeDelta send_result_delay(
const std::unique_ptr<viz::CopyOutputRequest>& request) {
return request->ipc_priority();
return request->send_result_delay();
}
static const gfx::Vector2d& scale_from(

@ -7,22 +7,15 @@ module viz.mojom;
import "gpu/ipc/common/mailbox.mojom";
import "gpu/ipc/common/sync_token.mojom";
import "services/viz/public/mojom/compositing/copy_output_result.mojom";
import "mojo/public/mojom/base/time.mojom";
import "mojo/public/mojom/base/unguessable_token.mojom";
import "ui/gfx/geometry/mojom/geometry.mojom";
// See components/viz/common/frame_sinks/copy_output_request.h.
// Specifies the task priority to use when sending a result over IPC.
enum CopyOutputRequestIpcPriority {
kDefault,
kBackground
};
// See components/viz/common/frame_sinks/copy_output_request.h.
struct CopyOutputRequest {
CopyOutputResultFormat result_format;
CopyOutputResultDestination result_destination;
CopyOutputRequestIpcPriority ipc_priority;
mojo_base.mojom.TimeDelta send_result_delay;
// Set both to (1,1) for no scaling. Both must have positive X and Y values.
gfx.mojom.Vector2d scale_from;

@ -2948,12 +2948,14 @@
],
"experiments": [
{
"name": "IPHWithFastEtc1Encoder",
"name": "IPHWithFastEtc1EncoderDelayed",
"params": {
"availability": "any",
"compress-screenshot-when-quiet": "true",
"event_trigger": "name:rtl_gesture_iph_trigger;comparator:==0;window:365;storage:365",
"event_used": "name:rtl_gesture_iph_show;comparator:==0;window:365;storage:365",
"percentage-of-ram-to-use": "0.5",
"screenshot-send-result-delay-ms": "400",
"session_rate": "<1",
"x_trigger": "",
"x_unhandled_gesture_threshold": "2"

@ -184,7 +184,7 @@ void DelegatedFrameHostAndroid::CopyFromCompositingSurface(
const gfx::Size& output_size,
base::OnceCallback<void(const SkBitmap&)> callback,
bool capture_exact_surface_id,
viz::CopyOutputRequest::IpcPriority ipc_priority) {
base::TimeDelta ipc_delay) {
DCHECK(CanCopyFromCompositingSurface());
const viz::SurfaceId surface_id(frame_sink_id_, local_surface_id_);
@ -213,7 +213,7 @@ void DelegatedFrameHostAndroid::CopyFromCompositingSurface(
std::move(copy_result).Run(scoped_bitmap.GetOutScopedBitmap());
},
std::move(callback), std::move(keep_surface_alive)));
request->set_ipc_priority(ipc_priority);
request->set_send_result_delay(ipc_delay);
// `CopyOutputRequestCallback` holds a `ReadbackRefCallback` which must only
// be executed on the UI thread. Since the result callback can be dispatched

@ -115,7 +115,7 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
const gfx::Size& output_size,
base::OnceCallback<void(const SkBitmap&)> callback,
bool capture_exact_surface_id,
viz::CopyOutputRequest::IpcPriority ipc_priority);
base::TimeDelta ipc_delay);
bool CanCopyFromCompositingSurface() const;
void CompositorFrameSinkChanged();