Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(145)

Side by Side Diff: content/renderer/pepper/pepper_compositor_host.cc

Issue 298023004: [PPAPI] Compositor API implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@compositor_api_def_new
Patch Set: Fix review issues and rebase Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 namespace {
34
35 int32_t VerifyCommittedLayer(
36 const ppapi::CompositorLayerData* old_layer,
37 const ppapi::CompositorLayerData* new_layer) {
38 if (old_layer && old_layer->type != new_layer->type)
39 return PP_ERROR_BADARGUMENT;
40
41 if (new_layer->type == ppapi::CompositorLayerData::TYPE_COLOR)
42 return PP_OK;
43
44 // Check texture layer.
45 if (new_layer->type == ppapi::CompositorLayerData::TYPE_TEXTURE) {
46 if (old_layer && new_layer->resource_id == old_layer->resource_id) {
47 if (memcmp(new_layer->texture.mailbox,
48 old_layer->texture.mailbox,
49 sizeof(ppapi::CompositorLayerData::Mailbox)) != 0) {
50 return PP_ERROR_BADARGUMENT;
51 }
52 } else {
53 gpu::Mailbox gpu_mailbox;
54 gpu_mailbox.SetName(new_layer->texture.mailbox);
55 if (!gpu_mailbox.Verify())
56 return PP_ERROR_BADARGUMENT;
57 }
58 return PP_OK;
59 }
60
61 // Check image layer.
62 if (new_layer->type == ppapi::CompositorLayerData::TYPE_IMAGE) {
63 if (old_layer && new_layer->resource_id == old_layer->resource_id) {
64 if (new_layer->image.host_resource != old_layer->image.host_resource)
65 return PP_ERROR_BADARGUMENT;
66 } else {
67 EnterResourceNoLock<PPB_ImageData_API> enter(
68 new_layer->image.host_resource, true);
69 if (enter.failed())
70 return PP_ERROR_BADRESOURCE;
71
72 // TODO(penghuang): support all kinds of image.
73 PP_ImageDataDesc desc;
74 if (enter.object()->Describe(&desc) != PP_TRUE ||
75 desc.stride != desc.size.width * 4 ||
76 desc.format != PP_IMAGEDATAFORMAT_RGBA_PREMUL) {
77 return PP_ERROR_BADARGUMENT;
78 }
79
80 int handle;
81 uint32_t byte_count;
82 if (enter.object()->GetSharedMemory(&handle, &byte_count) != PP_OK)
83 return PP_ERROR_FAILED;
84 }
85 return PP_OK;
86 }
87 return PP_ERROR_BADARGUMENT;
88 }
89
90 } // namespace
91
92 PepperCompositorHost::PepperCompositorHost(
93 RendererPpapiHost* host,
94 PP_Instance instance,
95 PP_Resource resource)
96 : ResourceHost(host->GetPpapiHost(), instance, resource),
97 bound_instance_(NULL),
98 weak_factory_(this) {
99 layer_ = cc::Layer::Create();
100 // TODO(penghuang): SetMasksToBounds() can be expensive if the layer is
101 // transformed. Possibly better could be to explicitly clip the child layers
102 // (by modifying their bounds).
103 layer_->SetMasksToBounds(true);
104 layer_->SetIsDrawable(true);
105 }
106
107 PepperCompositorHost::~PepperCompositorHost() {
108 // Unbind from the instance when destroyed if we're still bound.
109 if (bound_instance_)
110 bound_instance_->BindGraphics(bound_instance_->pp_instance(), 0);
111 }
112
113 bool PepperCompositorHost::BindToInstance(
114 PepperPluginInstanceImpl* new_instance) {
115 if (new_instance && new_instance->pp_instance() != pp_instance())
116 return false; // Can't bind other instance's contexts.
117 if (bound_instance_ == new_instance)
118 return true; // Rebinding the same device, nothing to do.
119 if (bound_instance_ && new_instance)
120 return false; // Can't change a bound device.
121 bound_instance_ = new_instance;
122 return true;
123 }
124
125 void PepperCompositorHost::ViewInitiatedPaint() {
126 if (!commit_layers_reply_context_.is_valid())
127 return;
128 host()->SendReply(commit_layers_reply_context_,
129 PpapiPluginMsg_Compositor_CommitLayersReply());
130 commit_layers_reply_context_ = ppapi::host::ReplyMessageContext();
131 }
132
133 void PepperCompositorHost::ViewFlushedPaint() {}
134
135 void PepperCompositorHost::UpdateLayer(
136 const scoped_refptr<cc::Layer>& layer,
137 const ppapi::CompositorLayerData* old_layer,
138 const ppapi::CompositorLayerData* new_layer) {
139 DCHECK(!old_layer || new_layer->type == old_layer->type);
140
141 // Always update properties on cc::Layer, because cc::Layer
142 // will ignore any setting with unchanged value.
143 layer->SetIsDrawable(true);
144 layer->SetBlendMode(SkXfermode::kSrcOver_Mode);
145 layer->SetOpacity(new_layer->opacity);
146 layer->SetBounds(PP_ToGfxSize(new_layer->size));
147 layer->SetTransformOrigin(gfx::Point3F(
148 new_layer->size.width / 2, new_layer->size.height / 2, 0.0f));
149
150 gfx::Transform transform(gfx::Transform::kSkipInitialization);
151 transform.matrix().setColMajorf(new_layer->transform);
152 layer->SetTransform(transform);
153
154 // Consider a (0,0,0,0) rect as no clip rect.
155 if (new_layer->clip_rect.point.x != 0 ||
156 new_layer->clip_rect.point.y != 0 ||
157 new_layer->clip_rect.size.width != 0 ||
158 new_layer->clip_rect.size.height != 0) {
159 scoped_refptr<cc::Layer> clip_parent = layer->parent();
160 if (clip_parent == layer_) {
161 // Create a clip parent layer, if it does not exist.
162 clip_parent = cc::Layer::Create();
163 clip_parent->SetMasksToBounds(true);
164 clip_parent->SetIsDrawable(true);
165 layer_->ReplaceChild(layer, clip_parent);
166 clip_parent->AddChild(layer);
167 }
168 gfx::Point position = PP_ToGfxPoint(new_layer->clip_rect.point);
169 clip_parent->SetPosition(position);
170 clip_parent->SetBounds(PP_ToGfxSize(new_layer->clip_rect.size));
171 layer->SetPosition(gfx::Point(-position.x(), -position.y()));
172 } else if (layer->parent() != layer_) {
173 // Remove the clip parent layer.
174 layer_->ReplaceChild(layer->parent(), layer);
175 layer->SetPosition(gfx::Point());
176 }
177
178 if (new_layer->type == ppapi::CompositorLayerData::TYPE_COLOR) {
179 layer->SetBackgroundColor(SkColorSetARGBMacro(new_layer->color.alpha * 255,
180 new_layer->color.red * 255,
181 new_layer->color.green * 255,
182 new_layer->color.blue * 255));
183 } else if (new_layer->type == ppapi::CompositorLayerData::TYPE_TEXTURE) {
184 scoped_refptr<cc::TextureLayer> texture_layer(
185 static_cast<cc::TextureLayer*>(layer.get()));
186 if (!old_layer || new_layer->resource_id != old_layer->resource_id) {
187 gpu::Mailbox gpu_mailbox;
188 gpu_mailbox.SetName(new_layer->texture.mailbox);
189 DCHECK(gpu_mailbox.Verify());
190 cc::TextureMailbox mailbox(gpu_mailbox,
191 GL_TEXTURE_2D,
192 new_layer->texture.sync_point);
193 texture_layer->SetTextureMailbox(mailbox,
194 cc::SingleReleaseCallback::Create(
195 base::Bind(&PepperCompositorHost::ResourceReleased,
196 weak_factory_.GetWeakPtr(),
197 new_layer->resource_id)));;
198 }
199 texture_layer->SetPremultipliedAlpha(new_layer->texture.premult_alpha);
200 gfx::RectF rect = PP_ToGfxRectF(new_layer->texture.source_rect);
201 texture_layer->SetUV(rect.origin(), rect.bottom_right());
202 } else if (new_layer->type == ppapi::CompositorLayerData::TYPE_IMAGE) {
203 if (!old_layer || new_layer->resource_id != old_layer->resource_id) {
204 scoped_refptr<cc::TextureLayer> image_layer(
205 static_cast<cc::TextureLayer*>(layer.get()));
206 EnterResourceNoLock<PPB_ImageData_API> enter(
207 new_layer->image.host_resource, true);
208 DCHECK(enter.succeeded());
209 PP_ImageDataDesc desc;
210 {
211 PP_Bool rv = enter.object()->Describe(&desc);
212 DCHECK_EQ(rv, PP_TRUE);
213 }
214 int handle;
215 uint32_t byte_count;
216 {
217 int32_t rv = enter.object()->GetSharedMemory(&handle, &byte_count);
218 DCHECK_EQ(rv, PP_OK);
219 }
220 #if defined(OS_WIN)
221 base::SharedMemoryHandle shm_handle =
222 static_cast<base::SharedMemoryHandle>(_dup(handle));
223 #else
224 base::SharedMemoryHandle shm_handle(dup(handle), false);
225 #endif
226 // Use a scoped_ptr to keep shared_memory alive until
227 // PepperCompositorHost::ImageReleased is called.
228 scoped_ptr<base::SharedMemory> shared_memory(
229 new base::SharedMemory(shm_handle, true));
230 shared_memory->Map(desc.stride * desc.size.height);
231 cc::TextureMailbox mailbox(shared_memory.get(),
232 PP_ToGfxSize(desc.size));
233 image_layer->SetTextureMailbox(mailbox,
234 cc::SingleReleaseCallback::Create(
235 base::Bind(&PepperCompositorHost::ImageReleased,
236 weak_factory_.GetWeakPtr(),
237 new_layer->resource_id,
238 base::Passed(&shared_memory))));
239
240 // ImageData is always premultiplied alpha.
241 image_layer->SetPremultipliedAlpha(true);
242 }
243 }
244 }
245
246 void PepperCompositorHost::ResourceReleased(int32_t id,
247 uint32_t sync_point,
248 bool is_lost) {
249 host()->SendUnsolicitedReply(
250 pp_resource(),
251 PpapiPluginMsg_Compositor_ReleaseResource(id, sync_point, is_lost));
252 }
253
254 void PepperCompositorHost::ImageReleased(
255 int32_t id,
256 const scoped_ptr<base::SharedMemory>& shared_memory,
257 uint32_t sync_point,
258 bool is_lost) {
259 ResourceReleased(id, sync_point, is_lost);
260 }
261
262 int32_t PepperCompositorHost::OnResourceMessageReceived(
263 const IPC::Message& msg,
264 HostMessageContext* context) {
265 PPAPI_BEGIN_MESSAGE_MAP(PepperCompositorHost, msg)
266 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
267 PpapiHostMsg_Compositor_CommitLayers, OnHostMsgCommitLayers)
268 PPAPI_END_MESSAGE_MAP()
269 return ppapi::host::ResourceHost::OnResourceMessageReceived(msg, context);
270 }
271
272 bool PepperCompositorHost::IsCompositorHost() {
273 return true;
274 }
275
276 int32_t PepperCompositorHost::OnHostMsgCommitLayers(
277 HostMessageContext* context,
278 const std::vector<ppapi::CompositorLayerData>& layers,
279 bool reset) {
280 // Do not support CommitLayers() on an unbounded compositor.
281 if (!bound_instance_)
282 return PP_ERROR_FAILED;
283
284 if (commit_layers_reply_context_.is_valid())
285 return PP_ERROR_INPROGRESS;
286
287 commit_layers_reply_context_ = context->MakeReplyMessageContext();
288
289 // Verfiy the layers first, if an error happens, we will return the error to
290 // plugin and keep current layers set by the previous CommitLayers()
291 // unchanged.
292 for (size_t i = 0; i < layers.size(); ++i) {
293 const ppapi::CompositorLayerData* old_layer = NULL;
294 if (!reset && i < layers_.size())
295 old_layer = &layers_[i].pp_layer;
296 int32_t rv = VerifyCommittedLayer(old_layer, &layers[i]);
297 if (rv != PP_OK)
298 return rv;
299 }
300
301 // ResetLayers() has been called, we need rebuild layer stack.
302 if (reset) {
303 layer_->RemoveAllChildren();
304 layers_.clear();
305 }
306
307 for (size_t i = 0; i < layers.size(); ++i) {
308 const ppapi::CompositorLayerData* pp_layer = &layers[i];
309 LayerData* data = i >= layers_.size() ? NULL : &layers_[i];
310 DCHECK(!data || data->cc_layer);
311 scoped_refptr<cc::Layer> cc_layer = data ? data->cc_layer : NULL;
312 ppapi::CompositorLayerData* old_layer = data ? &data->pp_layer : NULL;
313
314 if (!cc_layer) {
315 if (pp_layer->type == ppapi::CompositorLayerData::TYPE_COLOR) {
316 cc_layer = cc::SolidColorLayer::Create();
317 } else if (pp_layer->type == ppapi::CompositorLayerData::TYPE_TEXTURE ||
318 pp_layer->type == ppapi::CompositorLayerData::TYPE_IMAGE) {
319 cc_layer = cc::TextureLayer::CreateForMailbox(NULL);
320 }
321 layer_->AddChild(cc_layer);
322 }
323
324 UpdateLayer(cc_layer, old_layer, pp_layer);
325
326 if (old_layer) {
327 *old_layer = *pp_layer;
328 } else {
329 layers_.push_back(LayerData(cc_layer, *pp_layer));
330 }
331 }
332
333 return PP_OK_COMPLETIONPENDING;
334 }
335
336 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698