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