summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cc/cc.gyp2
-rw-r--r--cc/cc_tests.gyp4
-rw-r--r--cc/layers/layer.cc20
-rw-r--r--cc/output/copy_output_request.cc31
-rw-r--r--cc/output/copy_output_request.h41
-rw-r--r--cc/output/copy_output_result.cc39
-rw-r--r--cc/output/copy_output_result.h55
-rw-r--r--cc/output/gl_renderer.cc177
-rw-r--r--cc/output/gl_renderer.h20
-rw-r--r--cc/quads/render_pass_unittest.cc3
-rw-r--r--cc/test/layer_tree_pixel_test.cc152
-rw-r--r--cc/test/layer_tree_pixel_test.h17
-rw-r--r--cc/test/pixel_test.cc80
-rw-r--r--cc/test/pixel_test.h5
-rw-r--r--cc/test/pixel_test_output_surface.cc21
-rw-r--r--cc/test/pixel_test_output_surface.h37
-rw-r--r--cc/test/pixel_test_software_output_device.cc15
-rw-r--r--cc/test/pixel_test_software_output_device.h26
-rw-r--r--cc/trees/layer_tree_host_pixeltest_filters.cc2
-rw-r--r--cc/trees/layer_tree_host_pixeltest_readback.cc275
-rw-r--r--cc/trees/layer_tree_host_unittest.cc28
21 files changed, 858 insertions, 192 deletions
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 67b1821..f64974a 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -163,6 +163,8 @@
'output/context_provider.h',
'output/copy_output_request.cc',
'output/copy_output_request.h',
+ 'output/copy_output_result.cc',
+ 'output/copy_output_result.h',
'output/delegated_frame_data.h',
'output/delegated_frame_data.cc',
'output/delegating_renderer.cc',
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index bb89d4e..ad10da93 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -154,6 +154,10 @@
'test/paths.h',
'test/pixel_test.cc',
'test/pixel_test.h',
+ 'test/pixel_test_output_surface.cc',
+ 'test/pixel_test_output_surface.h',
+ 'test/pixel_test_software_output_device.cc',
+ 'test/pixel_test_software_output_device.h',
'test/render_pass_test_common.cc',
'test/render_pass_test_common.h',
'test/render_pass_test_utils.cc',
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 5ec0621..e1354b9 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -13,6 +13,7 @@
#include "cc/base/thread.h"
#include "cc/layers/layer_impl.h"
#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
#include "third_party/WebKit/public/platform/WebAnimationDelegate.h"
@@ -652,17 +653,16 @@ void Layer::SetPositionConstraint(const LayerPositionConstraint& constraint) {
}
static void RunCopyCallbackOnMainThread(scoped_ptr<CopyOutputRequest> request,
- scoped_ptr<SkBitmap> bitmap) {
- if (request->HasBitmapRequest())
- request->SendBitmapResult(bitmap.Pass());
+ scoped_ptr<CopyOutputResult> result) {
+ request->SendResult(result.Pass());
}
static void PostCopyCallbackToMainThread(Thread* main_thread,
scoped_ptr<CopyOutputRequest> request,
- scoped_ptr<SkBitmap> bitmap) {
+ scoped_ptr<CopyOutputResult> result) {
main_thread->PostTask(base::Bind(&RunCopyCallbackOnMainThread,
base::Passed(&request),
- base::Passed(&bitmap)));
+ base::Passed(&result)));
}
void Layer::PushPropertiesTo(LayerImpl* layer) {
@@ -713,11 +713,13 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
it != copy_requests_.end();
++it) {
scoped_ptr<CopyOutputRequest> original_request = copy_requests_.take(it);
+ const CopyOutputRequest& original_request_ref = *original_request;
scoped_ptr<CopyOutputRequest> main_thread_request =
- CopyOutputRequest::CreateBitmapRequest(base::Bind(
- &PostCopyCallbackToMainThread,
- layer_tree_host()->proxy()->MainThread(),
- base::Passed(&original_request)));
+ CopyOutputRequest::CreateRelayRequest(
+ original_request_ref,
+ base::Bind(&PostCopyCallbackToMainThread,
+ layer_tree_host()->proxy()->MainThread(),
+ base::Passed(&original_request)));
main_thread_copy_requests.push_back(main_thread_request.Pass());
}
copy_requests_.clear();
diff --git a/cc/output/copy_output_request.cc b/cc/output/copy_output_request.cc
index 437cce5..90ece04 100644
--- a/cc/output/copy_output_request.cc
+++ b/cc/output/copy_output_request.cc
@@ -4,27 +4,42 @@
#include "cc/output/copy_output_request.h"
+#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/logging.h"
+#include "cc/output/copy_output_result.h"
+#include "cc/resources/texture_mailbox.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace cc {
-CopyOutputRequest::CopyOutputRequest(const CopyAsBitmapCallback& callback)
- : bitmap_callback_(callback) {}
+CopyOutputRequest::CopyOutputRequest() {}
+
+CopyOutputRequest::CopyOutputRequest(
+ bool force_bitmap_result,
+ const CopyOutputRequestCallback& result_callback)
+ : force_bitmap_result_(force_bitmap_result),
+ result_callback_(result_callback) {
+}
CopyOutputRequest::~CopyOutputRequest() {
- SendEmptyResult();
+ if (!result_callback_.is_null())
+ SendResult(CopyOutputResult::CreateEmptyResult().Pass());
}
-void CopyOutputRequest::SendEmptyResult() {
- if (!bitmap_callback_.is_null())
- base::ResetAndReturn(&bitmap_callback_).Run(scoped_ptr<SkBitmap>());
+void CopyOutputRequest::SendResult(scoped_ptr<CopyOutputResult> result) {
+ base::ResetAndReturn(&result_callback_).Run(result.Pass());
}
void CopyOutputRequest::SendBitmapResult(scoped_ptr<SkBitmap> bitmap) {
- DCHECK(HasBitmapRequest());
- base::ResetAndReturn(&bitmap_callback_).Run(bitmap.Pass());
+ SendResult(CopyOutputResult::CreateBitmapResult(bitmap.Pass()).Pass());
+}
+
+void CopyOutputRequest::SendTextureResult(gfx::Size size,
+ scoped_ptr<TextureMailbox> texture) {
+ DCHECK(texture->IsTexture());
+ SendResult(CopyOutputResult::CreateTextureResult(size,
+ texture.Pass()).Pass());
}
} // namespace cc
diff --git a/cc/output/copy_output_request.h b/cc/output/copy_output_request.h
index d0ef48b..54fff1a 100644
--- a/cc/output/copy_output_request.h
+++ b/cc/output/copy_output_request.h
@@ -8,36 +8,59 @@
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
+#include "ui/gfx/size.h"
class SkBitmap;
namespace cc {
+class CopyOutputResult;
+class TextureMailbox;
class CC_EXPORT CopyOutputRequest {
public:
- typedef base::Callback<void(scoped_ptr<SkBitmap>)> CopyAsBitmapCallback;
+ typedef base::Callback<void(scoped_ptr<CopyOutputResult> result)>
+ CopyOutputRequestCallback;
+ static scoped_ptr<CopyOutputRequest> CreateEmptyRequest() {
+ return make_scoped_ptr(new CopyOutputRequest);
+ }
+ static scoped_ptr<CopyOutputRequest> CreateRequest(
+ const CopyOutputRequestCallback& result_callback) {
+ return make_scoped_ptr(new CopyOutputRequest(false, result_callback));
+ }
static scoped_ptr<CopyOutputRequest> CreateBitmapRequest(
- const CopyAsBitmapCallback& bitmap_callback) {
- return make_scoped_ptr(new CopyOutputRequest(bitmap_callback));
+ const CopyOutputRequestCallback& result_callback) {
+ return make_scoped_ptr(new CopyOutputRequest(true, result_callback));
+ }
+ static scoped_ptr<CopyOutputRequest> CreateRelayRequest(
+ const CopyOutputRequest& original_request,
+ const CopyOutputRequestCallback& result_callback) {
+ return make_scoped_ptr(new CopyOutputRequest(
+ original_request.force_bitmap_result(), result_callback));
}
~CopyOutputRequest();
- bool IsEmpty() const { return !HasBitmapRequest(); }
- bool HasBitmapRequest() const { return !bitmap_callback_.is_null(); }
+ bool IsEmpty() const { return result_callback_.is_null(); }
+ bool force_bitmap_result() const { return force_bitmap_result_; }
- void SendEmptyResult();
+ void SendResult(scoped_ptr<CopyOutputResult> result);
void SendBitmapResult(scoped_ptr<SkBitmap> bitmap);
+ void SendTextureResult(gfx::Size size,
+ scoped_ptr<TextureMailbox> texture_mailbox);
bool Equals(const CopyOutputRequest& other) const {
- return bitmap_callback_.Equals(other.bitmap_callback_);
+ return result_callback_.Equals(other.result_callback_) &&
+ force_bitmap_result_ == other.force_bitmap_result_;
}
private:
- explicit CopyOutputRequest(const CopyAsBitmapCallback& callback);
+ CopyOutputRequest();
+ explicit CopyOutputRequest(bool force_bitmap_result,
+ const CopyOutputRequestCallback& result_callback);
- CopyAsBitmapCallback bitmap_callback_;
+ bool force_bitmap_result_;
+ CopyOutputRequestCallback result_callback_;
};
} // namespace cc
diff --git a/cc/output/copy_output_result.cc b/cc/output/copy_output_result.cc
new file mode 100644
index 0000000..412a55d
--- /dev/null
+++ b/cc/output/copy_output_result.cc
@@ -0,0 +1,39 @@
+// 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 "cc/output/copy_output_result.h"
+
+#include "base/logging.h"
+#include "cc/resources/texture_mailbox.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace cc {
+
+CopyOutputResult::CopyOutputResult() {}
+
+CopyOutputResult::CopyOutputResult(scoped_ptr<SkBitmap> bitmap)
+ : size_(bitmap->width(), bitmap->height()),
+ bitmap_(bitmap.Pass()) {
+ DCHECK(bitmap_);
+}
+
+CopyOutputResult::CopyOutputResult(gfx::Size size,
+ scoped_ptr<TextureMailbox> texture_mailbox)
+ : size_(size),
+ texture_mailbox_(texture_mailbox.Pass()) {
+ DCHECK(texture_mailbox_);
+ DCHECK(texture_mailbox_->IsTexture());
+}
+
+CopyOutputResult::~CopyOutputResult() {}
+
+scoped_ptr<SkBitmap> CopyOutputResult::TakeBitmap() {
+ return bitmap_.Pass();
+}
+
+scoped_ptr<TextureMailbox> CopyOutputResult::TakeTexture() {
+ return texture_mailbox_.Pass();
+}
+
+} // namespace cc
diff --git a/cc/output/copy_output_result.h b/cc/output/copy_output_result.h
new file mode 100644
index 0000000..04cf2c6
--- /dev/null
+++ b/cc/output/copy_output_result.h
@@ -0,0 +1,55 @@
+// 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 CC_OUTPUT_COPY_OUTPUT_RESULT_H_
+#define CC_OUTPUT_COPY_OUTPUT_RESULT_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "ui/gfx/size.h"
+
+class SkBitmap;
+
+namespace cc {
+class TextureMailbox;
+
+class CC_EXPORT CopyOutputResult {
+ public:
+ static scoped_ptr<CopyOutputResult> CreateEmptyResult() {
+ return make_scoped_ptr(new CopyOutputResult);
+ }
+ static scoped_ptr<CopyOutputResult> CreateBitmapResult(
+ scoped_ptr<SkBitmap> bitmap) {
+ return make_scoped_ptr(new CopyOutputResult(bitmap.Pass()));
+ }
+ static scoped_ptr<CopyOutputResult> CreateTextureResult(
+ gfx::Size size,
+ scoped_ptr<TextureMailbox> texture_mailbox) {
+ return make_scoped_ptr(new CopyOutputResult(size, texture_mailbox.Pass()));
+ }
+
+ ~CopyOutputResult();
+
+ bool IsEmpty() const { return !HasBitmap() && !HasTexture(); }
+ bool HasBitmap() const { return !!bitmap_; }
+ bool HasTexture() const { return !!texture_mailbox_; }
+
+ gfx::Size size() const { return size_; }
+ scoped_ptr<SkBitmap> TakeBitmap();
+ scoped_ptr<TextureMailbox> TakeTexture();
+
+ private:
+ CopyOutputResult();
+ explicit CopyOutputResult(scoped_ptr<SkBitmap> bitmap);
+ explicit CopyOutputResult(gfx::Size size,
+ scoped_ptr<TextureMailbox> texture_mailbox);
+
+ gfx::Size size_;
+ scoped_ptr<SkBitmap> bitmap_;
+ scoped_ptr<TextureMailbox> texture_mailbox_;
+};
+
+} // namespace cc
+
+#endif // CC_OUTPUT_COPY_OUTPUT_RESULT_H_
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index fb5de4e..2a27ff7 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -21,6 +21,7 @@
#include "cc/output/compositor_frame_metadata.h"
#include "cc/output/context_provider.h"
#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
#include "cc/output/geometry_binding.h"
#include "cc/output/gl_frame_data.h"
#include "cc/output/output_surface.h"
@@ -136,7 +137,8 @@ GLRenderer::GLRenderer(RendererClient* client,
is_scissor_enabled_(false),
highp_threshold_min_(highp_threshold_min),
highp_threshold_cache_(0),
- on_demand_tile_raster_resource_id_(0) {
+ on_demand_tile_raster_resource_id_(0),
+ weak_factory_(this) {
DCHECK(context_);
}
@@ -599,19 +601,29 @@ scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters(
// FIXME: Do a single readback for both the surface and replica and cache the
// filtered results (once filter textures are not reused).
- gfx::Rect device_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect(
+ gfx::Rect window_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect(
contents_device_transform, SharedGeometryQuad().BoundingBox()));
int top, right, bottom, left;
filters.getOutsets(top, right, bottom, left);
- device_rect.Inset(-left, -top, -right, -bottom);
+ window_rect.Inset(-left, -top, -right, -bottom);
- device_rect.Intersect(frame->current_render_pass->output_rect);
+ window_rect.Intersect(
+ MoveFromDrawToWindowSpace(frame->current_render_pass->output_rect));
scoped_ptr<ScopedResource> device_background_texture =
ScopedResource::create(resource_provider_);
- if (!GetFramebufferTexture(device_background_texture.get(), device_rect))
+ if (!device_background_texture->Allocate(window_rect.size(),
+ GL_RGB,
+ ResourceProvider::TextureUsageAny)) {
return scoped_ptr<ScopedResource>();
+ } else {
+ ResourceProvider::ScopedWriteLockGL lock(resource_provider_,
+ device_background_texture->id());
+ GetFramebufferTexture(lock.texture_id(),
+ device_background_texture->format(),
+ window_rect);
+ }
SkBitmap filtered_device_background =
ApplyFilters(this, filters, device_background_texture.get());
@@ -658,7 +670,7 @@ scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters(
CopyTextureToFramebuffer(frame,
filtered_device_background_texture_id,
- device_rect,
+ window_rect,
device_to_framebuffer_transform,
flip_vertically);
}
@@ -2135,11 +2147,20 @@ void GLRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) {
pending_read.Pass());
// This is a syncronous call since the callback is null.
+ gfx::Rect window_rect = MoveFromDrawToWindowSpace(rect);
DoGetFramebufferPixels(static_cast<uint8*>(pixels),
- rect,
+ window_rect,
AsyncGetFramebufferPixelsCleanupCallback());
}
+void GLRenderer::DeleteTextureReleaseCallback(unsigned texture_id,
+ unsigned sync_point,
+ bool lost_resource) {
+ if (sync_point)
+ context_->waitSyncPoint(sync_point);
+ context_->deleteTexture(texture_id);
+}
+
void GLRenderer::GetFramebufferPixelsAsync(
gfx::Rect rect, scoped_ptr<CopyOutputRequest> request) {
DCHECK(!request->IsEmpty());
@@ -2148,8 +2169,56 @@ void GLRenderer::GetFramebufferPixelsAsync(
if (rect.IsEmpty())
return;
+ DCHECK(gfx::Rect(current_surface_size_).Contains(rect)) <<
+ "current_surface_size_: " << current_surface_size_.ToString() <<
+ " rect: " << rect.ToString();
+
+ gfx::Rect window_rect = MoveFromDrawToWindowSpace(rect);
+
+ if (!request->force_bitmap_result()) {
+ unsigned int texture_id = context_->createTexture();
+ GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id));
+ GLC(context_, context_->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
+ GLC(context_, context_->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+ GLC(context_, context_->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+ GLC(context_, context_->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+ GetFramebufferTexture(texture_id, GL_RGBA, window_rect);
+
+ gpu::Mailbox mailbox;
+ unsigned sync_point = 0;
+ GLC(context_, context_->genMailboxCHROMIUM(mailbox.name));
+ if (mailbox.IsZero()) {
+ context_->deleteTexture(texture_id);
+ request->SendResult(CopyOutputResult::CreateEmptyResult());
+ return;
+ }
+
+ GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id));
+ GLC(context_, context_->produceTextureCHROMIUM(
+ GL_TEXTURE_2D, mailbox.name));
+ GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0));
+ sync_point = context_->insertSyncPoint();
+ scoped_ptr<TextureMailbox> texture_mailbox = make_scoped_ptr(
+ new TextureMailbox(mailbox,
+ base::Bind(&GLRenderer::DeleteTextureReleaseCallback,
+ weak_factory_.GetWeakPtr(),
+ texture_id),
+ GL_TEXTURE_2D,
+ sync_point));
+ request->SendTextureResult(window_rect.size(), texture_mailbox.Pass());
+ return;
+ }
+
+ DCHECK(request->force_bitmap_result());
+
scoped_ptr<SkBitmap> bitmap(new SkBitmap);
- bitmap->setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height());
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config,
+ window_rect.width(),
+ window_rect.height());
bitmap->allocPixels();
scoped_ptr<SkAutoLockPixels> lock(new SkAutoLockPixels(*bitmap));
@@ -2169,14 +2238,15 @@ void GLRenderer::GetFramebufferPixelsAsync(
pending_read.Pass());
// This is an asyncronous call since the callback is not null.
- DoGetFramebufferPixels(pixels, rect, cleanup_callback);
+ DoGetFramebufferPixels(pixels, window_rect, cleanup_callback);
}
void GLRenderer::DoGetFramebufferPixels(
uint8* dest_pixels,
- gfx::Rect rect,
+ gfx::Rect window_rect,
const AsyncGetFramebufferPixelsCleanupCallback& cleanup_callback) {
- gfx::Rect window_rect = MoveFromDrawToWindowSpace(rect);
+ DCHECK_GE(window_rect.x(), 0);
+ DCHECK_GE(window_rect.y(), 0);
DCHECK_LE(window_rect.right(), current_surface_size_.width());
DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
@@ -2198,48 +2268,37 @@ void GLRenderer::DoGetFramebufferPixels(
temporary_texture = context_->createTexture();
GLC(context_, context_->bindTexture(GL_TEXTURE_2D, temporary_texture));
- GLC(context_,
- context_->texParameteri(
- GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
- GLC(context_,
- context_->texParameteri(
- GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
- GLC(context_,
- context_->texParameteri(
- GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
- GLC(context_,
- context_->texParameteri(
- GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+ GLC(context_, context_->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
+ GLC(context_, context_->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+ GLC(context_, context_->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+ GLC(context_, context_->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
// Copy the contents of the current (IOSurface-backed) framebuffer into a
// temporary texture.
- GLC(context_,
- context_->copyTexImage2D(GL_TEXTURE_2D,
- 0,
- GL_RGBA,
- 0,
- 0,
- current_surface_size_.width(),
- current_surface_size_.height(),
- 0));
+ GetFramebufferTexture(temporary_texture,
+ GL_RGBA,
+ gfx::Rect(current_surface_size_));
temporary_fbo = context_->createFramebuffer();
// Attach this texture to an FBO, and perform the readback from that FBO.
GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, temporary_fbo));
- GLC(context_,
- context_->framebufferTexture2D(GL_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D,
- temporary_texture,
- 0));
+ GLC(context_, context_->framebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ temporary_texture,
+ 0));
- DCHECK(context_->checkFramebufferStatus(GL_FRAMEBUFFER) ==
- GL_FRAMEBUFFER_COMPLETE);
+ DCHECK_EQ(static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE),
+ context_->checkFramebufferStatus(GL_FRAMEBUFFER));
}
unsigned buffer = context_->createBuffer();
GLC(context_, context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
buffer));
GLC(context_, context_->bufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
- 4 * rect.size().GetArea(),
+ 4 * window_rect.size().GetArea(),
NULL,
GL_STREAM_READ));
@@ -2269,7 +2328,7 @@ void GLRenderer::DoGetFramebufferPixels(
cleanup_callback,
buffer,
dest_pixels,
- rect.size());
+ window_rect.size());
// Save the finished_callback so it can be cancelled.
pending_async_read_pixels_.front()->finished_read_pixels_callback.Reset(
finished_callback);
@@ -2348,35 +2407,33 @@ void GLRenderer::PassOnSkBitmap(
scoped_ptr<SkAutoLockPixels> lock,
scoped_ptr<CopyOutputRequest> request,
bool success) {
- DCHECK(request->HasBitmapRequest());
+ DCHECK(request->force_bitmap_result());
lock.reset();
if (success)
request->SendBitmapResult(bitmap.Pass());
}
-bool GLRenderer::GetFramebufferTexture(ScopedResource* texture,
- gfx::Rect device_rect) {
- DCHECK(!texture->id() || (texture->size() == device_rect.size() &&
- texture->format() == GL_RGB));
-
- if (!texture->id() && !texture->Allocate(device_rect.size(),
- GL_RGB,
- ResourceProvider::TextureUsageAny))
- return false;
+void GLRenderer::GetFramebufferTexture(unsigned texture_id,
+ unsigned texture_format,
+ gfx::Rect window_rect) {
+ DCHECK(texture_id);
+ DCHECK_GE(window_rect.x(), 0);
+ DCHECK_GE(window_rect.y(), 0);
+ DCHECK_LE(window_rect.right(), current_surface_size_.width());
+ DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
- ResourceProvider::ScopedWriteLockGL lock(resource_provider_, texture->id());
- GLC(context_, context_->bindTexture(GL_TEXTURE_2D, lock.texture_id()));
+ GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id));
GLC(context_,
context_->copyTexImage2D(GL_TEXTURE_2D,
0,
- texture->format(),
- device_rect.x(),
- device_rect.y(),
- device_rect.width(),
- device_rect.height(),
+ texture_format,
+ window_rect.x(),
+ window_rect.y(),
+ window_rect.width(),
+ window_rect.height(),
0));
- return true;
+ GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0));
}
bool GLRenderer::UseScopedTexture(DrawingFrame* frame,
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h
index e5d80f1..21acdde 100644
--- a/cc/output/gl_renderer.h
+++ b/cc/output/gl_renderer.h
@@ -96,7 +96,9 @@ class CC_EXPORT GLRenderer
void GetFramebufferPixelsAsync(gfx::Rect rect,
scoped_ptr<CopyOutputRequest> request);
- bool GetFramebufferTexture(ScopedResource* resource, gfx::Rect device_rect);
+ void GetFramebufferTexture(unsigned texture_id,
+ unsigned texture_format,
+ gfx::Rect device_rect);
void ReleaseRenderPassTextures();
virtual void BindFramebufferToOutputSurface(DrawingFrame* frame) OVERRIDE;
@@ -197,18 +199,20 @@ class CC_EXPORT GLRenderer
AsyncGetFramebufferPixelsCleanupCallback;
void DoGetFramebufferPixels(
uint8* pixels,
- gfx::Rect rect,
+ gfx::Rect window_rect,
const AsyncGetFramebufferPixelsCleanupCallback& cleanup_callback);
void FinishedReadback(
const AsyncGetFramebufferPixelsCleanupCallback& cleanup_callback,
unsigned source_buffer,
uint8_t* dest_pixels,
gfx::Size size);
- void PassOnSkBitmap(
- scoped_ptr<SkBitmap> bitmap,
- scoped_ptr<SkAutoLockPixels> lock,
- scoped_ptr<CopyOutputRequest> request,
- bool success);
+ void PassOnSkBitmap(scoped_ptr<SkBitmap> bitmap,
+ scoped_ptr<SkAutoLockPixels> lock,
+ scoped_ptr<CopyOutputRequest> request,
+ bool success);
+ void DeleteTextureReleaseCallback(unsigned texture_id,
+ unsigned sync_point,
+ bool lost_resource);
void ReinitializeGrCanvas();
void ReinitializeGLState();
@@ -431,6 +435,8 @@ class CC_EXPORT GLRenderer
SkBitmap on_demand_tile_raster_bitmap_;
ResourceProvider::ResourceId on_demand_tile_raster_resource_id_;
+ base::WeakPtrFactory<GLRenderer> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(GLRenderer);
};
diff --git a/cc/quads/render_pass_unittest.cc b/cc/quads/render_pass_unittest.cc
index 1ab41e8..fdeb4f0 100644
--- a/cc/quads/render_pass_unittest.cc
+++ b/cc/quads/render_pass_unittest.cc
@@ -50,8 +50,7 @@ TEST(RenderPassTest, CopyShouldBeIdenticalExceptIdAndQuads) {
transform_to_root,
has_transparent_background,
has_occlusion_from_outside_target_surface);
- pass->copy_requests.push_back(CopyOutputRequest::CreateBitmapRequest(
- CopyOutputRequest::CopyAsBitmapCallback()));
+ pass->copy_requests.push_back(CopyOutputRequest::CreateEmptyRequest());
// Stick a quad in the pass, this should not get copied.
scoped_ptr<SharedQuadState> shared_state = SharedQuadState::Create();
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index 3c67e54..3d757ca 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -6,8 +6,12 @@
#include "base/path_service.h"
#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
+#include "cc/resources/texture_mailbox.h"
#include "cc/test/paths.h"
#include "cc/test/pixel_comparator.h"
+#include "cc/test/pixel_test_output_surface.h"
+#include "cc/test/pixel_test_software_output_device.h"
#include "cc/test/pixel_test_utils.h"
#include "cc/trees/layer_tree_impl.h"
#include "ui/gl/gl_implementation.h"
@@ -17,19 +21,37 @@
namespace cc {
LayerTreePixelTest::LayerTreePixelTest()
- : pixel_comparator_(new ExactPixelComparator(true)) {}
+ : pixel_comparator_(new ExactPixelComparator(true)), use_gl_(true) {}
LayerTreePixelTest::~LayerTreePixelTest() {}
scoped_ptr<OutputSurface> LayerTreePixelTest::CreateOutputSurface() {
- CHECK(gfx::InitializeGLBindings(gfx::kGLImplementationOSMesaGL));
-
- using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
- scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d(
- WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
- WebKit::WebGraphicsContext3D::Attributes()));
- return make_scoped_ptr(
- new OutputSurface(context3d.PassAs<WebKit::WebGraphicsContext3D>()));
+ gfx::Vector2d viewport_offset(20, 10);
+ gfx::Size surface_expansion_size(40, 60);
+ scoped_ptr<PixelTestOutputSurface> output_surface;
+
+ if (!use_gl_) {
+ scoped_ptr<PixelTestSoftwareOutputDevice> software_output_device(
+ new PixelTestSoftwareOutputDevice);
+ software_output_device->set_surface_expansion_size(surface_expansion_size);
+ output_surface = make_scoped_ptr(
+ new PixelTestOutputSurface(
+ software_output_device.PassAs<SoftwareOutputDevice>()));
+ } else {
+ CHECK(gfx::InitializeGLBindings(gfx::kGLImplementationOSMesaGL));
+
+ using WebKit::WebGraphicsContext3D;
+ using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
+ scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d(
+ WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
+ WebGraphicsContext3D::Attributes()));
+ output_surface = make_scoped_ptr(
+ new PixelTestOutputSurface(context3d.PassAs<WebGraphicsContext3D>()));
+ }
+
+ output_surface->set_viewport_offset(viewport_offset);
+ output_surface->set_surface_expansion_size(surface_expansion_size);
+ return output_surface.PassAs<OutputSurface>();
}
scoped_refptr<cc::ContextProvider>
@@ -48,31 +70,36 @@ LayerTreePixelTest::OffscreenContextProviderForCompositorThread() {
return provider;
}
-void LayerTreePixelTest::ReadbackResult(scoped_ptr<SkBitmap> bitmap) {
- ASSERT_TRUE(bitmap);
-
- base::FilePath test_data_dir;
- EXPECT_TRUE(PathService::Get(cc::DIR_TEST_DATA, &test_data_dir));
-
- // To rebaseline:
- // EXPECT_TRUE(WritePNGFile(*bitmap, test_data_dir.Append(ref_file_), true));
+scoped_ptr<CopyOutputRequest> LayerTreePixelTest::CreateCopyOutputRequest() {
+ return CopyOutputRequest::CreateBitmapRequest(
+ base::Bind(&LayerTreePixelTest::ReadbackResult, base::Unretained(this)));
+}
- EXPECT_TRUE(MatchesPNGFile(*bitmap,
- test_data_dir.Append(ref_file_),
- *pixel_comparator_));
+void LayerTreePixelTest::ReadbackResult(scoped_ptr<CopyOutputResult> result) {
+ ASSERT_TRUE(result->HasBitmap());
+ result_bitmap_ = result->TakeBitmap().Pass();
EndTest();
}
void LayerTreePixelTest::BeginTest() {
Layer* target = readback_target_ ? readback_target_
: layer_tree_host()->root_layer();
- target->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
- base::Bind(&LayerTreePixelTest::ReadbackResult,
- base::Unretained(this))));
+ target->RequestCopyOfOutput(CreateCopyOutputRequest().Pass());
PostSetNeedsCommitToMainThread();
}
-void LayerTreePixelTest::AfterTest() {}
+void LayerTreePixelTest::AfterTest() {
+ base::FilePath test_data_dir;
+ EXPECT_TRUE(PathService::Get(cc::DIR_TEST_DATA, &test_data_dir));
+ base::FilePath ref_file_path = test_data_dir.Append(ref_file_);
+
+ // To rebaseline:
+ // EXPECT_TRUE(WritePNGFile(*result_bitmap_, ref_file_path, true));
+
+ EXPECT_TRUE(MatchesPNGFile(*result_bitmap_,
+ ref_file_path,
+ *pixel_comparator_));
+}
scoped_refptr<SolidColorLayer> LayerTreePixelTest::CreateSolidColorLayer(
gfx::Rect rect, SkColor color) {
@@ -140,4 +167,81 @@ void LayerTreePixelTest::SetupTree() {
LayerTreeTest::SetupTree();
}
+scoped_ptr<SkBitmap> LayerTreePixelTest::CopyTextureMailboxToBitmap(
+ gfx::Size size,
+ const TextureMailbox& texture_mailbox) {
+ DCHECK(texture_mailbox.IsTexture());
+ if (!texture_mailbox.IsTexture())
+ return scoped_ptr<SkBitmap>();
+
+ using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
+ scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d(
+ WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
+ WebKit::WebGraphicsContext3D::Attributes()));
+
+ EXPECT_TRUE(context3d->makeContextCurrent());
+
+ if (texture_mailbox.sync_point())
+ context3d->waitSyncPoint(texture_mailbox.sync_point());
+
+ unsigned texture_id = context3d->createTexture();
+ context3d->bindTexture(GL_TEXTURE_2D, texture_id);
+ context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ context3d->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ context3d->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ context3d->consumeTextureCHROMIUM(texture_mailbox.target(),
+ texture_mailbox.data());
+ context3d->bindTexture(GL_TEXTURE_2D, 0);
+
+ unsigned fbo = context3d->createFramebuffer();
+ context3d->bindFramebuffer(GL_FRAMEBUFFER, fbo);
+ context3d->framebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ texture_id,
+ 0);
+ EXPECT_EQ(static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE),
+ context3d->checkFramebufferStatus(GL_FRAMEBUFFER));
+
+ scoped_ptr<uint8[]> pixels(new uint8[size.GetArea() * 4]);
+ context3d->readPixels(0,
+ 0,
+ size.width(),
+ size.height(),
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ pixels.get());
+
+ context3d->deleteFramebuffer(fbo);
+ context3d->deleteTexture(texture_id);
+
+ scoped_ptr<SkBitmap> bitmap(new SkBitmap);
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config,
+ size.width(),
+ size.height());
+ bitmap->allocPixels();
+
+ scoped_ptr<SkAutoLockPixels> lock(new SkAutoLockPixels(*bitmap));
+ uint8* out_pixels = static_cast<uint8*>(bitmap->getPixels());
+
+ size_t row_bytes = size.width() * 4;
+ size_t total_bytes = size.height() * row_bytes;
+ for (size_t dest_y = 0; dest_y < total_bytes; dest_y += row_bytes) {
+ // Flip Y axis.
+ size_t src_y = total_bytes - dest_y - row_bytes;
+ // Swizzle OpenGL -> Skia byte order.
+ for (size_t x = 0; x < row_bytes; x += 4) {
+ out_pixels[dest_y + x + SK_R32_SHIFT/8] = pixels.get()[src_y + x + 0];
+ out_pixels[dest_y + x + SK_G32_SHIFT/8] = pixels.get()[src_y + x + 1];
+ out_pixels[dest_y + x + SK_B32_SHIFT/8] = pixels.get()[src_y + x + 2];
+ out_pixels[dest_y + x + SK_A32_SHIFT/8] = pixels.get()[src_y + x + 3];
+ }
+ }
+
+ return bitmap.Pass();
+}
+
} // namespace cc
diff --git a/cc/test/layer_tree_pixel_test.h b/cc/test/layer_tree_pixel_test.h
index 1e5ddae..b485237 100644
--- a/cc/test/layer_tree_pixel_test.h
+++ b/cc/test/layer_tree_pixel_test.h
@@ -11,9 +11,14 @@
#ifndef CC_TEST_LAYER_TREE_PIXEL_TEST_H_
#define CC_TEST_LAYER_TREE_PIXEL_TEST_H_
+class SkBitmap;
+
namespace cc {
+class CopyOutputRequest;
+class CopyOutputResult;
class LayerTreeHost;
class PixelComparator;
+class TextureMailbox;
class LayerTreePixelTest : public LayerTreeTest {
protected:
@@ -26,7 +31,9 @@ class LayerTreePixelTest : public LayerTreeTest {
virtual scoped_refptr<cc::ContextProvider>
OffscreenContextProviderForCompositorThread() OVERRIDE;
- void ReadbackResult(scoped_ptr<SkBitmap> bitmap);
+ virtual scoped_ptr<CopyOutputRequest> CreateCopyOutputRequest();
+
+ void ReadbackResult(scoped_ptr<CopyOutputResult> result);
virtual void BeginTest() OVERRIDE;
virtual void SetupTree() OVERRIDE;
@@ -47,6 +54,10 @@ class LayerTreePixelTest : public LayerTreeTest {
Layer* target,
base::FilePath file_name);
+ scoped_ptr<SkBitmap> CopyTextureMailboxToBitmap(
+ gfx::Size size,
+ const TextureMailbox& texture_mailbox);
+
// Common CSS colors defined for tests to use.
enum Colors {
kCSSOrange = 0xffffa500,
@@ -56,10 +67,12 @@ class LayerTreePixelTest : public LayerTreeTest {
scoped_ptr<PixelComparator> pixel_comparator_;
- private:
+ protected:
+ bool use_gl_;
scoped_refptr<Layer> content_root_;
Layer* readback_target_;
base::FilePath ref_file_;
+ scoped_ptr<SkBitmap> result_bitmap_;
};
} // namespace cc
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index 1e75156..654804b 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -8,11 +8,14 @@
#include "base/run_loop.h"
#include "cc/output/compositor_frame_metadata.h"
#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
#include "cc/output/gl_renderer.h"
-#include "cc/output/output_surface.h"
+#include "cc/output/output_surface_client.h"
#include "cc/output/software_renderer.h"
#include "cc/resources/resource_provider.h"
#include "cc/test/paths.h"
+#include "cc/test/pixel_test_output_surface.h"
+#include "cc/test/pixel_test_software_output_device.h"
#include "cc/test/pixel_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/gl_implementation.h"
@@ -21,14 +24,15 @@
namespace cc {
-class PixelTest::PixelTestRendererClient : public RendererClient {
+class PixelTest::PixelTestRendererClient
+ : public RendererClient, public OutputSurfaceClient {
public:
explicit PixelTestRendererClient(gfx::Rect device_viewport)
: device_viewport_(device_viewport) {}
// RendererClient implementation.
virtual gfx::Rect DeviceViewport() const OVERRIDE {
- return device_viewport_ + test_expansion_offset_;
+ return device_viewport_;
}
virtual float DeviceScaleFactor() const OVERRIDE {
return 1.f;
@@ -51,56 +55,25 @@ class PixelTest::PixelTestRendererClient : public RendererClient {
return true;
}
- void SetTestExpansionOffset(gfx::Vector2d test_expansion_offset) {
- test_expansion_offset_ = test_expansion_offset;
+ // OutputSurfaceClient implementation.
+ virtual bool DeferredInitialize(
+ scoped_refptr<ContextProvider> offscreen_context_provider) OVERRIDE {
+ return false;
+ }
+ virtual void SetNeedsRedrawRect(gfx::Rect damage_rect) OVERRIDE {}
+ virtual void BeginFrame(base::TimeTicks frame_time) OVERRIDE {}
+ virtual void OnSwapBuffersComplete(const CompositorFrameAck* ack) OVERRIDE {}
+ virtual void DidLoseOutputSurface() OVERRIDE {}
+ virtual void SetExternalDrawConstraints(const gfx::Transform& transform,
+ gfx::Rect viewport) OVERRIDE {
+ device_viewport_ = viewport;
}
private:
gfx::Rect device_viewport_;
- gfx::Vector2d test_expansion_offset_;
LayerTreeSettings settings_;
};
-class PixelTest::PixelTestOutputSurface : public OutputSurface {
- public:
- explicit PixelTestOutputSurface(
- scoped_ptr<WebKit::WebGraphicsContext3D> context3d)
- : OutputSurface(context3d.Pass()) {}
- explicit PixelTestOutputSurface(
- scoped_ptr<cc::SoftwareOutputDevice> software_device)
- : OutputSurface(software_device.Pass()) {}
- virtual void Reshape(gfx::Size size, float scale_factor) OVERRIDE {
- OutputSurface::Reshape(
- gfx::Size(size.width() + test_expansion_size_.width(),
- size.height() + test_expansion_size_.height()),
- scale_factor);
- }
-
- void SetTestExpansionSize(gfx::Size test_expansion_size) {
- test_expansion_size_ = test_expansion_size;
- }
-
- private:
- gfx::Size test_expansion_size_;
-};
-
-class PixelTestSoftwareOutputDevice : public SoftwareOutputDevice {
- public:
- PixelTestSoftwareOutputDevice() {}
- virtual void Resize(gfx::Size size) OVERRIDE {
- SoftwareOutputDevice::Resize(
- gfx::Size(size.width() + test_expansion_size_.width(),
- size.height() + test_expansion_size_.height()));
- }
-
- void SetTestExpansionSize(gfx::Size test_expansion_size) {
- test_expansion_size_ = test_expansion_size;
- }
-
- private:
- gfx::Size test_expansion_size_;
-};
-
PixelTest::PixelTest()
: device_viewport_size_(gfx::Size(200, 200)),
fake_client_(
@@ -140,8 +113,9 @@ bool PixelTest::RunPixelTestWithReadbackTarget(
}
void PixelTest::ReadbackResult(base::Closure quit_run_loop,
- scoped_ptr<SkBitmap> bitmap) {
- result_bitmap_ = bitmap.Pass();
+ scoped_ptr<CopyOutputResult> result) {
+ ASSERT_TRUE(result->HasBitmap());
+ result_bitmap_ = result->TakeBitmap().Pass();
quit_run_loop.Run();
}
@@ -173,6 +147,8 @@ void PixelTest::SetUpGLRenderer(bool use_skia_gpu_backend) {
WebKit::WebGraphicsContext3D::Attributes()));
output_surface_.reset(new PixelTestOutputSurface(
context3d.PassAs<WebKit::WebGraphicsContext3D>()));
+ output_surface_->BindToClient(fake_client_.get());
+
resource_provider_ = ResourceProvider::Create(output_surface_.get(), 0);
renderer_ = GLRenderer::Create(fake_client_.get(),
output_surface_.get(),
@@ -189,12 +165,13 @@ void PixelTest::SetUpGLRenderer(bool use_skia_gpu_backend) {
void PixelTest::ForceExpandedViewport(gfx::Size surface_expansion,
gfx::Vector2d viewport_offset) {
static_cast<PixelTestOutputSurface*>(output_surface_.get())
- ->SetTestExpansionSize(surface_expansion);
- fake_client_->SetTestExpansionOffset(viewport_offset);
+ ->set_surface_expansion_size(surface_expansion);
+ static_cast<PixelTestOutputSurface*>(output_surface_.get())
+ ->set_viewport_offset(viewport_offset);
SoftwareOutputDevice* device = output_surface_->software_device();
if (device) {
static_cast<PixelTestSoftwareOutputDevice*>(device)
- ->SetTestExpansionSize(surface_expansion);
+ ->set_surface_expansion_size(surface_expansion);
}
}
@@ -203,6 +180,7 @@ void PixelTest::SetUpSoftwareRenderer() {
scoped_ptr<SoftwareOutputDevice> device(new PixelTestSoftwareOutputDevice());
output_surface_.reset(new PixelTestOutputSurface(device.Pass()));
+ output_surface_->BindToClient(fake_client_.get());
resource_provider_ = ResourceProvider::Create(output_surface_.get(), 0);
renderer_ = SoftwareRenderer::Create(
fake_client_.get(),
diff --git a/cc/test/pixel_test.h b/cc/test/pixel_test.h
index eb53e07..3c607ae 100644
--- a/cc/test/pixel_test.h
+++ b/cc/test/pixel_test.h
@@ -14,6 +14,7 @@
#define CC_TEST_PIXEL_TEST_H_
namespace cc {
+class CopyOutputResult;
class DirectRenderer;
class SoftwareRenderer;
class OutputSurface;
@@ -34,7 +35,6 @@ class PixelTest : public testing::Test {
const PixelComparator& comparator);
gfx::Size device_viewport_size_;
- class PixelTestOutputSurface;
class PixelTestRendererClient;
scoped_ptr<OutputSurface> output_surface_;
scoped_ptr<ResourceProvider> resource_provider_;
@@ -49,7 +49,8 @@ class PixelTest : public testing::Test {
gfx::Vector2d viewport_offset);
private:
- void ReadbackResult(base::Closure quit_run_loop, scoped_ptr<SkBitmap> bitmap);
+ void ReadbackResult(base::Closure quit_run_loop,
+ scoped_ptr<CopyOutputResult> result);
bool PixelsMatchReference(const base::FilePath& ref_file,
const PixelComparator& comparator);
diff --git a/cc/test/pixel_test_output_surface.cc b/cc/test/pixel_test_output_surface.cc
new file mode 100644
index 0000000..9a4d66a
--- /dev/null
+++ b/cc/test/pixel_test_output_surface.cc
@@ -0,0 +1,21 @@
+// 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 "cc/test/pixel_test_output_surface.h"
+
+#include "cc/output/output_surface_client.h"
+#include "ui/gfx/transform.h"
+
+namespace cc {
+
+void PixelTestOutputSurface::Reshape(gfx::Size size, float scale_factor) {
+ gfx::Size expanded_size(size.width() + surface_expansion_size_.width(),
+ size.height() + surface_expansion_size_.height());
+ OutputSurface::Reshape(expanded_size, scale_factor);
+
+ gfx::Rect offset_viewport = gfx::Rect(size) + viewport_offset_;
+ SetExternalDrawConstraints(gfx::Transform(), offset_viewport);
+}
+
+} // namespace cc
diff --git a/cc/test/pixel_test_output_surface.h b/cc/test/pixel_test_output_surface.h
new file mode 100644
index 0000000..ec7a828
--- /dev/null
+++ b/cc/test/pixel_test_output_surface.h
@@ -0,0 +1,37 @@
+// 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 CC_TEST_PIXEL_TEST_OUTPUT_SURFACE_H_
+#define CC_TEST_PIXEL_TEST_OUTPUT_SURFACE_H_
+
+#include "cc/output/output_surface.h"
+
+namespace cc {
+
+class PixelTestOutputSurface : public OutputSurface {
+ public:
+ explicit PixelTestOutputSurface(
+ scoped_ptr<WebKit::WebGraphicsContext3D> context3d)
+ : OutputSurface(context3d.Pass()) {}
+ explicit PixelTestOutputSurface(
+ scoped_ptr<cc::SoftwareOutputDevice> software_device)
+ : OutputSurface(software_device.Pass()) {}
+
+ virtual void Reshape(gfx::Size size, float scale_factor) OVERRIDE;
+
+ void set_surface_expansion_size(gfx::Size surface_expansion_size) {
+ surface_expansion_size_ = surface_expansion_size;
+ }
+ void set_viewport_offset(gfx::Vector2d viewport_offset) {
+ viewport_offset_ = viewport_offset;
+ }
+
+ private:
+ gfx::Size surface_expansion_size_;
+ gfx::Vector2d viewport_offset_;
+};
+
+} // namespace cc
+
+#endif // CC_TEST_PIXEL_TEST_OUTPUT_SURFACE_H_
diff --git a/cc/test/pixel_test_software_output_device.cc b/cc/test/pixel_test_software_output_device.cc
new file mode 100644
index 0000000..d4f0b88
--- /dev/null
+++ b/cc/test/pixel_test_software_output_device.cc
@@ -0,0 +1,15 @@
+// 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 "cc/test/pixel_test_software_output_device.h"
+
+namespace cc {
+
+void PixelTestSoftwareOutputDevice::Resize(gfx::Size size) {
+ gfx::Size expanded_size(size.width() + surface_expansion_size_.width(),
+ size.height() + surface_expansion_size_.height());
+ SoftwareOutputDevice::Resize(expanded_size);
+}
+
+} // namespace cc
diff --git a/cc/test/pixel_test_software_output_device.h b/cc/test/pixel_test_software_output_device.h
new file mode 100644
index 0000000..b652063
--- /dev/null
+++ b/cc/test/pixel_test_software_output_device.h
@@ -0,0 +1,26 @@
+// 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 CC_TEST_PIXEL_TEST_SOFTWARE_OUTPUT_DEVICE_H_
+#define CC_TEST_PIXEL_TEST_SOFTWARE_OUTPUT_DEVICE_H_
+
+#include "cc/output/software_output_device.h"
+
+namespace cc {
+
+class PixelTestSoftwareOutputDevice : public SoftwareOutputDevice {
+ public:
+ virtual void Resize(gfx::Size size) OVERRIDE;
+
+ void set_surface_expansion_size(gfx::Size surface_expansion_size) {
+ surface_expansion_size_ = surface_expansion_size;
+ }
+
+ private:
+ gfx::Size surface_expansion_size_;
+};
+
+} // namespace cc
+
+#endif // CC_TEST_PIXEL_TEST_SOFTWARE_OUTPUT_DEVICE_H_
diff --git a/cc/trees/layer_tree_host_pixeltest_filters.cc b/cc/trees/layer_tree_host_pixeltest_filters.cc
index 5383bfd1..3c7e346 100644
--- a/cc/trees/layer_tree_host_pixeltest_filters.cc
+++ b/cc/trees/layer_tree_host_pixeltest_filters.cc
@@ -60,7 +60,7 @@ TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOutsets) {
"background_filter_blur_outsets.png")));
}
-TEST_F(LayerTreeHostFiltersPixelTest, DISABLED_BackgroundFilterBlurOffAxis) {
+TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOffAxis) {
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
gfx::Rect(200, 200), SK_ColorWHITE);
diff --git a/cc/trees/layer_tree_host_pixeltest_readback.cc b/cc/trees/layer_tree_host_pixeltest_readback.cc
index f6a6ccb..cd59ed5 100644
--- a/cc/trees/layer_tree_host_pixeltest_readback.cc
+++ b/cc/trees/layer_tree_host_pixeltest_readback.cc
@@ -3,16 +3,113 @@
// found in the LICENSE file.
#include "build/build_config.h"
+#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
#include "cc/test/layer_tree_pixel_test.h"
+#include "cc/test/paths.h"
#if !defined(OS_ANDROID)
namespace cc {
namespace {
-class LayerTreeHostReadbackPixelTest : public LayerTreePixelTest {};
+class LayerTreeHostReadbackPixelTest : public LayerTreePixelTest {
+ protected:
+ LayerTreeHostReadbackPixelTest() : force_readback_as_bitmap_(false) {}
+
+ virtual scoped_ptr<CopyOutputRequest> CreateCopyOutputRequest() OVERRIDE {
+ if (force_readback_as_bitmap_) {
+ return CopyOutputRequest::CreateBitmapRequest(
+ base::Bind(&LayerTreeHostReadbackPixelTest::ReadbackResultAsBitmap,
+ base::Unretained(this)));
+ }
+
+ if (!use_gl_) {
+ return CopyOutputRequest::CreateRequest(
+ base::Bind(&LayerTreeHostReadbackPixelTest::ReadbackResultAsBitmap,
+ base::Unretained(this)));
+ }
+
+ return CopyOutputRequest::CreateRequest(
+ base::Bind(&LayerTreeHostReadbackPixelTest::ReadbackResultAsTexture,
+ base::Unretained(this)));
+ }
+
+ void ReadbackResultAsBitmap(scoped_ptr<CopyOutputResult> result) {
+ EXPECT_TRUE(result->HasBitmap());
+ result_bitmap_ = result->TakeBitmap().Pass();
+ EndTest();
+ }
+
+ void ReadbackResultAsTexture(scoped_ptr<CopyOutputResult> result) {
+ EXPECT_TRUE(result->HasTexture());
+
+ scoped_ptr<TextureMailbox> texture_mailbox = result->TakeTexture().Pass();
+ EXPECT_TRUE(texture_mailbox->IsValid());
+ EXPECT_TRUE(texture_mailbox->IsTexture());
+
+ scoped_ptr<SkBitmap> bitmap =
+ CopyTextureMailboxToBitmap(result->size(), *texture_mailbox);
+ ReadbackResultAsBitmap(CopyOutputResult::CreateBitmapResult(bitmap.Pass()));
+
+ texture_mailbox->RunReleaseCallback(0, false);
+ }
+
+ bool force_readback_as_bitmap_;
+};
+
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayer_Software) {
+ use_gl_ = false;
+ force_readback_as_bitmap_ = false;
+
+ scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> green = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorGREEN);
+ background->AddChild(green);
+
+ RunPixelTest(background,
+ base::FilePath(FILE_PATH_LITERAL(
+ "green.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayer_Software_Bitmap) {
+ use_gl_ = false;
+ force_readback_as_bitmap_ = true;
+
+ scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> green = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorGREEN);
+ background->AddChild(green);
+
+ RunPixelTest(background,
+ base::FilePath(FILE_PATH_LITERAL(
+ "green.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayer_GL_Bitmap) {
+ use_gl_ = true;
+ force_readback_as_bitmap_ = true;
+
+ scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> green = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorGREEN);
+ background->AddChild(green);
+
+ RunPixelTest(background,
+ base::FilePath(FILE_PATH_LITERAL(
+ "green.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayer_GL) {
+ use_gl_ = true;
+ force_readback_as_bitmap_ = false;
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayer) {
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
gfx::Rect(200, 200), SK_ColorWHITE);
@@ -25,7 +122,11 @@ TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayer) {
"green.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild) {
+TEST_F(LayerTreeHostReadbackPixelTest,
+ ReadbackRootLayerWithChild_Software) {
+ use_gl_ = false;
+ force_readback_as_bitmap_ = false;
+
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
gfx::Rect(200, 200), SK_ColorWHITE);
@@ -42,7 +143,50 @@ TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild) {
"green_with_blue_corner.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer) {
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild_GL_Bitmap) {
+ use_gl_ = true;
+ force_readback_as_bitmap_ = true;
+
+ scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> green = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorGREEN);
+ background->AddChild(green);
+
+ scoped_refptr<SolidColorLayer> blue = CreateSolidColorLayer(
+ gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
+ green->AddChild(blue);
+
+ RunPixelTest(background,
+ base::FilePath(FILE_PATH_LITERAL(
+ "green_with_blue_corner.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild_GL) {
+ use_gl_ = true;
+ force_readback_as_bitmap_ = false;
+
+ scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> green = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorGREEN);
+ background->AddChild(green);
+
+ scoped_refptr<SolidColorLayer> blue = CreateSolidColorLayer(
+ gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
+ green->AddChild(blue);
+
+ RunPixelTest(background,
+ base::FilePath(FILE_PATH_LITERAL(
+ "green_with_blue_corner.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer_Software) {
+ use_gl_ = false;
+ force_readback_as_bitmap_ = false;
+
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
gfx::Rect(200, 200), SK_ColorWHITE);
@@ -56,7 +200,62 @@ TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer) {
"green.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayer) {
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer_GL_Bitmap) {
+ use_gl_ = true;
+ force_readback_as_bitmap_ = true;
+
+ scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> green = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorGREEN);
+ background->AddChild(green);
+
+ RunPixelTestWithReadbackTarget(background,
+ green.get(),
+ base::FilePath(FILE_PATH_LITERAL(
+ "green.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer_GL) {
+ use_gl_ = true;
+ force_readback_as_bitmap_ = false;
+
+ scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> green = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorGREEN);
+ background->AddChild(green);
+
+ RunPixelTestWithReadbackTarget(background,
+ green.get(),
+ base::FilePath(FILE_PATH_LITERAL(
+ "green.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest,
+ ReadbackSmallNonRootLayer_Software) {
+ use_gl_ = false;
+ force_readback_as_bitmap_ = false;
+
+ scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> green = CreateSolidColorLayer(
+ gfx::Rect(100, 100, 100, 100), SK_ColorGREEN);
+ background->AddChild(green);
+
+ RunPixelTestWithReadbackTarget(background,
+ green.get(),
+ base::FilePath(FILE_PATH_LITERAL(
+ "green_small.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayer_GL_Bitmap) {
+ use_gl_ = true;
+ force_readback_as_bitmap_ = true;
+
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
gfx::Rect(200, 200), SK_ColorWHITE);
@@ -70,7 +269,71 @@ TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayer) {
"green_small.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayerWithChild) {
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayer_GL) {
+ use_gl_ = true;
+ force_readback_as_bitmap_ = false;
+
+ scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> green = CreateSolidColorLayer(
+ gfx::Rect(100, 100, 100, 100), SK_ColorGREEN);
+ background->AddChild(green);
+
+ RunPixelTestWithReadbackTarget(background,
+ green.get(),
+ base::FilePath(FILE_PATH_LITERAL(
+ "green_small.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest,
+ ReadbackSmallNonRootLayerWithChild_Software) {
+ use_gl_ = false;
+ force_readback_as_bitmap_ = false;
+
+ scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> green = CreateSolidColorLayer(
+ gfx::Rect(100, 100, 100, 100), SK_ColorGREEN);
+ background->AddChild(green);
+
+ scoped_refptr<SolidColorLayer> blue = CreateSolidColorLayer(
+ gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
+ green->AddChild(blue);
+
+ RunPixelTestWithReadbackTarget(background,
+ green.get(),
+ base::FilePath(FILE_PATH_LITERAL(
+ "green_small_with_blue_corner.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest,
+ ReadbackSmallNonRootLayerWithChild_GL_Bitmap) {
+ use_gl_ = true;
+ force_readback_as_bitmap_ = true;
+
+ scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
+ gfx::Rect(200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> green = CreateSolidColorLayer(
+ gfx::Rect(100, 100, 100, 100), SK_ColorGREEN);
+ background->AddChild(green);
+
+ scoped_refptr<SolidColorLayer> blue = CreateSolidColorLayer(
+ gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
+ green->AddChild(blue);
+
+ RunPixelTestWithReadbackTarget(background,
+ green.get(),
+ base::FilePath(FILE_PATH_LITERAL(
+ "green_small_with_blue_corner.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayerWithChild_GL) {
+ use_gl_ = true;
+ force_readback_as_bitmap_ = false;
+
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
gfx::Rect(200, 200), SK_ColorWHITE);
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index e4d192e..f4d245b 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -16,6 +16,7 @@
#include "cc/layers/picture_layer.h"
#include "cc/layers/scrollbar_layer.h"
#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
#include "cc/output/output_surface.h"
#include "cc/resources/prioritized_resource.h"
#include "cc/resources/prioritized_resource_manager.h"
@@ -2526,7 +2527,7 @@ class LayerTreeHostTestAsyncReadback : public LayerTreeHostTest {
switch (frame) {
case 1:
child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
- base::Bind(&LayerTreeHostTestAsyncReadback::BitmapCallback,
+ base::Bind(&LayerTreeHostTestAsyncReadback::CopyOutputCallback,
base::Unretained(this))));
EXPECT_EQ(0u, callbacks_.size());
break;
@@ -2539,13 +2540,13 @@ class LayerTreeHostTestAsyncReadback : public LayerTreeHostTest {
EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[0].ToString());
child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
- base::Bind(&LayerTreeHostTestAsyncReadback::BitmapCallback,
+ base::Bind(&LayerTreeHostTestAsyncReadback::CopyOutputCallback,
base::Unretained(this))));
root->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
- base::Bind(&LayerTreeHostTestAsyncReadback::BitmapCallback,
+ base::Bind(&LayerTreeHostTestAsyncReadback::CopyOutputCallback,
base::Unretained(this))));
child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
- base::Bind(&LayerTreeHostTestAsyncReadback::BitmapCallback,
+ base::Bind(&LayerTreeHostTestAsyncReadback::CopyOutputCallback,
base::Unretained(this))));
EXPECT_EQ(1u, callbacks_.size());
break;
@@ -2565,10 +2566,13 @@ class LayerTreeHostTestAsyncReadback : public LayerTreeHostTest {
}
}
- void BitmapCallback(scoped_ptr<SkBitmap> bitmap) {
+ void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
- EXPECT_TRUE(bitmap);
- callbacks_.push_back(gfx::Size(bitmap->width(), bitmap->height()));
+ EXPECT_TRUE(result->HasBitmap());
+ scoped_ptr<SkBitmap> bitmap = result->TakeBitmap().Pass();
+ EXPECT_EQ(result->size().ToString(),
+ gfx::Size(bitmap->width(), bitmap->height()).ToString());
+ callbacks_.push_back(result->size());
}
virtual void AfterTest() OVERRIDE {
@@ -2653,11 +2657,13 @@ class LayerTreeHostTestAsyncReadbackLayerDestroyed : public LayerTreeHostTest {
case 1:
main_destroyed_->RequestCopyOfOutput(
CopyOutputRequest::CreateBitmapRequest(base::Bind(
- &LayerTreeHostTestAsyncReadbackLayerDestroyed::BitmapCallback,
+ &LayerTreeHostTestAsyncReadbackLayerDestroyed::
+ CopyOutputCallback,
base::Unretained(this))));
impl_destroyed_->RequestCopyOfOutput(
CopyOutputRequest::CreateBitmapRequest(base::Bind(
- &LayerTreeHostTestAsyncReadbackLayerDestroyed::BitmapCallback,
+ &LayerTreeHostTestAsyncReadbackLayerDestroyed::
+ CopyOutputCallback,
base::Unretained(this))));
EXPECT_EQ(0, callback_count_);
@@ -2698,9 +2704,9 @@ class LayerTreeHostTestAsyncReadbackLayerDestroyed : public LayerTreeHostTest {
}
}
- void BitmapCallback(scoped_ptr<SkBitmap> bitmap) {
+ void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
- EXPECT_FALSE(bitmap);
+ EXPECT_TRUE(result->IsEmpty());
++callback_count_;
}