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