Chromium Code Reviews| Index: ppapi/proxy/compositor_layer_resource.cc |
| diff --git a/ppapi/proxy/compositor_layer_resource.cc b/ppapi/proxy/compositor_layer_resource.cc |
| index 829ff187391503fd4141c9eb5a11a5459728eb42..5cfdc91ee8ae38a92ee04cae7a1c956c228fece8 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,253 @@ 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(CompositorLayerData::TYPE_COLOR)) |
| + return PP_ERROR_BADARGUMENT; |
| + |
| + 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_.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( |
| + CompositorLayerData::TYPE_TEXTURE, release_callback); |
| + if (rv != PP_OK) |
| + return rv; |
| + |
| + 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(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_.resource_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( |
| + &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( |
| + CompositorLayerData::TYPE_IMAGE, release_callback); |
| + if (rv != PP_OK) |
| + return rv; |
| + |
| + 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_.size = size ? *size : desc.size; |
| + data_.resource_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( |
| + &OnImageReleased, |
| + ScopedPPResource(pp_resource()), // Keep layer alive. |
|
raymes
2014/06/10 05:00:37
Why do we need to keep the layer resource alive?
Peng
2014/06/10 11:44:22
Because any completion callback will be called wit
raymes
2014/06/11 00:21:06
But isn't it ok for the release callback to be cal
Peng
2014/06/11 01:43:11
Even if the CompositorLayerResource has been relea
raymes
2014/06/12 02:31:25
Ok that seems reasonable. Could you please add a c
Peng
2014/06/12 14:24:36
Done.
|
| + 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_.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_.transform); |
| + 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_.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_.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; |
| + } |
| + |
| + 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; |
| + case CompositorLayerData::TYPE_UNKNOWN: |
| + case CompositorLayerData::TYPE_COLOR: |
| + break; |
| + } |
| + 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_.type != CompositorLayerData::TYPE_TEXTURE) |
| + return PP_ERROR_BADARGUMENT; |
| + |
| + data_.texture.premult_alpha = PP_FromBool(premult); |
| + return PP_OK; |
| +} |
| + |
| +bool CompositorLayerResource::SetType(CompositorLayerData::Type type) { |
| + if (type != CompositorLayerData::TYPE_COLOR && |
| + type != CompositorLayerData::TYPE_TEXTURE && |
| + type != CompositorLayerData::TYPE_IMAGE) { |
| + NOTREACHED(); |
| + return false; |
| + } |
| + |
| + if (type != data_.type) { |
| + if (data_.type != CompositorLayerData::TYPE_UNKNOWN) |
| + return false; |
| + data_.type = type; |
| + } |
| + return true; |
| +} |
| + |
| +int32_t CompositorLayerResource::CheckForSetTextureAndImage( |
| + CompositorLayerData::Type 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 |