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.
5 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
8 #include <GLES2/gl2ext.h>
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"
21 RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {}
22 RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories(
23 GpuChannelHost* gpu_channel_host,
24 const scoped_refptr<ContextProviderCommandBuffer>& context_provider)
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_)
36 if (message_loop_->BelongsToCurrentThread()) {
38 message_loop_async_waiter_.Reset();
41 // Wait for the context to be acquired.
42 message_loop_->PostTask(
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();
52 RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories()
53 : aborted_waiter_(true, false),
54 message_loop_async_waiter_(false, false) {}
56 WebGraphicsContext3DCommandBufferImpl*
57 RendererGpuVideoAcceleratorFactories::GetContext3d() {
58 DCHECK(message_loop_->BelongsToCurrentThread());
59 if (!context_provider_)
61 WebGraphicsContext3DCommandBufferImpl* context =
62 context_provider_->Context3d();
63 if (context->isContextLost()) {
64 context_provider_->VerifyContexts();
65 context_provider_ = NULL;
71 void RendererGpuVideoAcceleratorFactories::AsyncBindContext() {
72 DCHECK(message_loop_->BelongsToCurrentThread());
73 if (!context_provider_->BindToCurrentThread())
74 context_provider_ = NULL;
75 message_loop_async_waiter_.Signal();
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();
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,
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,
106 return scoped_ptr<media::VideoDecodeAccelerator>();
111 scoped_ptr<media::VideoEncodeAccelerator>
112 RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator(
113 media::VideoEncodeAccelerator::Client* client) {
114 DCHECK(message_loop_->BelongsToCurrentThread());
116 return gpu_channel_host_->CreateVideoEncoder(client);
119 void RendererGpuVideoAcceleratorFactories::AsyncCreateVideoDecodeAccelerator(
120 media::VideoCodecProfile profile,
121 media::VideoDecodeAccelerator::Client* client) {
122 DCHECK(message_loop_->BelongsToCurrentThread());
124 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
125 if (context && context->GetCommandBufferProxy()) {
126 vda_ = gpu_channel_host_->CreateVideoDecoder(
127 context->GetCommandBufferProxy()->GetRouteID(), profile, client);
129 message_loop_async_waiter_.Signal();
132 uint32 RendererGpuVideoAcceleratorFactories::CreateTextures(
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);
141 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
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,
168 gles2->GenMailboxCHROMIUM(texture_mailboxes->at(i).name);
169 gles2->ProduceTextureCHROMIUM(texture_target,
170 texture_mailboxes->at(i).name);
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.
177 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
179 return gles2->InsertSyncPointCHROMIUM();
182 void RendererGpuVideoAcceleratorFactories::DeleteTexture(uint32 texture_id) {
183 DCHECK(message_loop_->BelongsToCurrentThread());
185 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
189 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
190 gles2->DeleteTextures(1, &texture_id);
191 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
194 void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point) {
195 DCHECK(message_loop_->BelongsToCurrentThread());
197 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
201 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
202 gles2->WaitSyncPointCHROMIUM(sync_point);
204 // Callers expect the WaitSyncPoint to affect the next IPCs. Make sure to
205 // flush the command buffers to ensure that.
206 gles2->ShallowFlushCHROMIUM();
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());
218 if (!message_loop_->BelongsToCurrentThread()) {
219 message_loop_->PostTask(
221 base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncReadPixels,
225 base::WaitableEvent* objects[] = {&aborted_waiter_,
226 &message_loop_async_waiter_};
227 if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0)
230 AsyncReadPixels(texture_id, size);
231 message_loop_async_waiter_.Reset();
233 read_pixels_bitmap_.setPixelRef(NULL);
236 void RendererGpuVideoAcceleratorFactories::AsyncReadPixels(
238 const gfx::Size& size) {
239 DCHECK(message_loop_->BelongsToCurrentThread());
240 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
242 message_loop_async_waiter_.Signal();
246 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
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);
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 && \
266 GLenum skia_format = GL_BGRA_EXT;
267 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
269 GLenum skia_format = GL_RGBA;
271 #error Unexpected Skia ARGB_8888 layout!
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();
286 base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory(
288 DCHECK(message_loop_->BelongsToCurrentThread());
289 return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get());
292 scoped_refptr<base::MessageLoopProxy>
293 RendererGpuVideoAcceleratorFactories::GetMessageLoop() {
294 return message_loop_;
297 void RendererGpuVideoAcceleratorFactories::Abort() { aborted_waiter_.Signal(); }
299 bool RendererGpuVideoAcceleratorFactories::IsAborted() {
300 return aborted_waiter_.IsSignaled();
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_;
315 RendererGpuVideoAcceleratorFactories::AsyncDestroyVideoDecodeAccelerator() {
316 // OK to release because Destroy() will delete the VDA instance.
318 vda_.release()->Destroy();
321 } // namespace content