Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1116)

Unified Diff: content/renderer/pepper/pepper_compositor_host.cc

Issue 298023004: [PPAPI] Compositor API implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@compositor_api_def_new
Patch Set: Use a clip parent for clip_rect Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/renderer/pepper/pepper_compositor_host.cc
diff --git a/content/renderer/pepper/pepper_compositor_host.cc b/content/renderer/pepper/pepper_compositor_host.cc
new file mode 100644
index 0000000000000000000000000000000000000000..37e2cc92d8cf46c8fd6a9ebddc06e5a2a6d4f196
--- /dev/null
+++ b/content/renderer/pepper/pepper_compositor_host.cc
@@ -0,0 +1,350 @@
+// Copyright 2014 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 "content/renderer/pepper/pepper_compositor_host.h"
+
+#include "base/logging.h"
+#include "base/memory/shared_memory.h"
+#include "cc/layers/layer.h"
+#include "cc/layers/solid_color_layer.h"
+#include "cc/layers/texture_layer.h"
+#include "cc/resources/texture_mailbox.h"
+#include "content/public/renderer/renderer_ppapi_host.h"
+#include "content/renderer/pepper/gfx_conversion.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
+#include "content/renderer/pepper/ppb_image_data_impl.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/host/dispatch_host_message.h"
+#include "ppapi/host/ppapi_host.h"
+#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/ppb_image_data_api.h"
+#include "third_party/khronos/GLES2/gl2.h"
+#include "ui/gfx/transform.h"
+
+using ppapi::host::HostMessageContext;
+using ppapi::thunk::EnterResourceNoLock;
+using ppapi::thunk::PPB_ImageData_API;
+
+namespace content {
+
+PepperCompositorHost::PepperCompositorHost(
+ RendererPpapiHost* host,
+ PP_Instance instance,
+ PP_Resource resource)
+ : ResourceHost(host->GetPpapiHost(), instance, resource),
+ bound_instance_(NULL),
+ weak_factory_(this) {
+ layer_ = cc::Layer::Create();
+ // TODO(penghuang): SetMasksToBounds() can be expensive if the layer is
+ // transformed. Possibly better could be to explicitly clip the child layers
+ // (by modifying their bounds).
+ layer_->SetMasksToBounds(true);
+ layer_->SetIsDrawable(true);
+}
+
+PepperCompositorHost::~PepperCompositorHost() {
+ // Unbind from the instance when destroyed if we're still bound.
+ if (bound_instance_)
+ bound_instance_->BindGraphics(bound_instance_->pp_instance(), 0);
+}
+
+bool PepperCompositorHost::BindToInstance(
+ PepperPluginInstanceImpl* new_instance) {
+ if (new_instance && new_instance->pp_instance() != pp_instance())
+ return false; // Can't bind other instance's contexts.
+ if (bound_instance_ == new_instance)
+ return true; // Rebinding the same device, nothing to do.
+ if (bound_instance_ && new_instance) {
+ NOTREACHED();
+ return false; // Can't change a bound device.
+ }
+ bound_instance_ = new_instance;
+ return true;
+}
+
+void PepperCompositorHost::ViewInitiatedPaint() {
+ if (!commit_layers_reply_context_.is_valid())
+ return;
+ host()->SendReply(commit_layers_reply_context_,
+ PpapiPluginMsg_Compositor_CommitLayersReply());
+ commit_layers_reply_context_ = ppapi::host::ReplyMessageContext();
+}
+
+void PepperCompositorHost::ViewFlushedPaint() {}
+
+void PepperCompositorHost::ResourceReleased(int32_t id,
+ uint32_t sync_point,
+ bool is_lost) {
+ host()->SendUnsolicitedReply(
+ pp_resource(),
+ PpapiPluginMsg_Compositor_ReleaseResource(id, sync_point, is_lost));
+}
+
+void PepperCompositorHost::ImageReleased(
+ int32_t id,
+ const scoped_ptr<base::SharedMemory>& shared_memory,
+ uint32_t sync_point,
+ bool is_lost) {
+ ResourceReleased(id, sync_point, is_lost);
+}
+
+int32_t PepperCompositorHost::OnResourceMessageReceived(
+ const IPC::Message& msg,
+ HostMessageContext* context) {
+ PPAPI_BEGIN_MESSAGE_MAP(PepperCompositorHost, msg)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(
+ PpapiHostMsg_Compositor_CommitLayers, OnHostMsgCommitLayers)
+ PPAPI_END_MESSAGE_MAP()
+ return ppapi::host::ResourceHost::OnResourceMessageReceived(msg, context);
+}
+
+bool PepperCompositorHost::IsCompositorHost() {
+ return true;
+}
+
+int32_t PepperCompositorHost::VerifyCommittedLayers(
+ const std::vector<ppapi::CompositorLayerData>& layers,
+ bool reset) {
+ for (size_t i = 0; i < layers.size(); ++i) {
+ const LayerData* data = NULL;
+ const ppapi::CompositorLayerData* old_layer = NULL;
+ const ppapi::CompositorLayerData* new_layer = &layers[i];
+ // Make sure the layer type is not changed.
+ if (!reset) {
+ data = i >= layers_.size() ? NULL : &layers_[i];
+ DCHECK(!data || data->cc_layer);
+ old_layer = data ? &data->pp_layer : NULL;
+ if (old_layer && old_layer->type != new_layer->type) {
+ NOTREACHED();
+ return PP_ERROR_BADARGUMENT;
+ }
+ }
+
+ if (new_layer->type == ppapi::CompositorLayerData::TYPE_COLOR)
+ continue;
+
+ // Check texture layer.
+ if (new_layer->type == ppapi::CompositorLayerData::TYPE_TEXTURE) {
+ if (old_layer && new_layer->resource_id == old_layer->resource_id) {
+ if (memcmp(new_layer->texture.mailbox,
+ old_layer->texture.mailbox,
+ sizeof(ppapi::CompositorLayerData::Mailbox)) != 0) {
+ NOTREACHED();
+ return PP_ERROR_BADARGUMENT;
+ }
+ } else {
+ gpu::Mailbox gpu_mailbox;
+ gpu_mailbox.SetName(new_layer->texture.mailbox);
+ if (!gpu_mailbox.Verify()) {
+ NOTREACHED();
+ return PP_ERROR_BADARGUMENT;
+ }
+ }
+ continue;
+ }
+
+ // Check image layer.
+ if (new_layer->type == ppapi::CompositorLayerData::TYPE_IMAGE) {
+ if (old_layer && new_layer->resource_id == old_layer->resource_id) {
+ if (new_layer->image.host_resource != old_layer->image.host_resource) {
+ return PP_ERROR_BADARGUMENT;
+ }
+ } else {
+ EnterResourceNoLock<PPB_ImageData_API> enter(
+ new_layer->image.host_resource, true);
+ if (enter.failed()) {
+ NOTREACHED();
+ return PP_ERROR_BADRESOURCE;
+ }
+
+ // TODO(penghuang): support all kinds of image.
+ PP_ImageDataDesc desc;
+ if (enter.object()->Describe(&desc) != PP_TRUE ||
+ desc.stride != desc.size.width * 4 ||
+ desc.format != PP_IMAGEDATAFORMAT_RGBA_PREMUL) {
+ NOTREACHED();
+ return PP_ERROR_BADARGUMENT;
+ }
+
+ int handle;
+ uint32_t byte_count;
+ if (enter.object()->GetSharedMemory(&handle, &byte_count) != PP_OK)
+ return PP_ERROR_FAILED;
+ }
+ continue;
+ }
+ return PP_ERROR_BADARGUMENT;
+ }
+ return PP_OK;
+}
raymes 2014/06/06 00:47:00 What I meant was to pull out just the body of the
Peng 2014/06/06 19:29:43 Done.
+
+void PepperCompositorHost::UpdateLayer(
+ const scoped_refptr<cc::Layer>& layer,
+ const ppapi::CompositorLayerData* old_layer,
+ const ppapi::CompositorLayerData* new_layer) {
+ DCHECK(!old_layer || new_layer->type == old_layer->type);
+
+ // Always update properties on cc::Layer, because cc::Layer
+ // will ignore any setting with unchanged value.
+ layer->SetIsDrawable(true);
+ layer->SetBlendMode(SkXfermode::kSrcOver_Mode);
+ layer->SetOpacity(new_layer->opacity);
+ layer->SetBounds(PP_ToGfxSize(new_layer->size));
+
+ gfx::Transform transform(gfx::Transform::kSkipInitialization);
+ transform.matrix().setColMajorf(new_layer->transform);
+ layer->SetTransform(transform);
+
+ // Consider a (0,0,0,0) rect as no clip rect.
+ if (new_layer->clip_rect.point.x != 0 ||
+ new_layer->clip_rect.point.y != 0 ||
+ new_layer->clip_rect.size.width != 0 ||
+ new_layer->clip_rect.size.height != 0) {
+ scoped_refptr<cc::Layer> clip_parent = layer->parent();
+ if (clip_parent == layer_) {
+ // Create a clip parent layer, if it does not exist.
+ clip_parent = cc::Layer::Create();
+ clip_parent->SetMasksToBounds(true);
+ clip_parent->SetIsDrawable(true);
+ layer_->ReplaceChild(layer, clip_parent);
+ clip_parent->AddChild(layer);
+ }
+ gfx::Point position = PP_ToGfxPoint(new_layer->clip_rect.point);
+ clip_parent->SetPosition(position);
+ clip_parent->SetBounds(PP_ToGfxSize(new_layer->clip_rect.size));
+ layer->SetPosition(gfx::Point(-position.x(), -position.y()));
+ } else if (layer->parent() != layer_) {
+ // Remove the clip parent layer.
+ layer_->ReplaceChild(layer->parent(), layer);
+ layer->SetPosition(gfx::Point());
+ }
+
+ if (new_layer->type == ppapi::CompositorLayerData::TYPE_COLOR) {
+ layer->SetBackgroundColor(SkColorSetARGBMacro(new_layer->color.alpha * 255,
+ new_layer->color.red * 255,
+ new_layer->color.green * 255,
+ new_layer->color.blue * 255));
+ } else if (new_layer->type == ppapi::CompositorLayerData::TYPE_TEXTURE) {
+ scoped_refptr<cc::TextureLayer> texture_layer(
+ static_cast<cc::TextureLayer*>(layer.get()));
+ if (!old_layer || new_layer->resource_id != old_layer->resource_id) {
+ gpu::Mailbox gpu_mailbox;
+ gpu_mailbox.SetName(new_layer->texture.mailbox);
+ DCHECK(gpu_mailbox.Verify());
+ cc::TextureMailbox mailbox(gpu_mailbox,
+ GL_TEXTURE_2D,
+ new_layer->texture.sync_point);
+ texture_layer->SetTextureMailbox(mailbox,
+ cc::SingleReleaseCallback::Create(
+ base::Bind(&PepperCompositorHost::ResourceReleased,
+ weak_factory_.GetWeakPtr(),
+ new_layer->resource_id)));;
+ }
+ texture_layer->SetPremultipliedAlpha(new_layer->texture.premult_alpha);
+ gfx::RectF rect = PP_ToGfxRectF(new_layer->texture.source_rect);
+ texture_layer->SetUV(rect.origin(), rect.bottom_right());
+ } else if (new_layer->type == ppapi::CompositorLayerData::TYPE_IMAGE) {
+ if (!old_layer || new_layer->resource_id != old_layer->resource_id) {
+ scoped_refptr<cc::TextureLayer> image_layer(
+ static_cast<cc::TextureLayer*>(layer.get()));
+ EnterResourceNoLock<PPB_ImageData_API> enter(
+ new_layer->image.host_resource, true);
+ DCHECK(enter.succeeded());
+ PP_ImageDataDesc desc;
+ {
+ PP_Bool rv = enter.object()->Describe(&desc);
+ DCHECK_EQ(rv, PP_TRUE);
+ }
+ int handle;
+ uint32_t byte_count;
+ {
+ int32_t rv = enter.object()->GetSharedMemory(&handle, &byte_count);
+ DCHECK_EQ(rv, PP_OK);
+ }
+#if defined(OS_WIN)
+ base::SharedMemoryHandle shm_handle =
+ static_cast<base::SharedMemoryHandle>(_dup(handle));
+#else
+ base::SharedMemoryHandle shm_handle(dup(handle), false);
+#endif
+ // Use a scoped_ptr to keep shared_memory alive until
+ // PepperCompositorHost::ImageReleased is called.
+ scoped_ptr<base::SharedMemory> shared_memory(
+ new base::SharedMemory(shm_handle, true));
+ CHECK(shared_memory->Map(desc.stride * desc.size.height));
+ cc::TextureMailbox mailbox(shared_memory.get(),
+ PP_ToGfxSize(desc.size));
+ image_layer->SetTextureMailbox(mailbox,
+ cc::SingleReleaseCallback::Create(
+ base::Bind(&PepperCompositorHost::ImageReleased,
+ weak_factory_.GetWeakPtr(),
+ new_layer->resource_id,
+ base::Passed(&shared_memory))));
+
+ // ImageData is always premultiplied alpha.
+ image_layer->SetPremultipliedAlpha(true);
+ }
+ }
+}
+
+int32_t PepperCompositorHost::OnHostMsgCommitLayers(
+ HostMessageContext* context,
+ const std::vector<ppapi::CompositorLayerData>& layers,
+ bool reset) {
+ // Do not support CommitLayers() on an unbounded compositor.
+ if (!bound_instance_)
+ return PP_ERROR_FAILED;
+
+ if (commit_layers_reply_context_.is_valid()) {
+ NOTREACHED();
+ return PP_ERROR_INPROGRESS;
+ }
+
+ commit_layers_reply_context_ = context->MakeReplyMessageContext();
+
+ // Verfiy the layers first, if an error happens, we will return the error to
+ // plugin and keep current layers set by the previous CommitLayers()
+ // unchanged.
+ int32_t rv = VerifyCommittedLayers(layers, reset);
+ if (rv != PP_OK)
+ return rv;
+
+ // ResetLayers() has been called, we need rebuild layer stack.
+ if (reset) {
+ layer_->RemoveAllChildren();
+ layers_.clear();
+ }
+
+ for (size_t i = 0; i < layers.size(); ++i) {
+ const ppapi::CompositorLayerData& pp_layer = layers[i];
+ LayerData* data = i >= layers_.size() ? NULL : &layers_[i];
+ DCHECK(!data || data->cc_layer);
+ scoped_refptr<cc::Layer> cc_layer = data ? data->cc_layer : NULL;
+ ppapi::CompositorLayerData* old_layer = data ? &data->pp_layer : NULL;
+
+ if (!cc_layer) {
+ if (pp_layer.type == ppapi::CompositorLayerData::TYPE_COLOR) {
+ cc_layer = cc::SolidColorLayer::Create();
+ } else if (pp_layer.type == ppapi::CompositorLayerData::TYPE_TEXTURE ||
+ pp_layer.type == ppapi::CompositorLayerData::TYPE_IMAGE) {
+ cc_layer = cc::TextureLayer::CreateForMailbox(NULL);
+ }
+ layer_->AddChild(cc_layer);
+ }
+
+ UpdateLayer(cc_layer, old_layer, &pp_layer);
+
+ if (old_layer) {
+ *old_layer = pp_layer;
+ } else {
+ layers_.push_back(LayerData(cc_layer, pp_layer));
+ }
+ }
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698