summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpenghuang@chromium.org <penghuang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-16 14:20:26 +0000
committerpenghuang@chromium.org <penghuang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-16 14:20:26 +0000
commitc44620b2cb57378a518ee97427e7c3d319507c8d (patch)
treeccc8f088aab4dc3758fc71de6b9eca133e3637c9
parentd765198b19590e158a609cc34c29af39b6cd9e9d (diff)
downloadchromium_src-c44620b2cb57378a518ee97427e7c3d319507c8d.zip
chromium_src-c44620b2cb57378a518ee97427e7c3d319507c8d.tar.gz
chromium_src-c44620b2cb57378a518ee97427e7c3d319507c8d.tar.bz2
[PPAPI] Compositor API implementation.
Implement the compositor API which allows a plugin to combine different sources of visual data efficiently, such as PPB_ImageData and OpengGL texture. API Proposal http://goo.gl/V7xcu3 BUG=374383 Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=277208 Review URL: https://codereview.chromium.org/298023004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@277422 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/content_renderer.gypi2
-rw-r--r--content/renderer/pepper/content_renderer_pepper_host_factory.cc5
-rw-r--r--content/renderer/pepper/gfx_conversion.h5
-rw-r--r--content/renderer/pepper/pepper_compositor_host.cc372
-rw-r--r--content/renderer/pepper/pepper_compositor_host.h101
-rw-r--r--content/renderer/pepper/pepper_plugin_instance_impl.cc71
-rw-r--r--content/renderer/pepper/pepper_plugin_instance_impl.h6
-rw-r--r--ppapi/examples/compositor/compositor.cc439
-rw-r--r--ppapi/examples/compositor/compositor.html28
-rw-r--r--ppapi/examples/compositor/spinning_cube.cc459
-rw-r--r--ppapi/examples/compositor/spinning_cube.h42
-rw-r--r--ppapi/host/resource_host.cc4
-rw-r--r--ppapi/host/resource_host.h1
-rw-r--r--ppapi/ppapi_internal.gyp1
-rw-r--r--ppapi/ppapi_shared.gypi2
-rw-r--r--ppapi/ppapi_tests.gypi16
-rw-r--r--ppapi/proxy/compositor_layer_resource.cc331
-rw-r--r--ppapi/proxy/compositor_layer_resource.h48
-rw-r--r--ppapi/proxy/compositor_resource.cc107
-rw-r--r--ppapi/proxy/compositor_resource.h45
-rw-r--r--ppapi/proxy/ppapi_messages.h59
-rw-r--r--ppapi/proxy/ppapi_param_traits.cc27
-rw-r--r--ppapi/proxy/ppapi_param_traits.h9
-rw-r--r--ppapi/proxy/ppb_instance_proxy.cc5
-rw-r--r--ppapi/shared_impl/compositor_layer_data.cc36
-rw-r--r--ppapi/shared_impl/compositor_layer_data.h119
26 files changed, 2300 insertions, 40 deletions
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index c7a3bfa..54fb0ed 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -475,6 +475,8 @@
'renderer/pepper/pepper_broker.h',
'renderer/pepper/pepper_browser_connection.cc',
'renderer/pepper/pepper_browser_connection.h',
+ 'renderer/pepper/pepper_compositor_host.cc',
+ 'renderer/pepper/pepper_compositor_host.h',
'renderer/pepper/pepper_device_enumeration_host_helper.cc',
'renderer/pepper/pepper_device_enumeration_host_helper.h',
'renderer/pepper/pepper_file_chooser_host.cc',
diff --git a/content/renderer/pepper/content_renderer_pepper_host_factory.cc b/content/renderer/pepper/content_renderer_pepper_host_factory.cc
index 26604f1..07afe47 100644
--- a/content/renderer/pepper/content_renderer_pepper_host_factory.cc
+++ b/content/renderer/pepper/content_renderer_pepper_host_factory.cc
@@ -9,6 +9,7 @@
#include "content/public/common/content_client.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/renderer/pepper/pepper_audio_input_host.h"
+#include "content/renderer/pepper/pepper_compositor_host.h"
#include "content/renderer/pepper/pepper_file_chooser_host.h"
#include "content/renderer/pepper/pepper_file_ref_renderer_host.h"
#include "content/renderer/pepper/pepper_file_system_host.h"
@@ -82,6 +83,10 @@ scoped_ptr<ResourceHost> ContentRendererPepperHostFactory::CreateResourceHost(
// Public interfaces.
switch (message.type()) {
+ case PpapiHostMsg_Compositor_Create::ID: {
+ return scoped_ptr<ResourceHost>(
+ new PepperCompositorHost(host_, instance, params.pp_resource()));
+ }
case PpapiHostMsg_FileRef_CreateForFileAPI::ID: {
PP_Resource file_system;
std::string internal_path;
diff --git a/content/renderer/pepper/gfx_conversion.h b/content/renderer/pepper/gfx_conversion.h
index 3b504ba..1c1fa11 100644
--- a/content/renderer/pepper/gfx_conversion.h
+++ b/content/renderer/pepper/gfx_conversion.h
@@ -10,6 +10,7 @@
#include "ppapi/c/pp_size.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
+#include "ui/gfx/rect_f.h"
#include "ui/gfx/size.h"
// Conversions for graphics types between our gfx library and PPAPI.
@@ -29,6 +30,10 @@ inline gfx::Rect PP_ToGfxRect(const PP_Rect& r) {
return gfx::Rect(r.point.x, r.point.y, r.size.width, r.size.height);
}
+inline gfx::RectF PP_ToGfxRectF(const PP_FloatRect& r) {
+ return gfx::RectF(r.point.x, r.point.y, r.size.width, r.size.height);
+}
+
inline PP_Rect PP_FromGfxRect(const gfx::Rect& r) {
return PP_MakeRectFromXYWH(r.x(), r.y(), r.width(), r.height());
}
diff --git a/content/renderer/pepper/pepper_compositor_host.cc b/content/renderer/pepper/pepper_compositor_host.cc
new file mode 100644
index 0000000..47c0fcc
--- /dev/null
+++ b/content/renderer/pepper/pepper_compositor_host.cc
@@ -0,0 +1,372 @@
+// 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 {
+
+namespace {
+
+int32_t VerifyCommittedLayer(
+ const ppapi::CompositorLayerData* old_layer,
+ const ppapi::CompositorLayerData* new_layer,
+ scoped_ptr<base::SharedMemory>* image_shm) {
+ if (!new_layer->is_valid())
+ return PP_ERROR_BADARGUMENT;
+
+ if (new_layer->color) {
+ // Make sure the old layer is a color layer too.
+ if (old_layer && !old_layer->color)
+ return PP_ERROR_BADARGUMENT;
+ return PP_OK;
+ }
+
+ if (new_layer->texture) {
+ if (old_layer) {
+ // Make sure the old layer is a texture layer too.
+ if (!new_layer->texture)
+ return PP_ERROR_BADARGUMENT;
+ // The mailbox should be same, if the resource_id is not changed.
+ if (new_layer->common.resource_id == old_layer->common.resource_id) {
+ if (new_layer->texture->mailbox != old_layer->texture->mailbox)
+ return PP_ERROR_BADARGUMENT;
+ return PP_OK;
+ }
+ }
+ if (!new_layer->texture->mailbox.Verify())
+ return PP_ERROR_BADARGUMENT;
+ return PP_OK;
+ }
+
+ if (new_layer->image) {
+ if (old_layer) {
+ // Make sure the old layer is an image layer too.
+ if (!new_layer->image)
+ return PP_ERROR_BADARGUMENT;
+ // The image data resource should be same, if the resource_id is not
+ // changed.
+ if (new_layer->common.resource_id == old_layer->common.resource_id) {
+ if (new_layer->image->resource != old_layer->image->resource)
+ return PP_ERROR_BADARGUMENT;
+ return PP_OK;
+ }
+ }
+ EnterResourceNoLock<PPB_ImageData_API> enter(new_layer->image->resource,
+ true);
+ if (enter.failed())
+ 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) {
+ return PP_ERROR_BADARGUMENT;
+ }
+
+ int handle;
+ uint32_t byte_count;
+ if (enter.object()->GetSharedMemory(&handle, &byte_count) != PP_OK)
+ return PP_ERROR_FAILED;
+
+#if defined(OS_WIN)
+ base::SharedMemoryHandle shm_handle;
+ if (!::DuplicateHandle(::GetCurrentProcess(),
+ reinterpret_cast<base::SharedMemoryHandle>(handle),
+ ::GetCurrentProcess(),
+ &shm_handle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS)) {
+ return PP_ERROR_FAILED;
+ }
+#else
+ base::SharedMemoryHandle shm_handle(dup(handle), false);
+#endif
+ image_shm->reset(new base::SharedMemory(shm_handle, true));
+ if (!(*image_shm)->Map(desc.stride * desc.size.height)) {
+ image_shm->reset();
+ return PP_ERROR_NOMEMORY;
+ }
+ return PP_OK;
+ }
+
+ return PP_ERROR_BADARGUMENT;
+}
+
+} // namespace
+
+PepperCompositorHost::LayerData::LayerData(
+ const scoped_refptr<cc::Layer>& cc,
+ const ppapi::CompositorLayerData& pp) : cc_layer(cc), pp_layer(pp) {}
+
+PepperCompositorHost::LayerData::~LayerData() {}
+
+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)
+ 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::UpdateLayer(
+ const scoped_refptr<cc::Layer>& layer,
+ const ppapi::CompositorLayerData* old_layer,
+ const ppapi::CompositorLayerData* new_layer,
+ scoped_ptr<base::SharedMemory> image_shm) {
+ // 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->common.opacity);
+ layer->SetBounds(PP_ToGfxSize(new_layer->common.size));
+ layer->SetTransformOrigin(gfx::Point3F(new_layer->common.size.width / 2,
+ new_layer->common.size.height / 2,
+ 0.0f));
+
+ gfx::Transform transform(gfx::Transform::kSkipInitialization);
+ transform.matrix().setColMajorf(new_layer->common.transform.matrix);
+ layer->SetTransform(transform);
+
+ // Consider a (0,0,0,0) rect as no clip rect.
+ if (new_layer->common.clip_rect.point.x != 0 ||
+ new_layer->common.clip_rect.point.y != 0 ||
+ new_layer->common.clip_rect.size.width != 0 ||
+ new_layer->common.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->common.clip_rect.point);
+ clip_parent->SetPosition(position);
+ clip_parent->SetBounds(PP_ToGfxSize(new_layer->common.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->color) {
+ layer->SetBackgroundColor(SkColorSetARGBMacro(
+ new_layer->color->alpha * 255,
+ new_layer->color->red * 255,
+ new_layer->color->green * 255,
+ new_layer->color->blue * 255));
+ return;
+ }
+
+ if (new_layer->texture) {
+ scoped_refptr<cc::TextureLayer> texture_layer(
+ static_cast<cc::TextureLayer*>(layer.get()));
+ if (!old_layer ||
+ new_layer->common.resource_id != old_layer->common.resource_id) {
+ cc::TextureMailbox mailbox(new_layer->texture->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->common.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());
+ return;
+ }
+
+ if (new_layer->image) {
+ if (!old_layer ||
+ new_layer->common.resource_id != old_layer->common.resource_id) {
+ scoped_refptr<cc::TextureLayer> image_layer(
+ static_cast<cc::TextureLayer*>(layer.get()));
+ EnterResourceNoLock<PPB_ImageData_API> enter(new_layer->image->resource,
+ true);
+ DCHECK(enter.succeeded());
+
+ // TODO(penghuang): support all kinds of image.
+ PP_ImageDataDesc desc;
+ PP_Bool rv = enter.object()->Describe(&desc);
+ DCHECK_EQ(rv, PP_TRUE);
+ DCHECK_EQ(desc.stride, desc.size.width * 4);
+ DCHECK_EQ(desc.format, PP_IMAGEDATAFORMAT_RGBA_PREMUL);
+
+ cc::TextureMailbox mailbox(image_shm.get(),
+ PP_ToGfxSize(desc.size));
+ image_layer->SetTextureMailbox(mailbox,
+ cc::SingleReleaseCallback::Create(
+ base::Bind(&PepperCompositorHost::ImageReleased,
+ weak_factory_.GetWeakPtr(),
+ new_layer->common.resource_id,
+ base::Passed(&image_shm))));
+
+ // ImageData is always premultiplied alpha.
+ image_layer->SetPremultipliedAlpha(true);
+ }
+ return;
+ }
+ // Should not be reached.
+ NOTREACHED();
+}
+
+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::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())
+ return PP_ERROR_INPROGRESS;
+
+ commit_layers_reply_context_ = context->MakeReplyMessageContext();
+
+ scoped_ptr<scoped_ptr<base::SharedMemory>[]> image_shms;
+ if (layers.size() > 0) {
+ image_shms.reset(new scoped_ptr<base::SharedMemory>[layers.size()]);
+ if (!image_shms)
+ return PP_ERROR_NOMEMORY;
+ // 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.
+ for (size_t i = 0; i < layers.size(); ++i) {
+ const ppapi::CompositorLayerData* old_layer = NULL;
+ if (!reset && i < layers_.size())
+ old_layer = &layers_[i].pp_layer;
+ int32_t rv = VerifyCommittedLayer(old_layer, &layers[i], &image_shms[i]);
+ 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->color)
+ cc_layer = cc::SolidColorLayer::Create();
+ else if (pp_layer->texture || pp_layer->image)
+ cc_layer = cc::TextureLayer::CreateForMailbox(NULL);
+ layer_->AddChild(cc_layer);
+ }
+
+ UpdateLayer(cc_layer, old_layer, pp_layer, image_shms[i].Pass());
+
+ if (old_layer)
+ *old_layer = *pp_layer;
+ else
+ layers_.push_back(LayerData(cc_layer, *pp_layer));
+ }
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+} // namespace content
diff --git a/content/renderer/pepper/pepper_compositor_host.h b/content/renderer/pepper/pepper_compositor_host.h
new file mode 100644
index 0000000..6d5a3ef
--- /dev/null
+++ b/content/renderer/pepper/pepper_compositor_host.h
@@ -0,0 +1,101 @@
+// 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.
+
+#ifndef CONTENT_RENDERER_PEPPER_PEPPER_COMPOSITOR_H_
+#define CONTENT_RENDERER_PEPPER_PEPPER_COMPOSITOR_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "ppapi/host/host_message_context.h"
+#include "ppapi/host/resource_host.h"
+#include "ppapi/shared_impl/compositor_layer_data.h"
+
+namespace base {
+class SharedMemory;
+} // namespace
+
+namespace cc {
+class Layer;
+} // namespace cc
+
+namespace content {
+
+class PepperPluginInstanceImpl;
+class RendererPpapiHost;
+
+class PepperCompositorHost : public ppapi::host::ResourceHost {
+ public:
+ PepperCompositorHost(RendererPpapiHost* host,
+ PP_Instance instance,
+ PP_Resource resource);
+ // Associates this device with the given plugin instance. You can pass NULL
+ // to clear the existing device. Returns true on success. In this case, a
+ // repaint of the page will also be scheduled. Failure means that the device
+ // is already bound to a different instance, and nothing will happen.
+ bool BindToInstance(PepperPluginInstanceImpl* new_instance);
+
+ const scoped_refptr<cc::Layer> layer() { return layer_; };
+
+ void ViewInitiatedPaint();
+ void ViewFlushedPaint();
+
+ private:
+ virtual ~PepperCompositorHost();
+
+ void UpdateLayer(const scoped_refptr<cc::Layer>& layer,
+ const ppapi::CompositorLayerData* old_layer,
+ const ppapi::CompositorLayerData* new_layer,
+ scoped_ptr<base::SharedMemory> image_shm);
+ void ResourceReleased(int32_t id,
+ uint32_t sync_point,
+ bool is_lost);
+ void ImageReleased(int32_t id,
+ const scoped_ptr<base::SharedMemory>& shared_memory,
+ uint32_t sync_point,
+ bool is_lost);
+
+ // ResourceMessageHandler overrides:
+ virtual int32_t OnResourceMessageReceived(
+ const IPC::Message& msg,
+ ppapi::host::HostMessageContext* context) OVERRIDE;
+
+ // ppapi::host::ResourceHost overrides:
+ virtual bool IsCompositorHost() OVERRIDE;
+
+ // Message handlers:
+ int32_t OnHostMsgCommitLayers(
+ ppapi::host::HostMessageContext* context,
+ const std::vector<ppapi::CompositorLayerData>& layers,
+ bool reset);
+
+ // Non-owning pointer to the plugin instance this context is currently bound
+ // to, if any. If the context is currently unbound, this will be NULL.
+ PepperPluginInstanceImpl* bound_instance_;
+
+ // The toplevel cc::Layer. It is the parent of other cc::Layers.
+ scoped_refptr<cc::Layer> layer_;
+
+ // A list of layers. It is used for updating layers' properties in
+ // subsequent CommitLayers() calls.
+ struct LayerData {
+ LayerData(const scoped_refptr<cc::Layer>& cc,
+ const ppapi::CompositorLayerData& pp);
+ ~LayerData();
+
+ scoped_refptr<cc::Layer> cc_layer;
+ ppapi::CompositorLayerData pp_layer;
+ };
+ std::vector<LayerData> layers_;
+
+ ppapi::host::ReplyMessageContext commit_layers_reply_context_;
+
+ base::WeakPtrFactory<PepperCompositorHost> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperCompositorHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_PEPPER_PEPPER_COMPOSITOR_H_
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc
index e6b5df1..735a7b9 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -35,6 +35,7 @@
#include "content/renderer/pepper/message_channel.h"
#include "content/renderer/pepper/npapi_glue.h"
#include "content/renderer/pepper/pepper_browser_connection.h"
+#include "content/renderer/pepper/pepper_compositor_host.h"
#include "content/renderer/pepper/pepper_file_ref_renderer_host.h"
#include "content/renderer/pepper/pepper_graphics_2d_host.h"
#include "content/renderer/pepper/pepper_in_process_router.h"
@@ -524,6 +525,7 @@ PepperPluginInstanceImpl::PepperPluginInstanceImpl(
full_frame_(false),
sent_initial_did_change_view_(false),
bound_graphics_2d_platform_(NULL),
+ bound_compositor_(NULL),
has_webkit_focus_(false),
has_content_area_focus_(false),
find_identifier_(-1),
@@ -731,11 +733,14 @@ void PepperPluginInstanceImpl::InvalidateRect(const gfx::Rect& rect) {
else
container_->invalidateRect(rect);
}
- if (texture_layer_) {
+
+ cc::Layer* layer =
+ texture_layer_ ? texture_layer_.get() : compositor_layer_.get();
+ if (layer) {
if (rect.IsEmpty()) {
- texture_layer_->SetNeedsDisplay();
+ layer->SetNeedsDisplay();
} else {
- texture_layer_->SetNeedsDisplayRect(rect);
+ layer->SetNeedsDisplayRect(rect);
}
}
}
@@ -743,7 +748,9 @@ void PepperPluginInstanceImpl::InvalidateRect(const gfx::Rect& rect) {
void PepperPluginInstanceImpl::ScrollRect(int dx,
int dy,
const gfx::Rect& rect) {
- if (texture_layer_) {
+ cc::Layer* layer =
+ texture_layer_ ? texture_layer_.get() : compositor_layer_.get();
+ if (layer) {
InvalidateRect(rect);
} else if (fullscreen_container_) {
fullscreen_container_->ScrollRect(dx, dy, rect);
@@ -1277,6 +1284,8 @@ void PepperPluginInstanceImpl::ViewInitiatedPaint() {
bound_graphics_2d_platform_->ViewInitiatedPaint();
else if (bound_graphics_3d_.get())
bound_graphics_3d_->ViewInitiatedPaint();
+ else if (bound_compositor_)
+ bound_compositor_->ViewInitiatedPaint();
}
void PepperPluginInstanceImpl::ViewFlushedPaint() {
@@ -1286,6 +1295,8 @@ void PepperPluginInstanceImpl::ViewFlushedPaint() {
bound_graphics_2d_platform_->ViewFlushedPaint();
else if (bound_graphics_3d_.get())
bound_graphics_3d_->ViewFlushedPaint();
+ else if (bound_compositor_)
+ bound_compositor_->ViewFlushedPaint();
}
void PepperPluginInstanceImpl::SetSelectedText(
@@ -1986,24 +1997,28 @@ void PepperPluginInstanceImpl::UpdateLayer() {
}
bool want_3d_layer = !mailbox.IsZero();
bool want_2d_layer = !!bound_graphics_2d_platform_;
- bool want_layer = want_3d_layer || want_2d_layer;
+ bool want_texture_layer = want_3d_layer || want_2d_layer;
+ bool want_compositor_layer = !!bound_compositor_;
- if ((want_layer == !!texture_layer_.get()) &&
+ if ((want_texture_layer == !!texture_layer_.get()) &&
(want_3d_layer == layer_is_hardware_) &&
+ (want_compositor_layer == !!compositor_layer_) &&
layer_bound_to_fullscreen_ == !!fullscreen_container_) {
UpdateLayerTransform();
return;
}
- if (texture_layer_) {
+ if (texture_layer_ || compositor_layer_) {
if (!layer_bound_to_fullscreen_)
container_->setWebLayer(NULL);
else if (fullscreen_container_)
fullscreen_container_->SetLayer(NULL);
web_layer_.reset();
texture_layer_ = NULL;
+ compositor_layer_ = NULL;
}
- if (want_layer) {
+
+ if (want_texture_layer) {
bool opaque = false;
if (want_3d_layer) {
DCHECK(bound_graphics_3d_.get());
@@ -2018,18 +2033,26 @@ void PepperPluginInstanceImpl::UpdateLayer() {
opaque = bound_graphics_2d_platform_->IsAlwaysOpaque();
texture_layer_->SetFlipped(false);
}
+
+ // Ignore transparency in fullscreen, since that's what Flash always
+ // wants to do, and that lets it not recreate a context if
+ // wmode=transparent was specified.
+ opaque = opaque || fullscreen_container_;
+ texture_layer_->SetContentsOpaque(opaque);
web_layer_.reset(new webkit::WebLayerImpl(texture_layer_));
+ } else if (want_compositor_layer) {
+ compositor_layer_ = bound_compositor_->layer();
+ web_layer_.reset(new webkit::WebLayerImpl(compositor_layer_));
+ }
+
+ if (web_layer_) {
if (fullscreen_container_) {
fullscreen_container_->SetLayer(web_layer_.get());
- // Ignore transparency in fullscreen, since that's what Flash always
- // wants to do, and that lets it not recreate a context if
- // wmode=transparent was specified.
- texture_layer_->SetContentsOpaque(true);
} else {
container_->setWebLayer(web_layer_.get());
- texture_layer_->SetContentsOpaque(opaque);
}
}
+
layer_bound_to_fullscreen_ = !!fullscreen_container_;
layer_is_hardware_ = want_3d_layer;
UpdateLayerTransform();
@@ -2211,6 +2234,10 @@ PP_Bool PepperPluginInstanceImpl::BindGraphics(PP_Instance instance,
bound_graphics_2d_platform_->BindToInstance(NULL);
bound_graphics_2d_platform_ = NULL;
}
+ if (bound_compositor_) {
+ bound_compositor_->BindToInstance(NULL);
+ bound_compositor_ = NULL;
+ }
// Special-case clearing the current device.
if (!device) {
@@ -2229,10 +2256,16 @@ PP_Bool PepperPluginInstanceImpl::BindGraphics(PP_Instance instance,
RendererPpapiHost::GetForPPInstance(instance)->GetPpapiHost();
ppapi::host::ResourceHost* host = ppapi_host->GetResourceHost(device);
PepperGraphics2DHost* graphics_2d = NULL;
+ PepperCompositorHost* compositor = NULL;
if (host) {
- if (host->IsGraphics2DHost())
+ if (host->IsGraphics2DHost()) {
graphics_2d = static_cast<PepperGraphics2DHost*>(host);
- DLOG_IF(ERROR, !graphics_2d) << "Resource is not PepperGraphics2DHost.";
+ } else if (host->IsCompositorHost()) {
+ compositor = static_cast<PepperCompositorHost*>(host);
+ } else {
+ DLOG(ERROR) <<
+ "Resource is not PepperCompositorHost or PepperGraphics2DHost.";
+ }
}
EnterResourceNoLock<PPB_Graphics3D_API> enter_3d(device, false);
@@ -2241,7 +2274,13 @@ PP_Bool PepperPluginInstanceImpl::BindGraphics(PP_Instance instance,
? static_cast<PPB_Graphics3D_Impl*>(enter_3d.object())
: NULL;
- if (graphics_2d) {
+ if (compositor) {
+ if (compositor->BindToInstance(this)) {
+ bound_compositor_ = compositor;
+ UpdateLayer();
+ return PP_TRUE;
+ }
+ } else if (graphics_2d) {
if (graphics_2d->BindToInstance(this)) {
bound_graphics_2d_platform_ = graphics_2d;
UpdateLayer();
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.h b/content/renderer/pepper/pepper_plugin_instance_impl.h
index 1acce13..5fb61d8 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.h
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.h
@@ -17,6 +17,7 @@
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "cc/layers/content_layer_client.h"
+#include "cc/layers/layer.h"
#include "cc/layers/texture_layer_client.h"
#include "content/common/content_export.h"
#include "content/public/renderer/pepper_plugin_instance.h"
@@ -102,6 +103,7 @@ namespace content {
class ContentDecryptorDelegate;
class FullscreenContainer;
class MessageChannel;
+class PepperCompositorHost;
class PepperGraphics2DHost;
class PluginModule;
class PluginObject;
@@ -687,6 +689,7 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
// NULL until we have been initialized.
blink::WebPluginContainer* container_;
+ scoped_refptr<cc::Layer> compositor_layer_;
scoped_refptr<cc::TextureLayer> texture_layer_;
scoped_ptr<blink::WebLayer> web_layer_;
bool layer_bound_to_fullscreen_;
@@ -710,9 +713,10 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
// same as the default values.
bool sent_initial_did_change_view_;
- // The current device context for painting in 2D and 3D.
+ // The current device context for painting in 2D, 3D or compositor.
scoped_refptr<PPB_Graphics3D_Impl> bound_graphics_3d_;
PepperGraphics2DHost* bound_graphics_2d_platform_;
+ PepperCompositorHost* bound_compositor_;
// We track two types of focus, one from WebKit, which is the focus among
// all elements of the page, one one from the browser, which is whether the
diff --git a/ppapi/examples/compositor/compositor.cc b/ppapi/examples/compositor/compositor.cc
new file mode 100644
index 0000000..d437bc84
--- /dev/null
+++ b/ppapi/examples/compositor/compositor.cc
@@ -0,0 +1,439 @@
+// 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.
+
+// Needed on Windows to get |M_PI| from math.h.
+#ifdef _WIN32
+#define _USE_MATH_DEFINES
+#endif
+
+#include <math.h>
+
+#include <vector>
+
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/pp_input_event.h"
+#include "ppapi/cpp/compositor.h"
+#include "ppapi/cpp/compositor_layer.h"
+#include "ppapi/cpp/graphics_3d.h"
+#include "ppapi/cpp/graphics_3d_client.h"
+#include "ppapi/cpp/image_data.h"
+#include "ppapi/cpp/input_event.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/rect.h"
+#include "ppapi/cpp/var_dictionary.h"
+#include "ppapi/examples/compositor/spinning_cube.h"
+#include "ppapi/lib/gl/gles2/gl2ext_ppapi.h"
+#include "ppapi/lib/gl/include/GLES2/gl2.h"
+#include "ppapi/lib/gl/include/GLES2/gl2ext.h"
+#include "ppapi/utility/completion_callback_factory.h"
+
+// Use assert as a poor-man's CHECK, even in non-debug mode.
+// Since <assert.h> redefines assert on every inclusion (it doesn't use
+// include-guards), make sure this is the last file #include'd in this file.
+#undef NDEBUG
+#include <assert.h>
+
+// When compiling natively on Windows, PostMessage can be #define-d to
+// something else.
+#ifdef PostMessage
+#undef PostMessage
+#endif
+
+// Assert |context_| isn't holding any GL Errors. Done as a macro instead of a
+// function to preserve line number information in the failure message.
+#define AssertNoGLError() \
+ PP_DCHECK(!glGetError());
+
+namespace {
+
+const int32_t kTextureWidth = 800;
+const int32_t kTextureHeight = 800;
+const int32_t kImageWidth = 256;
+const int32_t kImageHeight = 256;
+
+class DemoInstance : public pp::Instance, public pp::Graphics3DClient {
+ public:
+ DemoInstance(PP_Instance instance);
+ virtual ~DemoInstance();
+
+ // pp::Instance implementation (see PPP_Instance).
+ virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
+ virtual void DidChangeView(const pp::Rect& position,
+ const pp::Rect& clip);
+ virtual bool HandleInputEvent(const pp::InputEvent& event);
+
+ // pp::Graphics3DClient implementation.
+ virtual void Graphics3DContextLost();
+
+ private:
+ // GL-related functions.
+ void InitGL(int32_t result);
+ GLuint PrepareFramebuffer();
+ pp::ImageData PrepareImage();
+ void Paint(int32_t result, int32_t frame);
+ void OnTextureReleased(int32_t result, GLuint texture);
+ void OnImageReleased(int32_t result, const pp::ImageData& image);
+
+ pp::CompletionCallbackFactory<DemoInstance> callback_factory_;
+
+ // Owned data.
+ pp::Graphics3D* context_;
+
+ GLuint fbo_;
+ GLuint rbo_;
+
+ std::vector<GLuint> textures_;
+ std::vector<pp::ImageData> images_;
+
+ pp::Compositor compositor_;
+ pp::CompositorLayer color_layer_;
+ pp::CompositorLayer stable_texture_layer_;
+ pp::CompositorLayer texture_layer_;
+ pp::CompositorLayer image_layer_;
+
+ bool rebuild_layers_;
+ int32_t total_resource_;
+
+ SpinningCube* cube_;
+};
+
+DemoInstance::DemoInstance(PP_Instance instance)
+ : pp::Instance(instance),
+ pp::Graphics3DClient(this),
+ callback_factory_(this),
+ context_(NULL),
+ fbo_(0),
+ rbo_(0),
+ compositor_(this),
+ rebuild_layers_(false),
+ total_resource_(0),
+ cube_(new SpinningCube()) {
+ RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
+}
+
+DemoInstance::~DemoInstance() {
+ delete cube_;
+ assert(glTerminatePPAPI());
+ delete context_;
+}
+
+bool DemoInstance::Init(uint32_t /*argc*/,
+ const char* /*argn*/[],
+ const char* /*argv*/[]) {
+ return !!glInitializePPAPI(pp::Module::Get()->get_browser_interface());
+}
+
+void DemoInstance::DidChangeView(
+ const pp::Rect& position, const pp::Rect& /*clip*/) {
+ if (position.width() == 0 || position.height() == 0)
+ return;
+ // Initialize graphics.
+ InitGL(0);
+}
+
+bool DemoInstance::HandleInputEvent(const pp::InputEvent& event) {
+ switch (event.GetType()) {
+ case PP_INPUTEVENT_TYPE_MOUSEDOWN:
+ rebuild_layers_ = true;
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+void DemoInstance::Graphics3DContextLost() {
+ fbo_ = 0;
+ rbo_ = 0;
+ compositor_.ResetLayers();
+ color_layer_ = pp::CompositorLayer();
+ stable_texture_layer_ = pp::CompositorLayer();
+ texture_layer_ = pp::CompositorLayer();
+ image_layer_ = pp::CompositorLayer();
+ total_resource_ -= static_cast<int32_t>(textures_.size());
+ textures_.clear();
+ delete context_;
+ context_ = NULL;
+ cube_->OnGLContextLost();
+ pp::CompletionCallback cb = callback_factory_.NewCallback(
+ &DemoInstance::InitGL);
+ pp::Module::Get()->core()->CallOnMainThread(0, cb, 0);
+}
+
+void DemoInstance::InitGL(int32_t /*result*/) {
+ if (context_)
+ return;
+ int32_t context_attributes[] = {
+ PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
+ PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8,
+ PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8,
+ PP_GRAPHICS3DATTRIB_RED_SIZE, 8,
+ PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0,
+ PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0,
+ PP_GRAPHICS3DATTRIB_SAMPLES, 0,
+ PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0,
+ PP_GRAPHICS3DATTRIB_WIDTH, 32,
+ PP_GRAPHICS3DATTRIB_HEIGHT, 32,
+ PP_GRAPHICS3DATTRIB_NONE,
+ };
+ context_ = new pp::Graphics3D(this, context_attributes);
+ assert(!context_->is_null());
+ assert(BindGraphics(compositor_));
+
+ glSetCurrentContextPPAPI(context_->pp_resource());
+
+ cube_->Init(kTextureWidth, kTextureHeight);
+
+ Paint(PP_OK, 0);
+}
+
+GLuint DemoInstance::PrepareFramebuffer() {
+ GLuint texture = 0;
+ if (textures_.empty()) {
+ total_resource_++;
+ // Create a texture object
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureWidth, kTextureHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ } else {
+ texture = textures_.back();
+ textures_.pop_back();
+ }
+
+ if (!rbo_) {
+ // create a renderbuffer object to store depth info
+ glGenRenderbuffers(1, &rbo_);
+ glBindRenderbuffer(GL_RENDERBUFFER, rbo_);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
+ kTextureWidth, kTextureHeight);
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ }
+
+ if (!fbo_) {
+ // create a framebuffer object
+ glGenFramebuffers(1, &fbo_);
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
+
+ // attach the texture to FBO color attachment point
+ glFramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ texture,
+ 0);
+
+ // attach the renderbuffer to depth attachment point
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER,
+ GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER,
+ rbo_);
+
+ // check FBO status
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ assert(status == GL_FRAMEBUFFER_COMPLETE);
+
+ AssertNoGLError();
+ return texture;
+}
+
+pp::ImageData DemoInstance::PrepareImage() {
+ if (images_.empty()) {
+ total_resource_++;
+ return pp::ImageData(this,
+ PP_IMAGEDATAFORMAT_RGBA_PREMUL,
+ pp::Size(kImageWidth, kImageHeight),
+ false);
+ }
+ pp::ImageData image = images_.back();
+ images_.pop_back();
+ return image;
+}
+
+void DemoInstance::Paint(int32_t result, int32_t frame) {
+ assert(result == PP_OK);
+
+ if (result != PP_OK || !context_)
+ return;
+
+ int32_t rv;
+
+ if (rebuild_layers_) {
+ compositor_.ResetLayers();
+ color_layer_ = pp::CompositorLayer();
+ stable_texture_layer_ = pp::CompositorLayer();
+ texture_layer_ = pp::CompositorLayer();
+ image_layer_ = pp::CompositorLayer();
+ frame = 0;
+ rebuild_layers_ = false;
+ }
+
+ float factor_sin = sin(M_PI / 180 * frame);
+ float factor_cos = cos(M_PI / 180 * frame);
+ {
+ // Set the background color layer.
+ if (color_layer_.is_null()) {
+ color_layer_ = compositor_.AddLayer();
+ assert(!color_layer_.is_null());
+ static const float transform[16] = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f,
+ };
+ rv = color_layer_.SetTransform(transform);
+ assert(rv == PP_OK);
+ }
+ rv = color_layer_.SetColor(fabs(factor_sin),
+ fabs(factor_cos),
+ fabs(factor_sin * factor_cos),
+ 1.0f,
+ pp::Size(800, 600));
+ assert(rv == PP_OK);
+ }
+
+ {
+ // Set the image layer
+ if (image_layer_.is_null()) {
+ image_layer_ = compositor_.AddLayer();
+ assert(!image_layer_.is_null());
+ }
+ float x = frame % 800;
+ float y = 200 - 200 * factor_sin;
+ const float transform[16] = {
+ fabs(factor_sin) + 0.2f, 0.0f, 0.0f, 0.0f,
+ 0.0f, fabs(factor_sin) + 0.2f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ x, y, 0.0f, 1.0f,
+ };
+ rv = image_layer_.SetTransform(transform);
+ assert(rv == PP_OK);
+
+ pp::ImageData image = PrepareImage();
+ uint8_t *p = static_cast<uint8_t*>(image.data());
+ for (int x = 0; x < kImageWidth; ++x) {
+ for (int y = 0; y < kImageHeight; ++y) {
+ *(p++) = frame;
+ *(p++) = frame * x;
+ *(p++) = frame * y;
+ *(p++) = 255;
+ }
+ }
+ rv = image_layer_.SetImage(image, pp::Size(kImageWidth, kImageHeight),
+ callback_factory_.NewCallback(&DemoInstance::OnImageReleased, image));
+ assert(rv == PP_OK_COMPLETIONPENDING);
+ }
+
+ {
+ // Set the stable texture layer
+ if (stable_texture_layer_.is_null()) {
+ stable_texture_layer_ = compositor_.AddLayer();
+ assert(!stable_texture_layer_.is_null());
+ GLuint texture = PrepareFramebuffer();
+ cube_->UpdateForTimeDelta(0.02f);
+ cube_->Draw();
+ rv = stable_texture_layer_.SetTexture(
+ *context_,
+ texture, pp::Size(600, 600),
+ callback_factory_.NewCallback(&DemoInstance::OnTextureReleased,
+ texture));
+ assert(rv == PP_OK_COMPLETIONPENDING);
+ rv = stable_texture_layer_.SetPremultipliedAlpha(PP_FALSE);
+ assert(rv == PP_OK);
+ }
+
+ int32_t delta = 200 * fabsf(factor_sin);
+ if (delta != 0) {
+ int32_t x_y = 25 + delta;
+ int32_t w_h = 650 - delta - delta;
+ rv = stable_texture_layer_.SetClipRect(pp::Rect(x_y, x_y, w_h, w_h));
+ } else {
+ rv = stable_texture_layer_.SetClipRect(pp::Rect());
+ }
+ assert(rv == PP_OK);
+
+ const float transform[16] = {
+ factor_cos, -factor_sin, 0.0f, 0.0f,
+ factor_sin, factor_cos, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 50.0f, 50.0f, 0.0f, 1.0f,
+ };
+ rv = stable_texture_layer_.SetTransform(transform);
+ assert(rv == PP_OK);
+ }
+
+ {
+ // Set the dynamic texture layer.
+ if (texture_layer_.is_null()) {
+ texture_layer_ = compositor_.AddLayer();
+ assert(!texture_layer_.is_null());
+ static const float transform[16] = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 200.0f, 0.0f, 0.0f, 1.0f,
+ };
+ rv = texture_layer_.SetTransform(transform);
+ assert(rv == PP_OK);
+ }
+
+ GLuint texture = PrepareFramebuffer();
+ cube_->UpdateForTimeDelta(0.02f);
+ cube_->Draw();
+ rv = texture_layer_.SetTexture(*context_, texture, pp::Size(400, 400),
+ callback_factory_.NewCallback(&DemoInstance::OnTextureReleased,
+ texture));
+ assert(rv == PP_OK_COMPLETIONPENDING);
+ rv = texture_layer_.SetPremultipliedAlpha(PP_FALSE);
+ assert(rv == PP_OK);
+ }
+
+ rv = compositor_.CommitLayers(
+ callback_factory_.NewCallback(&DemoInstance::Paint, ++frame));
+ assert(rv == PP_OK_COMPLETIONPENDING);
+
+ pp::VarDictionary dict;
+ dict.Set(pp::Var("total_resource"), pp::Var(total_resource_));
+ dict.Set(pp::Var("free_resource"),
+ pp::Var((int32_t)(textures_.size() + images_.size())));
+ PostMessage(dict);
+}
+
+void DemoInstance::OnTextureReleased(int32_t result, GLuint texture) {
+ if (result == PP_OK)
+ textures_.push_back(texture);
+}
+
+void DemoInstance::OnImageReleased(int32_t result, const pp::ImageData& image) {
+ if (result == PP_OK)
+ images_.push_back(image);
+}
+
+// This object is the global object representing this plugin library as long
+// as it is loaded.
+class DemoModule : public pp::Module {
+ public:
+ DemoModule() : Module() {}
+ virtual ~DemoModule() {}
+
+ virtual pp::Instance* CreateInstance(PP_Instance instance) {
+ return new DemoInstance(instance);
+ }
+};
+
+} // anonymous namespace
+
+namespace pp {
+// Factory function for your specialization of the Module object.
+Module* CreateModule() {
+ return new DemoModule();
+}
+} // namespace pp
diff --git a/ppapi/examples/compositor/compositor.html b/ppapi/examples/compositor/compositor.html
new file mode 100644
index 0000000..a0dcfbe
--- /dev/null
+++ b/ppapi/examples/compositor/compositor.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+ <!--
+ 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.
+ -->
+<head>
+ <title>GLES2 Spinning Cube Example</title>
+</head>
+
+<body>
+
+<embed id="plugin" type="application/x-ppapi-example-compositor"
+ width="800" height="600"/> <br/>
+ Total resource: <input id="total" > <br/>
+ Free resource: <input id="free" > <br/>
+<script type="text/javascript">
+ var plugin = document.getElementById('plugin');
+ var total = document.getElementById('total');
+ var free = document.getElementById('free');
+ plugin.addEventListener('message', function(message) {
+ total.value = message.data.total_resource;
+ free.value = message.data.free_resource;
+ }, false);
+</script>
+</body>
+</html>
diff --git a/ppapi/examples/compositor/spinning_cube.cc b/ppapi/examples/compositor/spinning_cube.cc
new file mode 100644
index 0000000..2e76699
--- /dev/null
+++ b/ppapi/examples/compositor/spinning_cube.cc
@@ -0,0 +1,459 @@
+// 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.
+
+// This example program is based on Simple_VertexShader.c from:
+
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+#include "ppapi/examples/compositor/spinning_cube.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+
+#include "ppapi/lib/gl/include/GLES2/gl2.h"
+
+namespace {
+
+const float kPi = 3.14159265359f;
+
+int GenerateCube(GLuint *vbo_vertices,
+ GLuint *vbo_indices) {
+ const int num_indices = 36;
+
+ const GLfloat cube_vertices[] = {
+ -0.5f, -0.5f, -0.5f,
+ 0.5f, -0.5f, -0.5f,
+ 0.5f, -0.5f, 0.5f,
+ -0.5f, -0.5f, 0.5f,
+ -0.5f, 0.5f, -0.5f,
+ 0.5f, 0.5f, -0.5f,
+ 0.5f, 0.5f, 0.5f,
+ -0.5f, 0.5f, 0.5f,
+ };
+
+ const GLushort cube_indices[] = {
+ 0, 2, 1,
+ 0, 3, 2,
+ 4, 5, 6,
+ 4, 6, 7,
+ 3, 6, 2,
+ 3, 7, 6,
+ 0, 1, 5,
+ 0, 5, 4,
+ 0, 7, 3,
+ 0, 4, 7,
+ 1, 2, 6,
+ 1, 6, 5,
+ };
+
+ if (vbo_vertices) {
+ glGenBuffers(1, vbo_vertices);
+ glBindBuffer(GL_ARRAY_BUFFER, *vbo_vertices);
+ glBufferData(GL_ARRAY_BUFFER,
+ sizeof(cube_vertices),
+ cube_vertices,
+ GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+
+ if (vbo_indices) {
+ glGenBuffers(1, vbo_indices);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *vbo_indices);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER,
+ sizeof(cube_indices),
+ cube_indices,
+ GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
+ return num_indices;
+}
+
+GLuint LoadShader(GLenum type,
+ const char* shader_source) {
+ GLuint shader = glCreateShader(type);
+ glShaderSource(shader, 1, &shader_source, NULL);
+ glCompileShader(shader);
+
+ GLint compiled = 0;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+
+ if (!compiled) {
+ glDeleteShader(shader);
+ return 0;
+ }
+
+ return shader;
+}
+
+GLuint LoadProgram(const char* vertext_shader_source,
+ const char* fragment_shader_source) {
+ GLuint vertex_shader = LoadShader(GL_VERTEX_SHADER,
+ vertext_shader_source);
+ if (!vertex_shader)
+ return 0;
+
+ GLuint fragment_shader = LoadShader(GL_FRAGMENT_SHADER,
+ fragment_shader_source);
+ if (!fragment_shader) {
+ glDeleteShader(vertex_shader);
+ return 0;
+ }
+
+ GLuint program_object = glCreateProgram();
+ glAttachShader(program_object, vertex_shader);
+ glAttachShader(program_object, fragment_shader);
+
+ glLinkProgram(program_object);
+
+ glDeleteShader(vertex_shader);
+ glDeleteShader(fragment_shader);
+
+ GLint linked = 0;
+ glGetProgramiv(program_object, GL_LINK_STATUS, &linked);
+
+ if (!linked) {
+ glDeleteProgram(program_object);
+ return 0;
+ }
+
+ return program_object;
+}
+
+class ESMatrix {
+ public:
+ GLfloat m[4][4];
+
+ ESMatrix() {
+ LoadZero();
+ }
+
+ void LoadZero() {
+ memset(this, 0x0, sizeof(ESMatrix));
+ }
+
+ void LoadIdentity() {
+ LoadZero();
+ m[0][0] = 1.0f;
+ m[1][1] = 1.0f;
+ m[2][2] = 1.0f;
+ m[3][3] = 1.0f;
+ }
+
+ void Multiply(ESMatrix* a, ESMatrix* b) {
+ ESMatrix result;
+ for (int i = 0; i < 4; ++i) {
+ result.m[i][0] = (a->m[i][0] * b->m[0][0]) +
+ (a->m[i][1] * b->m[1][0]) +
+ (a->m[i][2] * b->m[2][0]) +
+ (a->m[i][3] * b->m[3][0]);
+
+ result.m[i][1] = (a->m[i][0] * b->m[0][1]) +
+ (a->m[i][1] * b->m[1][1]) +
+ (a->m[i][2] * b->m[2][1]) +
+ (a->m[i][3] * b->m[3][1]);
+
+ result.m[i][2] = (a->m[i][0] * b->m[0][2]) +
+ (a->m[i][1] * b->m[1][2]) +
+ (a->m[i][2] * b->m[2][2]) +
+ (a->m[i][3] * b->m[3][2]);
+
+ result.m[i][3] = (a->m[i][0] * b->m[0][3]) +
+ (a->m[i][1] * b->m[1][3]) +
+ (a->m[i][2] * b->m[2][3]) +
+ (a->m[i][3] * b->m[3][3]);
+ }
+ *this = result;
+ }
+
+ void Frustum(float left,
+ float right,
+ float bottom,
+ float top,
+ float near_z,
+ float far_z) {
+ float delta_x = right - left;
+ float delta_y = top - bottom;
+ float delta_z = far_z - near_z;
+
+ if ((near_z <= 0.0f) ||
+ (far_z <= 0.0f) ||
+ (delta_z <= 0.0f) ||
+ (delta_y <= 0.0f) ||
+ (delta_y <= 0.0f))
+ return;
+
+ ESMatrix frust;
+ frust.m[0][0] = 2.0f * near_z / delta_x;
+ frust.m[0][1] = frust.m[0][2] = frust.m[0][3] = 0.0f;
+
+ frust.m[1][1] = 2.0f * near_z / delta_y;
+ frust.m[1][0] = frust.m[1][2] = frust.m[1][3] = 0.0f;
+
+ frust.m[2][0] = (right + left) / delta_x;
+ frust.m[2][1] = (top + bottom) / delta_y;
+ frust.m[2][2] = -(near_z + far_z) / delta_z;
+ frust.m[2][3] = -1.0f;
+
+ frust.m[3][2] = -2.0f * near_z * far_z / delta_z;
+ frust.m[3][0] = frust.m[3][1] = frust.m[3][3] = 0.0f;
+
+ Multiply(&frust, this);
+ }
+
+ void Perspective(float fov_y, float aspect, float near_z, float far_z) {
+ GLfloat frustum_h = tanf(fov_y / 360.0f * kPi) * near_z;
+ GLfloat frustum_w = frustum_h * aspect;
+ Frustum(-frustum_w, frustum_w, -frustum_h, frustum_h, near_z, far_z);
+ }
+
+ void Translate(GLfloat tx, GLfloat ty, GLfloat tz) {
+ m[3][0] += m[0][0] * tx + m[1][0] * ty + m[2][0] * tz;
+ m[3][1] += m[0][1] * tx + m[1][1] * ty + m[2][1] * tz;
+ m[3][2] += m[0][2] * tx + m[1][2] * ty + m[2][2] * tz;
+ m[3][3] += m[0][3] * tx + m[1][3] * ty + m[2][3] * tz;
+ }
+
+ void Rotate(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
+ GLfloat mag = sqrtf(x * x + y * y + z * z);
+
+ GLfloat sin_angle = sinf(angle * kPi / 180.0f);
+ GLfloat cos_angle = cosf(angle * kPi / 180.0f);
+ if (mag > 0.0f) {
+ GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs;
+ GLfloat one_minus_cos;
+ ESMatrix rotation;
+
+ x /= mag;
+ y /= mag;
+ z /= mag;
+
+ xx = x * x;
+ yy = y * y;
+ zz = z * z;
+ xy = x * y;
+ yz = y * z;
+ zx = z * x;
+ xs = x * sin_angle;
+ ys = y * sin_angle;
+ zs = z * sin_angle;
+ one_minus_cos = 1.0f - cos_angle;
+
+ rotation.m[0][0] = (one_minus_cos * xx) + cos_angle;
+ rotation.m[0][1] = (one_minus_cos * xy) - zs;
+ rotation.m[0][2] = (one_minus_cos * zx) + ys;
+ rotation.m[0][3] = 0.0F;
+
+ rotation.m[1][0] = (one_minus_cos * xy) + zs;
+ rotation.m[1][1] = (one_minus_cos * yy) + cos_angle;
+ rotation.m[1][2] = (one_minus_cos * yz) - xs;
+ rotation.m[1][3] = 0.0F;
+
+ rotation.m[2][0] = (one_minus_cos * zx) - ys;
+ rotation.m[2][1] = (one_minus_cos * yz) + xs;
+ rotation.m[2][2] = (one_minus_cos * zz) + cos_angle;
+ rotation.m[2][3] = 0.0F;
+
+ rotation.m[3][0] = 0.0F;
+ rotation.m[3][1] = 0.0F;
+ rotation.m[3][2] = 0.0F;
+ rotation.m[3][3] = 1.0F;
+
+ Multiply(&rotation, this);
+ }
+ }
+};
+
+float RotationForTimeDelta(float delta_time) {
+ return delta_time * 40.0f;
+}
+
+float RotationForDragDistance(float drag_distance) {
+ return drag_distance / 5; // Arbitrary damping.
+}
+
+} // namespace
+
+class SpinningCube::GLState {
+ public:
+ GLState();
+
+ void OnGLContextLost();
+
+ GLfloat angle_; // Survives losing the GL context.
+
+ GLuint program_object_;
+ GLint position_location_;
+ GLint mvp_location_;
+ GLuint vbo_vertices_;
+ GLuint vbo_indices_;
+ int num_indices_;
+ ESMatrix mvp_matrix_;
+};
+
+SpinningCube::GLState::GLState()
+ : angle_(0) {
+ OnGLContextLost();
+}
+
+void SpinningCube::GLState::OnGLContextLost() {
+ program_object_ = 0;
+ position_location_ = 0;
+ mvp_location_ = 0;
+ vbo_vertices_ = 0;
+ vbo_indices_ = 0;
+ num_indices_ = 0;
+}
+
+SpinningCube::SpinningCube()
+ : initialized_(false),
+ width_(0),
+ height_(0),
+ state_(new GLState()),
+ fling_multiplier_(1.0f),
+ direction_(1) {
+ state_->angle_ = 45.0f;
+}
+
+SpinningCube::~SpinningCube() {
+ if (!initialized_)
+ return;
+ if (state_->vbo_vertices_)
+ glDeleteBuffers(1, &state_->vbo_vertices_);
+ if (state_->vbo_indices_)
+ glDeleteBuffers(1, &state_->vbo_indices_);
+ if (state_->program_object_)
+ glDeleteProgram(state_->program_object_);
+
+ delete state_;
+}
+
+void SpinningCube::Init(uint32_t width, uint32_t height) {
+ width_ = width;
+ height_ = height;
+
+ if (!initialized_) {
+ initialized_ = true;
+ const char vertext_shader_source[] =
+ "uniform mat4 u_mvpMatrix; \n"
+ "attribute vec4 a_position; \n"
+ "varying vec4 v_color; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = u_mvpMatrix * a_position; \n"
+ " v_color = vec4(a_position.x + 0.5, \n"
+ " a_position.y + 0.5, \n"
+ " a_position.z + 0.5, \n"
+ " 0.8); \n"
+ "} \n";
+
+ const char fragment_shader_source[] =
+ "precision mediump float; \n"
+ "varying vec4 v_color; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = v_color; \n"
+ "} \n";
+
+ state_->program_object_ = LoadProgram(
+ vertext_shader_source, fragment_shader_source);
+ state_->position_location_ = glGetAttribLocation(
+ state_->program_object_, "a_position");
+ state_->mvp_location_ = glGetUniformLocation(
+ state_->program_object_, "u_mvpMatrix");
+ state_->num_indices_ = GenerateCube(&state_->vbo_vertices_,
+ &state_->vbo_indices_);
+
+ glClearColor(0.0f, 0.0f, 0.0f, 0.2f);
+ }
+}
+
+void SpinningCube::OnGLContextLost() {
+ // TODO(yzshen): Is it correct that in this case we don't need to do cleanup
+ // for program and buffers?
+ initialized_ = false;
+ height_ = 0;
+ width_ = 0;
+ state_->OnGLContextLost();
+}
+
+void SpinningCube::SetFlingMultiplier(float drag_distance,
+ float drag_time) {
+ fling_multiplier_ = RotationForDragDistance(drag_distance) /
+ RotationForTimeDelta(drag_time);
+
+}
+
+void SpinningCube::UpdateForTimeDelta(float delta_time) {
+ state_->angle_ += RotationForTimeDelta(delta_time) * fling_multiplier_;
+ if (state_->angle_ >= 360.0f)
+ state_->angle_ -= 360.0f;
+
+ // Arbitrary 50-step linear reduction in spin speed.
+ if (fling_multiplier_ > 1.0f) {
+ fling_multiplier_ =
+ std::max(1.0f, fling_multiplier_ - (fling_multiplier_ - 1.0f) / 50);
+ }
+
+ Update();
+}
+
+void SpinningCube::UpdateForDragDistance(float distance) {
+ state_->angle_ += RotationForDragDistance(distance);
+ if (state_->angle_ >= 360.0f )
+ state_->angle_ -= 360.0f;
+
+ Update();
+}
+
+void SpinningCube::Draw() {
+ glViewport(0, 0, width_, height_);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_DEPTH_TEST);
+ glUseProgram(state_->program_object_);
+
+ glBindBuffer(GL_ARRAY_BUFFER, state_->vbo_vertices_);
+ glVertexAttribPointer(state_->position_location_,
+ 3,
+ GL_FLOAT,
+ GL_FALSE, 3 * sizeof(GLfloat),
+ 0);
+ glEnableVertexAttribArray(state_->position_location_);
+
+ glUniformMatrix4fv(state_->mvp_location_,
+ 1,
+ GL_FALSE,
+ (GLfloat*) &state_->mvp_matrix_.m[0][0]);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, state_->vbo_indices_);
+ glDrawElements(GL_TRIANGLES,
+ state_->num_indices_,
+ GL_UNSIGNED_SHORT,
+ 0);
+}
+
+void SpinningCube::Update() {
+ float aspect = static_cast<GLfloat>(width_) / static_cast<GLfloat>(height_);
+
+ ESMatrix perspective;
+ perspective.LoadIdentity();
+ perspective.Perspective(60.0f, aspect, 1.0f, 20.0f );
+
+ ESMatrix modelview;
+ modelview.LoadIdentity();
+ modelview.Translate(0.0, 0.0, -2.0);
+ modelview.Rotate(state_->angle_ * direction_, 1.0, 0.0, 1.0);
+
+ state_->mvp_matrix_.Multiply(&modelview, &perspective);
+}
diff --git a/ppapi/examples/compositor/spinning_cube.h b/ppapi/examples/compositor/spinning_cube.h
new file mode 100644
index 0000000..84a302c2
--- /dev/null
+++ b/ppapi/examples/compositor/spinning_cube.h
@@ -0,0 +1,42 @@
+// 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.
+
+#ifndef PPAPI_EXAMPLES_GLES2_SPINNING_CUBE_SPINNING_CUBE_H_
+#define PPAPI_EXAMPLES_GLES2_SPINNING_CUBE_SPINNING_CUBE_H_
+
+#include "ppapi/c/pp_stdint.h"
+
+class SpinningCube {
+ public:
+ SpinningCube();
+ ~SpinningCube();
+
+ void Init(uint32_t width, uint32_t height);
+ void set_direction(int direction) { direction_ = direction; }
+ void SetFlingMultiplier(float drag_distance, float drag_time);
+ void UpdateForTimeDelta(float delta_time);
+ void UpdateForDragDistance(float distance);
+ void Draw();
+
+ void OnGLContextLost();
+
+ private:
+ class GLState;
+
+ // Disallow copy and assign.
+ SpinningCube(const SpinningCube& other);
+ SpinningCube& operator=(const SpinningCube& other);
+
+ void Update();
+
+ bool initialized_;
+ uint32_t width_;
+ uint32_t height_;
+ // Owned ptr.
+ GLState* state_;
+ float fling_multiplier_;
+ int direction_;
+};
+
+#endif // PPAPI_EXAMPLES_GLES2_SPINNING_CUBE_SPINNING_CUBE_H_
diff --git a/ppapi/host/resource_host.cc b/ppapi/host/resource_host.cc
index b453398..2d5af58 100644
--- a/ppapi/host/resource_host.cc
+++ b/ppapi/host/resource_host.cc
@@ -48,6 +48,10 @@ void ResourceHost::SendReply(const ReplyMessageContext& context,
host_->SendReply(context, msg);
}
+bool ResourceHost::IsCompositorHost() {
+ return false;
+}
+
bool ResourceHost::IsFileRefHost() {
return false;
}
diff --git a/ppapi/host/resource_host.h b/ppapi/host/resource_host.h
index a9518ee..a2d3885 100644
--- a/ppapi/host/resource_host.h
+++ b/ppapi/host/resource_host.h
@@ -56,6 +56,7 @@ class PPAPI_HOST_EXPORT ResourceHost : public ResourceMessageHandler {
// Simple RTTI. A subclass that is a host for one of these APIs will override
// the appropriate function and return true.
+ virtual bool IsCompositorHost();
virtual bool IsFileRefHost();
virtual bool IsFileSystemHost();
virtual bool IsGraphics2DHost();
diff --git a/ppapi/ppapi_internal.gyp b/ppapi/ppapi_internal.gyp
index 3a07317..4c1614f 100644
--- a/ppapi/ppapi_internal.gyp
+++ b/ppapi/ppapi_internal.gyp
@@ -231,6 +231,7 @@
'ppapi.gyp:ppapi_c',
'../base/base.gyp:base_win64',
'../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64',
+ '../gpu/gpu.gyp:command_buffer_common_win64',
'../ipc/ipc.gyp:ipc_win64',
'../ui/events/latency_info_nacl.gyp:latency_info_nacl_win64',
],
diff --git a/ppapi/ppapi_shared.gypi b/ppapi/ppapi_shared.gypi
index d62758f..23b00de 100644
--- a/ppapi/ppapi_shared.gypi
+++ b/ppapi/ppapi_shared.gypi
@@ -17,6 +17,8 @@
'shared_impl/array_writer.h',
'shared_impl/callback_tracker.cc',
'shared_impl/callback_tracker.h',
+ 'shared_impl/compositor_layer_data.cc',
+ 'shared_impl/compositor_layer_data.h',
'shared_impl/dictionary_var.cc',
'shared_impl/dictionary_var.h',
'shared_impl/file_io_state_manager.cc',
diff --git a/ppapi/ppapi_tests.gypi b/ppapi/ppapi_tests.gypi
index 35b0ff1..bc02aa1 100644
--- a/ppapi/ppapi_tests.gypi
+++ b/ppapi/ppapi_tests.gypi
@@ -571,5 +571,21 @@
'examples/gles2_spinning_cube/spinning_cube.h',
],
},
+ {
+ 'target_name': 'ppapi_example_compositor',
+ 'dependencies': [
+ 'ppapi_example_skeleton',
+ 'ppapi.gyp:ppapi_cpp',
+ 'ppapi.gyp:ppapi_gles2',
+ ],
+ 'include_dirs': [
+ 'lib/gl/include',
+ ],
+ 'sources': [
+ 'examples/compositor/compositor.cc',
+ 'examples/compositor/spinning_cube.cc',
+ 'examples/compositor/spinning_cube.h',
+ ],
+ },
],
}
diff --git a/ppapi/proxy/compositor_layer_resource.cc b/ppapi/proxy/compositor_layer_resource.cc
index 829ff18..fb1bbe5 100644
--- a/ppapi/proxy/compositor_layer_resource.cc
+++ b/ppapi/proxy/compositor_layer_resource.cc
@@ -4,15 +4,99 @@
#include "ppapi/proxy/compositor_layer_resource.h"
+#include "base/logging.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "gpu/command_buffer/common/mailbox.h"
+#include "ppapi/proxy/compositor_resource.h"
+#include "ppapi/shared_impl/ppb_graphics_3d_shared.h"
+#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/ppb_graphics_3d_api.h"
+#include "ppapi/thunk/ppb_image_data_api.h"
+
+using gpu::gles2::GLES2Implementation;
+using ppapi::thunk::EnterResourceNoLock;
+using ppapi::thunk::PPB_ImageData_API;
+using ppapi::thunk::PPB_Graphics3D_API;
+
namespace ppapi {
namespace proxy {
-CompositorLayerResource::CompositorLayerResource(Connection connection,
- PP_Instance instance)
- : PluginResource(connection, instance) {
+namespace {
+
+class Scoped2DTextureBinder {
+ public:
+ Scoped2DTextureBinder(GLES2Implementation* gl, uint32_t id)
+ : gl_(gl), old_id_(-1) {
+ gl_->GetIntegerv(GL_TEXTURE_BINDING_2D, &old_id_);
+ gl_->BindTexture(GL_TEXTURE_2D, id);
+ }
+
+ ~Scoped2DTextureBinder() {
+ gl_->BindTexture(GL_TEXTURE_2D, old_id_);
+ }
+
+ private:
+ GLES2Implementation* gl_;
+ int32_t old_id_;
+};
+
+float clamp(float value) {
+ return std::min(std::max(value, 0.0f), 1.0f);
+}
+
+void OnTextureReleased(
+ const ScopedPPResource& layer,
+ const ScopedPPResource& context,
+ uint32_t texture,
+ const scoped_refptr<TrackedCallback>& release_callback,
+ uint32_t sync_point,
+ bool is_lost) {
+ if (!TrackedCallback::IsPending(release_callback))
+ return;
+
+ do {
+ if (!sync_point)
+ break;
+
+ EnterResourceNoLock<PPB_Graphics3D_API> enter(context.get(), true);
+ if (enter.failed())
+ break;
+
+ PPB_Graphics3D_Shared* graphics =
+ static_cast<PPB_Graphics3D_Shared*>(enter.object());
+
+ GLES2Implementation* gl = graphics->gles2_impl();
+ gl->WaitSyncPointCHROMIUM(sync_point);
+ } while (false);
+
+ release_callback->Run(is_lost ? PP_ERROR_FAILED : PP_OK);
+}
+
+void OnImageReleased(
+ const ScopedPPResource& layer,
+ const ScopedPPResource& image,
+ const scoped_refptr<TrackedCallback>& release_callback,
+ uint32_t sync_point,
+ bool is_lost) {
+ if (!TrackedCallback::IsPending(release_callback))
+ return;
+ release_callback->Run(PP_OK);
+}
+
+} // namespace
+
+CompositorLayerResource::CompositorLayerResource(
+ Connection connection,
+ PP_Instance instance,
+ const CompositorResource* compositor)
+ : PluginResource(connection, instance),
+ compositor_(compositor),
+ source_size_(PP_MakeFloatSize(0.0f, 0.0f)) {
}
CompositorLayerResource::~CompositorLayerResource() {
+ DCHECK(!compositor_);
+ DCHECK(release_callback_.is_null());
}
thunk::PPB_CompositorLayer_API*
@@ -25,47 +109,266 @@ int32_t CompositorLayerResource::SetColor(float red,
float blue,
float alpha,
const PP_Size* size) {
- return PP_ERROR_NOTSUPPORTED;
+ if (!compositor_)
+ return PP_ERROR_BADRESOURCE;
+
+ if (compositor_->IsInProgress())
+ return PP_ERROR_INPROGRESS;
+
+ if (!SetType(TYPE_COLOR))
+ return PP_ERROR_BADARGUMENT;
+ DCHECK(data_.color);
+
+ if (!size)
+ return PP_ERROR_BADARGUMENT;
+
+
+ data_.color->red = clamp(red);
+ data_.color->green = clamp(green);
+ data_.color->blue = clamp(blue);
+ data_.color->alpha = clamp(alpha);
+ data_.common.size = *size;
+
+ return PP_OK;
}
int32_t CompositorLayerResource::SetTexture(
PP_Resource context,
uint32_t texture,
const PP_Size* size,
- const scoped_refptr<ppapi::TrackedCallback>& callback) {
- return PP_ERROR_NOTSUPPORTED;
+ const scoped_refptr<TrackedCallback>& release_callback) {
+ int32_t rv = CheckForSetTextureAndImage(TYPE_TEXTURE, release_callback);
+ if (rv != PP_OK)
+ return rv;
+ DCHECK(data_.texture);
+
+ EnterResourceNoLock<PPB_Graphics3D_API> enter(context, true);
+ if (enter.failed())
+ return PP_ERROR_BADRESOURCE;
+
+ if (!size || size->width <= 0 || size->height <= 0)
+ return PP_ERROR_BADARGUMENT;
+
+ PPB_Graphics3D_Shared* graphics =
+ static_cast<PPB_Graphics3D_Shared*>(enter.object());
+
+ GLES2Implementation* gl = graphics->gles2_impl();
+ Scoped2DTextureBinder scoped_2d_texture_binder(gl, texture);
+
+ // Generate a Mailbox for the texture.
+ gl->GenMailboxCHROMIUM(
+ reinterpret_cast<GLbyte*>(data_.texture->mailbox.name));
+ gl->ProduceTextureCHROMIUM(
+ GL_TEXTURE_2D,
+ reinterpret_cast<const GLbyte*>(data_.texture->mailbox.name));
+
+ // Set the source size to (1, 1). It will be used to verify the source_rect
+ // passed to SetSourceRect().
+ source_size_ = PP_MakeFloatSize(1.0f, 1.0f);
+
+ data_.common.size = *size;
+ data_.common.resource_id = compositor_->GenerateResourceId();
+ data_.texture->sync_point = gl->InsertSyncPointCHROMIUM();
+ data_.texture->source_rect.point = PP_MakeFloatPoint(0.0f, 0.0f);
+ data_.texture->source_rect.size = source_size_;
+
+ // If the PP_Resource of this layer is released by the plugin, the
+ // release_callback will be aborted immediately, but the texture or image
+ // in this layer may still being used by chromium compositor. So we have to
+ // use ScopedPPResource to keep this resource alive until the texture or image
+ // is released by the chromium compositor.
+ release_callback_ = base::Bind(
+ &OnTextureReleased,
+ ScopedPPResource(pp_resource()), // Keep layer alive.
+ ScopedPPResource(context), // Keep context alive
+ texture,
+ release_callback);
+
+ return PP_OK_COMPLETIONPENDING;
}
int32_t CompositorLayerResource::SetImage(
PP_Resource image_data,
const PP_Size* size,
- const scoped_refptr<ppapi::TrackedCallback>& callback) {
- return PP_ERROR_NOTSUPPORTED;
+ const scoped_refptr<TrackedCallback>& release_callback) {
+ int32_t rv = CheckForSetTextureAndImage(TYPE_IMAGE, release_callback);
+ if (rv != PP_OK)
+ return rv;
+ DCHECK(data_.image);
+
+ EnterResourceNoLock<PPB_ImageData_API> enter(image_data, true);
+ if (enter.failed())
+ return PP_ERROR_BADRESOURCE;
+
+ PP_ImageDataDesc desc;
+ if (!enter.object()->Describe(&desc))
+ return PP_ERROR_BADARGUMENT;
+
+ // TODO(penghuang): Support image which width * 4 != stride.
+ if (desc.size.width * 4 != desc.stride)
+ return PP_ERROR_BADARGUMENT;
+
+ // TODO(penghuang): Support all formats.
+ if (desc.format != PP_IMAGEDATAFORMAT_RGBA_PREMUL)
+ return PP_ERROR_BADARGUMENT;
+
+ if (!size || size->width <= 0 || size->height <= 0)
+ return PP_ERROR_BADARGUMENT;
+
+ // Set the source size to image's size. It will be used to verify
+ // the source_rect passed to SetSourceRect().
+ source_size_ = PP_MakeFloatSize(desc.size.width, desc.size.height);
+
+ data_.common.size = size ? *size : desc.size;
+ data_.common.resource_id = compositor_->GenerateResourceId();
+ data_.image->resource = enter.resource()->host_resource().host_resource();
+ data_.image->source_rect.point = PP_MakeFloatPoint(0.0f, 0.0f);
+ data_.image->source_rect.size = source_size_;
+
+ release_callback_ = base::Bind(
+ &OnImageReleased,
+ ScopedPPResource(pp_resource()), // Keep layer alive.
+ ScopedPPResource(image_data), // Keep image_data alive.
+ release_callback);
+
+ return PP_OK_COMPLETIONPENDING;
}
int32_t CompositorLayerResource::SetClipRect(const PP_Rect* rect) {
- return PP_ERROR_NOTSUPPORTED;
+ if (!compositor_)
+ return PP_ERROR_BADRESOURCE;
+
+ if (compositor_->IsInProgress())
+ return PP_ERROR_INPROGRESS;
+
+ data_.common.clip_rect = rect ? *rect : PP_MakeRectFromXYWH(0, 0, 0, 0);
+ return PP_OK;
}
int32_t CompositorLayerResource::SetTransform(const float matrix[16]) {
- return PP_ERROR_NOTSUPPORTED;
+ if (!compositor_)
+ return PP_ERROR_BADRESOURCE;
+
+ if (compositor_->IsInProgress())
+ return PP_ERROR_INPROGRESS;
+
+ std::copy(matrix, matrix + 16, data_.common.transform.matrix);
+ return PP_OK;
}
int32_t CompositorLayerResource::SetOpacity(float opacity) {
- return PP_ERROR_NOTSUPPORTED;
+ if (!compositor_)
+ return PP_ERROR_BADRESOURCE;
+
+ if (compositor_->IsInProgress())
+ return PP_ERROR_INPROGRESS;
+
+ data_.common.opacity = clamp(opacity);
+ return PP_OK;
}
int32_t CompositorLayerResource::SetBlendMode(PP_BlendMode mode) {
- return PP_ERROR_NOTSUPPORTED;
+ if (!compositor_)
+ return PP_ERROR_BADRESOURCE;
+
+ if (compositor_->IsInProgress())
+ return PP_ERROR_INPROGRESS;
+
+ switch (mode) {
+ case PP_BLENDMODE_NONE:
+ case PP_BLENDMODE_SRC_OVER:
+ data_.common.blend_mode = mode;
+ return PP_OK;
+ }
+ return PP_ERROR_BADARGUMENT;
}
int32_t CompositorLayerResource::SetSourceRect(
const PP_FloatRect* rect) {
- return PP_ERROR_NOTSUPPORTED;
+ if (!compositor_)
+ return PP_ERROR_BADRESOURCE;
+
+ if (compositor_->IsInProgress())
+ return PP_ERROR_INPROGRESS;
+
+ if (!rect ||
+ rect->point.x < 0.0f ||
+ rect->point.y < 0.0f ||
+ rect->point.x + rect->size.width > source_size_.width ||
+ rect->point.y + rect->size.height > source_size_.height) {
+ return PP_ERROR_BADARGUMENT;
+ }
+
+ if (data_.texture) {
+ data_.texture->source_rect = *rect;
+ return PP_OK;
+ }
+ if (data_.image) {
+ data_.image->source_rect = *rect;
+ return PP_OK;
+ }
+ return PP_ERROR_BADARGUMENT;
}
int32_t CompositorLayerResource::SetPremultipliedAlpha(PP_Bool premult) {
- return PP_ERROR_NOTSUPPORTED;
+ if (!compositor_)
+ return PP_ERROR_BADRESOURCE;
+
+ if (compositor_->IsInProgress())
+ return PP_ERROR_INPROGRESS;
+
+ if (data_.texture) {
+ data_.texture->premult_alpha = PP_ToBool(premult);
+ return PP_OK;
+ }
+ return PP_ERROR_BADARGUMENT;
+}
+
+bool CompositorLayerResource::SetType(LayerType type) {
+ if (type == TYPE_COLOR) {
+ if (data_.is_null())
+ data_.color.reset(new CompositorLayerData::ColorLayer());
+ return data_.color;
+ }
+
+ if (type == TYPE_TEXTURE) {
+ if (data_.is_null())
+ data_.texture.reset(new CompositorLayerData::TextureLayer());
+ return data_.texture;
+ }
+
+ if (type == TYPE_IMAGE) {
+ if (data_.is_null())
+ data_.image.reset(new CompositorLayerData::ImageLayer());
+ return data_.image;
+ }
+
+ // Should not be reached.
+ DCHECK(false);
+ return false;
+}
+
+int32_t CompositorLayerResource::CheckForSetTextureAndImage(
+ LayerType type,
+ const scoped_refptr<TrackedCallback>& release_callback) {
+ if (!compositor_)
+ return PP_ERROR_BADRESOURCE;
+
+ if (compositor_->IsInProgress())
+ return PP_ERROR_INPROGRESS;
+
+ if (!SetType(type))
+ return PP_ERROR_BADARGUMENT;
+
+ // The layer's image has been set and it is not committed.
+ if (!release_callback_.is_null())
+ return PP_ERROR_INPROGRESS;
+
+ // Do not allow using a block callback as a release callback.
+ if (release_callback->is_blocking())
+ return PP_ERROR_BADARGUMENT;
+
+ return PP_OK;
}
} // namespace proxy
diff --git a/ppapi/proxy/compositor_layer_resource.h b/ppapi/proxy/compositor_layer_resource.h
index b620510..fafaa98 100644
--- a/ppapi/proxy/compositor_layer_resource.h
+++ b/ppapi/proxy/compositor_layer_resource.h
@@ -8,19 +8,40 @@
#include "ppapi/c/ppb_compositor_layer.h"
#include "ppapi/proxy/plugin_resource.h"
#include "ppapi/proxy/ppapi_proxy_export.h"
+#include "ppapi/shared_impl/compositor_layer_data.h"
+#include "ppapi/shared_impl/scoped_pp_resource.h"
#include "ppapi/thunk/ppb_compositor_layer_api.h"
namespace ppapi {
namespace proxy {
+class CompositorResource;
+
class PPAPI_PROXY_EXPORT CompositorLayerResource
: public PluginResource,
public thunk::PPB_CompositorLayer_API {
public:
+ // Release callback for texture or image layer.
+ typedef base::Callback<void(uint32_t, bool)> ReleaseCallback;
+
CompositorLayerResource(Connection connection,
- PP_Instance instance);
+ PP_Instance instance,
+ const CompositorResource* compositor);
+
+ const CompositorLayerData& data() const { return data_; }
+ const ReleaseCallback& release_callback() const {
+ return release_callback_;
+ }
+ void ResetReleaseCallback() { release_callback_.Reset(); }
+ void Invalidate() { compositor_ = NULL; }
private:
+ enum LayerType {
+ TYPE_COLOR,
+ TYPE_TEXTURE,
+ TYPE_IMAGE,
+ };
+
virtual ~CompositorLayerResource();
// Resource overrides:
@@ -36,11 +57,11 @@ class PPAPI_PROXY_EXPORT CompositorLayerResource
PP_Resource context,
uint32_t texture,
const PP_Size* size,
- const scoped_refptr<ppapi::TrackedCallback>& callback) OVERRIDE;
+ const scoped_refptr<TrackedCallback>& callback) OVERRIDE;
virtual int32_t SetImage(
PP_Resource image_data,
const PP_Size* size,
- const scoped_refptr<ppapi::TrackedCallback>& callback) OVERRIDE;
+ const scoped_refptr<TrackedCallback>& callback) OVERRIDE;
virtual int32_t SetClipRect(const PP_Rect* rect) OVERRIDE;
virtual int32_t SetTransform(const float matrix[16]) OVERRIDE;
virtual int32_t SetOpacity(float opacity) OVERRIDE;
@@ -48,6 +69,27 @@ class PPAPI_PROXY_EXPORT CompositorLayerResource
virtual int32_t SetSourceRect(const PP_FloatRect* rect) OVERRIDE;
virtual int32_t SetPremultipliedAlpha(PP_Bool premult) OVERRIDE;
+ bool SetType(LayerType type);
+ int32_t CheckForSetTextureAndImage(
+ LayerType type,
+ const scoped_refptr<TrackedCallback>& release_callback);
+
+ // The CompositorResource which own the layer. The layer is invalidated if
+ // compositor_ is NULL.
+ const CompositorResource* compositor_;
+
+ // Release callback for uncommitted texture or image. When CommitLayers() on
+ // the compositor_ is called, the callback will be copied into a map in the
+ // compositor_, and it will be reset to NULL.
+ ReleaseCallback release_callback_;
+
+ // Size of texture or image. It is used to verify the rect arg of
+ // SetSourceRect().
+ PP_FloatSize source_size_;
+
+ // Layer data.
+ CompositorLayerData data_;
+
DISALLOW_COPY_AND_ASSIGN(CompositorLayerResource);
};
diff --git a/ppapi/proxy/compositor_resource.cc b/ppapi/proxy/compositor_resource.cc
index 497e58a..3ada734 100644
--- a/ppapi/proxy/compositor_resource.cc
+++ b/ppapi/proxy/compositor_resource.cc
@@ -4,32 +4,131 @@
#include "ppapi/proxy/compositor_resource.h"
+#include "base/logging.h"
+#include "ppapi/proxy/ppapi_messages.h"
+
namespace ppapi {
namespace proxy {
CompositorResource::CompositorResource(Connection connection,
PP_Instance instance)
- : PluginResource(connection, instance) {
+ : PluginResource(connection, instance),
+ layer_reset_(true),
+ last_resource_id_(0) {
+ SendCreate(RENDERER, PpapiHostMsg_Compositor_Create());
}
CompositorResource::~CompositorResource() {
+ ResetLayersInternal();
}
thunk::PPB_Compositor_API* CompositorResource::AsPPB_Compositor_API() {
return this;
}
+void CompositorResource::OnReplyReceived(
+ const ResourceMessageReplyParams& params,
+ const IPC::Message& msg) {
+ PPAPI_BEGIN_MESSAGE_MAP(CompositorResource, msg)
+ PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
+ PpapiPluginMsg_Compositor_ReleaseResource,
+ OnPluginMsgReleaseResource)
+ PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(
+ PluginResource::OnReplyReceived(params, msg))
+ PPAPI_END_MESSAGE_MAP()
+}
+
PP_Resource CompositorResource::AddLayer() {
- return 0;
+ scoped_refptr<CompositorLayerResource> resource(new CompositorLayerResource(
+ connection(), pp_instance(), this));
+ layers_.push_back(resource);
+ return resource->GetReference();
}
int32_t CompositorResource::CommitLayers(
const scoped_refptr<ppapi::TrackedCallback>& callback) {
- return PP_ERROR_NOTSUPPORTED;
+ if (IsInProgress())
+ return PP_ERROR_INPROGRESS;
+
+ std::vector<CompositorLayerData> layers;
+ layers.reserve(layers_.size());
+
+ for (LayerList::const_iterator it = layers_.begin();
+ it != layers_.end(); ++it) {
+ if ((*it)->data().is_null())
+ return PP_ERROR_FAILED;
+ layers.push_back((*it)->data());
+ }
+
+ commit_callback_ = callback;
+ Call<PpapiPluginMsg_Compositor_CommitLayersReply>(
+ RENDERER,
+ PpapiHostMsg_Compositor_CommitLayers(layers, layer_reset_),
+ base::Bind(&CompositorResource::OnPluginMsgCommitLayersReply,
+ base::Unretained(this)),
+ callback);
+
+ return PP_OK_COMPLETIONPENDING;
}
int32_t CompositorResource::ResetLayers() {
- return PP_ERROR_NOTSUPPORTED;
+ if (IsInProgress())
+ return PP_ERROR_INPROGRESS;
+ ResetLayersInternal();
+ return PP_OK;
+}
+
+void CompositorResource::OnPluginMsgCommitLayersReply(
+ const ResourceMessageReplyParams& params) {
+ if (!TrackedCallback::IsPending(commit_callback_))
+ return;
+
+ // On success, we put layers' release_callbacks into a map,
+ // otherwise we will do nothing. So plugin may change layers and
+ // call CommitLayers() again.
+ if (params.result() == PP_OK) {
+ layer_reset_ = false;
+ for (LayerList::iterator it = layers_.begin();
+ it != layers_.end(); ++it) {
+ ReleaseCallback release_callback = (*it)->release_callback();
+ if (!release_callback.is_null()) {
+ release_callback_map_.insert(ReleaseCallbackMap::value_type(
+ (*it)->data().common.resource_id, release_callback));
+ (*it)->ResetReleaseCallback();
+ }
+ }
+ }
+
+ scoped_refptr<TrackedCallback> callback;
+ callback.swap(commit_callback_);
+ callback->Run(params.result());
+}
+
+void CompositorResource::OnPluginMsgReleaseResource(
+ const ResourceMessageReplyParams& params,
+ int32_t id,
+ uint32_t sync_point,
+ bool is_lost) {
+ ReleaseCallbackMap::iterator it = release_callback_map_.find(id);
+ DCHECK(it != release_callback_map_.end()) <<
+ "Can not found release_callback_ by id(" << id << ")!";
+ it->second.Run(sync_point, is_lost);
+ release_callback_map_.erase(it);
+}
+
+void CompositorResource::ResetLayersInternal() {
+ for (LayerList::iterator it = layers_.begin();
+ it != layers_.end(); ++it) {
+ ReleaseCallback release_callback = (*it)->release_callback();
+ if (!release_callback.is_null()) {
+ release_callback.Run(0, false);
+ (*it)->ResetReleaseCallback();
+ }
+ (*it)->Invalidate();
+ }
+
+ layers_.clear();
+ layer_reset_ = true;
}
} // namespace proxy
diff --git a/ppapi/proxy/compositor_resource.h b/ppapi/proxy/compositor_resource.h
index 1ad74b9..f3d13d4 100644
--- a/ppapi/proxy/compositor_resource.h
+++ b/ppapi/proxy/compositor_resource.h
@@ -5,6 +5,9 @@
#ifndef PPAPI_PROXY_COMPOSITOR_RESOURCE_H_
#define PPAPI_PROXY_COMPOSITOR_RESOURCE_H_
+#include <map>
+
+#include "ppapi/proxy/compositor_layer_resource.h"
#include "ppapi/proxy/plugin_resource.h"
#include "ppapi/proxy/ppapi_proxy_export.h"
#include "ppapi/thunk/ppb_compositor_api.h"
@@ -19,18 +22,58 @@ class PPAPI_PROXY_EXPORT CompositorResource
CompositorResource(Connection connection,
PP_Instance instance);
+ bool IsInProgress() const {
+ return TrackedCallback::IsPending(commit_callback_);
+ }
+
+ int32_t GenerateResourceId() const {
+ return ++last_resource_id_;
+ }
+
private:
virtual ~CompositorResource();
// Resource overrides:
virtual thunk::PPB_Compositor_API* AsPPB_Compositor_API() OVERRIDE;
+ // PluginResource overrides:
+ virtual void OnReplyReceived(const ResourceMessageReplyParams& params,
+ const IPC::Message& msg) OVERRIDE;
+
// thunk::PPB_Compositor_API overrides:
virtual PP_Resource AddLayer() OVERRIDE;
virtual int32_t CommitLayers(
- const scoped_refptr<ppapi::TrackedCallback>& callback) OVERRIDE;
+ const scoped_refptr<TrackedCallback>& callback) OVERRIDE;
virtual int32_t ResetLayers() OVERRIDE;
+ // IPC msg handlers:
+ void OnPluginMsgCommitLayersReply(const ResourceMessageReplyParams& params);
+ void OnPluginMsgReleaseResource(
+ const ResourceMessageReplyParams& params,
+ int32_t id,
+ uint32_t sync_point,
+ bool is_lost);
+
+ void ResetLayersInternal();
+
+ // Callback for CommitLayers().
+ scoped_refptr<TrackedCallback> commit_callback_;
+
+ // True if layers_ has been reset by ResetLayers().
+ bool layer_reset_;
+
+ // Layer stack.
+ typedef std::vector<scoped_refptr<CompositorLayerResource> > LayerList;
+ LayerList layers_;
+
+ // Release callback map for texture and image.
+ typedef CompositorLayerResource::ReleaseCallback ReleaseCallback;
+ typedef std::map<int32_t, ReleaseCallback> ReleaseCallbackMap;
+ ReleaseCallbackMap release_callback_map_;
+
+ // The last resource id for texture or image.
+ mutable int32_t last_resource_id_;
+
DISALLOW_COPY_AND_ASSIGN(CompositorResource);
};
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h
index 41b40ce..a1ef6d6 100644
--- a/ppapi/proxy/ppapi_messages.h
+++ b/ppapi/proxy/ppapi_messages.h
@@ -37,6 +37,7 @@
#include "ppapi/c/pp_size.h"
#include "ppapi/c/pp_time.h"
#include "ppapi/c/ppb_audio_config.h"
+#include "ppapi/c/ppb_compositor_layer.h"
#include "ppapi/c/ppb_image_data.h"
#include "ppapi/c/ppb_tcp_socket.h"
#include "ppapi/c/ppb_text_input_controller.h"
@@ -59,6 +60,7 @@
#include "ppapi/proxy/serialized_handle.h"
#include "ppapi/proxy/serialized_structs.h"
#include "ppapi/proxy/serialized_var.h"
+#include "ppapi/shared_impl/compositor_layer_data.h"
#include "ppapi/shared_impl/dir_contents.h"
#include "ppapi/shared_impl/file_growth.h"
#include "ppapi/shared_impl/file_path.h"
@@ -86,6 +88,7 @@
IPC_ENUM_TRAITS_MAX_VALUE(ppapi::TCPSocketVersion,
ppapi::TCP_SOCKET_VERSION_1_1_OR_ABOVE)
IPC_ENUM_TRAITS(PP_AudioSampleRate)
+IPC_ENUM_TRAITS_MAX_VALUE(PP_BlendMode, PP_BLENDMODE_LAST)
IPC_ENUM_TRAITS(PP_DeviceType_Dev)
IPC_ENUM_TRAITS(PP_DecryptorStreamType)
IPC_ENUM_TRAITS(PP_SessionType)
@@ -143,11 +146,21 @@ IPC_STRUCT_TRAITS_BEGIN(PP_Size)
IPC_STRUCT_TRAITS_MEMBER(width)
IPC_STRUCT_TRAITS_END()
+IPC_STRUCT_TRAITS_BEGIN(PP_FloatSize)
+ IPC_STRUCT_TRAITS_MEMBER(height)
+ IPC_STRUCT_TRAITS_MEMBER(width)
+IPC_STRUCT_TRAITS_END()
+
IPC_STRUCT_TRAITS_BEGIN(PP_Rect)
IPC_STRUCT_TRAITS_MEMBER(point)
IPC_STRUCT_TRAITS_MEMBER(size)
IPC_STRUCT_TRAITS_END()
+IPC_STRUCT_TRAITS_BEGIN(PP_FloatRect)
+ IPC_STRUCT_TRAITS_MEMBER(point)
+ IPC_STRUCT_TRAITS_MEMBER(size)
+IPC_STRUCT_TRAITS_END()
+
IPC_STRUCT_TRAITS_BEGIN(PP_ImageDataDesc)
IPC_STRUCT_TRAITS_MEMBER(format)
IPC_STRUCT_TRAITS_MEMBER(size)
@@ -222,6 +235,41 @@ IPC_STRUCT_TRAITS_BEGIN(ppapi::FileGrowth)
IPC_STRUCT_TRAITS_MEMBER(append_mode_write_amount)
IPC_STRUCT_TRAITS_END()
+IPC_STRUCT_TRAITS_BEGIN(ppapi::CompositorLayerData)
+ IPC_STRUCT_TRAITS_MEMBER(common)
+ IPC_STRUCT_TRAITS_MEMBER(color)
+ IPC_STRUCT_TRAITS_MEMBER(texture)
+ IPC_STRUCT_TRAITS_MEMBER(image)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(ppapi::CompositorLayerData::LayerCommon)
+ IPC_STRUCT_TRAITS_MEMBER(size)
+ IPC_STRUCT_TRAITS_MEMBER(clip_rect)
+ IPC_STRUCT_TRAITS_MEMBER(transform)
+ IPC_STRUCT_TRAITS_MEMBER(blend_mode)
+ IPC_STRUCT_TRAITS_MEMBER(opacity)
+ IPC_STRUCT_TRAITS_MEMBER(resource_id)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(ppapi::CompositorLayerData::ColorLayer)
+ IPC_STRUCT_TRAITS_MEMBER(red)
+ IPC_STRUCT_TRAITS_MEMBER(green)
+ IPC_STRUCT_TRAITS_MEMBER(blue)
+ IPC_STRUCT_TRAITS_MEMBER(alpha)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(ppapi::CompositorLayerData::ImageLayer)
+ IPC_STRUCT_TRAITS_MEMBER(resource)
+ IPC_STRUCT_TRAITS_MEMBER(source_rect)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(ppapi::CompositorLayerData::TextureLayer)
+ IPC_STRUCT_TRAITS_MEMBER(mailbox)
+ IPC_STRUCT_TRAITS_MEMBER(sync_point)
+ IPC_STRUCT_TRAITS_MEMBER(source_rect)
+ IPC_STRUCT_TRAITS_MEMBER(premult_alpha)
+IPC_STRUCT_TRAITS_END()
+
IPC_STRUCT_TRAITS_BEGIN(ppapi::DeviceRefData)
IPC_STRUCT_TRAITS_MEMBER(type)
IPC_STRUCT_TRAITS_MEMBER(name)
@@ -1299,6 +1347,17 @@ IPC_MESSAGE_CONTROL3(PpapiHostMsg_UMA_HistogramEnumeration,
IPC_MESSAGE_CONTROL0(PpapiHostMsg_UMA_IsCrashReportingEnabled);
IPC_MESSAGE_CONTROL0(PpapiPluginMsg_UMA_IsCrashReportingEnabledReply);
+// Compositor
+IPC_MESSAGE_CONTROL0(PpapiHostMsg_Compositor_Create)
+IPC_MESSAGE_CONTROL2(PpapiHostMsg_Compositor_CommitLayers,
+ std::vector<ppapi::CompositorLayerData> /* layers */,
+ bool /* reset */)
+IPC_MESSAGE_CONTROL0(PpapiPluginMsg_Compositor_CommitLayersReply)
+IPC_MESSAGE_CONTROL3(PpapiPluginMsg_Compositor_ReleaseResource,
+ int32_t /* id */,
+ uint32_t /* sync_point */,
+ bool /* is_lost */)
+
// File chooser.
IPC_MESSAGE_CONTROL0(PpapiHostMsg_FileChooser_Create)
IPC_MESSAGE_CONTROL4(PpapiHostMsg_FileChooser_Show,
diff --git a/ppapi/proxy/ppapi_param_traits.cc b/ppapi/proxy/ppapi_param_traits.cc
index 1e91f5c..1623395 100644
--- a/ppapi/proxy/ppapi_param_traits.cc
+++ b/ppapi/proxy/ppapi_param_traits.cc
@@ -633,4 +633,31 @@ void ParamTraits<ppapi::SocketOptionData>::Log(const param_type& p,
std::string* l) {
}
+// ppapi::CompositorLayerData --------------------------------------------------
+
+// static
+void ParamTraits<ppapi::CompositorLayerData::Transform>::Write(
+ Message* m,
+ const param_type& p) {
+ for (size_t i = 0; i < arraysize(p.matrix); i++)
+ ParamTraits<float>::Write(m, p.matrix[i]);
+}
+
+// static
+bool ParamTraits<ppapi::CompositorLayerData::Transform>::Read(
+ const Message* m,
+ PickleIterator* iter,
+ param_type* r) {
+ for (size_t i = 0; i < arraysize(r->matrix);i++) {
+ if (!ParamTraits<float>::Read(m, iter, &r->matrix[i]))
+ return false;
+ }
+ return true;
+}
+
+void ParamTraits<ppapi::CompositorLayerData::Transform>::Log(
+ const param_type& p,
+ std::string* l) {
+}
+
} // namespace IPC
diff --git a/ppapi/proxy/ppapi_param_traits.h b/ppapi/proxy/ppapi_param_traits.h
index 96ff11c..76dd10d 100644
--- a/ppapi/proxy/ppapi_param_traits.h
+++ b/ppapi/proxy/ppapi_param_traits.h
@@ -14,6 +14,7 @@
#include "ppapi/c/pp_rect.h"
#include "ppapi/c/pp_var.h"
#include "ppapi/proxy/ppapi_proxy_export.h"
+#include "ppapi/shared_impl/compositor_layer_data.h"
#include "ppapi/shared_impl/file_path.h"
#include "ppapi/shared_impl/file_ref_create_info.h"
#include "ppapi/shared_impl/media_stream_video_track_shared.h"
@@ -177,6 +178,14 @@ struct PPAPI_PROXY_EXPORT ParamTraits<ppapi::SocketOptionData> {
static void Log(const param_type& p, std::string* l);
};
+template<>
+struct PPAPI_PROXY_EXPORT ParamTraits<ppapi::CompositorLayerData::Transform> {
+ typedef ppapi::CompositorLayerData::Transform param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
} // namespace IPC
#endif // PPAPI_PROXY_PPAPI_PARAM_TRAITS_H_
diff --git a/ppapi/proxy/ppb_instance_proxy.cc b/ppapi/proxy/ppb_instance_proxy.cc
index 79664f6..48f4378 100644
--- a/ppapi/proxy/ppb_instance_proxy.cc
+++ b/ppapi/proxy/ppb_instance_proxy.cc
@@ -39,6 +39,7 @@
#include "ppapi/shared_impl/ppb_view_shared.h"
#include "ppapi/shared_impl/var.h"
#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/ppb_compositor_api.h"
#include "ppapi/thunk/ppb_graphics_2d_api.h"
#include "ppapi/thunk/ppb_graphics_3d_api.h"
#include "ppapi/thunk/thunk.h"
@@ -50,6 +51,7 @@
using ppapi::thunk::EnterInstanceNoLock;
using ppapi::thunk::EnterResourceNoLock;
+using ppapi::thunk::PPB_Compositor_API;
using ppapi::thunk::PPB_Graphics2D_API;
using ppapi::thunk::PPB_Graphics3D_API;
using ppapi::thunk::PPB_Instance_API;
@@ -232,9 +234,10 @@ PP_Bool PPB_Instance_Proxy::BindGraphics(PP_Instance instance,
// We need to pass different resource to Graphics 2D and 3D right now. Once
// 3D is migrated to the new design, we should be able to unify this.
+ EnterResourceNoLock<PPB_Compositor_API> enter_compositor(device, false);
EnterResourceNoLock<PPB_Graphics2D_API> enter_2d(device, false);
EnterResourceNoLock<PPB_Graphics3D_API> enter_3d(device, false);
- if (enter_2d.succeeded()) {
+ if (enter_compositor.succeeded() || enter_2d.succeeded()) {
dispatcher()->Send(new PpapiHostMsg_PPBInstance_BindGraphics(
API_ID_PPB_INSTANCE, instance, pp_resource));
return PP_TRUE;
diff --git a/ppapi/shared_impl/compositor_layer_data.cc b/ppapi/shared_impl/compositor_layer_data.cc
new file mode 100644
index 0000000..a4b51d37
--- /dev/null
+++ b/ppapi/shared_impl/compositor_layer_data.cc
@@ -0,0 +1,36 @@
+// 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 "ppapi/shared_impl/compositor_layer_data.h"
+
+namespace ppapi {
+
+namespace {
+
+template<typename T>
+void Copy(scoped_ptr<T>* a, const scoped_ptr<T>& b) {
+ if (b) {
+ if (!(*a))
+ a->reset(new T());
+ **a = *b;
+ } else {
+ a->reset();
+ }
+}
+
+} // namespace
+
+const CompositorLayerData& CompositorLayerData::operator=(
+ const CompositorLayerData& other) {
+ DCHECK(other.is_null() || other.is_valid());
+
+ common = other.common;
+ Copy(&color, other.color);
+ Copy(&texture, other.texture);
+ Copy(&image, other.image);
+
+ return *this;
+}
+
+} // namespace ppapi
diff --git a/ppapi/shared_impl/compositor_layer_data.h b/ppapi/shared_impl/compositor_layer_data.h
new file mode 100644
index 0000000..b51fcd7
--- /dev/null
+++ b/ppapi/shared_impl/compositor_layer_data.h
@@ -0,0 +1,119 @@
+// 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.
+
+#ifndef PPAPI_SHARED_IMPL_COMPOSITOR_LAYER_DATA_H_
+#define PPAPI_SHARED_IMPL_COMPOSITOR_LAYER_DATA_H_
+
+#include <string.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/common/mailbox.h"
+#include "ppapi/c/ppb_compositor_layer.h"
+#include "ppapi/shared_impl/host_resource.h"
+#include "ppapi/shared_impl/ppapi_shared_export.h"
+
+namespace ppapi {
+
+struct PPAPI_SHARED_EXPORT CompositorLayerData {
+
+ struct Transform {
+ Transform() {
+ matrix[0] = 1.0f;
+ matrix[1] = 0.0f;
+ matrix[2] = 0.0f;
+ matrix[3] = 0.0f;
+ matrix[4] = 0.0f;
+ matrix[5] = 1.0f;
+ matrix[6] = 0.0f;
+ matrix[7] = 0.0f;
+ matrix[8] = 0.0f;
+ matrix[9] = 0.0f;
+ matrix[10] = 1.0f;
+ matrix[11] = 0.0f;
+ matrix[12] = 0.0f;
+ matrix[13] = 0.0f;
+ matrix[14] = 0.0f;
+ matrix[15] = 1.0f;
+ }
+
+ float matrix[16];
+ };
+
+ struct LayerCommon {
+ LayerCommon()
+ : size(PP_MakeSize(0, 0)),
+ clip_rect(PP_MakeRectFromXYWH(0, 0, 0, 0)),
+ blend_mode(PP_BLENDMODE_SRC_OVER),
+ opacity(1.0f),
+ resource_id(0) {
+ }
+
+ PP_Size size;
+ PP_Rect clip_rect;
+ Transform transform;
+ PP_BlendMode blend_mode;
+ float opacity;
+ uint32_t resource_id;
+ };
+
+ struct ColorLayer {
+ ColorLayer() : red(0.0f), green(0.0f), blue(0.0f), alpha(0.0f) {}
+
+ float red;
+ float green;
+ float blue;
+ float alpha;
+ };
+
+ struct ImageLayer {
+ ImageLayer()
+ : resource(0),
+ source_rect(PP_MakeFloatRectFromXYWH(0.0f, 0.0f, 0.0f, 0.0f)) {}
+
+ PP_Resource resource;
+ PP_FloatRect source_rect;
+ };
+
+ struct TextureLayer {
+ TextureLayer()
+ : sync_point(0),
+ source_rect(PP_MakeFloatRectFromXYWH(0.0f, 0.0f, 1.0f, 1.0f)),
+ premult_alpha(true) {}
+
+ gpu::Mailbox mailbox;
+ uint32_t sync_point;
+ PP_FloatRect source_rect;
+ bool premult_alpha;
+ };
+
+ CompositorLayerData() {}
+
+ CompositorLayerData(const CompositorLayerData& other) {
+ *this = other;
+ }
+
+ bool is_null() const {
+ return !(color || texture || image);
+ }
+
+ bool is_valid() const {
+ int i = 0;
+ if (color) ++i;
+ if (texture) ++i;
+ if (image) ++i;
+ return i == 1;
+ }
+
+ const CompositorLayerData& operator=(const CompositorLayerData& other);
+
+ LayerCommon common;
+ scoped_ptr<ColorLayer> color;
+ scoped_ptr<TextureLayer> texture;
+ scoped_ptr<ImageLayer> image;
+};
+
+} // namespace ppapi
+
+#endif // PPAPI_SHARED_IMPL_COMPOSITOR_LAYER_DATA_H_