Commit 6c6f3ad3 authored by ckitagawa's avatar ckitagawa Committed by Commit Bot

[Paint Preview] Support cancelling requests and finite parallelism

This CL restricts the number of outbound requests to the paint preview
compositor for processing bitmaps to 4. This should limit the peak
memory usage and might reduce OOM crashes.

This CL also makes it possible to cancel queued requests. As a result,
when flinging or zooming where many requests are made at once, it is
possible to clear pending requests for tiles that exit the viewport
before the request is served.

Bug: 1142545
Change-Id: I8f4859c61e5ffd1fa017dd840fac57fe8deb79ce
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2497825
Commit-Queue: Calder Kitagawa <ckitagawa@chromium.org>
Reviewed-by: default avatarMehran Mahmoudi <mahmoudi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#821418}
parent 32e57d47
...@@ -298,6 +298,8 @@ public class TabbedPaintPreviewTest { ...@@ -298,6 +298,8 @@ public class TabbedPaintPreviewTest {
* Dummy implementation of {@link PlayerCompositorDelegate}. * Dummy implementation of {@link PlayerCompositorDelegate}.
*/ */
public static class TestCompositorDelegate implements PlayerCompositorDelegate { public static class TestCompositorDelegate implements PlayerCompositorDelegate {
private int mNextRequestId;
TestCompositorDelegate(NativePaintPreviewServiceProvider service, GURL url, TestCompositorDelegate(NativePaintPreviewServiceProvider service, GURL url,
String directoryKey, @NonNull CompositorListener compositorListener, String directoryKey, @NonNull CompositorListener compositorListener,
Callback<Integer> compositorErrorCallback) { Callback<Integer> compositorErrorCallback) {
...@@ -313,15 +315,26 @@ public class TabbedPaintPreviewTest { ...@@ -313,15 +315,26 @@ public class TabbedPaintPreviewTest {
} }
@Override @Override
public void requestBitmap(UnguessableToken frameGuid, Rect clipRect, float scaleFactor, public int requestBitmap(UnguessableToken frameGuid, Rect clipRect, float scaleFactor,
Callback<Bitmap> bitmapCallback, Runnable errorCallback) { Callback<Bitmap> bitmapCallback, Runnable errorCallback) {
new Handler().postDelayed(() -> { new Handler().postDelayed(() -> {
Bitmap emptyBitmap = Bitmap.createBitmap( Bitmap emptyBitmap = Bitmap.createBitmap(
clipRect.width(), clipRect.height(), Bitmap.Config.ARGB_4444); clipRect.width(), clipRect.height(), Bitmap.Config.ARGB_4444);
bitmapCallback.onResult(emptyBitmap); bitmapCallback.onResult(emptyBitmap);
}, 100); }, 100);
int requestId = mNextRequestId;
mNextRequestId++;
return requestId;
}
@Override
public boolean cancelBitmapRequest(int requestId) {
return false;
} }
@Override
public void cancelAllBitmapRequests() {}
@Override @Override
public GURL onClick(UnguessableToken frameGuid, int x, int y) { public GURL onClick(UnguessableToken frameGuid, int x, int y) {
return null; return null;
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
source_set("player") { source_set("player") {
sources = [ sources = [
"bitmap_request.cc",
"bitmap_request.h",
"compositor_status.h", "compositor_status.h",
"player_compositor_delegate.cc", "player_compositor_delegate.cc",
"player_compositor_delegate.h", "player_compositor_delegate.h",
......
...@@ -70,10 +70,24 @@ public interface PlayerCompositorDelegate { ...@@ -70,10 +70,24 @@ public interface PlayerCompositorDelegate {
* @param bitmapCallback The callback that receives the bitmap once it's ready. Won't get called * @param bitmapCallback The callback that receives the bitmap once it's ready. Won't get called
* if there are any errors. * if there are any errors.
* @param errorCallback Gets notified if there are any errors. Won't get called otherwise. * @param errorCallback Gets notified if there are any errors. Won't get called otherwise.
* @return an int representing the ID for the bitmap request. Can be used with {@link
* cancelBitmapRequest(int)} to cancel the request if possible.
*/ */
void requestBitmap(UnguessableToken frameGuid, Rect clipRect, float scaleFactor, int requestBitmap(UnguessableToken frameGuid, Rect clipRect, float scaleFactor,
Callback<Bitmap> bitmapCallback, Runnable errorCallback); Callback<Bitmap> bitmapCallback, Runnable errorCallback);
/**
* Cancels the bitmap request for the provided ID.
* @param requestID the request to try to cancel.
* @return true on successful cancellation.
*/
boolean cancelBitmapRequest(int requestId);
/**
* Cancels all outstanding bitmap requests.
*/
void cancelAllBitmapRequests();
/** /**
* Sends a click event for a frame to native for link hit testing. * Sends a click event for a frame to native for link hit testing.
* @param frameGuid The GUID of the frame. * @param frameGuid The GUID of the frame.
......
...@@ -49,17 +49,37 @@ class PlayerCompositorDelegateImpl implements PlayerCompositorDelegate { ...@@ -49,17 +49,37 @@ class PlayerCompositorDelegateImpl implements PlayerCompositorDelegate {
} }
@Override @Override
public void requestBitmap(UnguessableToken frameGuid, Rect clipRect, float scaleFactor, public int requestBitmap(UnguessableToken frameGuid, Rect clipRect, float scaleFactor,
Callback<Bitmap> bitmapCallback, Runnable errorCallback) { Callback<Bitmap> bitmapCallback, Runnable errorCallback) {
if (mNativePlayerCompositorDelegate == 0) { if (mNativePlayerCompositorDelegate == 0) {
return; return -1;
} }
PlayerCompositorDelegateImplJni.get().requestBitmap(mNativePlayerCompositorDelegate, return PlayerCompositorDelegateImplJni.get().requestBitmap(mNativePlayerCompositorDelegate,
frameGuid, bitmapCallback, errorCallback, scaleFactor, clipRect.left, clipRect.top, frameGuid, bitmapCallback, errorCallback, scaleFactor, clipRect.left, clipRect.top,
clipRect.width(), clipRect.height()); clipRect.width(), clipRect.height());
} }
@Override
public boolean cancelBitmapRequest(int requestId) {
if (mNativePlayerCompositorDelegate == 0) {
return false;
}
return PlayerCompositorDelegateImplJni.get().cancelBitmapRequest(
mNativePlayerCompositorDelegate, requestId);
}
@Override
public void cancelAllBitmapRequests() {
if (mNativePlayerCompositorDelegate == 0) {
return;
}
PlayerCompositorDelegateImplJni.get().cancelAllBitmapRequests(
mNativePlayerCompositorDelegate);
}
@Override @Override
public GURL onClick(UnguessableToken frameGuid, int x, int y) { public GURL onClick(UnguessableToken frameGuid, int x, int y) {
if (mNativePlayerCompositorDelegate == 0) { if (mNativePlayerCompositorDelegate == 0) {
...@@ -98,9 +118,11 @@ class PlayerCompositorDelegateImpl implements PlayerCompositorDelegate { ...@@ -98,9 +118,11 @@ class PlayerCompositorDelegateImpl implements PlayerCompositorDelegate {
long initialize(PlayerCompositorDelegateImpl caller, long nativePaintPreviewBaseService, long initialize(PlayerCompositorDelegateImpl caller, long nativePaintPreviewBaseService,
String urlSpec, String directoryKey, Callback<Integer> compositorErrorCallback); String urlSpec, String directoryKey, Callback<Integer> compositorErrorCallback);
void destroy(long nativePlayerCompositorDelegateAndroid); void destroy(long nativePlayerCompositorDelegateAndroid);
void requestBitmap(long nativePlayerCompositorDelegateAndroid, UnguessableToken frameGuid, int requestBitmap(long nativePlayerCompositorDelegateAndroid, UnguessableToken frameGuid,
Callback<Bitmap> bitmapCallback, Runnable errorCallback, float scaleFactor, Callback<Bitmap> bitmapCallback, Runnable errorCallback, float scaleFactor,
int clipX, int clipY, int clipWidth, int clipHeight); int clipX, int clipY, int clipWidth, int clipHeight);
boolean cancelBitmapRequest(long nativePlayerCompositorDelegateAndroid, int requestId);
void cancelAllBitmapRequests(long nativePlayerCompositorDelegateAndroid);
String onClick(long nativePlayerCompositorDelegateAndroid, UnguessableToken frameGuid, String onClick(long nativePlayerCompositorDelegateAndroid, UnguessableToken frameGuid,
int x, int y); int x, int y);
void setCompressOnClose( void setCompressOnClose(
......
...@@ -85,6 +85,7 @@ public class PlayerFrameBitmapState { ...@@ -85,6 +85,7 @@ public class PlayerFrameBitmapState {
*/ */
void lock() { void lock() {
mRequiredBitmaps = null; mRequiredBitmaps = null;
mCompositorDelegate.cancelAllBitmapRequests();
} }
/** /**
...@@ -160,6 +161,8 @@ public class PlayerFrameBitmapState { ...@@ -160,6 +161,8 @@ public class PlayerFrameBitmapState {
requestBitmapForAdjacentTiles(row, col); requestBitmapForAdjacentTiles(row, col);
} }
} }
cancelUnrequiredPendingRequests();
} }
private void requestBitmapForAdjacentTiles(int row, int col) { private void requestBitmapForAdjacentTiles(int row, int col) {
...@@ -198,9 +201,14 @@ public class PlayerFrameBitmapState { ...@@ -198,9 +201,14 @@ public class PlayerFrameBitmapState {
BitmapRequestHandler bitmapRequestHandler = BitmapRequestHandler bitmapRequestHandler =
new BitmapRequestHandler(row, col, mScaleFactor, mVisibleBitmaps[row][col]); new BitmapRequestHandler(row, col, mScaleFactor, mVisibleBitmaps[row][col]);
mPendingBitmapRequests[row][col] = bitmapRequestHandler; mPendingBitmapRequests[row][col] = bitmapRequestHandler;
mCompositorDelegate.requestBitmap(mGuid, int requestId = mCompositorDelegate.requestBitmap(mGuid,
new Rect(x, y, x + mTileSize.getWidth(), y + mTileSize.getHeight()), mScaleFactor, new Rect(x, y, x + mTileSize.getWidth(), y + mTileSize.getHeight()), mScaleFactor,
bitmapRequestHandler, bitmapRequestHandler::onError); bitmapRequestHandler, bitmapRequestHandler::onError);
// It is possible that the request failed immediately, so make sure the request still
// exists.
if (mPendingBitmapRequests[row][col] != null) {
mPendingBitmapRequests[row][col].setRequestId(requestId);
}
return true; return true;
} }
...@@ -258,6 +266,27 @@ public class PlayerFrameBitmapState { ...@@ -258,6 +266,27 @@ public class PlayerFrameBitmapState {
} }
} }
private void cancelUnrequiredPendingRequests() {
if (mPendingBitmapRequests == null || mRequiredBitmaps == null) return;
assert mPendingBitmapRequests.length == mRequiredBitmaps.length;
assert (mPendingBitmapRequests.length > 0)
? mPendingBitmapRequests[0].length == mRequiredBitmaps[0].length
: true;
for (int row = 0; row < mPendingBitmapRequests.length; row++) {
for (int col = 0; col < mPendingBitmapRequests[row].length; col++) {
if (mPendingBitmapRequests[row][col] != null && !mRequiredBitmaps[row][col]) {
// If the cancellation failed, the bitmap is being processed already. If this
// happens don't delete the request.
if (mPendingBitmapRequests[row][col].cancel()) {
mPendingBitmapRequests[row][col] = null;
}
}
}
}
}
/** /**
* Used as the callback for bitmap requests from the Paint Preview compositor. * Used as the callback for bitmap requests from the Paint Preview compositor.
*/ */
...@@ -266,6 +295,7 @@ public class PlayerFrameBitmapState { ...@@ -266,6 +295,7 @@ public class PlayerFrameBitmapState {
int mRequestCol; int mRequestCol;
float mRequestScaleFactor; float mRequestScaleFactor;
boolean mVisible; boolean mVisible;
int mRequestId;
private BitmapRequestHandler( private BitmapRequestHandler(
int requestRow, int requestCol, float requestScaleFactor, boolean visible) { int requestRow, int requestCol, float requestScaleFactor, boolean visible) {
...@@ -279,6 +309,14 @@ public class PlayerFrameBitmapState { ...@@ -279,6 +309,14 @@ public class PlayerFrameBitmapState {
mVisible = visible; mVisible = visible;
} }
private void setRequestId(int requestId) {
mRequestId = requestId;
}
private boolean cancel() {
return mCompositorDelegate.cancelBitmapRequest(mRequestId);
}
/** /**
* Called when bitmap is successfully composited. * Called when bitmap is successfully composited.
* @param result * @param result
......
...@@ -175,14 +175,26 @@ public class PlayerFrameMediatorTest { ...@@ -175,14 +175,26 @@ public class PlayerFrameMediatorTest {
private class TestPlayerCompositorDelegate implements PlayerCompositorDelegate { private class TestPlayerCompositorDelegate implements PlayerCompositorDelegate {
List<RequestedBitmap> mRequestedBitmap = new ArrayList<>(); List<RequestedBitmap> mRequestedBitmap = new ArrayList<>();
List<ClickedPoint> mClickedPoints = new ArrayList<>(); List<ClickedPoint> mClickedPoints = new ArrayList<>();
private int mNextRequestId;
@Override @Override
public void requestBitmap(UnguessableToken frameGuid, Rect clipRect, float scaleFactor, public int requestBitmap(UnguessableToken frameGuid, Rect clipRect, float scaleFactor,
Callback<Bitmap> bitmapCallback, Runnable errorCallback) { Callback<Bitmap> bitmapCallback, Runnable errorCallback) {
mRequestedBitmap.add(new RequestedBitmap( mRequestedBitmap.add(new RequestedBitmap(
frameGuid, new Rect(clipRect), scaleFactor, bitmapCallback, errorCallback)); frameGuid, new Rect(clipRect), scaleFactor, bitmapCallback, errorCallback));
int requestId = mNextRequestId;
mNextRequestId++;
return requestId;
} }
@Override
public boolean cancelBitmapRequest(int requestId) {
return false;
}
@Override
public void cancelAllBitmapRequests() {}
@Override @Override
public GURL onClick(UnguessableToken frameGuid, int x, int y) { public GURL onClick(UnguessableToken frameGuid, int x, int y) {
mClickedPoints.add(new ClickedPoint(frameGuid, x, y)); mClickedPoints.add(new ClickedPoint(frameGuid, x, y));
......
...@@ -31,6 +31,10 @@ namespace paint_preview { ...@@ -31,6 +31,10 @@ namespace paint_preview {
namespace { namespace {
// To minimize peak memory usage limit the number of concurrent bitmap requests
// to 4.
constexpr size_t kMaxParallelBitmapRequests = 4;
ScopedJavaLocalRef<jobjectArray> ToJavaUnguessableTokenArray( ScopedJavaLocalRef<jobjectArray> ToJavaUnguessableTokenArray(
JNIEnv* env, JNIEnv* env,
const std::vector<base::UnguessableToken>& tokens) { const std::vector<base::UnguessableToken>& tokens) {
...@@ -88,7 +92,7 @@ PlayerCompositorDelegateAndroid::PlayerCompositorDelegateAndroid( ...@@ -88,7 +92,7 @@ PlayerCompositorDelegateAndroid::PlayerCompositorDelegateAndroid(
base::android::ConvertJavaStringToUTF8(env, j_directory_key)}, base::android::ConvertJavaStringToUTF8(env, j_directory_key)},
base::BindOnce(&base::android::RunIntCallbackAndroid, base::BindOnce(&base::android::RunIntCallbackAndroid,
ScopedJavaGlobalRef<jobject>(j_compositor_error_callback)), ScopedJavaGlobalRef<jobject>(j_compositor_error_callback)),
base::TimeDelta::FromSeconds(15)); base::TimeDelta::FromSeconds(15), kMaxParallelBitmapRequests);
java_ref_.Reset(env, j_object); java_ref_.Reset(env, j_object);
} }
...@@ -190,7 +194,7 @@ void PlayerCompositorDelegateAndroid::CompositeResponseFramesToVectors( ...@@ -190,7 +194,7 @@ void PlayerCompositorDelegateAndroid::CompositeResponseFramesToVectors(
} }
} }
void PlayerCompositorDelegateAndroid::RequestBitmap( jint PlayerCompositorDelegateAndroid::RequestBitmap(
JNIEnv* env, JNIEnv* env,
const JavaParamRef<jobject>& j_frame_guid, const JavaParamRef<jobject>& j_frame_guid,
const JavaParamRef<jobject>& j_bitmap_callback, const JavaParamRef<jobject>& j_bitmap_callback,
...@@ -204,7 +208,7 @@ void PlayerCompositorDelegateAndroid::RequestBitmap( ...@@ -204,7 +208,7 @@ void PlayerCompositorDelegateAndroid::RequestBitmap(
"paint_preview", "PlayerCompositorDelegateAndroid::RequestBitmap", "paint_preview", "PlayerCompositorDelegateAndroid::RequestBitmap",
TRACE_ID_LOCAL(request_id_)); TRACE_ID_LOCAL(request_id_));
PlayerCompositorDelegate::RequestBitmap( int32_t id = PlayerCompositorDelegate::RequestBitmap(
base::android::UnguessableTokenAndroid::FromJavaUnguessableToken( base::android::UnguessableTokenAndroid::FromJavaUnguessableToken(
env, j_frame_guid), env, j_frame_guid),
gfx::Rect(j_clip_x, j_clip_y, j_clip_width, j_clip_height), gfx::Rect(j_clip_x, j_clip_y, j_clip_width, j_clip_height),
...@@ -215,6 +219,19 @@ void PlayerCompositorDelegateAndroid::RequestBitmap( ...@@ -215,6 +219,19 @@ void PlayerCompositorDelegateAndroid::RequestBitmap(
ScopedJavaGlobalRef<jobject>(j_error_callback), ScopedJavaGlobalRef<jobject>(j_error_callback),
request_id_)); request_id_));
++request_id_; ++request_id_;
return static_cast<jint>(id);
}
jboolean PlayerCompositorDelegateAndroid::CancelBitmapRequest(
JNIEnv* env,
jint j_request_id) {
return static_cast<jboolean>(PlayerCompositorDelegate::CancelBitmapRequest(
static_cast<int32_t>(j_request_id)));
}
void PlayerCompositorDelegateAndroid::CancelAllBitmapRequests(JNIEnv* env) {
PlayerCompositorDelegate::CancelAllBitmapRequests();
} }
void PlayerCompositorDelegateAndroid::OnBitmapCallback( void PlayerCompositorDelegateAndroid::OnBitmapCallback(
......
...@@ -32,7 +32,7 @@ class PlayerCompositorDelegateAndroid : public PlayerCompositorDelegate { ...@@ -32,7 +32,7 @@ class PlayerCompositorDelegateAndroid : public PlayerCompositorDelegate {
// Called from Java when there is a request for a new bitmap. When the bitmap // Called from Java when there is a request for a new bitmap. When the bitmap
// is ready, it will be passed to j_bitmap_callback. In case of any failure, // is ready, it will be passed to j_bitmap_callback. In case of any failure,
// j_error_callback will be called. // j_error_callback will be called.
void RequestBitmap( jint RequestBitmap(
JNIEnv* env, JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_frame_guid, const base::android::JavaParamRef<jobject>& j_frame_guid,
const base::android::JavaParamRef<jobject>& j_bitmap_callback, const base::android::JavaParamRef<jobject>& j_bitmap_callback,
...@@ -43,6 +43,10 @@ class PlayerCompositorDelegateAndroid : public PlayerCompositorDelegate { ...@@ -43,6 +43,10 @@ class PlayerCompositorDelegateAndroid : public PlayerCompositorDelegate {
jint j_clip_width, jint j_clip_width,
jint j_clip_height); jint j_clip_height);
jboolean CancelBitmapRequest(JNIEnv* env, jint j_request_id);
void CancelAllBitmapRequests(JNIEnv* env);
// Called from Java on touch event on a frame. // Called from Java on touch event on a frame.
base::android::ScopedJavaLocalRef<jstring> OnClick( base::android::ScopedJavaLocalRef<jstring> OnClick(
JNIEnv* env, JNIEnv* env,
......
// Copyright 2020 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 "components/paint_preview/player/bitmap_request.h"
namespace paint_preview {
BitmapRequest::BitmapRequest(const base::UnguessableToken& frame_guid,
const gfx::Rect& clip_rect,
float scale_factor,
BitmapRequestCallback callback)
: frame_guid(frame_guid),
clip_rect(clip_rect),
scale_factor(scale_factor),
callback(std::move(callback)) {}
BitmapRequest::~BitmapRequest() = default;
BitmapRequest& BitmapRequest::operator=(BitmapRequest&& other) = default;
BitmapRequest::BitmapRequest(BitmapRequest&& other) = default;
} // namespace paint_preview
// Copyright 2020 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 COMPONENTS_PAINT_PREVIEW_PLAYER_BITMAP_REQUEST_H_
#define COMPONENTS_PAINT_PREVIEW_PLAYER_BITMAP_REQUEST_H_
#include "base/callback.h"
#include "base/unguessable_token.h"
#include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/geometry/rect.h"
namespace paint_preview {
struct BitmapRequest {
using BitmapRequestCallback =
base::OnceCallback<void(mojom::PaintPreviewCompositor::BitmapStatus,
const SkBitmap&)>;
BitmapRequest(const base::UnguessableToken& frame_guid,
const gfx::Rect& clip_rect,
float scale_factor,
BitmapRequestCallback callback);
~BitmapRequest();
BitmapRequest& operator=(BitmapRequest&& other) noexcept;
BitmapRequest(BitmapRequest&& other) noexcept;
base::UnguessableToken frame_guid;
gfx::Rect clip_rect;
float scale_factor;
BitmapRequestCallback callback;
};
} // namespace paint_preview
#endif // COMPONENTS_PAINT_PREVIEW_PLAYER_BITMAP_REQUEST_H_
...@@ -116,7 +116,8 @@ void PlayerCompositorDelegate::Initialize( ...@@ -116,7 +116,8 @@ void PlayerCompositorDelegate::Initialize(
const GURL& expected_url, const GURL& expected_url,
const DirectoryKey& key, const DirectoryKey& key,
base::OnceCallback<void(int)> compositor_error, base::OnceCallback<void(int)> compositor_error,
base::TimeDelta timeout_duration) { base::TimeDelta timeout_duration,
size_t max_requests) {
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("paint_preview", TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("paint_preview",
"PlayerCompositorDelegate CreateCompositor", "PlayerCompositorDelegate CreateCompositor",
TRACE_ID_LOCAL(this)); TRACE_ID_LOCAL(this));
...@@ -126,7 +127,8 @@ void PlayerCompositorDelegate::Initialize( ...@@ -126,7 +127,8 @@ void PlayerCompositorDelegate::Initialize(
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
InitializeInternal(paint_preview_service, expected_url, key, InitializeInternal(paint_preview_service, expected_url, key,
std::move(compositor_error), timeout_duration); std::move(compositor_error), timeout_duration,
max_requests);
} }
void PlayerCompositorDelegate::InitializeWithFakeServiceForTest( void PlayerCompositorDelegate::InitializeWithFakeServiceForTest(
...@@ -135,6 +137,7 @@ void PlayerCompositorDelegate::InitializeWithFakeServiceForTest( ...@@ -135,6 +137,7 @@ void PlayerCompositorDelegate::InitializeWithFakeServiceForTest(
const DirectoryKey& key, const DirectoryKey& key,
base::OnceCallback<void(int)> compositor_error, base::OnceCallback<void(int)> compositor_error,
base::TimeDelta timeout_duration, base::TimeDelta timeout_duration,
size_t max_requests,
std::unique_ptr<PaintPreviewCompositorService, base::OnTaskRunnerDeleter> std::unique_ptr<PaintPreviewCompositorService, base::OnTaskRunnerDeleter>
fake_compositor_service) { fake_compositor_service) {
paint_preview_compositor_service_ = std::move(fake_compositor_service); paint_preview_compositor_service_ = std::move(fake_compositor_service);
...@@ -143,7 +146,8 @@ void PlayerCompositorDelegate::InitializeWithFakeServiceForTest( ...@@ -143,7 +146,8 @@ void PlayerCompositorDelegate::InitializeWithFakeServiceForTest(
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
InitializeInternal(paint_preview_service, expected_url, key, InitializeInternal(paint_preview_service, expected_url, key,
std::move(compositor_error), timeout_duration); std::move(compositor_error), timeout_duration,
max_requests);
} }
void PlayerCompositorDelegate::InitializeInternal( void PlayerCompositorDelegate::InitializeInternal(
...@@ -151,7 +155,9 @@ void PlayerCompositorDelegate::InitializeInternal( ...@@ -151,7 +155,9 @@ void PlayerCompositorDelegate::InitializeInternal(
const GURL& expected_url, const GURL& expected_url,
const DirectoryKey& key, const DirectoryKey& key,
base::OnceCallback<void(int)> compositor_error, base::OnceCallback<void(int)> compositor_error,
base::TimeDelta timeout_duration) { base::TimeDelta timeout_duration,
size_t max_requests) {
max_requests_ = max_requests;
compositor_error_ = std::move(compositor_error); compositor_error_ = std::move(compositor_error);
paint_preview_service_ = paint_preview_service; paint_preview_service_ = paint_preview_service;
key_ = key; key_ = key;
...@@ -173,21 +179,46 @@ void PlayerCompositorDelegate::InitializeInternal( ...@@ -173,21 +179,46 @@ void PlayerCompositorDelegate::InitializeInternal(
} }
} }
void PlayerCompositorDelegate::RequestBitmap( int32_t PlayerCompositorDelegate::RequestBitmap(
const base::UnguessableToken& frame_guid, const base::UnguessableToken& frame_guid,
const gfx::Rect& clip_rect, const gfx::Rect& clip_rect,
float scale_factor, float scale_factor,
base::OnceCallback<void(mojom::PaintPreviewCompositor::BitmapStatus, base::OnceCallback<void(mojom::PaintPreviewCompositor::BitmapStatus,
const SkBitmap&)> callback) { const SkBitmap&)> callback) {
DCHECK(IsInitialized()); DCHECK(IsInitialized());
const int32_t request_id = next_request_id_;
next_request_id_++;
if (!paint_preview_compositor_client_) { if (!paint_preview_compositor_client_) {
std::move(callback).Run( std::move(callback).Run(
mojom::PaintPreviewCompositor::BitmapStatus::kMissingFrame, SkBitmap()); mojom::PaintPreviewCompositor::BitmapStatus::kMissingFrame, SkBitmap());
return; return request_id;
} }
paint_preview_compositor_client_->BitmapForSeparatedFrame( bitmap_request_queue_.push(request_id);
frame_guid, clip_rect, scale_factor, std::move(callback)); pending_bitmap_requests_.emplace(
request_id,
BitmapRequest(frame_guid, clip_rect, scale_factor,
base::BindOnce(
&PlayerCompositorDelegate::BitmapRequestCallbackAdapter,
weak_factory_.GetWeakPtr(), std::move(callback))));
ProcessBitmapRequestsFromQueue();
return request_id;
}
bool PlayerCompositorDelegate::CancelBitmapRequest(int32_t request_id) {
auto it = pending_bitmap_requests_.find(request_id);
if (it == pending_bitmap_requests_.end())
return false;
pending_bitmap_requests_.erase(it);
return true;
}
void PlayerCompositorDelegate::CancelAllBitmapRequests() {
while (bitmap_request_queue_.size())
bitmap_request_queue_.pop();
pending_bitmap_requests_.clear();
} }
std::vector<const GURL*> PlayerCompositorDelegate::OnClick( std::vector<const GURL*> PlayerCompositorDelegate::OnClick(
...@@ -342,4 +373,33 @@ void PlayerCompositorDelegate::OnCompositorTimeout() { ...@@ -342,4 +373,33 @@ void PlayerCompositorDelegate::OnCompositorTimeout() {
} }
} }
void PlayerCompositorDelegate::ProcessBitmapRequestsFromQueue() {
while (active_requests_ < max_requests_ && bitmap_request_queue_.size()) {
int request_id = bitmap_request_queue_.front();
bitmap_request_queue_.pop();
auto it = pending_bitmap_requests_.find(request_id);
if (it == pending_bitmap_requests_.end())
continue;
BitmapRequest& request = it->second;
active_requests_++;
paint_preview_compositor_client_->BitmapForSeparatedFrame(
request.frame_guid, request.clip_rect, request.scale_factor,
std::move(request.callback));
pending_bitmap_requests_.erase(it);
}
}
void PlayerCompositorDelegate::BitmapRequestCallbackAdapter(
base::OnceCallback<void(mojom::PaintPreviewCompositor::BitmapStatus,
const SkBitmap&)> callback,
mojom::PaintPreviewCompositor::BitmapStatus status,
const SkBitmap& bitmap) {
std::move(callback).Run(status, bitmap);
active_requests_--;
ProcessBitmapRequestsFromQueue();
}
} // namespace paint_preview } // namespace paint_preview
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/unguessable_token.h" #include "base/unguessable_token.h"
#include "components/paint_preview/browser/hit_tester.h" #include "components/paint_preview/browser/hit_tester.h"
#include "components/paint_preview/browser/paint_preview_base_service.h" #include "components/paint_preview/browser/paint_preview_base_service.h"
#include "components/paint_preview/player/bitmap_request.h"
#include "components/paint_preview/player/compositor_status.h" #include "components/paint_preview/player/compositor_status.h"
#include "components/paint_preview/public/paint_preview_compositor_client.h" #include "components/paint_preview/public/paint_preview_compositor_client.h"
#include "components/paint_preview/public/paint_preview_compositor_service.h" #include "components/paint_preview/public/paint_preview_compositor_service.h"
...@@ -44,7 +45,8 @@ class PlayerCompositorDelegate { ...@@ -44,7 +45,8 @@ class PlayerCompositorDelegate {
const GURL& url, const GURL& url,
const DirectoryKey& key, const DirectoryKey& key,
base::OnceCallback<void(int)> compositor_error, base::OnceCallback<void(int)> compositor_error,
base::TimeDelta timeout_duration); base::TimeDelta timeout_duration,
size_t max_requests);
// Returns whether initialization has happened. // Returns whether initialization has happened.
bool IsInitialized() const { return paint_preview_service_; } bool IsInitialized() const { return paint_preview_service_; }
...@@ -60,14 +62,23 @@ class PlayerCompositorDelegate { ...@@ -60,14 +62,23 @@ class PlayerCompositorDelegate {
mojom::PaintPreviewBeginCompositeResponsePtr composite_response) {} mojom::PaintPreviewBeginCompositeResponsePtr composite_response) {}
// Called when there is a request for a new bitmap. When the bitmap // Called when there is a request for a new bitmap. When the bitmap
// is ready, it will be passed to callback. // is ready, it will be passed to callback. Returns an ID for the request.
void RequestBitmap( // Pass this ID to `CancelBitmapRequest(int32_t)` to cancel the request if it
// hasn't already been sent.
int32_t RequestBitmap(
const base::UnguessableToken& frame_guid, const base::UnguessableToken& frame_guid,
const gfx::Rect& clip_rect, const gfx::Rect& clip_rect,
float scale_factor, float scale_factor,
base::OnceCallback<void(mojom::PaintPreviewCompositor::BitmapStatus, base::OnceCallback<void(mojom::PaintPreviewCompositor::BitmapStatus,
const SkBitmap&)> callback); const SkBitmap&)> callback);
// Cancels the bitmap request associated with `request_id` if possible.
// Returns true on success.
bool CancelBitmapRequest(int32_t request_id);
// Cancels all pending bitmap requests.
void CancelAllBitmapRequests();
// Called on touch event on a frame. // Called on touch event on a frame.
std::vector<const GURL*> OnClick(const base::UnguessableToken& frame_guid, std::vector<const GURL*> OnClick(const base::UnguessableToken& frame_guid,
const gfx::Rect& rect); const gfx::Rect& rect);
...@@ -81,6 +92,7 @@ class PlayerCompositorDelegate { ...@@ -81,6 +92,7 @@ class PlayerCompositorDelegate {
const DirectoryKey& key, const DirectoryKey& key,
base::OnceCallback<void(int)> compositor_error, base::OnceCallback<void(int)> compositor_error,
base::TimeDelta timeout_duration, base::TimeDelta timeout_duration,
size_t max_requests,
std::unique_ptr<PaintPreviewCompositorService, base::OnTaskRunnerDeleter> std::unique_ptr<PaintPreviewCompositorService, base::OnTaskRunnerDeleter>
fake_compositor_service); fake_compositor_service);
...@@ -100,7 +112,8 @@ class PlayerCompositorDelegate { ...@@ -100,7 +112,8 @@ class PlayerCompositorDelegate {
const GURL& expected_url, const GURL& expected_url,
const DirectoryKey& key, const DirectoryKey& key,
base::OnceCallback<void(int)> compositor_error, base::OnceCallback<void(int)> compositor_error,
base::TimeDelta timeout_duration); base::TimeDelta timeout_duration,
size_t max_requests);
void OnCompositorReadyStatusAdapter( void OnCompositorReadyStatusAdapter(
mojom::PaintPreviewCompositor::BeginCompositeStatus status, mojom::PaintPreviewCompositor::BeginCompositeStatus status,
...@@ -122,18 +135,34 @@ class PlayerCompositorDelegate { ...@@ -122,18 +135,34 @@ class PlayerCompositorDelegate {
void SendCompositeRequest( void SendCompositeRequest(
mojom::PaintPreviewBeginCompositeRequestPtr begin_composite_request); mojom::PaintPreviewBeginCompositeRequestPtr begin_composite_request);
void ProcessBitmapRequestsFromQueue();
void BitmapRequestCallbackAdapter(
base::OnceCallback<void(mojom::PaintPreviewCompositor::BitmapStatus,
const SkBitmap&)> callback,
mojom::PaintPreviewCompositor::BitmapStatus status,
const SkBitmap& bitmap);
PaintPreviewBaseService* paint_preview_service_{nullptr}; PaintPreviewBaseService* paint_preview_service_{nullptr};
DirectoryKey key_; DirectoryKey key_;
bool compress_on_close_{true}; bool compress_on_close_{true};
std::unique_ptr<PaintPreviewCompositorService, base::OnTaskRunnerDeleter> std::unique_ptr<PaintPreviewCompositorService, base::OnTaskRunnerDeleter>
paint_preview_compositor_service_; paint_preview_compositor_service_;
std::unique_ptr<PaintPreviewCompositorClient, base::OnTaskRunnerDeleter> std::unique_ptr<PaintPreviewCompositorClient, base::OnTaskRunnerDeleter>
paint_preview_compositor_client_; paint_preview_compositor_client_;
base::CancelableOnceClosure timeout_; base::CancelableOnceClosure timeout_;
int max_requests_{1};
base::flat_map<base::UnguessableToken, std::unique_ptr<HitTester>> base::flat_map<base::UnguessableToken, std::unique_ptr<HitTester>>
hit_testers_; hit_testers_;
std::unique_ptr<PaintPreviewProto> proto_; std::unique_ptr<PaintPreviewProto> proto_;
int active_requests_{0};
int32_t next_request_id_{0};
base::queue<int32_t> bitmap_request_queue_;
std::map<int32_t, BitmapRequest> pending_bitmap_requests_;
base::WeakPtrFactory<PlayerCompositorDelegate> weak_factory_{this}; base::WeakPtrFactory<PlayerCompositorDelegate> weak_factory_{this};
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment