#include "cc/resources/texture_mailbox.h"
#include "cc/surfaces/surface_factory.h"
#include "content/browser/compositor/resize_lock.h"
+#include "content/browser/gpu/compositor_util.h"
#include "content/common/gpu/client/gl_helper.h"
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
#include "content/public/common/content_switches.h"
#include "media/base/video_frame.h"
#include "media/base/video_util.h"
#include "skia/ext/image_operations.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/effects/SkLumaColorFilter.h"
#include "ui/gfx/frame_time.h"
namespace content {
DelegatedFrameHost::DelegatedFrameHost(DelegatedFrameHostClient* client)
: client_(client),
- use_surfaces_(base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUseSurfaces)),
+ use_surfaces_(UseSurfacesEnabled()),
last_output_surface_id_(0),
pending_delegated_ack_count_(0),
skipped_frames_(false),
void DelegatedFrameHost::WasShown(const ui::LatencyInfo& latency_info) {
delegated_frame_evictor_->SetVisible(true);
- if (surface_id_.is_null() && !frame_provider_ &&
+ if (surface_id_.is_null() && !frame_provider_.get() &&
!released_front_lock_.get()) {
ui::Compositor* compositor = client_->GetCompositor();
if (compositor)
void DelegatedFrameHost::RequestCopyOfOutput(
scoped_ptr<cc::CopyOutputRequest> request) {
- client_->GetLayer()->RequestCopyOfOutput(request.Pass());
+ if (use_surfaces_) {
+ if (surface_factory_ && !surface_id_.is_null())
+ surface_factory_->RequestCopyOfSurface(surface_id_, request.Pass());
+ else
+ request->SendEmptyResult();
+ } else {
+ client_->GetLayer()->RequestCopyOfOutput(request.Pass());
+ }
}
void DelegatedFrameHost::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& output_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
+ CopyFromCompositingSurfaceCallback& callback,
const SkColorType color_type) {
// Only ARGB888 and RGB565 supported as of now.
- bool format_support = ((color_type == kRGB_565_SkColorType) ||
+ bool format_support = ((color_type == kAlpha_8_SkColorType) ||
+ (color_type == kRGB_565_SkColorType) ||
(color_type == kN32_SkColorType));
DCHECK(format_support);
if (!CanCopyToBitmap()) {
}
last_output_surface_id_ = output_surface_id;
}
+ bool modified_layers = false;
+ ui::Compositor* compositor = client_->GetCompositor();
if (frame_size.IsEmpty()) {
DCHECK(frame_data->resource_list.empty());
EvictDelegatedFrame();
+ modified_layers = true;
} else {
if (use_surfaces_) {
if (!surface_factory_) {
}
if (surface_id_.is_null() || frame_size != current_surface_size_ ||
frame_size_in_dip != current_frame_size_in_dip_) {
+ // TODO(jbauman): Wait to destroy this surface until the parent has
+ // finished using it.
if (!surface_id_.is_null())
surface_factory_->Destroy(surface_id_);
surface_id_ = id_allocator_->GenerateId();
surface_factory_->Create(surface_id_, frame_size);
client_->GetLayer()->SetShowSurface(surface_id_, frame_size_in_dip);
current_surface_size_ = frame_size;
+ modified_layers = true;
}
scoped_ptr<cc::CompositorFrame> compositor_frame =
make_scoped_ptr(new cc::CompositorFrame());
compositor_frame->delegated_frame_data = frame_data.Pass();
- surface_factory_->SubmitFrame(surface_id_, compositor_frame.Pass());
+
+ compositor_frame->metadata.latency_info.swap(skipped_latency_info_list_);
+ compositor_frame->metadata.latency_info.insert(
+ compositor_frame->metadata.latency_info.end(),
+ latency_info.begin(),
+ latency_info.end());
+
+ base::Closure ack_callback;
+ if (compositor) {
+ ack_callback = base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck,
+ AsWeakPtr(),
+ output_surface_id);
+ }
+ surface_factory_->SubmitFrame(
+ surface_id_, compositor_frame.Pass(), ack_callback);
} else {
- if (!resource_collection_) {
+ if (!resource_collection_.get()) {
resource_collection_ = new cc::DelegatedFrameResourceCollection;
resource_collection_->SetClient(this);
}
} else {
frame_provider_->SetFrameData(frame_data.Pass());
}
+ modified_layers = true;
}
}
released_front_lock_ = NULL;
current_frame_size_in_dip_ = frame_size_in_dip;
CheckResizeLock();
- client_->SchedulePaintInRect(damage_rect_in_dip);
+ if (modified_layers && !damage_rect_in_dip.IsEmpty()) {
+ // TODO(jbauman): Need to always tell the window observer about the
+ // damage.
+ client_->GetLayer()->OnDelegatedFrameDamage(damage_rect_in_dip);
+ }
pending_delegated_ack_count_++;
- ui::Compositor* compositor = client_->GetCompositor();
if (!compositor) {
SendDelegatedFrameAck(output_surface_id);
- } else {
+ } else if (!use_surfaces_) {
std::vector<ui::LatencyInfo>::const_iterator it;
for (it = latency_info.begin(); it != latency_info.end(); ++it)
compositor->SetLatencyInfo(*it);
cc::CompositorFrameAck ack;
if (!surface_returned_resources_.empty())
ack.resources.swap(surface_returned_resources_);
- if (resource_collection_)
+ if (resource_collection_.get())
resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
RenderWidgetHostImpl::SendSwapCompositorFrameAck(host->GetRoutingID(),
output_surface_id,
if (!surface_returned_resources_.empty()) {
ack.resources.swap(surface_returned_resources_);
} else {
- DCHECK(resource_collection_);
+ DCHECK(resource_collection_.get());
resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
}
DCHECK(!ack.resources.empty());
}
if (result->HasTexture()) {
+ // GPU-accelerated path
PrepareTextureCopyOutputResult(dst_size_in_pixel, color_type,
callback,
result.Pass());
}
DCHECK(result->HasBitmap());
+ // Software path
PrepareBitmapCopyOutputResult(dst_size_in_pixel, color_type, callback,
result.Pass());
}
base::ScopedClosureRunner scoped_callback_runner(
base::Bind(callback, false, SkBitmap()));
+ // TODO(sikugu): We should be able to validate the format here using
+ // GLHelper::IsReadbackConfigSupported before we processs the result.
+ // See crbug.com/415682.
scoped_ptr<SkBitmap> bitmap(new SkBitmap);
- if (!bitmap->allocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
- dst_size_in_pixel.height(),
- color_type,
- kOpaque_SkAlphaType)))
+ if (!bitmap->tryAllocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
+ dst_size_in_pixel.height(),
+ color_type,
+ kOpaque_SkAlphaType)))
return;
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
const SkColorType color_type,
const base::Callback<void(bool, const SkBitmap&)>& callback,
scoped_ptr<cc::CopyOutputResult> result) {
- if (color_type != kN32_SkColorType) {
+ if (color_type != kN32_SkColorType && color_type != kAlpha_8_SkColorType) {
NOTIMPLEMENTED();
callback.Run(false, SkBitmap());
return;
DCHECK(result->HasBitmap());
scoped_ptr<SkBitmap> source = result->TakeBitmap();
DCHECK(source);
- SkBitmap bitmap = skia::ImageOperations::Resize(
- *source,
- skia::ImageOperations::RESIZE_BEST,
- dst_size_in_pixel.width(),
- dst_size_in_pixel.height());
- callback.Run(true, bitmap);
+ SkBitmap scaled_bitmap;
+ if (source->width() != dst_size_in_pixel.width() ||
+ source->height() != dst_size_in_pixel.height()) {
+ scaled_bitmap =
+ skia::ImageOperations::Resize(*source,
+ skia::ImageOperations::RESIZE_BEST,
+ dst_size_in_pixel.width(),
+ dst_size_in_pixel.height());
+ } else {
+ scaled_bitmap = *source;
+ }
+ if (color_type == kN32_SkColorType) {
+ DCHECK_EQ(scaled_bitmap.colorType(), kN32_SkColorType);
+ callback.Run(true, scaled_bitmap);
+ return;
+ }
+ DCHECK_EQ(color_type, kAlpha_8_SkColorType);
+ // The software path currently always returns N32 bitmap regardless of the
+ // |color_type| we ask for.
+ DCHECK_EQ(scaled_bitmap.colorType(), kN32_SkColorType);
+ // Paint |scaledBitmap| to alpha-only |grayscale_bitmap|.
+ SkBitmap grayscale_bitmap;
+ bool success = grayscale_bitmap.tryAllocPixels(
+ SkImageInfo::MakeA8(scaled_bitmap.width(), scaled_bitmap.height()));
+ if (!success) {
+ callback.Run(false, SkBitmap());
+ return;
+ }
+ SkCanvas canvas(grayscale_bitmap);
+ SkPaint paint;
+ skia::RefPtr<SkColorFilter> filter =
+ skia::AdoptRef(SkLumaColorFilter::Create());
+ paint.setColorFilter(filter.get());
+ canvas.drawBitmap(scaled_bitmap, SkIntToScalar(0), SkIntToScalar(0), &paint);
+ callback.Run(true, grayscale_bitmap);
}
// static
dfh->idle_frame_subscriber_textures_.push_back(subscriber_texture);
}
+// static
void DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo(
base::WeakPtr<DelegatedFrameHost> dfh,
const base::Callback<void(bool)>& callback,
if (release_callback) {
// A release callback means the texture came from the compositor, so there
// should be no |subscriber_texture|.
- DCHECK(!subscriber_texture);
+ DCHECK(!subscriber_texture.get());
bool lost_resource = sync_point == 0;
release_callback->Run(sync_point, lost_resource);
}
if (resource_collection_.get())
resource_collection_->SetClient(NULL);
- DCHECK(!vsync_manager_);
+ DCHECK(!vsync_manager_.get());
}
void DelegatedFrameHost::RunOnCommitCallbacks() {
void DelegatedFrameHost::AddedToWindow() {
ui::Compositor* compositor = client_->GetCompositor();
if (compositor) {
- DCHECK(!vsync_manager_);
+ DCHECK(!vsync_manager_.get());
vsync_manager_ = compositor->vsync_manager();
vsync_manager_->AddObserver(this);
}
if (compositor && compositor->HasObserver(this))
compositor->RemoveObserver(this);
- if (vsync_manager_) {
+ if (vsync_manager_.get()) {
vsync_manager_->RemoveObserver(this);
vsync_manager_ = NULL;
}
}
void DelegatedFrameHost::LockResources() {
- DCHECK(frame_provider_ || !surface_id_.is_null());
+ DCHECK(frame_provider_.get() || !surface_id_.is_null());
delegated_frame_evictor_->LockFrame();
}
void DelegatedFrameHost::UnlockResources() {
- DCHECK(frame_provider_ || !surface_id_.is_null());
+ DCHECK(frame_provider_.get() || !surface_id_.is_null());
delegated_frame_evictor_->UnlockFrame();
}