blob: 09a63b18053558659ae5d7939958ae1e82cb7f7b [file] [log] [blame]
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +01001// 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
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +01007#include "base/logging.h"
Torne (Richard Coles)6e8cce62014-08-19 13:00:08 +01008#include "gpu/GLES2/gl2extchromium.h"
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +01009#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
17using gpu::gles2::GLES2Implementation;
18using ppapi::thunk::EnterResourceNoLock;
19using ppapi::thunk::PPB_ImageData_API;
20using ppapi::thunk::PPB_Graphics3D_API;
21
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010022namespace ppapi {
23namespace proxy {
24
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +010025namespace {
26
27float clamp(float value) {
28 return std::min(std::max(value, 0.0f), 1.0f);
29}
30
31void OnTextureReleased(
32 const ScopedPPResource& layer,
33 const ScopedPPResource& context,
34 uint32_t texture,
35 const scoped_refptr<TrackedCallback>& release_callback,
Torne (Richard Coles)6d86b772014-06-25 10:30:53 +010036 int32_t result,
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +010037 uint32_t sync_point,
38 bool is_lost) {
39 if (!TrackedCallback::IsPending(release_callback))
40 return;
41
Torne (Richard Coles)6d86b772014-06-25 10:30:53 +010042 if (result != PP_OK) {
43 release_callback->Run(result);
44 return;
45 }
46
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +010047 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
65void OnImageReleased(
66 const ScopedPPResource& layer,
67 const ScopedPPResource& image,
68 const scoped_refptr<TrackedCallback>& release_callback,
Torne (Richard Coles)6d86b772014-06-25 10:30:53 +010069 int32_t result,
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +010070 uint32_t sync_point,
71 bool is_lost) {
72 if (!TrackedCallback::IsPending(release_callback))
73 return;
Torne (Richard Coles)6d86b772014-06-25 10:30:53 +010074 release_callback->Run(result);
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +010075}
76
77} // namespace
78
79CompositorLayerResource::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)) {
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010086}
87
88CompositorLayerResource::~CompositorLayerResource() {
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +010089 DCHECK(!compositor_);
90 DCHECK(release_callback_.is_null());
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010091}
92
93thunk::PPB_CompositorLayer_API*
94CompositorLayerResource::AsPPB_CompositorLayer_API() {
95 return this;
96}
97
98int32_t CompositorLayerResource::SetColor(float red,
99 float green,
100 float blue,
101 float alpha,
102 const PP_Size* size) {
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100103 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
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100116 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;
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100123}
124
Torne (Richard Coles)6e8cce62014-08-19 13:00:08 +0100125int32_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
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100133int32_t CompositorLayerResource::SetTexture(
134 PP_Resource context,
Torne (Richard Coles)6e8cce62014-08-19 13:00:08 +0100135 uint32_t target,
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100136 uint32_t texture,
137 const PP_Size* size,
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100138 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
Torne (Richard Coles)6e8cce62014-08-19 13:00:08 +0100148 if (target != GL_TEXTURE_2D &&
149 target != GL_TEXTURE_EXTERNAL_OES &&
150 target != GL_TEXTURE_RECTANGLE_ARB) {
151 return PP_ERROR_BADARGUMENT;
152 }
153
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100154 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(
Torne (Richard Coles)6e8cce62014-08-19 13:00:08 +0100166 texture, target,
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100167 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();
Torne (Richard Coles)6e8cce62014-08-19 13:00:08 +0100175 data_.texture->target = target;
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100176 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;
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100193}
194
195int32_t CompositorLayerResource::SetImage(
196 PP_Resource image_data,
197 const PP_Size* size,
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100198 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
Torne (Richard Coles)6d86b772014-06-25 10:30:53 +0100233 // 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.
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100238 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;
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100245}
246
247int32_t CompositorLayerResource::SetClipRect(const PP_Rect* rect) {
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100248 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;
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100256}
257
258int32_t CompositorLayerResource::SetTransform(const float matrix[16]) {
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100259 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;
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100267}
268
269int32_t CompositorLayerResource::SetOpacity(float opacity) {
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100270 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;
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100278}
279
280int32_t CompositorLayerResource::SetBlendMode(PP_BlendMode mode) {
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100281 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;
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100294}
295
296int32_t CompositorLayerResource::SetSourceRect(
297 const PP_FloatRect* rect) {
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100298 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;
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100321}
322
323int32_t CompositorLayerResource::SetPremultipliedAlpha(PP_Bool premult) {
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100324 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
337bool 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
361int32_t CompositorLayerResource::CheckForSetTextureAndImage(
362 LayerType type,
363 const scoped_refptr<TrackedCallback>& release_callback) {
Torne (Richard Coles)6d86b772014-06-25 10:30:53 +0100364 if (!compositor_)
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100365 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;
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100382}
383
384} // namespace proxy
385} // namespace ppapi