OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h" | 5 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h" |
6 | 6 |
7 #include <GLES2/gl2.h> | 7 #include <GLES2/gl2.h> |
8 #include <GLES2/gl2ext.h> | 8 #include <GLES2/gl2ext.h> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "content/child/child_thread.h" | 11 #include "content/child/child_thread.h" |
12 #include "content/common/gpu/client/context_provider_command_buffer.h" | 12 #include "content/common/gpu/client/context_provider_command_buffer.h" |
13 #include "content/common/gpu/client/gpu_channel_host.h" | 13 #include "content/common/gpu/client/gpu_channel_host.h" |
14 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" | 14 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" |
15 #include "content/renderer/render_thread_impl.h" | 15 #include "content/renderer/render_thread_impl.h" |
16 #include "gpu/command_buffer/client/gles2_implementation.h" | 16 #include "gpu/command_buffer/client/gles2_implementation.h" |
| 17 #include "third_party/skia/include/core/SkBitmap.h" |
17 #include "third_party/skia/include/core/SkPixelRef.h" | 18 #include "third_party/skia/include/core/SkPixelRef.h" |
18 | 19 |
19 namespace content { | 20 namespace content { |
20 | 21 |
21 RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {} | 22 RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {} |
22 RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories( | 23 RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories( |
23 GpuChannelHost* gpu_channel_host, | 24 GpuChannelHost* gpu_channel_host, |
| 25 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy, |
24 const scoped_refptr<ContextProviderCommandBuffer>& context_provider) | 26 const scoped_refptr<ContextProviderCommandBuffer>& context_provider) |
25 : message_loop_( | 27 : message_loop_proxy_(message_loop_proxy), |
26 RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy()), | |
27 gpu_channel_host_(gpu_channel_host), | 28 gpu_channel_host_(gpu_channel_host), |
28 context_provider_(context_provider), | 29 context_provider_(context_provider), |
29 thread_safe_sender_(ChildThread::current()->thread_safe_sender()), | 30 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 | 31 |
56 WebGraphicsContext3DCommandBufferImpl* | 32 WebGraphicsContext3DCommandBufferImpl* |
57 RendererGpuVideoAcceleratorFactories::GetContext3d() { | 33 RendererGpuVideoAcceleratorFactories::GetContext3d() { |
58 DCHECK(message_loop_->BelongsToCurrentThread()); | 34 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
59 if (!context_provider_) | 35 if (!context_provider_) |
60 return NULL; | 36 return NULL; |
61 WebGraphicsContext3DCommandBufferImpl* context = | 37 WebGraphicsContext3DCommandBufferImpl* context = |
62 context_provider_->Context3d(); | 38 context_provider_->Context3d(); |
63 if (context->isContextLost()) { | 39 if (context->isContextLost()) { |
64 context_provider_->VerifyContexts(); | 40 context_provider_->VerifyContexts(); |
65 context_provider_ = NULL; | 41 context_provider_ = NULL; |
66 return NULL; | 42 return NULL; |
67 } | 43 } |
68 return context; | 44 return context; |
69 } | 45 } |
70 | 46 |
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> | 47 scoped_ptr<media::VideoDecodeAccelerator> |
79 RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator( | 48 RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator( |
80 media::VideoCodecProfile profile, | 49 media::VideoCodecProfile profile, |
81 media::VideoDecodeAccelerator::Client* client) { | 50 media::VideoDecodeAccelerator::Client* client) { |
82 if (message_loop_->BelongsToCurrentThread()) { | 51 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
83 AsyncCreateVideoDecodeAccelerator(profile, client); | 52 |
84 message_loop_async_waiter_.Reset(); | 53 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
85 return vda_.Pass(); | 54 if (context && context->GetCommandBufferProxy()) { |
| 55 return gpu_channel_host_->CreateVideoDecoder( |
| 56 context->GetCommandBufferProxy()->GetRouteID(), profile, client); |
86 } | 57 } |
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 | 58 |
96 base::WaitableEvent* objects[] = {&aborted_waiter_, | 59 return scoped_ptr<media::VideoDecodeAccelerator>(); |
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 } | 60 } |
110 | 61 |
111 scoped_ptr<media::VideoEncodeAccelerator> | 62 scoped_ptr<media::VideoEncodeAccelerator> |
112 RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator( | 63 RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator( |
113 media::VideoEncodeAccelerator::Client* client) { | 64 media::VideoEncodeAccelerator::Client* client) { |
114 DCHECK(message_loop_->BelongsToCurrentThread()); | 65 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
115 | 66 |
116 return gpu_channel_host_->CreateVideoEncoder(client); | 67 return gpu_channel_host_->CreateVideoEncoder(client); |
117 } | 68 } |
118 | 69 |
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( | 70 uint32 RendererGpuVideoAcceleratorFactories::CreateTextures( |
133 int32 count, | 71 int32 count, |
134 const gfx::Size& size, | 72 const gfx::Size& size, |
135 std::vector<uint32>* texture_ids, | 73 std::vector<uint32>* texture_ids, |
136 std::vector<gpu::Mailbox>* texture_mailboxes, | 74 std::vector<gpu::Mailbox>* texture_mailboxes, |
137 uint32 texture_target) { | 75 uint32 texture_target) { |
138 DCHECK(message_loop_->BelongsToCurrentThread()); | 76 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
139 DCHECK(texture_target); | 77 DCHECK(texture_target); |
140 | 78 |
141 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); | 79 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
142 if (!context) | 80 if (!context) |
143 return 0; | 81 return 0; |
144 | 82 |
145 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); | 83 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); |
146 texture_ids->resize(count); | 84 texture_ids->resize(count); |
147 texture_mailboxes->resize(count); | 85 texture_mailboxes->resize(count); |
148 gles2->GenTextures(count, &texture_ids->at(0)); | 86 gles2->GenTextures(count, &texture_ids->at(0)); |
(...skipping 24 matching lines...) Expand all Loading... |
173 // We need a glFlush here to guarantee the decoder (in the GPU process) can | 111 // 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 | 112 // use the texture ids we return here. Since textures are expected to be |
175 // reused, this should not be unacceptably expensive. | 113 // reused, this should not be unacceptably expensive. |
176 gles2->Flush(); | 114 gles2->Flush(); |
177 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); | 115 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); |
178 | 116 |
179 return gles2->InsertSyncPointCHROMIUM(); | 117 return gles2->InsertSyncPointCHROMIUM(); |
180 } | 118 } |
181 | 119 |
182 void RendererGpuVideoAcceleratorFactories::DeleteTexture(uint32 texture_id) { | 120 void RendererGpuVideoAcceleratorFactories::DeleteTexture(uint32 texture_id) { |
183 DCHECK(message_loop_->BelongsToCurrentThread()); | 121 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
184 | 122 |
185 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); | 123 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
186 if (!context) | 124 if (!context) |
187 return; | 125 return; |
188 | 126 |
189 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); | 127 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); |
190 gles2->DeleteTextures(1, &texture_id); | 128 gles2->DeleteTextures(1, &texture_id); |
191 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); | 129 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); |
192 } | 130 } |
193 | 131 |
194 void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point) { | 132 void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point) { |
195 DCHECK(message_loop_->BelongsToCurrentThread()); | 133 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
196 | 134 |
197 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); | 135 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
198 if (!context) | 136 if (!context) |
199 return; | 137 return; |
200 | 138 |
201 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); | 139 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); |
202 gles2->WaitSyncPointCHROMIUM(sync_point); | 140 gles2->WaitSyncPointCHROMIUM(sync_point); |
203 } | 141 } |
204 | 142 |
205 void RendererGpuVideoAcceleratorFactories::ReadPixels(uint32 texture_id, | 143 void RendererGpuVideoAcceleratorFactories::ReadPixels(uint32 texture_id, |
206 const gfx::Size& size, | 144 const gfx::Size& size, |
207 const SkBitmap& pixels) { | 145 const SkBitmap& pixels) { |
208 // SkBitmaps use the SkPixelRef object to refcount the underlying pixels. | 146 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
209 // Multiple SkBitmaps can share a SkPixelRef instance. We use this to | |
210 // ensure that the underlying pixels in the SkBitmap passed in remain valid | |
211 // until the AsyncReadPixels() call completes. | |
212 read_pixels_bitmap_.setPixelRef(pixels.pixelRef()); | |
213 | 147 |
214 if (!message_loop_->BelongsToCurrentThread()) { | |
215 message_loop_->PostTask( | |
216 FROM_HERE, | |
217 base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncReadPixels, | |
218 this, | |
219 texture_id, | |
220 size)); | |
221 base::WaitableEvent* objects[] = {&aborted_waiter_, | |
222 &message_loop_async_waiter_}; | |
223 if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0) | |
224 return; | |
225 } else { | |
226 AsyncReadPixels(texture_id, size); | |
227 message_loop_async_waiter_.Reset(); | |
228 } | |
229 read_pixels_bitmap_.setPixelRef(NULL); | |
230 } | |
231 | |
232 void RendererGpuVideoAcceleratorFactories::AsyncReadPixels( | |
233 uint32 texture_id, | |
234 const gfx::Size& size) { | |
235 DCHECK(message_loop_->BelongsToCurrentThread()); | |
236 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); | 148 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
237 if (!context) { | 149 if (!context) |
238 message_loop_async_waiter_.Signal(); | |
239 return; | 150 return; |
240 } | |
241 | 151 |
242 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); | 152 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); |
243 | 153 |
244 GLuint tmp_texture; | 154 GLuint tmp_texture; |
245 gles2->GenTextures(1, &tmp_texture); | 155 gles2->GenTextures(1, &tmp_texture); |
246 gles2->BindTexture(GL_TEXTURE_2D, tmp_texture); | 156 gles2->BindTexture(GL_TEXTURE_2D, tmp_texture); |
247 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 157 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
248 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 158 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
249 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 159 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
250 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 160 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
(...skipping 14 matching lines...) Expand all Loading... |
265 GLenum skia_format = GL_RGBA; | 175 GLenum skia_format = GL_RGBA; |
266 #else | 176 #else |
267 #error Unexpected Skia ARGB_8888 layout! | 177 #error Unexpected Skia ARGB_8888 layout! |
268 #endif | 178 #endif |
269 gles2->ReadPixels(0, | 179 gles2->ReadPixels(0, |
270 0, | 180 0, |
271 size.width(), | 181 size.width(), |
272 size.height(), | 182 size.height(), |
273 skia_format, | 183 skia_format, |
274 GL_UNSIGNED_BYTE, | 184 GL_UNSIGNED_BYTE, |
275 read_pixels_bitmap_.pixelRef()->pixels()); | 185 pixels.pixelRef()->pixels()); |
276 gles2->DeleteFramebuffers(1, &fb); | 186 gles2->DeleteFramebuffers(1, &fb); |
277 gles2->DeleteTextures(1, &tmp_texture); | 187 gles2->DeleteTextures(1, &tmp_texture); |
278 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); | 188 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); |
279 message_loop_async_waiter_.Signal(); | |
280 } | 189 } |
281 | 190 |
282 base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory( | 191 base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory( |
283 size_t size) { | 192 size_t size) { |
284 DCHECK(message_loop_->BelongsToCurrentThread()); | 193 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
285 return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get()); | 194 return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get()); |
286 } | 195 } |
287 | 196 |
288 scoped_refptr<base::MessageLoopProxy> | 197 scoped_refptr<base::MessageLoopProxy> |
289 RendererGpuVideoAcceleratorFactories::GetMessageLoop() { | 198 RendererGpuVideoAcceleratorFactories::GetMessageLoop() { |
290 return message_loop_; | 199 return message_loop_proxy_; |
291 } | |
292 | |
293 void RendererGpuVideoAcceleratorFactories::Abort() { aborted_waiter_.Signal(); } | |
294 | |
295 bool RendererGpuVideoAcceleratorFactories::IsAborted() { | |
296 return aborted_waiter_.IsSignaled(); | |
297 } | |
298 | |
299 scoped_refptr<RendererGpuVideoAcceleratorFactories> | |
300 RendererGpuVideoAcceleratorFactories::Clone() { | |
301 scoped_refptr<RendererGpuVideoAcceleratorFactories> factories = | |
302 new RendererGpuVideoAcceleratorFactories(); | |
303 factories->message_loop_ = message_loop_; | |
304 factories->gpu_channel_host_ = gpu_channel_host_; | |
305 factories->context_provider_ = context_provider_; | |
306 factories->thread_safe_sender_ = thread_safe_sender_; | |
307 return factories; | |
308 } | |
309 | |
310 void | |
311 RendererGpuVideoAcceleratorFactories::AsyncDestroyVideoDecodeAccelerator() { | |
312 // OK to release because Destroy() will delete the VDA instance. | |
313 if (vda_) | |
314 vda_.release()->Destroy(); | |
315 } | 200 } |
316 | 201 |
317 } // namespace content | 202 } // namespace content |
OLD | NEW |