- add sources.
[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 "third_party/skia/include/core/SkPixelRef.h"
18
19 namespace content {
20
21 RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {}
22 RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories(
23     GpuChannelHost* gpu_channel_host,
24     const scoped_refptr<ContextProviderCommandBuffer>& context_provider)
25     : message_loop_(
26           RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy()),
27       gpu_channel_host_(gpu_channel_host),
28       context_provider_(context_provider),
29       thread_safe_sender_(ChildThread::current()->thread_safe_sender()),
30       aborted_waiter_(true, false),
31       message_loop_async_waiter_(false, false) {
32   // |context_provider_| is only required to support HW-accelerated decode.
33   if (!context_provider_)
34     return;
35
36   if (message_loop_->BelongsToCurrentThread()) {
37     AsyncBindContext();
38     message_loop_async_waiter_.Reset();
39     return;
40   }
41   // Wait for the context to be acquired.
42   message_loop_->PostTask(
43       FROM_HERE,
44       base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncBindContext,
45                  // Unretained to avoid ref/deref'ing |*this|, which is not yet
46                  // stored in a scoped_refptr.  Safe because the Wait() below
47                  // keeps us alive until this task completes.
48                  base::Unretained(this)));
49   message_loop_async_waiter_.Wait();
50 }
51
52 RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories()
53     : aborted_waiter_(true, false),
54       message_loop_async_waiter_(false, false) {}
55
56 WebGraphicsContext3DCommandBufferImpl*
57 RendererGpuVideoAcceleratorFactories::GetContext3d() {
58   DCHECK(message_loop_->BelongsToCurrentThread());
59   if (!context_provider_)
60     return NULL;
61   WebGraphicsContext3DCommandBufferImpl* context =
62       context_provider_->Context3d();
63   if (context->isContextLost()) {
64     context_provider_->VerifyContexts();
65     context_provider_ = NULL;
66     return NULL;
67   }
68   return context;
69 }
70
71 void RendererGpuVideoAcceleratorFactories::AsyncBindContext() {
72   DCHECK(message_loop_->BelongsToCurrentThread());
73   if (!context_provider_->BindToCurrentThread())
74     context_provider_ = NULL;
75   message_loop_async_waiter_.Signal();
76 }
77
78 scoped_ptr<media::VideoDecodeAccelerator>
79 RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator(
80     media::VideoCodecProfile profile,
81     media::VideoDecodeAccelerator::Client* client) {
82   if (message_loop_->BelongsToCurrentThread()) {
83     AsyncCreateVideoDecodeAccelerator(profile, client);
84     message_loop_async_waiter_.Reset();
85     return vda_.Pass();
86   }
87   // The VDA is returned in the vda_ member variable by the
88   // AsyncCreateVideoDecodeAccelerator() function.
89   message_loop_->PostTask(FROM_HERE,
90                           base::Bind(&RendererGpuVideoAcceleratorFactories::
91                                          AsyncCreateVideoDecodeAccelerator,
92                                      this,
93                                      profile,
94                                      client));
95
96   base::WaitableEvent* objects[] = {&aborted_waiter_,
97                                     &message_loop_async_waiter_};
98   if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0) {
99     // If we are aborting and the VDA is created by the
100     // AsyncCreateVideoDecodeAccelerator() function later we need to ensure
101     // that it is destroyed on the same thread.
102     message_loop_->PostTask(FROM_HERE,
103                             base::Bind(&RendererGpuVideoAcceleratorFactories::
104                                            AsyncDestroyVideoDecodeAccelerator,
105                                        this));
106     return scoped_ptr<media::VideoDecodeAccelerator>();
107   }
108   return vda_.Pass();
109 }
110
111 scoped_ptr<media::VideoEncodeAccelerator>
112 RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator(
113     media::VideoEncodeAccelerator::Client* client) {
114   DCHECK(message_loop_->BelongsToCurrentThread());
115
116   return gpu_channel_host_->CreateVideoEncoder(client);
117 }
118
119 void RendererGpuVideoAcceleratorFactories::AsyncCreateVideoDecodeAccelerator(
120     media::VideoCodecProfile profile,
121     media::VideoDecodeAccelerator::Client* client) {
122   DCHECK(message_loop_->BelongsToCurrentThread());
123
124   WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
125   if (context && context->GetCommandBufferProxy()) {
126     vda_ = gpu_channel_host_->CreateVideoDecoder(
127         context->GetCommandBufferProxy()->GetRouteID(), profile, client);
128   }
129   message_loop_async_waiter_.Signal();
130 }
131
132 uint32 RendererGpuVideoAcceleratorFactories::CreateTextures(
133     int32 count,
134     const gfx::Size& size,
135     std::vector<uint32>* texture_ids,
136     std::vector<gpu::Mailbox>* texture_mailboxes,
137     uint32 texture_target) {
138   DCHECK(message_loop_->BelongsToCurrentThread());
139   DCHECK(texture_target);
140
141   WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
142   if (!context)
143     return 0;
144
145   gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
146   texture_ids->resize(count);
147   texture_mailboxes->resize(count);
148   gles2->GenTextures(count, &texture_ids->at(0));
149   for (int i = 0; i < count; ++i) {
150     gles2->ActiveTexture(GL_TEXTURE0);
151     uint32 texture_id = texture_ids->at(i);
152     gles2->BindTexture(texture_target, texture_id);
153     gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
154     gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
155     gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
156     gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
157     if (texture_target == GL_TEXTURE_2D) {
158       gles2->TexImage2D(texture_target,
159                         0,
160                         GL_RGBA,
161                         size.width(),
162                         size.height(),
163                         0,
164                         GL_RGBA,
165                         GL_UNSIGNED_BYTE,
166                         NULL);
167     }
168     gles2->GenMailboxCHROMIUM(texture_mailboxes->at(i).name);
169     gles2->ProduceTextureCHROMIUM(texture_target,
170                                   texture_mailboxes->at(i).name);
171   }
172
173   // We need a glFlush here to guarantee the decoder (in the GPU process) can
174   // use the texture ids we return here.  Since textures are expected to be
175   // reused, this should not be unacceptably expensive.
176   gles2->Flush();
177   DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
178
179   return gles2->InsertSyncPointCHROMIUM();
180 }
181
182 void RendererGpuVideoAcceleratorFactories::DeleteTexture(uint32 texture_id) {
183   DCHECK(message_loop_->BelongsToCurrentThread());
184
185   WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
186   if (!context)
187     return;
188
189   gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
190   gles2->DeleteTextures(1, &texture_id);
191   DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
192 }
193
194 void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point) {
195   DCHECK(message_loop_->BelongsToCurrentThread());
196
197   WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
198   if (!context)
199     return;
200
201   gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
202   gles2->WaitSyncPointCHROMIUM(sync_point);
203
204   // Callers expect the WaitSyncPoint to affect the next IPCs. Make sure to
205   // flush the command buffers to ensure that.
206   gles2->ShallowFlushCHROMIUM();
207 }
208
209 void RendererGpuVideoAcceleratorFactories::ReadPixels(uint32 texture_id,
210                                                       const gfx::Size& size,
211                                                       const SkBitmap& pixels) {
212   // SkBitmaps use the SkPixelRef object to refcount the underlying pixels.
213   // Multiple SkBitmaps can share a SkPixelRef instance. We use this to
214   // ensure that the underlying pixels in the SkBitmap passed in remain valid
215   // until the AsyncReadPixels() call completes.
216   read_pixels_bitmap_.setPixelRef(pixels.pixelRef());
217
218   if (!message_loop_->BelongsToCurrentThread()) {
219     message_loop_->PostTask(
220         FROM_HERE,
221         base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncReadPixels,
222                    this,
223                    texture_id,
224                    size));
225     base::WaitableEvent* objects[] = {&aborted_waiter_,
226                                       &message_loop_async_waiter_};
227     if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0)
228       return;
229   } else {
230     AsyncReadPixels(texture_id, size);
231     message_loop_async_waiter_.Reset();
232   }
233   read_pixels_bitmap_.setPixelRef(NULL);
234 }
235
236 void RendererGpuVideoAcceleratorFactories::AsyncReadPixels(
237     uint32 texture_id,
238     const gfx::Size& size) {
239   DCHECK(message_loop_->BelongsToCurrentThread());
240   WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
241   if (!context) {
242     message_loop_async_waiter_.Signal();
243     return;
244   }
245
246   gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
247
248   GLuint tmp_texture;
249   gles2->GenTextures(1, &tmp_texture);
250   gles2->BindTexture(GL_TEXTURE_2D, tmp_texture);
251   gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
252   gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
253   gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
254   gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
255   context->copyTextureCHROMIUM(
256       GL_TEXTURE_2D, texture_id, tmp_texture, 0, GL_RGBA, GL_UNSIGNED_BYTE);
257
258   GLuint fb;
259   gles2->GenFramebuffers(1, &fb);
260   gles2->BindFramebuffer(GL_FRAMEBUFFER, fb);
261   gles2->FramebufferTexture2D(
262       GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_texture, 0);
263   gles2->PixelStorei(GL_PACK_ALIGNMENT, 4);
264 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
265     SK_A32_SHIFT == 24
266   GLenum skia_format = GL_BGRA_EXT;
267 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
268     SK_A32_SHIFT == 24
269   GLenum skia_format = GL_RGBA;
270 #else
271 #error Unexpected Skia ARGB_8888 layout!
272 #endif
273   gles2->ReadPixels(0,
274                     0,
275                     size.width(),
276                     size.height(),
277                     skia_format,
278                     GL_UNSIGNED_BYTE,
279                     read_pixels_bitmap_.pixelRef()->pixels());
280   gles2->DeleteFramebuffers(1, &fb);
281   gles2->DeleteTextures(1, &tmp_texture);
282   DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
283   message_loop_async_waiter_.Signal();
284 }
285
286 base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory(
287     size_t size) {
288   DCHECK(message_loop_->BelongsToCurrentThread());
289   return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get());
290 }
291
292 scoped_refptr<base::MessageLoopProxy>
293 RendererGpuVideoAcceleratorFactories::GetMessageLoop() {
294   return message_loop_;
295 }
296
297 void RendererGpuVideoAcceleratorFactories::Abort() { aborted_waiter_.Signal(); }
298
299 bool RendererGpuVideoAcceleratorFactories::IsAborted() {
300   return aborted_waiter_.IsSignaled();
301 }
302
303 scoped_refptr<RendererGpuVideoAcceleratorFactories>
304 RendererGpuVideoAcceleratorFactories::Clone() {
305   scoped_refptr<RendererGpuVideoAcceleratorFactories> factories =
306       new RendererGpuVideoAcceleratorFactories();
307   factories->message_loop_ = message_loop_;
308   factories->gpu_channel_host_ = gpu_channel_host_;
309   factories->context_provider_ = context_provider_;
310   factories->thread_safe_sender_ = thread_safe_sender_;
311   return factories;
312 }
313
314 void
315 RendererGpuVideoAcceleratorFactories::AsyncDestroyVideoDecodeAccelerator() {
316   // OK to release because Destroy() will delete the VDA instance.
317   if (vda_)
318     vda_.release()->Destroy();
319 }
320
321 }  // namespace content