Home | History | Annotate | Download | only in media
      1 // Copyright 2013 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_accelerator_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/context_provider_command_buffer.h"
     13 #include "content/common/gpu/client/gpu_channel_host.h"
     14 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
     15 #include "content/renderer/render_thread_impl.h"
     16 #include "gpu/command_buffer/client/gles2_implementation.h"
     17 #include "media/video/video_decode_accelerator.h"
     18 #include "media/video/video_encode_accelerator.h"
     19 #include "third_party/skia/include/core/SkBitmap.h"
     20 #include "third_party/skia/include/core/SkPixelRef.h"
     21 
     22 namespace content {
     23 
     24 // static
     25 scoped_refptr<RendererGpuVideoAcceleratorFactories>
     26 RendererGpuVideoAcceleratorFactories::Create(
     27     GpuChannelHost* gpu_channel_host,
     28     const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
     29     const scoped_refptr<ContextProviderCommandBuffer>& context_provider) {
     30   scoped_refptr<RendererGpuVideoAcceleratorFactories> factories =
     31       new RendererGpuVideoAcceleratorFactories(
     32           gpu_channel_host, message_loop_proxy, context_provider);
     33   // Post task from outside constructor, since AddRef()/Release() is unsafe from
     34   // within.
     35   message_loop_proxy->PostTask(
     36       FROM_HERE,
     37       base::Bind(&RendererGpuVideoAcceleratorFactories::BindContext,
     38                  factories));
     39   return factories;
     40 }
     41 
     42 RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories(
     43     GpuChannelHost* gpu_channel_host,
     44     const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
     45     const scoped_refptr<ContextProviderCommandBuffer>& context_provider)
     46     : task_runner_(message_loop_proxy),
     47       gpu_channel_host_(gpu_channel_host),
     48       context_provider_(context_provider),
     49       thread_safe_sender_(ChildThread::current()->thread_safe_sender()) {}
     50 
     51 RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {}
     52 
     53 void RendererGpuVideoAcceleratorFactories::BindContext() {
     54   DCHECK(task_runner_->BelongsToCurrentThread());
     55   if (!context_provider_->BindToCurrentThread())
     56     context_provider_ = NULL;
     57 }
     58 
     59 WebGraphicsContext3DCommandBufferImpl*
     60 RendererGpuVideoAcceleratorFactories::GetContext3d() {
     61   DCHECK(task_runner_->BelongsToCurrentThread());
     62   if (!context_provider_)
     63     return NULL;
     64   if (context_provider_->IsContextLost()) {
     65     context_provider_->VerifyContexts();
     66     context_provider_ = NULL;
     67     return NULL;
     68   }
     69   return context_provider_->WebContext3D();
     70 }
     71 
     72 scoped_ptr<media::VideoDecodeAccelerator>
     73 RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator() {
     74   DCHECK(task_runner_->BelongsToCurrentThread());
     75 
     76   WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
     77   if (context && context->GetCommandBufferProxy()) {
     78     return gpu_channel_host_->CreateVideoDecoder(
     79         context->GetCommandBufferProxy()->GetRouteID());
     80   }
     81 
     82   return scoped_ptr<media::VideoDecodeAccelerator>();
     83 }
     84 
     85 scoped_ptr<media::VideoEncodeAccelerator>
     86 RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator() {
     87   DCHECK(task_runner_->BelongsToCurrentThread());
     88 
     89   WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
     90   if (context && context->GetCommandBufferProxy()) {
     91     return gpu_channel_host_->CreateVideoEncoder(
     92         context->GetCommandBufferProxy()->GetRouteID());
     93   }
     94 
     95   return scoped_ptr<media::VideoEncodeAccelerator>();
     96 }
     97 
     98 bool RendererGpuVideoAcceleratorFactories::CreateTextures(
     99     int32 count,
    100     const gfx::Size& size,
    101     std::vector<uint32>* texture_ids,
    102     std::vector<gpu::Mailbox>* texture_mailboxes,
    103     uint32 texture_target) {
    104   DCHECK(task_runner_->BelongsToCurrentThread());
    105   DCHECK(texture_target);
    106 
    107   WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
    108   if (!context)
    109     return false;
    110 
    111   gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
    112   texture_ids->resize(count);
    113   texture_mailboxes->resize(count);
    114   gles2->GenTextures(count, &texture_ids->at(0));
    115   for (int i = 0; i < count; ++i) {
    116     gles2->ActiveTexture(GL_TEXTURE0);
    117     uint32 texture_id = texture_ids->at(i);
    118     gles2->BindTexture(texture_target, texture_id);
    119     gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    120     gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    121     gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    122     gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    123     if (texture_target == GL_TEXTURE_2D) {
    124       gles2->TexImage2D(texture_target,
    125                         0,
    126                         GL_RGBA,
    127                         size.width(),
    128                         size.height(),
    129                         0,
    130                         GL_RGBA,
    131                         GL_UNSIGNED_BYTE,
    132                         NULL);
    133     }
    134     gles2->GenMailboxCHROMIUM(texture_mailboxes->at(i).name);
    135     gles2->ProduceTextureCHROMIUM(texture_target,
    136                                   texture_mailboxes->at(i).name);
    137   }
    138 
    139   // We need ShallowFlushCHROMIUM() here to order the command buffer commands
    140   // with respect to IPC to the GPU process, to guarantee that the decoder in
    141   // the GPU process can use these textures as soon as it receives IPC
    142   // notification of them.
    143   gles2->ShallowFlushCHROMIUM();
    144   DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
    145   return true;
    146 }
    147 
    148 void RendererGpuVideoAcceleratorFactories::DeleteTexture(uint32 texture_id) {
    149   DCHECK(task_runner_->BelongsToCurrentThread());
    150 
    151   WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
    152   if (!context)
    153     return;
    154 
    155   gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
    156   gles2->DeleteTextures(1, &texture_id);
    157   DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
    158 }
    159 
    160 void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point) {
    161   DCHECK(task_runner_->BelongsToCurrentThread());
    162 
    163   WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
    164   if (!context)
    165     return;
    166 
    167   gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
    168   gles2->WaitSyncPointCHROMIUM(sync_point);
    169 
    170   // Callers expect the WaitSyncPoint to affect the next IPCs. Make sure to
    171   // flush the command buffers to ensure that.
    172   gles2->ShallowFlushCHROMIUM();
    173 }
    174 
    175 void RendererGpuVideoAcceleratorFactories::ReadPixels(
    176     uint32 texture_id,
    177     const gfx::Rect& visible_rect,
    178     const SkBitmap& pixels) {
    179   DCHECK(task_runner_->BelongsToCurrentThread());
    180 
    181   WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
    182   if (!context)
    183     return;
    184 
    185   gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
    186 
    187   GLuint tmp_texture;
    188   gles2->GenTextures(1, &tmp_texture);
    189   gles2->BindTexture(GL_TEXTURE_2D, tmp_texture);
    190   gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    191   gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    192   gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    193   gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    194   context->copyTextureCHROMIUM(
    195       GL_TEXTURE_2D, texture_id, tmp_texture, 0, GL_RGBA, GL_UNSIGNED_BYTE);
    196 
    197   GLuint fb;
    198   gles2->GenFramebuffers(1, &fb);
    199   gles2->BindFramebuffer(GL_FRAMEBUFFER, fb);
    200   gles2->FramebufferTexture2D(
    201       GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_texture, 0);
    202   gles2->PixelStorei(GL_PACK_ALIGNMENT, 4);
    203 
    204 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
    205     SK_A32_SHIFT == 24
    206   GLenum skia_format = GL_BGRA_EXT;
    207   GLenum read_format = GL_BGRA_EXT;
    208   GLint supported_format = 0;
    209   GLint supported_type = 0;
    210   gles2->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &supported_format);
    211   gles2->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &supported_type);
    212   if (supported_format != GL_BGRA_EXT || supported_type != GL_UNSIGNED_BYTE) {
    213     read_format = GL_RGBA;
    214   }
    215 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
    216     SK_A32_SHIFT == 24
    217   GLenum skia_format = GL_RGBA;
    218   GLenum read_format = GL_RGBA;
    219 #else
    220 #error Unexpected Skia ARGB_8888 layout!
    221 #endif
    222   gles2->ReadPixels(visible_rect.x(),
    223                     visible_rect.y(),
    224                     visible_rect.width(),
    225                     visible_rect.height(),
    226                     read_format,
    227                     GL_UNSIGNED_BYTE,
    228                     pixels.pixelRef()->pixels());
    229   gles2->DeleteFramebuffers(1, &fb);
    230   gles2->DeleteTextures(1, &tmp_texture);
    231 
    232   if (skia_format != read_format) {
    233     DCHECK(read_format == GL_RGBA);
    234     int pixel_count = visible_rect.width() * visible_rect.height();
    235     uint32_t* pixels_ptr = static_cast<uint32_t*>(pixels.pixelRef()->pixels());
    236     for (int i = 0; i < pixel_count; ++i) {
    237         uint32_t r = pixels_ptr[i] & 0xFF;
    238         uint32_t g = (pixels_ptr[i] >> 8) & 0xFF;
    239         uint32_t b = (pixels_ptr[i] >> 16) & 0xFF;
    240         uint32_t a = (pixels_ptr[i] >> 24) & 0xFF;
    241         pixels_ptr[i] = (r << SK_R32_SHIFT) |
    242                         (g << SK_G32_SHIFT) |
    243                         (b << SK_B32_SHIFT) |
    244                         (a << SK_A32_SHIFT);
    245     }
    246   }
    247 
    248   DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
    249 }
    250 
    251 base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory(
    252     size_t size) {
    253   DCHECK(task_runner_->BelongsToCurrentThread());
    254   return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get());
    255 }
    256 
    257 scoped_refptr<base::SingleThreadTaskRunner>
    258 RendererGpuVideoAcceleratorFactories::GetTaskRunner() {
    259   return task_runner_;
    260 }
    261 
    262 }  // namespace content
    263