Upstream version 7.36.149.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/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 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
204     SK_A32_SHIFT == 24
205   GLenum skia_format = GL_BGRA_EXT;
206 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
207     SK_A32_SHIFT == 24
208   GLenum skia_format = GL_RGBA;
209 #else
210 #error Unexpected Skia ARGB_8888 layout!
211 #endif
212   gles2->ReadPixels(visible_rect.x(),
213                     visible_rect.y(),
214                     visible_rect.width(),
215                     visible_rect.height(),
216                     skia_format,
217                     GL_UNSIGNED_BYTE,
218                     pixels.pixelRef()->pixels());
219   gles2->DeleteFramebuffers(1, &fb);
220   gles2->DeleteTextures(1, &tmp_texture);
221   DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
222 }
223
224 base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory(
225     size_t size) {
226   DCHECK(task_runner_->BelongsToCurrentThread());
227   return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get());
228 }
229
230 scoped_refptr<base::SingleThreadTaskRunner>
231 RendererGpuVideoAcceleratorFactories::GetTaskRunner() {
232   return task_runner_;
233 }
234
235 }  // namespace content