Home | History | Annotate | Download | only in media
      1 // Copyright (c) 2012 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 "content/renderer/media/renderer_gpu_video_decoder_factories.h"
      6 
      7 #include <GLES2/gl2.h>
      8 #include <GLES2/gl2ext.h>
      9 
     10 #include "base/bind.h"
     11 #include "content/child/child_thread.h"
     12 #include "content/common/gpu/client/gpu_channel_host.h"
     13 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
     14 #include "gpu/command_buffer/client/gles2_implementation.h"
     15 #include "gpu/ipc/command_buffer_proxy.h"
     16 #include "third_party/skia/include/core/SkPixelRef.h"
     17 
     18 namespace content {
     19 
     20 RendererGpuVideoDecoderFactories::~RendererGpuVideoDecoderFactories() {}
     21 RendererGpuVideoDecoderFactories::RendererGpuVideoDecoderFactories(
     22     GpuChannelHost* gpu_channel_host,
     23     const scoped_refptr<base::MessageLoopProxy>& message_loop,
     24     WebGraphicsContext3DCommandBufferImpl* context)
     25     : message_loop_(message_loop),
     26       main_message_loop_(base::MessageLoopProxy::current()),
     27       gpu_channel_host_(gpu_channel_host),
     28       aborted_waiter_(true, false),
     29       message_loop_async_waiter_(false, false),
     30       render_thread_async_waiter_(false, false) {
     31   if (message_loop_->BelongsToCurrentThread()) {
     32     AsyncGetContext(context);
     33     message_loop_async_waiter_.Reset();
     34     return;
     35   }
     36   // Wait for the context to be acquired.
     37   message_loop_->PostTask(FROM_HERE, base::Bind(
     38       &RendererGpuVideoDecoderFactories::AsyncGetContext,
     39       // Unretained to avoid ref/deref'ing |*this|, which is not yet stored in a
     40       // scoped_refptr.  Safe because the Wait() below keeps us alive until this
     41       // task completes.
     42       base::Unretained(this),
     43       // OK to pass raw because the pointee is only deleted on the compositor
     44       // thread, and only as the result of a PostTask from the render thread
     45       // which can only happen after this function returns, so our PostTask will
     46       // run first.
     47       context));
     48   message_loop_async_waiter_.Wait();
     49 }
     50 
     51 RendererGpuVideoDecoderFactories::RendererGpuVideoDecoderFactories()
     52     : aborted_waiter_(true, false),
     53       message_loop_async_waiter_(false, false),
     54       render_thread_async_waiter_(false, false) {}
     55 
     56 void RendererGpuVideoDecoderFactories::AsyncGetContext(
     57     WebGraphicsContext3DCommandBufferImpl* context) {
     58   context_ = context->AsWeakPtr();
     59   if (context_.get()) {
     60     if (context_->makeContextCurrent()) {
     61       // Called once per media player, but is a no-op after the first one in
     62       // each renderer.
     63       context_->insertEventMarkerEXT("GpuVDAContext3D");
     64     }
     65   }
     66   message_loop_async_waiter_.Signal();
     67 }
     68 
     69 media::VideoDecodeAccelerator*
     70 RendererGpuVideoDecoderFactories::CreateVideoDecodeAccelerator(
     71     media::VideoCodecProfile profile,
     72     media::VideoDecodeAccelerator::Client* client) {
     73   if (message_loop_->BelongsToCurrentThread()) {
     74     AsyncCreateVideoDecodeAccelerator(profile, client);
     75     message_loop_async_waiter_.Reset();
     76     return vda_.release();
     77   }
     78   // The VDA is returned in the vda_ member variable by the
     79   // AsyncCreateVideoDecodeAccelerator() function.
     80   message_loop_->PostTask(FROM_HERE, base::Bind(
     81       &RendererGpuVideoDecoderFactories::AsyncCreateVideoDecodeAccelerator,
     82       this, profile, client));
     83 
     84   base::WaitableEvent* objects[] = {&aborted_waiter_,
     85                                     &message_loop_async_waiter_};
     86   if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0) {
     87     // If we are aborting and the VDA is created by the
     88     // AsyncCreateVideoDecodeAccelerator() function later we need to ensure
     89     // that it is destroyed on the same thread.
     90     message_loop_->PostTask(FROM_HERE, base::Bind(
     91         &RendererGpuVideoDecoderFactories::AsyncDestroyVideoDecodeAccelerator,
     92         this));
     93     return NULL;
     94   }
     95   return vda_.release();
     96 }
     97 
     98 void RendererGpuVideoDecoderFactories::AsyncCreateVideoDecodeAccelerator(
     99       media::VideoCodecProfile profile,
    100       media::VideoDecodeAccelerator::Client* client) {
    101   DCHECK(message_loop_->BelongsToCurrentThread());
    102 
    103   if (context_.get() && context_->GetCommandBufferProxy()) {
    104     vda_ = gpu_channel_host_->CreateVideoDecoder(
    105         context_->GetCommandBufferProxy()->GetRouteID(), profile, client);
    106   }
    107   message_loop_async_waiter_.Signal();
    108 }
    109 
    110 uint32 RendererGpuVideoDecoderFactories::CreateTextures(
    111     int32 count, const gfx::Size& size,
    112     std::vector<uint32>* texture_ids,
    113     std::vector<gpu::Mailbox>* texture_mailboxes,
    114     uint32 texture_target) {
    115   uint32 sync_point = 0;
    116 
    117   if (message_loop_->BelongsToCurrentThread()) {
    118     AsyncCreateTextures(count, size, texture_target, &sync_point);
    119     texture_ids->swap(created_textures_);
    120     texture_mailboxes->swap(created_texture_mailboxes_);
    121     message_loop_async_waiter_.Reset();
    122     return sync_point;
    123   }
    124   message_loop_->PostTask(FROM_HERE, base::Bind(
    125       &RendererGpuVideoDecoderFactories::AsyncCreateTextures, this,
    126       count, size, texture_target, &sync_point));
    127 
    128   base::WaitableEvent* objects[] = {&aborted_waiter_,
    129                                     &message_loop_async_waiter_};
    130   if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0)
    131     return 0;
    132   texture_ids->swap(created_textures_);
    133   texture_mailboxes->swap(created_texture_mailboxes_);
    134   return sync_point;
    135 }
    136 
    137 void RendererGpuVideoDecoderFactories::AsyncCreateTextures(
    138     int32 count, const gfx::Size& size, uint32 texture_target,
    139     uint32* sync_point) {
    140   DCHECK(message_loop_->BelongsToCurrentThread());
    141   DCHECK(texture_target);
    142 
    143   if (!context_.get()) {
    144     message_loop_async_waiter_.Signal();
    145     return;
    146   }
    147   gpu::gles2::GLES2Implementation* gles2 = context_->GetImplementation();
    148   created_textures_.resize(count);
    149   created_texture_mailboxes_.resize(count);
    150   gles2->GenTextures(count, &created_textures_[0]);
    151   for (int i = 0; i < count; ++i) {
    152     gles2->ActiveTexture(GL_TEXTURE0);
    153     uint32 texture_id = created_textures_[i];
    154     gles2->BindTexture(texture_target, texture_id);
    155     gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    156     gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    157     gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    158     gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    159     if (texture_target == GL_TEXTURE_2D) {
    160       gles2->TexImage2D(texture_target, 0, GL_RGBA, size.width(), size.height(),
    161                         0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    162     }
    163     gles2->GenMailboxCHROMIUM(created_texture_mailboxes_[i].name);
    164     gles2->ProduceTextureCHROMIUM(texture_target,
    165                                   created_texture_mailboxes_[i].name);
    166   }
    167 
    168   // We need a glFlush here to guarantee the decoder (in the GPU process) can
    169   // use the texture ids we return here.  Since textures are expected to be
    170   // reused, this should not be unacceptably expensive.
    171   gles2->Flush();
    172   DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
    173 
    174   *sync_point = gles2->InsertSyncPointCHROMIUM();
    175   message_loop_async_waiter_.Signal();
    176 }
    177 
    178 void RendererGpuVideoDecoderFactories::DeleteTexture(uint32 texture_id) {
    179   if (message_loop_->BelongsToCurrentThread()) {
    180     AsyncDeleteTexture(texture_id);
    181     return;
    182   }
    183   message_loop_->PostTask(FROM_HERE, base::Bind(
    184       &RendererGpuVideoDecoderFactories::AsyncDeleteTexture, this, texture_id));
    185 }
    186 
    187 void RendererGpuVideoDecoderFactories::AsyncDeleteTexture(uint32 texture_id) {
    188   DCHECK(message_loop_->BelongsToCurrentThread());
    189   if (!context_.get())
    190     return;
    191 
    192   gpu::gles2::GLES2Implementation* gles2 = context_->GetImplementation();
    193   gles2->DeleteTextures(1, &texture_id);
    194   DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
    195 }
    196 
    197 void RendererGpuVideoDecoderFactories::WaitSyncPoint(uint32 sync_point) {
    198   if (message_loop_->BelongsToCurrentThread()) {
    199     AsyncWaitSyncPoint(sync_point);
    200     message_loop_async_waiter_.Reset();
    201     return;
    202   }
    203 
    204   message_loop_->PostTask(FROM_HERE, base::Bind(
    205       &RendererGpuVideoDecoderFactories::AsyncWaitSyncPoint,
    206       this,
    207       sync_point));
    208   base::WaitableEvent* objects[] = {&aborted_waiter_,
    209                                     &message_loop_async_waiter_};
    210   base::WaitableEvent::WaitMany(objects, arraysize(objects));
    211 }
    212 
    213 void RendererGpuVideoDecoderFactories::AsyncWaitSyncPoint(uint32 sync_point) {
    214   DCHECK(message_loop_->BelongsToCurrentThread());
    215   if (!context_) {
    216     message_loop_async_waiter_.Signal();
    217     return;
    218   }
    219 
    220   gpu::gles2::GLES2Implementation* gles2 = context_->GetImplementation();
    221   gles2->WaitSyncPointCHROMIUM(sync_point);
    222   message_loop_async_waiter_.Signal();
    223 }
    224 
    225 void RendererGpuVideoDecoderFactories::ReadPixels(
    226     uint32 texture_id, uint32 texture_target, const gfx::Size& size,
    227     const SkBitmap& pixels) {
    228   // SkBitmaps use the SkPixelRef object to refcount the underlying pixels.
    229   // Multiple SkBitmaps can share a SkPixelRef instance. We use this to
    230   // ensure that the underlying pixels in the SkBitmap passed in remain valid
    231   // until the AsyncReadPixels() call completes.
    232   read_pixels_bitmap_.setPixelRef(pixels.pixelRef());
    233 
    234   if (!message_loop_->BelongsToCurrentThread()) {
    235     message_loop_->PostTask(FROM_HERE, base::Bind(
    236         &RendererGpuVideoDecoderFactories::AsyncReadPixels, this,
    237         texture_id, texture_target, size));
    238     base::WaitableEvent* objects[] = {&aborted_waiter_,
    239                                       &message_loop_async_waiter_};
    240     if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0)
    241       return;
    242   } else {
    243     AsyncReadPixels(texture_id, texture_target, size);
    244     message_loop_async_waiter_.Reset();
    245   }
    246   read_pixels_bitmap_.setPixelRef(NULL);
    247 }
    248 
    249 void RendererGpuVideoDecoderFactories::AsyncReadPixels(
    250     uint32 texture_id, uint32 texture_target, const gfx::Size& size) {
    251   DCHECK(message_loop_->BelongsToCurrentThread());
    252   if (!context_.get()) {
    253     message_loop_async_waiter_.Signal();
    254     return;
    255   }
    256 
    257   gpu::gles2::GLES2Implementation* gles2 = context_->GetImplementation();
    258 
    259   GLuint tmp_texture;
    260   gles2->GenTextures(1, &tmp_texture);
    261   gles2->BindTexture(texture_target, tmp_texture);
    262   gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    263   gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    264   gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    265   gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    266   context_->copyTextureCHROMIUM(
    267       texture_target, texture_id, tmp_texture, 0, GL_RGBA, GL_UNSIGNED_BYTE);
    268 
    269   GLuint fb;
    270   gles2->GenFramebuffers(1, &fb);
    271   gles2->BindFramebuffer(GL_FRAMEBUFFER, fb);
    272   gles2->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
    273                               texture_target, tmp_texture, 0);
    274   gles2->PixelStorei(GL_PACK_ALIGNMENT, 4);
    275   gles2->ReadPixels(0, 0, size.width(), size.height(), GL_BGRA_EXT,
    276       GL_UNSIGNED_BYTE, read_pixels_bitmap_.pixelRef()->pixels());
    277   gles2->DeleteFramebuffers(1, &fb);
    278   gles2->DeleteTextures(1, &tmp_texture);
    279   DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
    280   message_loop_async_waiter_.Signal();
    281 }
    282 
    283 base::SharedMemory* RendererGpuVideoDecoderFactories::CreateSharedMemory(
    284     size_t size) {
    285   if (main_message_loop_->BelongsToCurrentThread()) {
    286     return ChildThread::current()->AllocateSharedMemory(size);
    287   }
    288   main_message_loop_->PostTask(FROM_HERE, base::Bind(
    289       &RendererGpuVideoDecoderFactories::AsyncCreateSharedMemory, this,
    290       size));
    291 
    292   base::WaitableEvent* objects[] = {&aborted_waiter_,
    293                                     &render_thread_async_waiter_};
    294   if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0)
    295     return NULL;
    296   return shared_memory_segment_.release();
    297 }
    298 
    299 void RendererGpuVideoDecoderFactories::AsyncCreateSharedMemory(size_t size) {
    300   DCHECK_EQ(base::MessageLoop::current(),
    301             ChildThread::current()->message_loop());
    302 
    303   shared_memory_segment_.reset(
    304       ChildThread::current()->AllocateSharedMemory(size));
    305   render_thread_async_waiter_.Signal();
    306 }
    307 
    308 scoped_refptr<base::MessageLoopProxy>
    309 RendererGpuVideoDecoderFactories::GetMessageLoop() {
    310   return message_loop_;
    311 }
    312 
    313 void RendererGpuVideoDecoderFactories::Abort() {
    314   aborted_waiter_.Signal();
    315 }
    316 
    317 bool RendererGpuVideoDecoderFactories::IsAborted() {
    318   return aborted_waiter_.IsSignaled();
    319 }
    320 
    321 scoped_refptr<media::GpuVideoDecoderFactories>
    322 RendererGpuVideoDecoderFactories::Clone() {
    323   scoped_refptr<RendererGpuVideoDecoderFactories> factories =
    324       new RendererGpuVideoDecoderFactories();
    325   factories->message_loop_ = message_loop_;
    326   factories->main_message_loop_ = main_message_loop_;
    327   factories->gpu_channel_host_ = gpu_channel_host_;
    328   factories->context_ = context_;
    329   return factories;
    330 }
    331 
    332 void RendererGpuVideoDecoderFactories::AsyncDestroyVideoDecodeAccelerator() {
    333   // OK to release because Destroy() will delete the VDA instance.
    334   if (vda_)
    335     vda_.release()->Destroy();
    336 }
    337 
    338 }  // namespace content
    339