• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "ppapi/proxy/compositor_layer_resource.h"
6 
7 #include "base/logging.h"
8 #include "gpu/command_buffer/client/gles2_implementation.h"
9 #include "gpu/command_buffer/common/mailbox.h"
10 #include "ppapi/proxy/compositor_resource.h"
11 #include "ppapi/shared_impl/ppb_graphics_3d_shared.h"
12 #include "ppapi/thunk/enter.h"
13 #include "ppapi/thunk/ppb_graphics_3d_api.h"
14 #include "ppapi/thunk/ppb_image_data_api.h"
15 
16 using gpu::gles2::GLES2Implementation;
17 using ppapi::thunk::EnterResourceNoLock;
18 using ppapi::thunk::PPB_ImageData_API;
19 using ppapi::thunk::PPB_Graphics3D_API;
20 
21 namespace ppapi {
22 namespace proxy {
23 
24 namespace {
25 
clamp(float value)26 float clamp(float value) {
27   return std::min(std::max(value, 0.0f), 1.0f);
28 }
29 
OnTextureReleased(const ScopedPPResource & layer,const ScopedPPResource & context,uint32_t texture,const scoped_refptr<TrackedCallback> & release_callback,int32_t result,uint32_t sync_point,bool is_lost)30 void OnTextureReleased(
31     const ScopedPPResource& layer,
32     const ScopedPPResource& context,
33     uint32_t texture,
34     const scoped_refptr<TrackedCallback>& release_callback,
35     int32_t result,
36     uint32_t sync_point,
37     bool is_lost) {
38   if (!TrackedCallback::IsPending(release_callback))
39     return;
40 
41   if (result != PP_OK) {
42     release_callback->Run(result);
43     return;
44   }
45 
46   do {
47     if (!sync_point)
48       break;
49 
50     EnterResourceNoLock<PPB_Graphics3D_API> enter(context.get(), true);
51     if (enter.failed())
52       break;
53 
54     PPB_Graphics3D_Shared* graphics =
55         static_cast<PPB_Graphics3D_Shared*>(enter.object());
56 
57     GLES2Implementation* gl = graphics->gles2_impl();
58     gl->WaitSyncPointCHROMIUM(sync_point);
59   } while (false);
60 
61   release_callback->Run(is_lost ? PP_ERROR_FAILED : PP_OK);
62 }
63 
OnImageReleased(const ScopedPPResource & layer,const ScopedPPResource & image,const scoped_refptr<TrackedCallback> & release_callback,int32_t result,uint32_t sync_point,bool is_lost)64 void OnImageReleased(
65     const ScopedPPResource& layer,
66     const ScopedPPResource& image,
67     const scoped_refptr<TrackedCallback>& release_callback,
68     int32_t result,
69     uint32_t sync_point,
70     bool is_lost) {
71   if (!TrackedCallback::IsPending(release_callback))
72     return;
73   release_callback->Run(result);
74 }
75 
76 }  // namespace
77 
CompositorLayerResource(Connection connection,PP_Instance instance,const CompositorResource * compositor)78 CompositorLayerResource::CompositorLayerResource(
79     Connection connection,
80     PP_Instance instance,
81     const CompositorResource* compositor)
82     : PluginResource(connection, instance),
83       compositor_(compositor),
84       source_size_(PP_MakeFloatSize(0.0f, 0.0f)) {
85 }
86 
~CompositorLayerResource()87 CompositorLayerResource::~CompositorLayerResource() {
88   DCHECK(!compositor_);
89   DCHECK(release_callback_.is_null());
90 }
91 
92 thunk::PPB_CompositorLayer_API*
AsPPB_CompositorLayer_API()93 CompositorLayerResource::AsPPB_CompositorLayer_API() {
94   return this;
95 }
96 
SetColor(float red,float green,float blue,float alpha,const PP_Size * size)97 int32_t CompositorLayerResource::SetColor(float red,
98                                           float green,
99                                           float blue,
100                                           float alpha,
101                                           const PP_Size* size) {
102   if (!compositor_)
103     return PP_ERROR_BADRESOURCE;
104 
105   if (compositor_->IsInProgress())
106     return PP_ERROR_INPROGRESS;
107 
108   if (!SetType(TYPE_COLOR))
109     return PP_ERROR_BADARGUMENT;
110   DCHECK(data_.color);
111 
112   if (!size)
113     return PP_ERROR_BADARGUMENT;
114 
115   data_.color->red = clamp(red);
116   data_.color->green = clamp(green);
117   data_.color->blue = clamp(blue);
118   data_.color->alpha = clamp(alpha);
119   data_.common.size = *size;
120 
121   return PP_OK;
122 }
123 
SetTexture(PP_Resource context,uint32_t texture,const PP_Size * size,const scoped_refptr<TrackedCallback> & release_callback)124 int32_t CompositorLayerResource::SetTexture(
125     PP_Resource context,
126     uint32_t texture,
127     const PP_Size* size,
128     const scoped_refptr<TrackedCallback>& release_callback) {
129   int32_t rv = CheckForSetTextureAndImage(TYPE_TEXTURE, release_callback);
130   if (rv != PP_OK)
131     return rv;
132   DCHECK(data_.texture);
133 
134   EnterResourceNoLock<PPB_Graphics3D_API> enter(context, true);
135   if (enter.failed())
136     return PP_ERROR_BADRESOURCE;
137 
138   if (!size || size->width <= 0 || size->height <= 0)
139     return PP_ERROR_BADARGUMENT;
140 
141   PPB_Graphics3D_Shared* graphics =
142       static_cast<PPB_Graphics3D_Shared*>(enter.object());
143 
144   GLES2Implementation* gl = graphics->gles2_impl();
145 
146   // Generate a Mailbox for the texture.
147   gl->GenMailboxCHROMIUM(
148       reinterpret_cast<GLbyte*>(data_.texture->mailbox.name));
149   gl->ProduceTextureDirectCHROMIUM(
150       texture, GL_TEXTURE_2D,
151       reinterpret_cast<const GLbyte*>(data_.texture->mailbox.name));
152 
153   // Set the source size to (1, 1). It will be used to verify the source_rect
154   // passed to SetSourceRect().
155   source_size_ = PP_MakeFloatSize(1.0f, 1.0f);
156 
157   data_.common.size = *size;
158   data_.common.resource_id = compositor_->GenerateResourceId();
159   data_.texture->sync_point = gl->InsertSyncPointCHROMIUM();
160   data_.texture->source_rect.point = PP_MakeFloatPoint(0.0f, 0.0f);
161   data_.texture->source_rect.size = source_size_;
162 
163   // If the PP_Resource of this layer is released by the plugin, the
164   // release_callback will be aborted immediately, but the texture or image
165   // in this layer may still being used by chromium compositor. So we have to
166   // use ScopedPPResource to keep this resource alive until the texture or image
167   // is released by the chromium compositor.
168   release_callback_ = base::Bind(
169       &OnTextureReleased,
170       ScopedPPResource(pp_resource()), // Keep layer alive.
171       ScopedPPResource(context), // Keep context alive
172       texture,
173       release_callback);
174 
175   return PP_OK_COMPLETIONPENDING;
176 }
177 
SetImage(PP_Resource image_data,const PP_Size * size,const scoped_refptr<TrackedCallback> & release_callback)178 int32_t CompositorLayerResource::SetImage(
179     PP_Resource image_data,
180     const PP_Size* size,
181     const scoped_refptr<TrackedCallback>& release_callback) {
182   int32_t rv = CheckForSetTextureAndImage(TYPE_IMAGE, release_callback);
183   if (rv != PP_OK)
184     return rv;
185   DCHECK(data_.image);
186 
187   EnterResourceNoLock<PPB_ImageData_API> enter(image_data, true);
188   if (enter.failed())
189     return PP_ERROR_BADRESOURCE;
190 
191   PP_ImageDataDesc desc;
192   if (!enter.object()->Describe(&desc))
193     return PP_ERROR_BADARGUMENT;
194 
195   // TODO(penghuang): Support image which width * 4 != stride.
196   if (desc.size.width * 4 != desc.stride)
197     return PP_ERROR_BADARGUMENT;
198 
199   // TODO(penghuang): Support all formats.
200   if (desc.format != PP_IMAGEDATAFORMAT_RGBA_PREMUL)
201     return PP_ERROR_BADARGUMENT;
202 
203   if (!size || size->width <= 0 || size->height <= 0)
204     return PP_ERROR_BADARGUMENT;
205 
206   // Set the source size to image's size. It will be used to verify
207   // the source_rect passed to SetSourceRect().
208   source_size_ = PP_MakeFloatSize(desc.size.width, desc.size.height);
209 
210   data_.common.size = size ? *size : desc.size;
211   data_.common.resource_id = compositor_->GenerateResourceId();
212   data_.image->resource = enter.resource()->host_resource().host_resource();
213   data_.image->source_rect.point = PP_MakeFloatPoint(0.0f, 0.0f);
214   data_.image->source_rect.size = source_size_;
215 
216   // If the PP_Resource of this layer is released by the plugin, the
217   // release_callback will be aborted immediately, but the texture or image
218   // in this layer may still being used by chromium compositor. So we have to
219   // use ScopedPPResource to keep this resource alive until the texture or image
220   // is released by the chromium compositor.
221   release_callback_ = base::Bind(
222       &OnImageReleased,
223       ScopedPPResource(pp_resource()), // Keep layer alive.
224       ScopedPPResource(image_data), // Keep image_data alive.
225       release_callback);
226 
227   return PP_OK_COMPLETIONPENDING;
228 }
229 
SetClipRect(const PP_Rect * rect)230 int32_t CompositorLayerResource::SetClipRect(const PP_Rect* rect) {
231   if (!compositor_)
232     return PP_ERROR_BADRESOURCE;
233 
234   if (compositor_->IsInProgress())
235     return PP_ERROR_INPROGRESS;
236 
237   data_.common.clip_rect = rect ? *rect : PP_MakeRectFromXYWH(0, 0, 0, 0);
238   return PP_OK;
239 }
240 
SetTransform(const float matrix[16])241 int32_t CompositorLayerResource::SetTransform(const float matrix[16]) {
242   if (!compositor_)
243     return PP_ERROR_BADRESOURCE;
244 
245   if (compositor_->IsInProgress())
246     return PP_ERROR_INPROGRESS;
247 
248   std::copy(matrix, matrix + 16, data_.common.transform.matrix);
249   return PP_OK;
250 }
251 
SetOpacity(float opacity)252 int32_t CompositorLayerResource::SetOpacity(float opacity) {
253   if (!compositor_)
254     return PP_ERROR_BADRESOURCE;
255 
256   if (compositor_->IsInProgress())
257     return PP_ERROR_INPROGRESS;
258 
259   data_.common.opacity = clamp(opacity);
260   return PP_OK;
261 }
262 
SetBlendMode(PP_BlendMode mode)263 int32_t CompositorLayerResource::SetBlendMode(PP_BlendMode mode) {
264   if (!compositor_)
265     return PP_ERROR_BADRESOURCE;
266 
267   if (compositor_->IsInProgress())
268     return PP_ERROR_INPROGRESS;
269 
270   switch (mode) {
271     case PP_BLENDMODE_NONE:
272     case PP_BLENDMODE_SRC_OVER:
273       data_.common.blend_mode = mode;
274       return PP_OK;
275   }
276   return PP_ERROR_BADARGUMENT;
277 }
278 
SetSourceRect(const PP_FloatRect * rect)279 int32_t CompositorLayerResource::SetSourceRect(
280     const PP_FloatRect* rect) {
281   if (!compositor_)
282     return PP_ERROR_BADRESOURCE;
283 
284   if (compositor_->IsInProgress())
285     return PP_ERROR_INPROGRESS;
286 
287   if (!rect ||
288       rect->point.x < 0.0f ||
289       rect->point.y < 0.0f ||
290       rect->point.x + rect->size.width > source_size_.width ||
291       rect->point.y + rect->size.height > source_size_.height) {
292     return PP_ERROR_BADARGUMENT;
293   }
294 
295   if (data_.texture) {
296     data_.texture->source_rect = *rect;
297     return PP_OK;
298   }
299   if (data_.image) {
300     data_.image->source_rect = *rect;
301     return PP_OK;
302   }
303   return PP_ERROR_BADARGUMENT;
304 }
305 
SetPremultipliedAlpha(PP_Bool premult)306 int32_t CompositorLayerResource::SetPremultipliedAlpha(PP_Bool premult) {
307   if (!compositor_)
308     return PP_ERROR_BADRESOURCE;
309 
310   if (compositor_->IsInProgress())
311     return PP_ERROR_INPROGRESS;
312 
313   if (data_.texture) {
314     data_.texture->premult_alpha = PP_ToBool(premult);
315     return PP_OK;
316   }
317   return PP_ERROR_BADARGUMENT;
318 }
319 
SetType(LayerType type)320 bool CompositorLayerResource::SetType(LayerType type) {
321   if (type == TYPE_COLOR) {
322     if (data_.is_null())
323       data_.color.reset(new CompositorLayerData::ColorLayer());
324     return data_.color;
325   }
326 
327   if (type == TYPE_TEXTURE) {
328     if (data_.is_null())
329       data_.texture.reset(new CompositorLayerData::TextureLayer());
330     return data_.texture;
331   }
332 
333   if (type == TYPE_IMAGE) {
334     if (data_.is_null())
335       data_.image.reset(new CompositorLayerData::ImageLayer());
336     return data_.image;
337   }
338 
339   // Should not be reached.
340   DCHECK(false);
341   return false;
342 }
343 
CheckForSetTextureAndImage(LayerType type,const scoped_refptr<TrackedCallback> & release_callback)344 int32_t CompositorLayerResource::CheckForSetTextureAndImage(
345     LayerType type,
346     const scoped_refptr<TrackedCallback>& release_callback) {
347   if (!compositor_)
348     return PP_ERROR_BADRESOURCE;
349 
350   if (compositor_->IsInProgress())
351     return PP_ERROR_INPROGRESS;
352 
353   if (!SetType(type))
354     return PP_ERROR_BADARGUMENT;
355 
356   // The layer's image has been set and it is not committed.
357   if (!release_callback_.is_null())
358     return PP_ERROR_INPROGRESS;
359 
360   // Do not allow using a block callback as a release callback.
361   if (release_callback->is_blocking())
362     return PP_ERROR_BADARGUMENT;
363 
364   return PP_OK;
365 }
366 
367 }  // namespace proxy
368 }  // namespace ppapi
369