Chromium Code Reviews| 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 |