Fix build break
[chromium-blink-merge.git] / content / renderer / media / renderer_gpu_video_decoder_factories.cc
blob1f0e85a754badb76c2f739d0ec3b049ed7ca7af3
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"
7 #include <GLES2/gl2.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"
18 namespace content {
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);
31 return;
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
38 // task completes.
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
43 // run first.
44 context));
45 async_waiter_.Wait();
48 void RendererGpuVideoDecoderFactories::AsyncGetContext(
49 WebGraphicsContext3DCommandBufferImpl* context) {
50 context_ = context->AsWeakPtr();
51 if (context_) {
52 if (context_->makeContextCurrent()) {
53 // Called once per media player, but is a no-op after the first one in
54 // each renderer.
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,
79 this));
80 return NULL;
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(),
93 profile, client));
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)
109 return false;
110 texture_ids->swap(created_textures_);
111 return true;
114 void RendererGpuVideoDecoderFactories::AsyncCreateTextures(
115 int32 count, const gfx::Size& size, uint32 texture_target) {
116 DCHECK(message_loop_->BelongsToCurrentThread());
117 DCHECK(texture_target);
119 if (!context_) {
120 async_waiter_.Signal();
121 return;
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.
142 gles2->Flush();
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());
155 if (!context_)
156 return;
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)
178 return;
179 } else {
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());
188 if (!context_) {
189 async_waiter_.Signal();
190 return;
193 gpu::gles2::GLES2Implementation* gles2 = context_->GetImplementation();
195 GLuint tmp_texture;
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);
205 GLuint fb;
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(
220 size_t size) {
221 DCHECK_NE(MessageLoop::current(), ChildThread::current()->message_loop());
222 ChildThread::current()->message_loop()->PostTask(FROM_HERE, base::Bind(
223 &RendererGpuVideoDecoderFactories::AsyncCreateSharedMemory, this,
224 size));
226 base::WaitableEvent* objects[] = {&aborted_waiter_, &async_waiter_};
227 if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0)
228 return NULL;
229 return shared_memory_segment_.release();
232 void RendererGpuVideoDecoderFactories::AsyncCreateSharedMemory(
233 size_t size) {
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.
256 if (vda_)
257 vda_.release()->Destroy();
260 } // namespace content