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