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" | |
18 #include "third_party/skia/include/core/SkPixelRef.h" | 17 #include "third_party/skia/include/core/SkPixelRef.h" |
19 | 18 |
20 namespace content { | 19 namespace content { |
21 | 20 |
22 RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {} | 21 RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {} |
23 RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories( | 22 RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories( |
24 GpuChannelHost* gpu_channel_host, | 23 GpuChannelHost* gpu_channel_host, |
25 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy, | |
26 const scoped_refptr<ContextProviderCommandBuffer>& context_provider) | 24 const scoped_refptr<ContextProviderCommandBuffer>& context_provider) |
27 : task_runner_(message_loop_proxy), | 25 : task_runner_( |
| 26 RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy()), |
28 gpu_channel_host_(gpu_channel_host), | 27 gpu_channel_host_(gpu_channel_host), |
29 context_provider_(context_provider), | 28 context_provider_(context_provider), |
30 thread_safe_sender_(ChildThread::current()->thread_safe_sender()) {} | 29 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) {} |
31 | 55 |
32 WebGraphicsContext3DCommandBufferImpl* | 56 WebGraphicsContext3DCommandBufferImpl* |
33 RendererGpuVideoAcceleratorFactories::GetContext3d() { | 57 RendererGpuVideoAcceleratorFactories::GetContext3d() { |
34 DCHECK(task_runner_->BelongsToCurrentThread()); | 58 DCHECK(task_runner_->BelongsToCurrentThread()); |
35 if (!context_provider_) | 59 if (!context_provider_) |
36 return NULL; | 60 return NULL; |
37 if (context_provider_->IsContextLost()) { | 61 if (context_provider_->IsContextLost()) { |
38 context_provider_->VerifyContexts(); | 62 context_provider_->VerifyContexts(); |
39 context_provider_ = NULL; | 63 context_provider_ = NULL; |
40 return NULL; | 64 return NULL; |
41 } | 65 } |
42 return context_provider_->WebContext3D(); | 66 return context_provider_->WebContext3D(); |
43 } | 67 } |
44 | 68 |
| 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 |
45 scoped_ptr<media::VideoDecodeAccelerator> | 76 scoped_ptr<media::VideoDecodeAccelerator> |
46 RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator( | 77 RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator( |
47 media::VideoCodecProfile profile, | 78 media::VideoCodecProfile profile, |
48 media::VideoDecodeAccelerator::Client* client) { | 79 media::VideoDecodeAccelerator::Client* client) { |
49 DCHECK(task_runner_->BelongsToCurrentThread()); | 80 if (task_runner_->BelongsToCurrentThread()) { |
| 81 AsyncCreateVideoDecodeAccelerator(profile, client); |
| 82 task_runner_async_waiter_.Reset(); |
| 83 return vda_.Pass(); |
| 84 } |
| 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)); |
50 | 93 |
51 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); | 94 base::WaitableEvent* objects[] = {&aborted_waiter_, |
52 if (context && context->GetCommandBufferProxy()) { | 95 &task_runner_async_waiter_}; |
53 return gpu_channel_host_->CreateVideoDecoder( | 96 if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0) { |
54 context->GetCommandBufferProxy()->GetRouteID(), profile, client); | 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>(); |
55 } | 105 } |
56 | 106 return vda_.Pass(); |
57 return scoped_ptr<media::VideoDecodeAccelerator>(); | |
58 } | 107 } |
59 | 108 |
60 scoped_ptr<media::VideoEncodeAccelerator> | 109 scoped_ptr<media::VideoEncodeAccelerator> |
61 RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator( | 110 RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator( |
62 media::VideoEncodeAccelerator::Client* client) { | 111 media::VideoEncodeAccelerator::Client* client) { |
63 DCHECK(task_runner_->BelongsToCurrentThread()); | 112 DCHECK(task_runner_->BelongsToCurrentThread()); |
64 | 113 |
65 return gpu_channel_host_->CreateVideoEncoder(client); | 114 return gpu_channel_host_->CreateVideoEncoder(client); |
66 } | 115 } |
67 | 116 |
| 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 |
68 uint32 RendererGpuVideoAcceleratorFactories::CreateTextures( | 130 uint32 RendererGpuVideoAcceleratorFactories::CreateTextures( |
69 int32 count, | 131 int32 count, |
70 const gfx::Size& size, | 132 const gfx::Size& size, |
71 std::vector<uint32>* texture_ids, | 133 std::vector<uint32>* texture_ids, |
72 std::vector<gpu::Mailbox>* texture_mailboxes, | 134 std::vector<gpu::Mailbox>* texture_mailboxes, |
73 uint32 texture_target) { | 135 uint32 texture_target) { |
74 DCHECK(task_runner_->BelongsToCurrentThread()); | 136 DCHECK(task_runner_->BelongsToCurrentThread()); |
75 DCHECK(texture_target); | 137 DCHECK(texture_target); |
76 | 138 |
77 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); | 139 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 return; | 197 return; |
136 | 198 |
137 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); | 199 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); |
138 gles2->WaitSyncPointCHROMIUM(sync_point); | 200 gles2->WaitSyncPointCHROMIUM(sync_point); |
139 | 201 |
140 // Callers expect the WaitSyncPoint to affect the next IPCs. Make sure to | 202 // Callers expect the WaitSyncPoint to affect the next IPCs. Make sure to |
141 // flush the command buffers to ensure that. | 203 // flush the command buffers to ensure that. |
142 gles2->ShallowFlushCHROMIUM(); | 204 gles2->ShallowFlushCHROMIUM(); |
143 } | 205 } |
144 | 206 |
145 void RendererGpuVideoAcceleratorFactories::ReadPixels( | 207 void RendererGpuVideoAcceleratorFactories::ReadPixels(uint32 texture_id, |
| 208 const gfx::Size& size, |
| 209 const SkBitmap& pixels) { |
| 210 // SkBitmaps use the SkPixelRef object to refcount the underlying pixels. |
| 211 // Multiple SkBitmaps can share a SkPixelRef instance. We use this to |
| 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 |
| 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( |
146 uint32 texture_id, | 235 uint32 texture_id, |
147 const gfx::Rect& visible_rect, | 236 const gfx::Size& size) { |
148 const SkBitmap& pixels) { | |
149 DCHECK(task_runner_->BelongsToCurrentThread()); | 237 DCHECK(task_runner_->BelongsToCurrentThread()); |
150 | |
151 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); | 238 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
152 if (!context) | 239 if (!context) { |
| 240 task_runner_async_waiter_.Signal(); |
153 return; | 241 return; |
| 242 } |
154 | 243 |
155 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); | 244 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); |
156 | 245 |
157 GLuint tmp_texture; | 246 GLuint tmp_texture; |
158 gles2->GenTextures(1, &tmp_texture); | 247 gles2->GenTextures(1, &tmp_texture); |
159 gles2->BindTexture(GL_TEXTURE_2D, tmp_texture); | 248 gles2->BindTexture(GL_TEXTURE_2D, tmp_texture); |
160 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 249 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
161 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 250 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
162 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 251 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
163 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 252 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
164 context->copyTextureCHROMIUM( | 253 context->copyTextureCHROMIUM( |
165 GL_TEXTURE_2D, texture_id, tmp_texture, 0, GL_RGBA, GL_UNSIGNED_BYTE); | 254 GL_TEXTURE_2D, texture_id, tmp_texture, 0, GL_RGBA, GL_UNSIGNED_BYTE); |
166 | 255 |
167 GLuint fb; | 256 GLuint fb; |
168 gles2->GenFramebuffers(1, &fb); | 257 gles2->GenFramebuffers(1, &fb); |
169 gles2->BindFramebuffer(GL_FRAMEBUFFER, fb); | 258 gles2->BindFramebuffer(GL_FRAMEBUFFER, fb); |
170 gles2->FramebufferTexture2D( | 259 gles2->FramebufferTexture2D( |
171 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_texture, 0); | 260 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_texture, 0); |
172 gles2->PixelStorei(GL_PACK_ALIGNMENT, 4); | 261 gles2->PixelStorei(GL_PACK_ALIGNMENT, 4); |
173 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \ | 262 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \ |
174 SK_A32_SHIFT == 24 | 263 SK_A32_SHIFT == 24 |
175 GLenum skia_format = GL_BGRA_EXT; | 264 GLenum skia_format = GL_BGRA_EXT; |
176 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \ | 265 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \ |
177 SK_A32_SHIFT == 24 | 266 SK_A32_SHIFT == 24 |
178 GLenum skia_format = GL_RGBA; | 267 GLenum skia_format = GL_RGBA; |
179 #else | 268 #else |
180 #error Unexpected Skia ARGB_8888 layout! | 269 #error Unexpected Skia ARGB_8888 layout! |
181 #endif | 270 #endif |
182 gles2->ReadPixels(visible_rect.x(), | 271 gles2->ReadPixels(0, |
183 visible_rect.y(), | 272 0, |
184 visible_rect.width(), | 273 size.width(), |
185 visible_rect.height(), | 274 size.height(), |
186 skia_format, | 275 skia_format, |
187 GL_UNSIGNED_BYTE, | 276 GL_UNSIGNED_BYTE, |
188 pixels.pixelRef()->pixels()); | 277 read_pixels_bitmap_.pixelRef()->pixels()); |
189 gles2->DeleteFramebuffers(1, &fb); | 278 gles2->DeleteFramebuffers(1, &fb); |
190 gles2->DeleteTextures(1, &tmp_texture); | 279 gles2->DeleteTextures(1, &tmp_texture); |
191 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); | 280 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); |
| 281 task_runner_async_waiter_.Signal(); |
192 } | 282 } |
193 | 283 |
194 base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory( | 284 base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory( |
195 size_t size) { | 285 size_t size) { |
196 DCHECK(task_runner_->BelongsToCurrentThread()); | 286 DCHECK(task_runner_->BelongsToCurrentThread()); |
197 return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get()); | 287 return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get()); |
198 } | 288 } |
199 | 289 |
200 scoped_refptr<base::SingleThreadTaskRunner> | 290 scoped_refptr<base::SingleThreadTaskRunner> |
201 RendererGpuVideoAcceleratorFactories::GetTaskRunner() { | 291 RendererGpuVideoAcceleratorFactories::GetTaskRunner() { |
202 return task_runner_; | 292 return task_runner_; |
203 } | 293 } |
204 | 294 |
| 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 |
205 } // namespace content | 319 } // namespace content |
OLD | NEW |