OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/common/gpu/media/gpu_video_decode_accelerator.h" | 5 #include "content/common/gpu/media/gpu_video_decode_accelerator.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 16 matching lines...) Expand all Loading... |
27 #include "content/common/gpu/media/dxva_video_decode_accelerator.h" | 27 #include "content/common/gpu/media/dxva_video_decode_accelerator.h" |
28 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11) | 28 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11) |
29 #include "content/common/gpu/media/exynos_video_decode_accelerator.h" | 29 #include "content/common/gpu/media/exynos_video_decode_accelerator.h" |
30 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11) | 30 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11) |
31 #include "ui/gl/gl_context_glx.h" | 31 #include "ui/gl/gl_context_glx.h" |
32 #include "content/common/gpu/media/vaapi_video_decode_accelerator.h" | 32 #include "content/common/gpu/media/vaapi_video_decode_accelerator.h" |
33 #elif defined(OS_ANDROID) | 33 #elif defined(OS_ANDROID) |
34 #include "content/common/gpu/media/android_video_decode_accelerator.h" | 34 #include "content/common/gpu/media/android_video_decode_accelerator.h" |
35 #endif | 35 #endif |
36 | 36 |
37 #include "gpu/command_buffer/service/texture_manager.h" | |
38 #include "ui/gfx/size.h" | 37 #include "ui/gfx/size.h" |
39 | 38 |
40 namespace content { | 39 namespace content { |
41 | 40 |
42 static bool MakeDecoderContextCurrent( | 41 static bool MakeDecoderContextCurrent( |
43 const base::WeakPtr<GpuCommandBufferStub> stub) { | 42 const base::WeakPtr<GpuCommandBufferStub> stub) { |
44 if (!stub.get()) { | 43 if (!stub.get()) { |
45 DLOG(ERROR) << "Stub is gone; won't MakeCurrent()."; | 44 DLOG(ERROR) << "Stub is gone; won't MakeCurrent()."; |
46 return false; | 45 return false; |
47 } | 46 } |
48 | 47 |
49 if (!stub->decoder()->MakeCurrent()) { | 48 if (!stub->decoder()->MakeCurrent()) { |
50 DLOG(ERROR) << "Failed to MakeCurrent()"; | 49 DLOG(ERROR) << "Failed to MakeCurrent()"; |
51 return false; | 50 return false; |
52 } | 51 } |
53 | 52 |
54 return true; | 53 return true; |
55 } | 54 } |
56 | 55 |
| 56 // A helper class that works like AutoLock but only acquires the lock when |
| 57 // DCHECK is on. |
| 58 class DebugAutoLock { |
| 59 public: |
| 60 explicit DebugAutoLock(base::Lock& lock) : lock_(lock) { |
| 61 if (DCHECK_IS_ON()) |
| 62 lock_.Acquire(); |
| 63 } |
| 64 |
| 65 ~DebugAutoLock() { |
| 66 if (DCHECK_IS_ON()) { |
| 67 lock_.AssertAcquired(); |
| 68 lock_.Release(); |
| 69 } |
| 70 } |
| 71 |
| 72 private: |
| 73 base::Lock& lock_; |
| 74 DISALLOW_COPY_AND_ASSIGN(DebugAutoLock); |
| 75 }; |
| 76 |
57 class GpuVideoDecodeAccelerator::MessageFilter | 77 class GpuVideoDecodeAccelerator::MessageFilter |
58 : public IPC::ChannelProxy::MessageFilter { | 78 : public IPC::ChannelProxy::MessageFilter { |
59 public: | 79 public: |
60 MessageFilter(GpuVideoDecodeAccelerator* owner, int32 host_route_id) | 80 MessageFilter(GpuVideoDecodeAccelerator* owner, int32 host_route_id) |
61 : owner_(owner), host_route_id_(host_route_id) {} | 81 : owner_(owner), host_route_id_(host_route_id) {} |
62 | 82 |
63 virtual void OnChannelError() OVERRIDE { channel_ = NULL; } | 83 virtual void OnChannelError() OVERRIDE { channel_ = NULL; } |
64 | 84 |
65 virtual void OnChannelClosing() OVERRIDE { channel_ = NULL; } | 85 virtual void OnChannelClosing() OVERRIDE { channel_ = NULL; } |
66 | 86 |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 } | 189 } |
170 | 190 |
171 void GpuVideoDecodeAccelerator::DismissPictureBuffer( | 191 void GpuVideoDecodeAccelerator::DismissPictureBuffer( |
172 int32 picture_buffer_id) { | 192 int32 picture_buffer_id) { |
173 // Notify client that picture buffer is now unused. | 193 // Notify client that picture buffer is now unused. |
174 if (!Send(new AcceleratedVideoDecoderHostMsg_DismissPictureBuffer( | 194 if (!Send(new AcceleratedVideoDecoderHostMsg_DismissPictureBuffer( |
175 host_route_id_, picture_buffer_id))) { | 195 host_route_id_, picture_buffer_id))) { |
176 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_DismissPictureBuffer) " | 196 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_DismissPictureBuffer) " |
177 << "failed"; | 197 << "failed"; |
178 } | 198 } |
| 199 DebugAutoLock auto_lock(debug_uncleared_textures_lock_); |
| 200 uncleared_textures_.erase(picture_buffer_id); |
179 } | 201 } |
180 | 202 |
181 void GpuVideoDecodeAccelerator::PictureReady( | 203 void GpuVideoDecodeAccelerator::PictureReady( |
182 const media::Picture& picture) { | 204 const media::Picture& picture) { |
| 205 // VDA may call PictureReady on IO thread. SetTextureCleared should run on |
| 206 // the child thread. VDA is responsible to call PictureReady on the child |
| 207 // thread when a picture buffer is delivered the first time. |
| 208 if (child_message_loop_->BelongsToCurrentThread()) { |
| 209 SetTextureCleared(picture); |
| 210 } else { |
| 211 DCHECK(io_message_loop_->BelongsToCurrentThread()); |
| 212 if (DCHECK_IS_ON()) { |
| 213 DebugAutoLock auto_lock(debug_uncleared_textures_lock_); |
| 214 DCHECK_EQ(0u, uncleared_textures_.count(picture.picture_buffer_id())); |
| 215 } |
| 216 } |
| 217 |
183 if (!Send(new AcceleratedVideoDecoderHostMsg_PictureReady( | 218 if (!Send(new AcceleratedVideoDecoderHostMsg_PictureReady( |
184 host_route_id_, | 219 host_route_id_, |
185 picture.picture_buffer_id(), | 220 picture.picture_buffer_id(), |
186 picture.bitstream_buffer_id()))) { | 221 picture.bitstream_buffer_id()))) { |
187 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_PictureReady) failed"; | 222 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_PictureReady) failed"; |
188 } | 223 } |
189 } | 224 } |
190 | 225 |
191 void GpuVideoDecodeAccelerator::NotifyError( | 226 void GpuVideoDecodeAccelerator::NotifyError( |
192 media::VideoDecodeAccelerator::Error error) { | 227 media::VideoDecodeAccelerator::Error error) { |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
298 if (buffer_ids.size() != texture_ids.size()) { | 333 if (buffer_ids.size() != texture_ids.size()) { |
299 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); | 334 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); |
300 return; | 335 return; |
301 } | 336 } |
302 | 337 |
303 gpu::gles2::GLES2Decoder* command_decoder = stub_->decoder(); | 338 gpu::gles2::GLES2Decoder* command_decoder = stub_->decoder(); |
304 gpu::gles2::TextureManager* texture_manager = | 339 gpu::gles2::TextureManager* texture_manager = |
305 command_decoder->GetContextGroup()->texture_manager(); | 340 command_decoder->GetContextGroup()->texture_manager(); |
306 | 341 |
307 std::vector<media::PictureBuffer> buffers; | 342 std::vector<media::PictureBuffer> buffers; |
| 343 std::vector<scoped_refptr<gpu::gles2::TextureRef> > textures; |
308 for (uint32 i = 0; i < buffer_ids.size(); ++i) { | 344 for (uint32 i = 0; i < buffer_ids.size(); ++i) { |
309 if (buffer_ids[i] < 0) { | 345 if (buffer_ids[i] < 0) { |
310 DLOG(ERROR) << "Buffer id " << buffer_ids[i] << " out of range"; | 346 DLOG(ERROR) << "Buffer id " << buffer_ids[i] << " out of range"; |
311 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); | 347 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); |
312 return; | 348 return; |
313 } | 349 } |
314 gpu::gles2::TextureRef* texture_ref = texture_manager->GetTexture( | 350 gpu::gles2::TextureRef* texture_ref = texture_manager->GetTexture( |
315 texture_ids[i]); | 351 texture_ids[i]); |
316 if (!texture_ref) { | 352 if (!texture_ref) { |
317 DLOG(ERROR) << "Failed to find texture id " << texture_ids[i]; | 353 DLOG(ERROR) << "Failed to find texture id " << texture_ids[i]; |
318 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); | 354 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); |
319 return; | 355 return; |
320 } | 356 } |
321 gpu::gles2::Texture* info = texture_ref->texture(); | 357 gpu::gles2::Texture* info = texture_ref->texture(); |
322 if (info->target() != texture_target_) { | 358 if (info->target() != texture_target_) { |
323 DLOG(ERROR) << "Texture target mismatch for texture id " | 359 DLOG(ERROR) << "Texture target mismatch for texture id " |
324 << texture_ids[i]; | 360 << texture_ids[i]; |
325 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); | 361 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); |
326 return; | 362 return; |
327 } | 363 } |
328 if (texture_target_ == GL_TEXTURE_EXTERNAL_OES) { | 364 if (texture_target_ == GL_TEXTURE_EXTERNAL_OES) { |
329 // GL_TEXTURE_EXTERNAL_OES textures have their dimensions defined by the | 365 // GL_TEXTURE_EXTERNAL_OES textures have their dimensions defined by the |
330 // underlying EGLImage. Use |texture_dimensions_| for this size. The | 366 // underlying EGLImage. Use |texture_dimensions_| for this size. |
331 // textures cannot be rendered to or cleared, so we set |cleared| true to | |
332 // skip clearing. | |
333 texture_manager->SetLevelInfo(texture_ref, | 367 texture_manager->SetLevelInfo(texture_ref, |
334 GL_TEXTURE_EXTERNAL_OES, | 368 GL_TEXTURE_EXTERNAL_OES, |
335 0, | 369 0, |
336 0, | 370 0, |
337 texture_dimensions_.width(), | 371 texture_dimensions_.width(), |
338 texture_dimensions_.height(), | 372 texture_dimensions_.height(), |
339 1, | 373 1, |
340 0, | 374 0, |
341 0, | 375 0, |
342 0, | 376 0, |
343 true); | 377 false); |
344 } else { | 378 } else { |
345 // For other targets, texture dimensions should already be defined. | 379 // For other targets, texture dimensions should already be defined. |
346 GLsizei width = 0, height = 0; | 380 GLsizei width = 0, height = 0; |
347 info->GetLevelSize(texture_target_, 0, &width, &height); | 381 info->GetLevelSize(texture_target_, 0, &width, &height); |
348 if (width != texture_dimensions_.width() || | 382 if (width != texture_dimensions_.width() || |
349 height != texture_dimensions_.height()) { | 383 height != texture_dimensions_.height()) { |
350 DLOG(ERROR) << "Size mismatch for texture id " << texture_ids[i]; | 384 DLOG(ERROR) << "Size mismatch for texture id " << texture_ids[i]; |
351 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); | 385 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); |
352 return; | 386 return; |
353 } | 387 } |
354 } | 388 } |
355 if (!texture_manager->ClearRenderableLevels(command_decoder, texture_ref)) { | |
356 DLOG(ERROR) << "Failed to Clear texture id " << texture_ids[i]; | |
357 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | |
358 return; | |
359 } | |
360 uint32 service_texture_id; | 389 uint32 service_texture_id; |
361 if (!command_decoder->GetServiceTextureId( | 390 if (!command_decoder->GetServiceTextureId( |
362 texture_ids[i], &service_texture_id)) { | 391 texture_ids[i], &service_texture_id)) { |
363 DLOG(ERROR) << "Failed to translate texture!"; | 392 DLOG(ERROR) << "Failed to translate texture!"; |
364 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | 393 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); |
365 return; | 394 return; |
366 } | 395 } |
367 buffers.push_back(media::PictureBuffer( | 396 buffers.push_back(media::PictureBuffer( |
368 buffer_ids[i], texture_dimensions_, service_texture_id)); | 397 buffer_ids[i], texture_dimensions_, service_texture_id)); |
| 398 textures.push_back(texture_ref); |
369 } | 399 } |
370 video_decode_accelerator_->AssignPictureBuffers(buffers); | 400 video_decode_accelerator_->AssignPictureBuffers(buffers); |
| 401 DebugAutoLock auto_lock(debug_uncleared_textures_lock_); |
| 402 for (uint32 i = 0; i < buffer_ids.size(); ++i) |
| 403 uncleared_textures_[buffer_ids[i]] = textures[i]; |
371 } | 404 } |
372 | 405 |
373 void GpuVideoDecodeAccelerator::OnReusePictureBuffer( | 406 void GpuVideoDecodeAccelerator::OnReusePictureBuffer( |
374 int32 picture_buffer_id) { | 407 int32 picture_buffer_id) { |
375 DCHECK(video_decode_accelerator_.get()); | 408 DCHECK(video_decode_accelerator_.get()); |
376 video_decode_accelerator_->ReusePictureBuffer(picture_buffer_id); | 409 video_decode_accelerator_->ReusePictureBuffer(picture_buffer_id); |
377 } | 410 } |
378 | 411 |
379 void GpuVideoDecodeAccelerator::OnFlush() { | 412 void GpuVideoDecodeAccelerator::OnFlush() { |
380 DCHECK(video_decode_accelerator_.get()); | 413 DCHECK(video_decode_accelerator_.get()); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 } | 472 } |
440 | 473 |
441 bool GpuVideoDecodeAccelerator::Send(IPC::Message* message) { | 474 bool GpuVideoDecodeAccelerator::Send(IPC::Message* message) { |
442 DCHECK(stub_); | 475 DCHECK(stub_); |
443 if (filter_.get() && io_message_loop_->BelongsToCurrentThread()) | 476 if (filter_.get() && io_message_loop_->BelongsToCurrentThread()) |
444 return filter_->SendOnIOThread(message); | 477 return filter_->SendOnIOThread(message); |
445 DCHECK(child_message_loop_->BelongsToCurrentThread()); | 478 DCHECK(child_message_loop_->BelongsToCurrentThread()); |
446 return stub_->channel()->Send(message); | 479 return stub_->channel()->Send(message); |
447 } | 480 } |
448 | 481 |
| 482 void GpuVideoDecodeAccelerator::SetTextureCleared( |
| 483 const media::Picture& picture) { |
| 484 DCHECK(child_message_loop_->BelongsToCurrentThread()); |
| 485 DebugAutoLock auto_lock(debug_uncleared_textures_lock_); |
| 486 std::map<int32, scoped_refptr<gpu::gles2::TextureRef> >::iterator it; |
| 487 it = uncleared_textures_.find(picture.picture_buffer_id()); |
| 488 if (it == uncleared_textures_.end()) |
| 489 return; // the texture has been cleared |
| 490 |
| 491 scoped_refptr<gpu::gles2::TextureRef> texture_ref = it->second; |
| 492 GLenum target = texture_ref->texture()->target(); |
| 493 gpu::gles2::TextureManager* texture_manager = |
| 494 stub_->decoder()->GetContextGroup()->texture_manager(); |
| 495 DCHECK(!texture_ref->texture()->IsLevelCleared(target, 0)); |
| 496 texture_manager->SetLevelCleared(texture_ref, target, 0, true); |
| 497 uncleared_textures_.erase(it); |
| 498 } |
| 499 |
449 } // namespace content | 500 } // namespace content |
OLD | NEW |