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.
5 #include "content/renderer/media/renderer_gpu_video_decoder_factories.h"
8 #include <GLES2/gl2ext.h>
10 #include "base/bind.h"
11 #include "content/common/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"
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 gpu_channel_host_(gpu_channel_host
),
27 aborted_waiter_(true, false),
28 async_waiter_(false, false) {
29 if (message_loop_
->BelongsToCurrentThread()) {
30 AsyncGetContext(context
);
33 // Threaded compositor requires us to wait for the context to be acquired.
34 message_loop_
->PostTask(FROM_HERE
, base::Bind(
35 &RendererGpuVideoDecoderFactories::AsyncGetContext
,
36 // Unretained to avoid ref/deref'ing |*this|, which is not yet stored in a
37 // scoped_refptr. Safe because the Wait() below keeps us alive until this
39 base::Unretained(this),
40 // OK to pass raw because the pointee is only deleted on the compositor
41 // thread, and only as the result of a PostTask from the render thread
42 // which can only happen after this function returns, so our PostTask will
48 void RendererGpuVideoDecoderFactories::AsyncGetContext(
49 WebGraphicsContext3DCommandBufferImpl
* context
) {
50 context_
= context
->AsWeakPtr();
52 if (context_
->makeContextCurrent()) {
53 // Called once per media player, but is a no-op after the first one in
55 context_
->insertEventMarkerEXT("GpuVDAContext3D");
58 async_waiter_
.Signal();
61 media::VideoDecodeAccelerator
*
62 RendererGpuVideoDecoderFactories::CreateVideoDecodeAccelerator(
63 media::VideoCodecProfile profile
,
64 media::VideoDecodeAccelerator::Client
* client
) {
65 DCHECK(!message_loop_
->BelongsToCurrentThread());
66 // The VDA is returned in the vda_ member variable by the
67 // AsyncCreateVideoDecodeAccelerator() function.
68 message_loop_
->PostTask(FROM_HERE
, base::Bind(
69 &RendererGpuVideoDecoderFactories::AsyncCreateVideoDecodeAccelerator
,
70 this, profile
, client
));
72 base::WaitableEvent
* objects
[] = {&aborted_waiter_
, &async_waiter_
};
73 if (base::WaitableEvent::WaitMany(objects
, arraysize(objects
)) == 0) {
74 // If we are aborting and the VDA is created by the
75 // AsyncCreateVideoDecodeAccelerator() function later we need to ensure
76 // that it is destroyed on the same thread.
77 message_loop_
->PostTask(FROM_HERE
, base::Bind(
78 &RendererGpuVideoDecoderFactories::AsyncDestroyVideoDecodeAccelerator
,
82 return vda_
.release();
85 void RendererGpuVideoDecoderFactories::AsyncCreateVideoDecodeAccelerator(
86 media::VideoCodecProfile profile
,
87 media::VideoDecodeAccelerator::Client
* client
) {
88 DCHECK(message_loop_
->BelongsToCurrentThread());
90 if (context_
&& context_
->GetCommandBufferProxy()) {
91 vda_
.reset(gpu_channel_host_
->CreateVideoDecoder(
92 context_
->GetCommandBufferProxy()->GetRouteID(),
95 async_waiter_
.Signal();
98 bool RendererGpuVideoDecoderFactories::CreateTextures(
99 int32 count
, const gfx::Size
& size
,
100 std::vector
<uint32
>* texture_ids
,
101 uint32 texture_target
) {
102 DCHECK(!message_loop_
->BelongsToCurrentThread());
103 message_loop_
->PostTask(FROM_HERE
, base::Bind(
104 &RendererGpuVideoDecoderFactories::AsyncCreateTextures
, this,
105 count
, size
, texture_target
));
107 base::WaitableEvent
* objects
[] = {&aborted_waiter_
, &async_waiter_
};
108 if (base::WaitableEvent::WaitMany(objects
, arraysize(objects
)) == 0)
110 texture_ids
->swap(created_textures_
);
114 void RendererGpuVideoDecoderFactories::AsyncCreateTextures(
115 int32 count
, const gfx::Size
& size
, uint32 texture_target
) {
116 DCHECK(message_loop_
->BelongsToCurrentThread());
117 DCHECK(texture_target
);
120 async_waiter_
.Signal();
123 gpu::gles2::GLES2Implementation
* gles2
= context_
->GetImplementation();
124 created_textures_
.resize(count
);
125 gles2
->GenTextures(count
, &created_textures_
[0]);
126 for (int i
= 0; i
< count
; ++i
) {
127 gles2
->ActiveTexture(GL_TEXTURE0
);
128 uint32 texture_id
= created_textures_
[i
];
129 gles2
->BindTexture(texture_target
, texture_id
);
130 gles2
->TexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
131 gles2
->TexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
132 gles2
->TexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
133 gles2
->TexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
134 if (texture_target
== GL_TEXTURE_2D
) {
135 gles2
->TexImage2D(texture_target
, 0, GL_RGBA
, size
.width(), size
.height(),
136 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
139 // We need a glFlush here to guarantee the decoder (in the GPU process) can
140 // use the texture ids we return here. Since textures are expected to be
141 // reused, this should not be unacceptably expensive.
143 DCHECK_EQ(gles2
->GetError(), static_cast<GLenum
>(GL_NO_ERROR
));
144 async_waiter_
.Signal();
147 void RendererGpuVideoDecoderFactories::DeleteTexture(uint32 texture_id
) {
148 DCHECK(!message_loop_
->BelongsToCurrentThread());
149 message_loop_
->PostTask(FROM_HERE
, base::Bind(
150 &RendererGpuVideoDecoderFactories::AsyncDeleteTexture
, this, texture_id
));
153 void RendererGpuVideoDecoderFactories::AsyncDeleteTexture(uint32 texture_id
) {
154 DCHECK(message_loop_
->BelongsToCurrentThread());
158 gpu::gles2::GLES2Implementation
* gles2
= context_
->GetImplementation();
159 gles2
->DeleteTextures(1, &texture_id
);
160 DCHECK_EQ(gles2
->GetError(), static_cast<GLenum
>(GL_NO_ERROR
));
163 void RendererGpuVideoDecoderFactories::ReadPixels(
164 uint32 texture_id
, uint32 texture_target
, const gfx::Size
& size
,
165 const SkBitmap
& pixels
) {
166 // SkBitmaps use the SkPixelRef object to refcount the underlying pixels.
167 // Multiple SkBitmaps can share a SkPixelRef instance. We use this to
168 // ensure that the underlying pixels in the SkBitmap passed in remain valid
169 // until the AsyncReadPixels() call completes.
170 read_pixels_bitmap_
.setPixelRef(pixels
.pixelRef());
172 if (!message_loop_
->BelongsToCurrentThread()) {
173 message_loop_
->PostTask(FROM_HERE
, base::Bind(
174 &RendererGpuVideoDecoderFactories::AsyncReadPixels
, this,
175 texture_id
, texture_target
, size
));
176 base::WaitableEvent
* objects
[] = {&aborted_waiter_
, &async_waiter_
};
177 if (base::WaitableEvent::WaitMany(objects
, arraysize(objects
)) == 0)
180 AsyncReadPixels(texture_id
, texture_target
, size
);
182 read_pixels_bitmap_
.setPixelRef(NULL
);
185 void RendererGpuVideoDecoderFactories::AsyncReadPixels(
186 uint32 texture_id
, uint32 texture_target
, const gfx::Size
& size
) {
187 DCHECK(message_loop_
->BelongsToCurrentThread());
189 async_waiter_
.Signal();
193 gpu::gles2::GLES2Implementation
* gles2
= context_
->GetImplementation();
196 gles2
->GenTextures(1, &tmp_texture
);
197 gles2
->BindTexture(texture_target
, tmp_texture
);
198 gles2
->TexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
199 gles2
->TexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
200 gles2
->TexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
201 gles2
->TexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
202 context_
->copyTextureCHROMIUM(
203 texture_target
, texture_id
, tmp_texture
, 0, GL_RGBA
);
206 gles2
->GenFramebuffers(1, &fb
);
207 gles2
->BindFramebuffer(GL_FRAMEBUFFER
, fb
);
208 gles2
->FramebufferTexture2D(GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
209 texture_target
, tmp_texture
, 0);
210 gles2
->PixelStorei(GL_PACK_ALIGNMENT
, 4);
211 gles2
->ReadPixels(0, 0, size
.width(), size
.height(), GL_BGRA_EXT
,
212 GL_UNSIGNED_BYTE
, read_pixels_bitmap_
.pixelRef()->pixels());
213 gles2
->DeleteFramebuffers(1, &fb
);
214 gles2
->DeleteTextures(1, &tmp_texture
);
215 DCHECK_EQ(gles2
->GetError(), static_cast<GLenum
>(GL_NO_ERROR
));
216 async_waiter_
.Signal();
219 base::SharedMemory
* RendererGpuVideoDecoderFactories::CreateSharedMemory(
221 DCHECK_NE(MessageLoop::current(), ChildThread::current()->message_loop());
222 ChildThread::current()->message_loop()->PostTask(FROM_HERE
, base::Bind(
223 &RendererGpuVideoDecoderFactories::AsyncCreateSharedMemory
, this,
226 base::WaitableEvent
* objects
[] = {&aborted_waiter_
, &async_waiter_
};
227 if (base::WaitableEvent::WaitMany(objects
, arraysize(objects
)) == 0)
229 return shared_memory_segment_
.release();
232 void RendererGpuVideoDecoderFactories::AsyncCreateSharedMemory(
234 DCHECK_EQ(MessageLoop::current(), ChildThread::current()->message_loop());
236 shared_memory_segment_
.reset(
237 ChildThread::current()->AllocateSharedMemory(size
));
238 async_waiter_
.Signal();
241 scoped_refptr
<base::MessageLoopProxy
>
242 RendererGpuVideoDecoderFactories::GetMessageLoop() {
243 return message_loop_
;
246 void RendererGpuVideoDecoderFactories::Abort() {
247 aborted_waiter_
.Signal();
250 bool RendererGpuVideoDecoderFactories::IsAborted() {
251 return aborted_waiter_
.IsSignaled();
254 void RendererGpuVideoDecoderFactories::AsyncDestroyVideoDecodeAccelerator() {
255 // OK to release because Destroy() will delete the VDA instance.
257 vda_
.release()->Destroy();
260 } // namespace content