Index: ppapi/proxy/compositor_resource.cc |
diff --git a/ppapi/proxy/compositor_resource.cc b/ppapi/proxy/compositor_resource.cc |
index 497e58a5e6020b4ceef9c562453f7aae3944f762..a787eac4a8c5a27f6e600b4958f8f36c26f0c42e 100644 |
--- a/ppapi/proxy/compositor_resource.cc |
+++ b/ppapi/proxy/compositor_resource.cc |
@@ -4,12 +4,315 @@ |
#include "ppapi/proxy/compositor_resource.h" |
+#include <algorithm> |
+ |
+#include "base/logging.h" |
+#include "gpu/command_buffer/client/gles2_implementation.h" |
+#include "gpu/command_buffer/common/mailbox.h" |
+#include "ppapi/proxy/compositor_layer_resource.h" |
+#include "ppapi/proxy/ppapi_messages.h" |
+#include "ppapi/shared_impl/ppb_graphics_3d_shared.h" |
+#include "ppapi/shared_impl/var.h" |
+#include "ppapi/thunk/enter.h" |
+#include "ppapi/thunk/ppb_graphics_3d_api.h" |
+#include "ppapi/thunk/ppb_image_data_api.h" |
+ |
+using ppapi::thunk::EnterResourceNoLock; |
+using ppapi::thunk::PPB_Graphics3D_API; |
+ |
namespace ppapi { |
namespace proxy { |
+namespace { |
+ |
+class Scoped2DTextureBinder { |
+ public: |
+ Scoped2DTextureBinder(gpu::gles2::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: |
+ gpu::gles2::GLES2Implementation* gl_; |
+ int32_t old_id_; |
+}; |
+ |
+} // namespace |
+ |
+CompositorResource::LayerImpl::LayerImpl(CompositorResource* compositor) |
+ : compositor_(compositor), |
+ source_size_(PP_MakeFloatSize(0.0f, 0.0f)) { |
+} |
+ |
+CompositorResource::LayerImpl::~LayerImpl() {} |
+ |
+int32_t CompositorResource::LayerImpl::SetColor( |
+ uint8_t red, |
+ uint8_t green, |
+ uint8_t blue, |
+ uint8_t alpha, |
+ const struct PP_Size* size) { |
+ if (compositor_->IsInProgress()) |
+ return PP_ERROR_INPROGRESS; |
+ |
+ if (!SetType(CompositorLayerData::TYPE_COLOR)) |
+ return PP_ERROR_BADARGUMENT; |
+ |
+ if (!size) |
+ return PP_ERROR_BADARGUMENT; |
+ |
+ data_.color.red = red; |
+ data_.color.green = green; |
+ data_.color.blue = blue; |
+ data_.color.alpha = alpha; |
+ data_.size = *size; |
+ |
+ return PP_OK; |
+} |
+ |
+int32_t CompositorResource::LayerImpl::SetTexture( |
+ PP_Resource context, |
+ uint32_t texture, |
+ const struct PP_Size* size, |
+ const scoped_refptr<ppapi::TrackedCallback>& release_callback) { |
+ if (compositor_->IsInProgress()) |
+ return PP_ERROR_INPROGRESS; |
+ |
+ if (!SetType(CompositorLayerData::TYPE_TEXTURE)) |
+ return PP_ERROR_BADARGUMENT; |
+ |
+ // The layer's texture has been set and it is not committed. |
+ if (!release_callback_.is_null()) |
+ return PP_ERROR_INPROGRESS; |
+ |
+ EnterResourceNoLock<PPB_Graphics3D_API> enter(context, true); |
+ if (enter.failed()) |
+ return PP_ERROR_BADARGUMENT; |
+ |
+ if (!size || size->width <= 0 || size->height <= 0) |
+ return PP_ERROR_BADARGUMENT; |
+ |
+ // Do not allow using a block callback as a release callback. |
+ if (release_callback->is_blocking()) |
+ return PP_ERROR_BADARGUMENT; |
+ |
+ PPB_Graphics3D_Shared* graphics = |
+ static_cast<PPB_Graphics3D_Shared*>(enter.object()); |
+ |
+ gpu::gles2::GLES2Implementation* gl = graphics->gles2_impl(); |
+ Scoped2DTextureBinder scoped_2d_texture_binder(gl, texture); |
+ |
+ // Generate a Mailbox for the texture. |
+ gl->GenMailboxCHROMIUM(data_.texture.mailbox); |
+ gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, data_.texture.mailbox); |
+ |
+ // 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_.texture.id = compositor_->GenerateResourceId(); |
+ data_.texture.sync_point = gl->InsertSyncPointCHROMIUM(); |
+ data_.size = *size; |
+ data_.texture.source_rect.point = PP_MakeFloatPoint(0.0f, 0.0f); |
+ data_.texture.source_rect.size = source_size_; |
+ |
+ release_callback_ = base::Bind( |
+ &CompositorResource::LayerImpl::OnTextureReleased, |
+ AsWeakPtr(), |
+ ScopedPPResource(context), // Keep context alive |
+ texture, |
+ release_callback); |
+ |
+ return PP_OK_COMPLETIONPENDING; |
+} |
+ |
+int32_t CompositorResource::LayerImpl::SetImage( |
+ PP_Resource image_data, |
+ const struct PP_Size* size, |
+ const scoped_refptr<ppapi::TrackedCallback>& release_callback) { |
+ if (compositor_->IsInProgress()) |
+ return PP_ERROR_INPROGRESS; |
+ |
+ if (!SetType(CompositorLayerData::TYPE_IMAGE)) |
+ return PP_ERROR_BADARGUMENT; |
+ |
+ EnterResourceNoLock<thunk::PPB_ImageData_API> enter(image_data, true); |
+ if (enter.failed()) |
+ 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; |
+ |
+ 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; |
+ |
+ // Do not allow using a block callback as a release callback. |
+ if (release_callback->is_blocking()) |
+ 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_.size = size ? *size : desc.size; |
+ data_.image.id = compositor_->GenerateResourceId(); |
+ data_.image.instance = enter.resource()->host_resource().instance(); |
+ data_.image.host_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( |
+ &CompositorResource::LayerImpl::OnImageReleased, |
+ AsWeakPtr(), |
+ ScopedPPResource(image_data), // Keep image_data alive. |
+ release_callback); |
+ |
+ return PP_OK_COMPLETIONPENDING; |
+} |
+ |
+int32_t CompositorResource::LayerImpl::SetClipRect(const struct PP_Rect* rect) { |
+ if (compositor_->IsInProgress()) |
+ return PP_ERROR_INPROGRESS; |
+ |
+ data_.clip_rect = rect ? *rect : PP_MakeRectFromXYWH(0, 0, 0, 0); |
+ return PP_OK; |
+} |
+ |
+int32_t CompositorResource::LayerImpl::SetTransform(const float matrix[16]) { |
+ if (compositor_->IsInProgress()) |
+ return PP_ERROR_INPROGRESS; |
+ |
+ std::copy(matrix, matrix + 16, data_.transform); |
+ return PP_OK; |
+} |
+ |
+int32_t CompositorResource::LayerImpl::SetOpacity(uint8_t opacity) { |
+ if (compositor_->IsInProgress()) |
+ return PP_ERROR_INPROGRESS; |
+ |
+ data_.opacity = opacity; |
+ return PP_OK; |
+} |
+ |
+int32_t CompositorResource::LayerImpl::SetBlendMode(PP_BlendMode mode) { |
+ if (compositor_->IsInProgress()) |
+ return PP_ERROR_INPROGRESS; |
+ |
+ switch (mode) { |
+ case PP_BLENDMODE_NONE: |
+ case PP_BLENDMODE_SRC_OVER: |
+ data_.blend_mode = mode; |
+ return PP_OK; |
+ default: |
+ break; |
raymes
2014/06/03 00:43:22
nit: get rid of the default: case altogether (and
Peng
2014/06/03 18:32:24
I tried without default:. The compiler will give a
raymes
2014/06/04 01:11:38
This is because it is missing PP_BLENDMODE_LAST. I
Peng
2014/06/05 00:50:38
Done.
|
+ } |
+ return PP_ERROR_BADARGUMENT; |
+} |
+ |
+int32_t CompositorResource::LayerImpl::SetSourceRect( |
+ const struct PP_FloatRect* rect) { |
+ 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; |
+ |
+ switch (data_.type) { |
+ case CompositorLayerData::TYPE_TEXTURE: |
+ data_.texture.source_rect = *rect; |
+ return PP_OK; |
+ case CompositorLayerData::TYPE_IMAGE: |
+ data_.image.source_rect = *rect; |
+ return PP_OK; |
+ default: |
+ break; |
+ } |
+ return PP_ERROR_BADARGUMENT; |
+} |
+ |
+int32_t CompositorResource::LayerImpl::SetPremultipliedAlpha(PP_Bool premult) { |
+ if (compositor_->IsInProgress()) |
+ return PP_ERROR_INPROGRESS; |
+ |
+ if (data_.type != CompositorLayerData::TYPE_TEXTURE) |
+ return PP_ERROR_BADARGUMENT; |
+ |
+ data_.texture.premult_alpha = PP_FromBool(premult); |
+ return PP_OK; |
+} |
+ |
+bool CompositorResource::LayerImpl::SetType(CompositorLayerData::Type type) { |
+ DCHECK(type == CompositorLayerData::TYPE_COLOR || |
+ type == CompositorLayerData::TYPE_TEXTURE || |
+ type == CompositorLayerData::TYPE_IMAGE); |
+ if (type != data_.type) { |
+ if (data_.type != CompositorLayerData::TYPE_UNKNOWN) |
+ return false; |
+ data_.type = type; |
+ } |
+ return true; |
+} |
+ |
+void CompositorResource::LayerImpl::OnTextureReleased( |
+ const ScopedPPResource& context, |
+ uint32_t texture, |
+ const scoped_refptr<TrackedCallback>& release_callback, |
+ uint32_t sync_point, |
+ bool is_lost) { |
+ 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()); |
+ |
+ gpu::gles2::GLES2Implementation* gl = graphics->gles2_impl(); |
+ gl->WaitSyncPointCHROMIUM(sync_point); |
+ } while (false); |
+ |
+ release_callback->Run(PP_OK); |
+} |
+ |
+void CompositorResource::LayerImpl::OnImageReleased( |
+ const ScopedPPResource& image, |
+ const scoped_refptr<TrackedCallback>& release_callback, |
+ uint32_t sync_point, |
+ bool is_lost) { |
+ release_callback->Run(PP_OK); |
+} |
+ |
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() { |
@@ -19,17 +322,129 @@ 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; |
+ LayerImpl* layer = new LayerImpl(this); |
+ layers_.push_back(layer); |
+ CompositorLayerResource *resource = new CompositorLayerResource( |
+ connection(), pp_instance(), layer->AsWeakPtr()); |
+ 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 (ScopedVector<LayerImpl>::const_iterator it = layers_.begin(); |
+ it != layers_.end(); ++it) { |
+ switch ((*it)->data().type) { |
+ case CompositorLayerData::TYPE_UNKNOWN: |
+ return PP_ERROR_FAILED; |
+ case CompositorLayerData::TYPE_COLOR: |
+ case CompositorLayerData::TYPE_TEXTURE: |
+ case CompositorLayerData::TYPE_IMAGE: |
+ layers.push_back((*it)->data()); |
+ continue; |
+ default: |
+ NOTREACHED(); |
+ } |
+ } |
+ |
+ 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; |
+ |
+ // Call release_callback for every layer. |
+ for (ScopedVector<LayerImpl>::iterator it = layers_.begin(); |
+ it != layers_.end(); ++it) { |
+ ReleaseCallback release_callback = (*it)->release_callback(); |
+ if (!release_callback.is_null()) |
+ release_callback.Run(0, false); |
+ } |
+ |
+ layers_.clear(); |
+ layer_reset_ = true; |
+ 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 (ScopedVector<LayerImpl>::iterator it = layers_.begin(); |
+ it != layers_.end(); ++it) { |
+ switch ((*it)->data().type) { |
+ case CompositorLayerData::TYPE_TEXTURE: { |
+ ReleaseCallback release_callback = (*it)->release_callback(); |
+ (*it)->ResetReleaseCallback(); |
+ if (!release_callback.is_null()) { |
+ release_callback_map_.insert(ReleaseCallbackMap::value_type( |
+ (*it)->data().texture.id, release_callback)); |
+ } |
+ break; |
+ } |
+ case CompositorLayerData::TYPE_IMAGE: { |
+ ReleaseCallback release_callback = (*it)->release_callback(); |
+ (*it)->ResetReleaseCallback(); |
+ if (!release_callback.is_null()) { |
+ release_callback_map_.insert(ReleaseCallbackMap::value_type( |
+ (*it)->data().image.id, release_callback)); |
+ } |
+ break; |
+ } |
+ default: |
+ break; |
+ } |
+ } |
+ } |
+ |
+ 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); |
} |
} // namespace proxy |