diff options
-rw-r--r-- | cc/cc.gyp | 2 | ||||
-rw-r--r-- | cc/cc_tests.gyp | 4 | ||||
-rw-r--r-- | cc/layers/layer.cc | 20 | ||||
-rw-r--r-- | cc/output/copy_output_request.cc | 31 | ||||
-rw-r--r-- | cc/output/copy_output_request.h | 41 | ||||
-rw-r--r-- | cc/output/copy_output_result.cc | 39 | ||||
-rw-r--r-- | cc/output/copy_output_result.h | 55 | ||||
-rw-r--r-- | cc/output/gl_renderer.cc | 177 | ||||
-rw-r--r-- | cc/output/gl_renderer.h | 20 | ||||
-rw-r--r-- | cc/quads/render_pass_unittest.cc | 3 | ||||
-rw-r--r-- | cc/test/layer_tree_pixel_test.cc | 152 | ||||
-rw-r--r-- | cc/test/layer_tree_pixel_test.h | 17 | ||||
-rw-r--r-- | cc/test/pixel_test.cc | 80 | ||||
-rw-r--r-- | cc/test/pixel_test.h | 5 | ||||
-rw-r--r-- | cc/test/pixel_test_output_surface.cc | 21 | ||||
-rw-r--r-- | cc/test/pixel_test_output_surface.h | 37 | ||||
-rw-r--r-- | cc/test/pixel_test_software_output_device.cc | 15 | ||||
-rw-r--r-- | cc/test/pixel_test_software_output_device.h | 26 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_pixeltest_filters.cc | 2 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_pixeltest_readback.cc | 275 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_unittest.cc | 28 |
21 files changed, 858 insertions, 192 deletions
@@ -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_; } |