OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/renderer/pepper/pepper_compositor_host.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/memory/shared_memory.h" | |
9 #include "cc/layers/layer.h" | |
10 #include "cc/layers/solid_color_layer.h" | |
11 #include "cc/layers/texture_layer.h" | |
12 #include "cc/resources/texture_mailbox.h" | |
13 #include "content/public/renderer/renderer_ppapi_host.h" | |
14 #include "content/renderer/pepper/gfx_conversion.h" | |
15 #include "content/renderer/pepper/host_globals.h" | |
16 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" | |
17 #include "content/renderer/pepper/ppb_image_data_impl.h" | |
18 #include "ppapi/c/pp_errors.h" | |
19 #include "ppapi/host/dispatch_host_message.h" | |
20 #include "ppapi/host/ppapi_host.h" | |
21 #include "ppapi/proxy/ppapi_messages.h" | |
22 #include "ppapi/thunk/enter.h" | |
23 #include "ppapi/thunk/ppb_image_data_api.h" | |
24 #include "third_party/khronos/GLES2/gl2.h" | |
25 #include "ui/gfx/transform.h" | |
26 | |
27 using ppapi::host::HostMessageContext; | |
28 using ppapi::thunk::EnterResourceNoLock; | |
29 using ppapi::thunk::PPB_ImageData_API; | |
30 | |
31 namespace content { | |
32 | |
33 PepperCompositorHost::PepperCompositorHost( | |
34 RendererPpapiHost* host, | |
35 PP_Instance instance, | |
36 PP_Resource resource) | |
37 : ResourceHost(host->GetPpapiHost(), instance, resource), | |
38 bound_instance_(NULL), | |
39 weak_factory_(this) { | |
40 layer_ = cc::Layer::Create(); | |
41 // TODO(penghuang): SetMasksToBounds() can be expensive if the layer is | |
42 // transformed. Possibly better could be to explicitly clip the child layers | |
43 // (by modifying their bounds). | |
44 layer_->SetMasksToBounds(true); | |
45 layer_->SetIsDrawable(true); | |
46 } | |
47 | |
48 PepperCompositorHost::~PepperCompositorHost() { | |
49 // Unbind from the instance when destroyed if we're still bound. | |
50 if (bound_instance_) | |
51 bound_instance_->BindGraphics(bound_instance_->pp_instance(), 0); | |
52 } | |
53 | |
54 bool PepperCompositorHost::BindToInstance( | |
55 PepperPluginInstanceImpl* new_instance) { | |
56 if (new_instance && new_instance->pp_instance() != pp_instance()) | |
57 return false; // Can't bind other instance's contexts. | |
58 if (bound_instance_ == new_instance) | |
59 return true; // Rebinding the same device, nothing to do. | |
60 if (bound_instance_ && new_instance) { | |
61 NOTREACHED(); | |
piman
2014/06/09 18:27:24
Then just DCHECK. No need to pay the cost of doing
Peng
2014/06/10 16:20:28
Done.
| |
62 return false; // Can't change a bound device. | |
63 } | |
64 bound_instance_ = new_instance; | |
65 return true; | |
66 } | |
67 | |
68 void PepperCompositorHost::ViewInitiatedPaint() { | |
69 if (!commit_layers_reply_context_.is_valid()) | |
70 return; | |
71 host()->SendReply(commit_layers_reply_context_, | |
72 PpapiPluginMsg_Compositor_CommitLayersReply()); | |
73 commit_layers_reply_context_ = ppapi::host::ReplyMessageContext(); | |
74 } | |
75 | |
76 void PepperCompositorHost::ViewFlushedPaint() {} | |
77 | |
78 void PepperCompositorHost::ResourceReleased(int32_t id, | |
79 uint32_t sync_point, | |
80 bool is_lost) { | |
81 host()->SendUnsolicitedReply( | |
82 pp_resource(), | |
83 PpapiPluginMsg_Compositor_ReleaseResource(id, sync_point, is_lost)); | |
84 } | |
85 | |
86 void PepperCompositorHost::ImageReleased( | |
87 int32_t id, | |
88 const scoped_ptr<base::SharedMemory>& shared_memory, | |
89 uint32_t sync_point, | |
90 bool is_lost) { | |
91 ResourceReleased(id, sync_point, is_lost); | |
92 } | |
93 | |
94 int32_t PepperCompositorHost::OnResourceMessageReceived( | |
95 const IPC::Message& msg, | |
96 HostMessageContext* context) { | |
97 PPAPI_BEGIN_MESSAGE_MAP(PepperCompositorHost, msg) | |
98 PPAPI_DISPATCH_HOST_RESOURCE_CALL( | |
99 PpapiHostMsg_Compositor_CommitLayers, OnHostMsgCommitLayers) | |
100 PPAPI_END_MESSAGE_MAP() | |
101 return ppapi::host::ResourceHost::OnResourceMessageReceived(msg, context); | |
102 } | |
103 | |
104 bool PepperCompositorHost::IsCompositorHost() { | |
105 return true; | |
106 } | |
107 | |
108 int32_t PepperCompositorHost::VerifyCommittedLayers( | |
109 const std::vector<ppapi::CompositorLayerData>& layers, | |
110 bool reset) { | |
111 for (size_t i = 0; i < layers.size(); ++i) { | |
112 const ppapi::CompositorLayerData& pp_layer = layers[i]; | |
113 // Make sure the layer type is not changed. | |
114 if (!reset) { | |
115 const LayerData* data = i >= layers_.size() ? NULL : &layers_[i]; | |
116 DCHECK(!data || data->cc_layer); | |
117 const ppapi::CompositorLayerData* old_layer = | |
118 data ? &data->pp_layer : NULL; | |
119 if (old_layer && old_layer->type != pp_layer.type) { | |
120 NOTREACHED(); | |
121 return PP_ERROR_BADARGUMENT; | |
122 } | |
123 } | |
124 | |
125 if (pp_layer.type == ppapi::CompositorLayerData::TYPE_COLOR || | |
126 pp_layer.type == ppapi::CompositorLayerData::TYPE_TEXTURE) { | |
127 continue; | |
128 } | |
129 | |
130 // Check image layer. | |
131 if (pp_layer.type == ppapi::CompositorLayerData::TYPE_IMAGE) { | |
132 EnterResourceNoLock<PPB_ImageData_API> enter( | |
133 pp_layer.image.host_resource, true); | |
134 if (enter.failed()) { | |
135 NOTREACHED(); | |
136 return PP_ERROR_BADRESOURCE; | |
137 } | |
138 | |
139 // TODO(penghuang): support all kinds of image. | |
140 PP_ImageDataDesc desc; | |
141 if (enter.object()->Describe(&desc) != PP_TRUE || | |
142 desc.stride != desc.size.width * 4 || | |
143 desc.format != PP_IMAGEDATAFORMAT_RGBA_PREMUL) { | |
144 NOTREACHED(); | |
145 return PP_ERROR_BADARGUMENT; | |
146 } | |
147 | |
148 int handle; | |
149 uint32_t byte_count; | |
150 if (enter.object()->GetSharedMemory(&handle, &byte_count) != PP_OK) | |
151 return PP_ERROR_FAILED; | |
152 continue; | |
153 } | |
154 return PP_ERROR_BADARGUMENT; | |
155 } | |
156 return PP_OK; | |
157 } | |
158 | |
159 void PepperCompositorHost::UpdateLayer( | |
160 const scoped_refptr<cc::Layer>& layer, | |
161 const ppapi::CompositorLayerData* old_layer, | |
162 const ppapi::CompositorLayerData* new_layer) { | |
163 DCHECK(!old_layer || new_layer->type == old_layer->type); | |
164 | |
165 // Always update properties on cc::Layer, because cc::Layer | |
166 // will ignore any setting with unchanged value. | |
167 layer->SetIsDrawable(true); | |
168 layer->SetAnchorPoint(gfx::PointF()); | |
169 layer->SetBlendMode(SkXfermode::kSrcOver_Mode); | |
170 layer->SetOpacity(new_layer->opacity); | |
171 | |
172 gfx::Transform transform(gfx::Transform::kSkipInitialization); | |
173 transform.matrix().setColMajorf(new_layer->transform); | |
174 layer->SetTransform(transform); | |
175 | |
176 // Consider a (0,0,0,0) rect as no clip rect. | |
177 if (new_layer->clip_rect.point.x != 0 || | |
178 new_layer->clip_rect.point.y != 0 || | |
179 new_layer->clip_rect.size.width != 0 || | |
180 new_layer->clip_rect.size.height != 0) { | |
181 gfx::Rect clip = PP_ToGfxRect(new_layer->clip_rect); | |
182 gfx::RectF clipf(clip.x(), clip.y(), clip.width(), clip.height()); | |
183 bool rv = transform.TransformRectReverse(&clipf); | |
184 DCHECK(rv); | |
185 gfx::Size size(clipf.width(), clipf.height()); | |
186 size.SetToMin(PP_ToGfxSize(new_layer->size)); | |
187 layer->SetBounds(size); | |
188 layer->SetPosition(gfx::Point(clipf.x(), clipf.y())); | |
189 } else { | |
190 layer->SetBounds(PP_ToGfxSize(new_layer->size)); | |
191 layer->SetPosition(gfx::Point()); | |
192 } | |
193 | |
194 if (new_layer->type == ppapi::CompositorLayerData::TYPE_COLOR) { | |
195 layer->SetBackgroundColor(SkColorSetARGBMacro(new_layer->color.alpha * 255, | |
196 new_layer->color.red * 255, | |
197 new_layer->color.green * 255, | |
198 new_layer->color.blue * 255)); | |
199 } else if (new_layer->type == ppapi::CompositorLayerData::TYPE_TEXTURE) { | |
200 scoped_refptr<cc::TextureLayer> texture_layer( | |
201 static_cast<cc::TextureLayer*>(layer.get())); | |
202 if (!old_layer || new_layer->resource_id != old_layer->resource_id) { | |
203 gpu::Mailbox gpu_mailbox; | |
204 gpu_mailbox.SetName(new_layer->texture.mailbox); | |
205 cc::TextureMailbox mailbox(gpu_mailbox, | |
206 GL_TEXTURE_2D, | |
207 new_layer->texture.sync_point); | |
208 texture_layer->SetTextureMailbox(mailbox, | |
209 cc::SingleReleaseCallback::Create( | |
210 base::Bind(&PepperCompositorHost::ResourceReleased, | |
211 weak_factory_.GetWeakPtr(), | |
212 new_layer->resource_id)));; | |
213 } | |
214 texture_layer->SetPremultipliedAlpha(new_layer->texture.premult_alpha); | |
215 gfx::RectF rect = PP_ToGfxRectF(new_layer->texture.source_rect); | |
216 texture_layer->SetUV(rect.origin(), rect.bottom_right()); | |
217 } else if (new_layer->type == ppapi::CompositorLayerData::TYPE_IMAGE) { | |
218 if (!old_layer || new_layer->resource_id != old_layer->resource_id) { | |
219 scoped_refptr<cc::TextureLayer> image_layer( | |
220 static_cast<cc::TextureLayer*>(layer.get())); | |
221 EnterResourceNoLock<PPB_ImageData_API> enter( | |
222 new_layer->image.host_resource, true); | |
223 DCHECK(enter.succeeded()); | |
224 PP_ImageDataDesc desc; | |
225 { | |
226 PP_Bool rv = enter.object()->Describe(&desc); | |
227 DCHECK_EQ(rv, PP_TRUE); | |
228 } | |
229 int handle; | |
230 uint32_t byte_count; | |
231 { | |
232 int32_t rv = enter.object()->GetSharedMemory(&handle, &byte_count); | |
233 DCHECK_EQ(rv, PP_OK); | |
234 } | |
235 #if defined(OS_WIN) | |
236 base::SharedMemoryHandle shm_handle = | |
237 static_cast<base::SharedMemoryHandle>(_dup(handle)); | |
238 #else | |
239 base::SharedMemoryHandle shm_handle(dup(handle), false); | |
240 #endif | |
241 // Use a scoped_ptr to keep shared_memory alive until | |
242 // PepperCompositorHost::ImageReleased is called. | |
243 scoped_ptr<base::SharedMemory> shared_memory( | |
244 new base::SharedMemory(shm_handle, true)); | |
245 CHECK(shared_memory->Map(desc.stride * desc.size.height)); | |
246 cc::TextureMailbox mailbox(shared_memory.get(), | |
247 PP_ToGfxSize(desc.size)); | |
248 image_layer->SetTextureMailbox(mailbox, | |
249 cc::SingleReleaseCallback::Create( | |
250 base::Bind(&PepperCompositorHost::ImageReleased, | |
251 weak_factory_.GetWeakPtr(), | |
252 new_layer->resource_id, | |
253 base::Passed(&shared_memory)))); | |
254 | |
255 // ImageData is always premultiplied alpha. | |
256 image_layer->SetPremultipliedAlpha(true); | |
257 } | |
258 } | |
259 } | |
260 | |
261 int32_t PepperCompositorHost::OnHostMsgCommitLayers( | |
262 HostMessageContext* context, | |
263 const std::vector<ppapi::CompositorLayerData>& layers, | |
264 bool reset) { | |
265 // Do not support CommitLayers() on an unbounded compositor. | |
266 if (!bound_instance_) | |
267 return PP_ERROR_FAILED; | |
268 | |
269 if (commit_layers_reply_context_.is_valid()) { | |
270 NOTREACHED(); | |
271 return PP_ERROR_INPROGRESS; | |
272 } | |
273 | |
274 commit_layers_reply_context_ = context->MakeReplyMessageContext(); | |
275 | |
276 // Verfiy the layers first, if an error happens, we will return the error to | |
277 // plugin and keep current layers set by the previous CommitLayers() | |
278 // unchanged. | |
279 int32_t rv = VerifyCommittedLayers(layers, reset); | |
280 if (rv != PP_OK) | |
281 return rv; | |
282 | |
283 // ResetLayers() has been called, we need rebuild layer stack. | |
284 if (reset) { | |
285 layer_->RemoveAllChildren(); | |
286 layers_.clear(); | |
287 } | |
288 | |
289 for (size_t i = 0; i < layers.size(); ++i) { | |
290 const ppapi::CompositorLayerData& pp_layer = layers[i]; | |
291 LayerData* data = i >= layers_.size() ? NULL : &layers_[i]; | |
292 DCHECK(!data || data->cc_layer); | |
293 scoped_refptr<cc::Layer> cc_layer = data ? data->cc_layer : NULL; | |
294 ppapi::CompositorLayerData* old_layer = data ? &data->pp_layer : NULL; | |
295 | |
296 if (!cc_layer) { | |
297 if (pp_layer.type == ppapi::CompositorLayerData::TYPE_COLOR) { | |
298 cc_layer = cc::SolidColorLayer::Create(); | |
299 } else if (pp_layer.type == ppapi::CompositorLayerData::TYPE_TEXTURE || | |
300 pp_layer.type == ppapi::CompositorLayerData::TYPE_IMAGE) { | |
301 cc_layer = cc::TextureLayer::CreateForMailbox(NULL); | |
302 } | |
303 } | |
304 | |
305 UpdateLayer(cc_layer, old_layer, &pp_layer); | |
306 | |
307 if (old_layer) { | |
308 *old_layer = pp_layer; | |
309 } else { | |
310 layer_->AddChild(cc_layer); | |
311 layers_.push_back(LayerData(cc_layer, pp_layer)); | |
312 } | |
313 } | |
314 | |
315 return PP_OK_COMPLETIONPENDING; | |
316 } | |
317 | |
318 } // namespace content | |
OLD | NEW |