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