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"
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
;
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
,
37 const scoped_refptr
<TrackedCallback
>& release_callback
,
41 if (!TrackedCallback::IsPending(release_callback
))
44 if (result
!= PP_OK
) {
45 release_callback
->Run(result
);
53 EnterResourceNoLock
<PPB_Graphics3D_API
> enter(context
.get(), true);
57 PPB_Graphics3D_Shared
* graphics
=
58 static_cast<PPB_Graphics3D_Shared
*>(enter
.object());
60 GLES2Implementation
* gl
= graphics
->gles2_impl();
61 gl
->WaitSyncPointCHROMIUM(sync_point
);
64 release_callback
->Run(is_lost
? PP_ERROR_FAILED
: PP_OK
);
68 const ScopedPPResource
& layer
,
69 const ScopedPPResource
& image
,
70 const scoped_refptr
<TrackedCallback
>& release_callback
,
74 if (!TrackedCallback::IsPending(release_callback
))
76 release_callback
->Run(result
);
81 CompositorLayerResource::CompositorLayerResource(
82 Connection connection
,
84 const CompositorResource
* compositor
)
85 : PluginResource(connection
, instance
),
86 compositor_(compositor
),
87 source_size_(PP_MakeFloatSize(0.0f
, 0.0f
)) {
90 CompositorLayerResource::~CompositorLayerResource() {
92 DCHECK(release_callback_
.is_null());
95 thunk::PPB_CompositorLayer_API
*
96 CompositorLayerResource::AsPPB_CompositorLayer_API() {
100 int32_t CompositorLayerResource::SetColor(float red
,
104 const PP_Size
* size
) {
106 return PP_ERROR_BADRESOURCE
;
108 if (compositor_
->IsInProgress())
109 return PP_ERROR_INPROGRESS
;
111 if (!SetType(TYPE_COLOR
))
112 return PP_ERROR_BADARGUMENT
;
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
;
127 int32_t CompositorLayerResource::SetTexture0_1(
131 const scoped_refptr
<TrackedCallback
>& release_callback
) {
132 return SetTexture(context
, GL_TEXTURE_2D
, texture
, size
, release_callback
);
135 int32_t CompositorLayerResource::SetTexture(
140 const scoped_refptr
<TrackedCallback
>& release_callback
) {
141 int32_t rv
= CheckForSetTextureAndImage(TYPE_TEXTURE
, release_callback
);
144 DCHECK(data_
.texture
);
146 EnterResourceNoLock
<PPB_Graphics3D_API
> enter(context
, true);
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(
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(
189 ScopedPPResource(pp_resource()), // Keep layer alive.
190 ScopedPPResource(context
), // Keep context alive
194 return PP_OK_COMPLETIONPENDING
;
197 int32_t CompositorLayerResource::SetImage(
198 PP_Resource image_data
,
200 const scoped_refptr
<TrackedCallback
>& release_callback
) {
201 int32_t rv
= CheckForSetTextureAndImage(TYPE_IMAGE
, release_callback
);
206 EnterResourceNoLock
<PPB_ImageData_API
> enter(image_data
, true);
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(
242 ScopedPPResource(pp_resource()), // Keep layer alive.
243 ScopedPPResource(image_data
), // Keep image_data alive.
246 return PP_OK_COMPLETIONPENDING
;
249 int32_t CompositorLayerResource::SetClipRect(const PP_Rect
* rect
) {
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);
260 int32_t CompositorLayerResource::SetTransform(const float matrix
[16]) {
262 return PP_ERROR_BADRESOURCE
;
264 if (compositor_
->IsInProgress())
265 return PP_ERROR_INPROGRESS
;
267 std::copy(matrix
, matrix
+ 16, data_
.common
.transform
.matrix
);
271 int32_t CompositorLayerResource::SetOpacity(float opacity
) {
273 return PP_ERROR_BADRESOURCE
;
275 if (compositor_
->IsInProgress())
276 return PP_ERROR_INPROGRESS
;
278 data_
.common
.opacity
= clamp(opacity
);
282 int32_t CompositorLayerResource::SetBlendMode(PP_BlendMode mode
) {
284 return PP_ERROR_BADRESOURCE
;
286 if (compositor_
->IsInProgress())
287 return PP_ERROR_INPROGRESS
;
290 case PP_BLENDMODE_NONE
:
291 case PP_BLENDMODE_SRC_OVER
:
292 data_
.common
.blend_mode
= mode
;
295 return PP_ERROR_BADARGUMENT
;
298 int32_t CompositorLayerResource::SetSourceRect(
299 const PP_FloatRect
* rect
) {
301 return PP_ERROR_BADRESOURCE
;
303 if (compositor_
->IsInProgress())
304 return PP_ERROR_INPROGRESS
;
306 const float kEpsilon
= std::numeric_limits
<float>::epsilon();
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
;
316 data_
.texture
->source_rect
= *rect
;
320 data_
.image
->source_rect
= *rect
;
323 return PP_ERROR_BADARGUMENT
;
326 int32_t CompositorLayerResource::SetPremultipliedAlpha(PP_Bool premult
) {
328 return PP_ERROR_BADRESOURCE
;
330 if (compositor_
->IsInProgress())
331 return PP_ERROR_INPROGRESS
;
334 data_
.texture
->premult_alpha
= PP_ToBool(premult
);
337 return PP_ERROR_BADARGUMENT
;
340 bool CompositorLayerResource::SetType(LayerType type
) {
341 if (type
== TYPE_COLOR
) {
343 data_
.color
.reset(new CompositorLayerData::ColorLayer());
347 if (type
== TYPE_TEXTURE
) {
349 data_
.texture
.reset(new CompositorLayerData::TextureLayer());
350 return data_
.texture
;
353 if (type
== TYPE_IMAGE
) {
355 data_
.image
.reset(new CompositorLayerData::ImageLayer());
359 // Should not be reached.
364 int32_t CompositorLayerResource::CheckForSetTextureAndImage(
366 const scoped_refptr
<TrackedCallback
>& release_callback
) {
368 return PP_ERROR_BADRESOURCE
;
370 if (compositor_
->IsInProgress())
371 return PP_ERROR_INPROGRESS
;
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
;