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 386