Home | History | Annotate | Download | only in proxy
      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