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/dxva_video_decode_accelerator_win.h" | 5 #include "content/common/gpu/media/dxva_video_decode_accelerator_win.h" |
6 | 6 |
7 #if !defined(OS_WIN) | 7 #if !defined(OS_WIN) |
8 #error This file should only be built on Windows. | 8 #error This file should only be built on Windows. |
9 #endif // !defined(OS_WIN) | 9 #endif // !defined(OS_WIN) |
10 | 10 |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 // Maximum number of iterations we allow before aborting the attempt to flush | 159 // Maximum number of iterations we allow before aborting the attempt to flush |
160 // the batched queries to the driver and allow torn/corrupt frames to be | 160 // the batched queries to the driver and allow torn/corrupt frames to be |
161 // rendered. | 161 // rendered. |
162 kFlushDecoderSurfaceTimeoutMs = 1, | 162 kFlushDecoderSurfaceTimeoutMs = 1, |
163 // Maximum iterations where we try to flush the d3d device. | 163 // Maximum iterations where we try to flush the d3d device. |
164 kMaxIterationsForD3DFlush = 4, | 164 kMaxIterationsForD3DFlush = 4, |
165 // We only request 5 picture buffers from the client which are used to hold | 165 // We only request 5 picture buffers from the client which are used to hold |
166 // the decoded samples. These buffers are then reused when the client tells | 166 // the decoded samples. These buffers are then reused when the client tells |
167 // us that it is done with the buffer. | 167 // us that it is done with the buffer. |
168 kNumPictureBuffers = 5, | 168 kNumPictureBuffers = 5, |
| 169 // The keyed mutex should always be released before the other thread |
| 170 // attempts to acquire it, so AcquireSync should always return immediately. |
| 171 kAcquireSyncWaitMs = 0, |
169 }; | 172 }; |
170 | 173 |
171 static IMFSample* CreateEmptySample() { | 174 static IMFSample* CreateEmptySample() { |
172 base::win::ScopedComPtr<IMFSample> sample; | 175 base::win::ScopedComPtr<IMFSample> sample; |
173 HRESULT hr = MFCreateSample(sample.Receive()); | 176 HRESULT hr = MFCreateSample(sample.Receive()); |
174 RETURN_ON_HR_FAILURE(hr, "MFCreateSample failed", NULL); | 177 RETURN_ON_HR_FAILURE(hr, "MFCreateSample failed", NULL); |
175 return sample.Detach(); | 178 return sample.Detach(); |
176 } | 179 } |
177 | 180 |
178 // Creates a Media Foundation sample with one buffer of length |buffer_length| | 181 // Creates a Media Foundation sample with one buffer of length |buffer_length| |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
342 // Maintains information about a DXVA picture buffer, i.e. whether it is | 345 // Maintains information about a DXVA picture buffer, i.e. whether it is |
343 // available for rendering, the texture information, etc. | 346 // available for rendering, the texture information, etc. |
344 struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer { | 347 struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer { |
345 public: | 348 public: |
346 static linked_ptr<DXVAPictureBuffer> Create( | 349 static linked_ptr<DXVAPictureBuffer> Create( |
347 const DXVAVideoDecodeAccelerator& decoder, | 350 const DXVAVideoDecodeAccelerator& decoder, |
348 const media::PictureBuffer& buffer, | 351 const media::PictureBuffer& buffer, |
349 EGLConfig egl_config); | 352 EGLConfig egl_config); |
350 ~DXVAPictureBuffer(); | 353 ~DXVAPictureBuffer(); |
351 | 354 |
352 void ReusePictureBuffer(); | 355 bool InitializeTexture(const DXVAVideoDecodeAccelerator& decoder, |
| 356 bool use_rgb); |
| 357 |
| 358 bool ReusePictureBuffer(); |
353 // Copies the output sample data to the picture buffer provided by the | 359 // Copies the output sample data to the picture buffer provided by the |
354 // client. | 360 // client. |
355 // The dest_surface parameter contains the decoded bits. | 361 // The dest_surface parameter contains the decoded bits. |
356 bool CopyOutputSampleDataToPictureBuffer( | 362 bool CopyOutputSampleDataToPictureBuffer( |
357 DXVAVideoDecodeAccelerator* decoder, | 363 DXVAVideoDecodeAccelerator* decoder, |
358 IDirect3DSurface9* dest_surface, | 364 IDirect3DSurface9* dest_surface, |
359 ID3D11Texture2D* dx11_texture, | 365 ID3D11Texture2D* dx11_texture, |
360 int input_buffer_id); | 366 int input_buffer_id); |
361 | 367 |
362 bool available() const { | 368 bool available() const { |
363 return available_; | 369 return available_; |
364 } | 370 } |
365 | 371 |
366 void set_available(bool available) { | 372 void set_available(bool available) { |
367 available_ = available; | 373 available_ = available; |
368 } | 374 } |
369 | 375 |
370 int id() const { | 376 int id() const { |
371 return picture_buffer_.id(); | 377 return picture_buffer_.id(); |
372 } | 378 } |
373 | 379 |
374 gfx::Size size() const { | 380 gfx::Size size() const { |
375 return picture_buffer_.size(); | 381 return picture_buffer_.size(); |
376 } | 382 } |
377 | 383 |
378 // Called when the source surface |src_surface| is copied to the destination | 384 // Called when the source surface |src_surface| is copied to the destination |
379 // |dest_surface| | 385 // |dest_surface| |
380 void CopySurfaceComplete(IDirect3DSurface9* src_surface, | 386 bool CopySurfaceComplete(IDirect3DSurface9* src_surface, |
381 IDirect3DSurface9* dest_surface); | 387 IDirect3DSurface9* dest_surface); |
382 | 388 |
383 private: | 389 private: |
384 explicit DXVAPictureBuffer(const media::PictureBuffer& buffer); | 390 explicit DXVAPictureBuffer(const media::PictureBuffer& buffer); |
385 | 391 |
386 bool available_; | 392 bool available_; |
387 media::PictureBuffer picture_buffer_; | 393 media::PictureBuffer picture_buffer_; |
388 EGLSurface decoding_surface_; | 394 EGLSurface decoding_surface_; |
| 395 |
| 396 HANDLE texture_share_handle_; |
389 base::win::ScopedComPtr<IDirect3DTexture9> decoding_texture_; | 397 base::win::ScopedComPtr<IDirect3DTexture9> decoding_texture_; |
390 base::win::ScopedComPtr<ID3D11Texture2D> dx11_decoding_texture_; | 398 base::win::ScopedComPtr<ID3D11Texture2D> dx11_decoding_texture_; |
391 | 399 |
| 400 base::win::ScopedComPtr<IDXGIKeyedMutex> egl_keyed_mutex_; |
| 401 base::win::ScopedComPtr<IDXGIKeyedMutex> dx11_keyed_mutex_; |
| 402 |
| 403 // This is the last value that was used to release the keyed mutex. |
| 404 uint64_t keyed_mutex_value_; |
| 405 |
392 // The following |IDirect3DSurface9| interface pointers are used to hold | 406 // The following |IDirect3DSurface9| interface pointers are used to hold |
393 // references on the surfaces during the course of a StretchRect operation | 407 // references on the surfaces during the course of a StretchRect operation |
394 // to copy the source surface to the target. The references are released | 408 // to copy the source surface to the target. The references are released |
395 // when the StretchRect operation i.e. the copy completes. | 409 // when the StretchRect operation i.e. the copy completes. |
396 base::win::ScopedComPtr<IDirect3DSurface9> decoder_surface_; | 410 base::win::ScopedComPtr<IDirect3DSurface9> decoder_surface_; |
397 base::win::ScopedComPtr<IDirect3DSurface9> target_surface_; | 411 base::win::ScopedComPtr<IDirect3DSurface9> target_surface_; |
398 | 412 |
399 // This ID3D11Texture2D interface pointer is used to hold a reference to the | 413 // This ID3D11Texture2D interface pointer is used to hold a reference to the |
400 // decoder texture during the course of a copy operation. This reference is | 414 // decoder texture during the course of a copy operation. This reference is |
401 // released when the copy completes. | 415 // released when the copy completes. |
(...skipping 13 matching lines...) Expand all Loading... |
415 const media::PictureBuffer& buffer, | 429 const media::PictureBuffer& buffer, |
416 EGLConfig egl_config) { | 430 EGLConfig egl_config) { |
417 linked_ptr<DXVAPictureBuffer> picture_buffer(new DXVAPictureBuffer(buffer)); | 431 linked_ptr<DXVAPictureBuffer> picture_buffer(new DXVAPictureBuffer(buffer)); |
418 | 432 |
419 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); | 433 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); |
420 | 434 |
421 EGLint use_rgb = 1; | 435 EGLint use_rgb = 1; |
422 eglGetConfigAttrib(egl_display, egl_config, EGL_BIND_TO_TEXTURE_RGB, | 436 eglGetConfigAttrib(egl_display, egl_config, EGL_BIND_TO_TEXTURE_RGB, |
423 &use_rgb); | 437 &use_rgb); |
424 | 438 |
| 439 if (!picture_buffer->InitializeTexture(decoder, !!use_rgb)) |
| 440 return linked_ptr<DXVAPictureBuffer>(nullptr); |
| 441 |
425 EGLint attrib_list[] = { | 442 EGLint attrib_list[] = { |
426 EGL_WIDTH, buffer.size().width(), | 443 EGL_WIDTH, buffer.size().width(), |
427 EGL_HEIGHT, buffer.size().height(), | 444 EGL_HEIGHT, buffer.size().height(), |
428 EGL_TEXTURE_FORMAT, use_rgb ? EGL_TEXTURE_RGB : EGL_TEXTURE_RGBA, | 445 EGL_TEXTURE_FORMAT, use_rgb ? EGL_TEXTURE_RGB : EGL_TEXTURE_RGBA, |
429 EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, | 446 EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, |
430 EGL_NONE | 447 EGL_NONE |
431 }; | 448 }; |
432 | 449 |
433 picture_buffer->decoding_surface_ = eglCreatePbufferSurface( | 450 picture_buffer->decoding_surface_ = eglCreatePbufferFromClientBuffer( |
434 egl_display, | 451 egl_display, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, |
435 egl_config, | 452 picture_buffer->texture_share_handle_, egl_config, attrib_list); |
436 attrib_list); | |
437 RETURN_ON_FAILURE(picture_buffer->decoding_surface_, | 453 RETURN_ON_FAILURE(picture_buffer->decoding_surface_, |
438 "Failed to create surface", | 454 "Failed to create surface", |
439 linked_ptr<DXVAPictureBuffer>(NULL)); | 455 linked_ptr<DXVAPictureBuffer>(NULL)); |
440 | 456 if (decoder.d3d11_device_ && decoder.use_keyed_mutex_) { |
441 HANDLE share_handle = NULL; | 457 void* keyed_mutex = nullptr; |
442 EGLBoolean ret = eglQuerySurfacePointerANGLE( | 458 EGLBoolean ret = eglQuerySurfacePointerANGLE( |
443 egl_display, | 459 egl_display, picture_buffer->decoding_surface_, |
444 picture_buffer->decoding_surface_, | 460 EGL_DXGI_KEYED_MUTEX_ANGLE, &keyed_mutex); |
445 EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, | 461 RETURN_ON_FAILURE(keyed_mutex && ret == EGL_TRUE, |
446 &share_handle); | 462 "Failed to query ANGLE keyed mutex", |
447 | 463 linked_ptr<DXVAPictureBuffer>(nullptr)); |
448 RETURN_ON_FAILURE(share_handle && ret == EGL_TRUE, | 464 picture_buffer->egl_keyed_mutex_ = base::win::ScopedComPtr<IDXGIKeyedMutex>( |
449 "Failed to query ANGLE surface pointer", | 465 static_cast<IDXGIKeyedMutex*>(keyed_mutex)); |
450 linked_ptr<DXVAPictureBuffer>(NULL)); | |
451 | |
452 HRESULT hr = E_FAIL; | |
453 if (decoder.d3d11_device_) { | |
454 base::win::ScopedComPtr<ID3D11Resource> resource; | |
455 hr = decoder.d3d11_device_->OpenSharedResource( | |
456 share_handle, | |
457 __uuidof(ID3D11Resource), | |
458 reinterpret_cast<void**>(resource.Receive())); | |
459 RETURN_ON_HR_FAILURE(hr, "Failed to open shared resource", | |
460 linked_ptr<DXVAPictureBuffer>(NULL)); | |
461 hr = picture_buffer->dx11_decoding_texture_.QueryFrom(resource.get()); | |
462 } else { | |
463 hr = decoder.d3d9_device_ex_->CreateTexture( | |
464 buffer.size().width(), | |
465 buffer.size().height(), | |
466 1, | |
467 D3DUSAGE_RENDERTARGET, | |
468 use_rgb ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8, | |
469 D3DPOOL_DEFAULT, | |
470 picture_buffer->decoding_texture_.Receive(), | |
471 &share_handle); | |
472 } | 466 } |
473 RETURN_ON_HR_FAILURE(hr, "Failed to create texture", | |
474 linked_ptr<DXVAPictureBuffer>(NULL)); | |
475 picture_buffer->use_rgb_ = !!use_rgb; | 467 picture_buffer->use_rgb_ = !!use_rgb; |
476 return picture_buffer; | 468 return picture_buffer; |
477 } | 469 } |
478 | 470 |
| 471 bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::InitializeTexture( |
| 472 const DXVAVideoDecodeAccelerator& decoder, |
| 473 bool use_rgb) { |
| 474 DCHECK(!texture_share_handle_); |
| 475 if (decoder.d3d11_device_) { |
| 476 D3D11_TEXTURE2D_DESC desc; |
| 477 desc.Width = picture_buffer_.size().width(); |
| 478 desc.Height = picture_buffer_.size().height(); |
| 479 desc.MipLevels = 1; |
| 480 desc.ArraySize = 1; |
| 481 desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; |
| 482 desc.SampleDesc.Count = 1; |
| 483 desc.SampleDesc.Quality = 0; |
| 484 desc.Usage = D3D11_USAGE_DEFAULT; |
| 485 desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; |
| 486 desc.CPUAccessFlags = 0; |
| 487 desc.MiscFlags = decoder.use_keyed_mutex_ |
| 488 ? D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX |
| 489 : D3D11_RESOURCE_MISC_SHARED; |
| 490 |
| 491 HRESULT hr = decoder.d3d11_device_->CreateTexture2D( |
| 492 &desc, nullptr, dx11_decoding_texture_.Receive()); |
| 493 RETURN_ON_HR_FAILURE(hr, "Failed to create texture", false); |
| 494 if (decoder.use_keyed_mutex_) { |
| 495 hr = dx11_keyed_mutex_.QueryFrom(dx11_decoding_texture_.get()); |
| 496 RETURN_ON_HR_FAILURE(hr, "Failed to get keyed mutex", false); |
| 497 } |
| 498 |
| 499 base::win::ScopedComPtr<IDXGIResource> resource; |
| 500 hr = resource.QueryFrom(dx11_decoding_texture_.get()); |
| 501 DCHECK(SUCCEEDED(hr)); |
| 502 hr = resource->GetSharedHandle(&texture_share_handle_); |
| 503 RETURN_ON_FAILURE(SUCCEEDED(hr) && texture_share_handle_, |
| 504 "Failed to query shared handle", false); |
| 505 |
| 506 } else { |
| 507 HRESULT hr = E_FAIL; |
| 508 hr = decoder.d3d9_device_ex_->CreateTexture( |
| 509 picture_buffer_.size().width(), picture_buffer_.size().height(), 1, |
| 510 D3DUSAGE_RENDERTARGET, use_rgb ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8, |
| 511 D3DPOOL_DEFAULT, decoding_texture_.Receive(), &texture_share_handle_); |
| 512 RETURN_ON_HR_FAILURE(hr, "Failed to create texture", false); |
| 513 RETURN_ON_FAILURE(texture_share_handle_, "Failed to query shared handle", |
| 514 false); |
| 515 } |
| 516 return true; |
| 517 } |
| 518 |
479 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::DXVAPictureBuffer( | 519 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::DXVAPictureBuffer( |
480 const media::PictureBuffer& buffer) | 520 const media::PictureBuffer& buffer) |
481 : available_(true), | 521 : available_(true), |
482 picture_buffer_(buffer), | 522 picture_buffer_(buffer), |
483 decoding_surface_(NULL), | 523 decoding_surface_(NULL), |
484 use_rgb_(true) { | 524 texture_share_handle_(nullptr), |
485 } | 525 keyed_mutex_value_(0), |
| 526 use_rgb_(true) {} |
486 | 527 |
487 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::~DXVAPictureBuffer() { | 528 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::~DXVAPictureBuffer() { |
488 if (decoding_surface_) { | 529 if (decoding_surface_) { |
489 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); | 530 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); |
490 | 531 |
491 eglReleaseTexImage( | 532 eglReleaseTexImage( |
492 egl_display, | 533 egl_display, |
493 decoding_surface_, | 534 decoding_surface_, |
494 EGL_BACK_BUFFER); | 535 EGL_BACK_BUFFER); |
495 | 536 |
496 eglDestroySurface( | 537 eglDestroySurface( |
497 egl_display, | 538 egl_display, |
498 decoding_surface_); | 539 decoding_surface_); |
499 decoding_surface_ = NULL; | 540 decoding_surface_ = NULL; |
500 } | 541 } |
501 } | 542 } |
502 | 543 |
503 void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() { | 544 bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() { |
504 DCHECK(decoding_surface_); | 545 DCHECK(decoding_surface_); |
505 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); | 546 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); |
506 eglReleaseTexImage( | 547 eglReleaseTexImage( |
507 egl_display, | 548 egl_display, |
508 decoding_surface_, | 549 decoding_surface_, |
509 EGL_BACK_BUFFER); | 550 EGL_BACK_BUFFER); |
510 decoder_surface_.Release(); | 551 decoder_surface_.Release(); |
511 target_surface_.Release(); | 552 target_surface_.Release(); |
512 decoder_dx11_texture_.Release(); | 553 decoder_dx11_texture_.Release(); |
513 set_available(true); | 554 set_available(true); |
| 555 if (egl_keyed_mutex_) { |
| 556 HRESULT hr = egl_keyed_mutex_->ReleaseSync(++keyed_mutex_value_); |
| 557 RETURN_ON_FAILURE(hr == S_OK, "Could not release sync mutex", false); |
| 558 } |
| 559 return true; |
514 } | 560 } |
515 | 561 |
516 bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer:: | 562 bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer:: |
517 CopyOutputSampleDataToPictureBuffer( | 563 CopyOutputSampleDataToPictureBuffer( |
518 DXVAVideoDecodeAccelerator* decoder, | 564 DXVAVideoDecodeAccelerator* decoder, |
519 IDirect3DSurface9* dest_surface, | 565 IDirect3DSurface9* dest_surface, |
520 ID3D11Texture2D* dx11_texture, | 566 ID3D11Texture2D* dx11_texture, |
521 int input_buffer_id) { | 567 int input_buffer_id) { |
522 DCHECK(dest_surface || dx11_texture); | 568 DCHECK(dest_surface || dx11_texture); |
523 if (dx11_texture) { | 569 if (dx11_texture) { |
524 // Grab a reference on the decoder texture. This reference will be released | 570 // Grab a reference on the decoder texture. This reference will be released |
525 // when we receive a notification that the copy was completed or when the | 571 // when we receive a notification that the copy was completed or when the |
526 // DXVAPictureBuffer instance is destroyed. | 572 // DXVAPictureBuffer instance is destroyed. |
527 decoder_dx11_texture_ = dx11_texture; | 573 decoder_dx11_texture_ = dx11_texture; |
528 decoder->CopyTexture(dx11_texture, dx11_decoding_texture_.get(), NULL, | 574 decoder->CopyTexture(dx11_texture, dx11_decoding_texture_.get(), |
529 id(), input_buffer_id); | 575 dx11_keyed_mutex_, keyed_mutex_value_, NULL, id(), |
| 576 input_buffer_id); |
530 return true; | 577 return true; |
531 } | 578 } |
532 D3DSURFACE_DESC surface_desc; | 579 D3DSURFACE_DESC surface_desc; |
533 HRESULT hr = dest_surface->GetDesc(&surface_desc); | 580 HRESULT hr = dest_surface->GetDesc(&surface_desc); |
534 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); | 581 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); |
535 | 582 |
536 D3DSURFACE_DESC texture_desc; | 583 D3DSURFACE_DESC texture_desc; |
537 decoding_texture_->GetLevelDesc(0, &texture_desc); | 584 decoding_texture_->GetLevelDesc(0, &texture_desc); |
538 | 585 |
539 if (texture_desc.Width != surface_desc.Width || | 586 if (texture_desc.Width != surface_desc.Width || |
(...skipping 19 matching lines...) Expand all Loading... |
559 hr = decoding_texture_->GetSurfaceLevel(0, target_surface_.Receive()); | 606 hr = decoding_texture_->GetSurfaceLevel(0, target_surface_.Receive()); |
560 RETURN_ON_HR_FAILURE(hr, "Failed to get surface from texture", false); | 607 RETURN_ON_HR_FAILURE(hr, "Failed to get surface from texture", false); |
561 | 608 |
562 decoder_surface_ = dest_surface; | 609 decoder_surface_ = dest_surface; |
563 | 610 |
564 decoder->CopySurface(decoder_surface_.get(), target_surface_.get(), id(), | 611 decoder->CopySurface(decoder_surface_.get(), target_surface_.get(), id(), |
565 input_buffer_id); | 612 input_buffer_id); |
566 return true; | 613 return true; |
567 } | 614 } |
568 | 615 |
569 void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::CopySurfaceComplete( | 616 bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::CopySurfaceComplete( |
570 IDirect3DSurface9* src_surface, | 617 IDirect3DSurface9* src_surface, |
571 IDirect3DSurface9* dest_surface) { | 618 IDirect3DSurface9* dest_surface) { |
572 DCHECK(!available()); | 619 DCHECK(!available()); |
573 | 620 |
574 GLint current_texture = 0; | 621 GLint current_texture = 0; |
575 glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); | 622 glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); |
576 | 623 |
577 glBindTexture(GL_TEXTURE_2D, picture_buffer_.texture_id()); | 624 glBindTexture(GL_TEXTURE_2D, picture_buffer_.texture_id()); |
578 | 625 |
579 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 626 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
580 | 627 |
581 if (src_surface && dest_surface) { | 628 if (src_surface && dest_surface) { |
582 DCHECK_EQ(src_surface, decoder_surface_.get()); | 629 DCHECK_EQ(src_surface, decoder_surface_.get()); |
583 DCHECK_EQ(dest_surface, target_surface_.get()); | 630 DCHECK_EQ(dest_surface, target_surface_.get()); |
584 decoder_surface_.Release(); | 631 decoder_surface_.Release(); |
585 target_surface_.Release(); | 632 target_surface_.Release(); |
586 } else { | 633 } else { |
587 DCHECK(decoder_dx11_texture_.get()); | 634 DCHECK(decoder_dx11_texture_.get()); |
588 decoder_dx11_texture_.Release(); | 635 decoder_dx11_texture_.Release(); |
589 } | 636 } |
| 637 if (egl_keyed_mutex_) { |
| 638 keyed_mutex_value_++; |
| 639 HRESULT result = |
| 640 egl_keyed_mutex_->AcquireSync(keyed_mutex_value_, kAcquireSyncWaitMs); |
| 641 RETURN_ON_FAILURE(result == S_OK, "Could not acquire sync mutex", false); |
| 642 } |
590 | 643 |
591 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); | 644 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); |
592 eglBindTexImage( | 645 eglBindTexImage( |
593 egl_display, | 646 egl_display, |
594 decoding_surface_, | 647 decoding_surface_, |
595 EGL_BACK_BUFFER); | 648 EGL_BACK_BUFFER); |
596 | 649 |
597 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 650 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
598 glBindTexture(GL_TEXTURE_2D, current_texture); | 651 glBindTexture(GL_TEXTURE_2D, current_texture); |
| 652 return true; |
599 } | 653 } |
600 | 654 |
601 DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo( | 655 DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo( |
602 int32_t buffer_id, | 656 int32_t buffer_id, |
603 IMFSample* sample) | 657 IMFSample* sample) |
604 : input_buffer_id(buffer_id), picture_buffer_id(-1) { | 658 : input_buffer_id(buffer_id), picture_buffer_id(-1) { |
605 output_sample.Attach(sample); | 659 output_sample.Attach(sample); |
606 } | 660 } |
607 | 661 |
608 DXVAVideoDecodeAccelerator::PendingSampleInfo::~PendingSampleInfo() {} | 662 DXVAVideoDecodeAccelerator::PendingSampleInfo::~PendingSampleInfo() {} |
609 | 663 |
610 DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( | 664 DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( |
611 const base::Callback<bool(void)>& make_context_current, | 665 const base::Callback<bool(void)>& make_context_current, |
612 gfx::GLContext* gl_context) | 666 gfx::GLContext* gl_context) |
613 : client_(NULL), | 667 : client_(NULL), |
614 dev_manager_reset_token_(0), | 668 dev_manager_reset_token_(0), |
615 dx11_dev_manager_reset_token_(0), | 669 dx11_dev_manager_reset_token_(0), |
616 egl_config_(NULL), | 670 egl_config_(NULL), |
617 state_(kUninitialized), | 671 state_(kUninitialized), |
618 pictures_requested_(false), | 672 pictures_requested_(false), |
619 inputs_before_decode_(0), | 673 inputs_before_decode_(0), |
620 sent_drain_message_(false), | 674 sent_drain_message_(false), |
621 make_context_current_(make_context_current), | 675 make_context_current_(make_context_current), |
622 codec_(media::kUnknownVideoCodec), | 676 codec_(media::kUnknownVideoCodec), |
623 decoder_thread_("DXVAVideoDecoderThread"), | 677 decoder_thread_("DXVAVideoDecoderThread"), |
624 pending_flush_(false), | 678 pending_flush_(false), |
625 use_dx11_(false), | 679 use_dx11_(false), |
| 680 use_keyed_mutex_(false), |
626 dx11_video_format_converter_media_type_needs_init_(true), | 681 dx11_video_format_converter_media_type_needs_init_(true), |
627 gl_context_(gl_context), | 682 gl_context_(gl_context), |
628 using_angle_device_(false), | 683 using_angle_device_(false), |
629 weak_this_factory_(this) { | 684 weak_this_factory_(this) { |
630 weak_ptr_ = weak_this_factory_.GetWeakPtr(); | 685 weak_ptr_ = weak_this_factory_.GetWeakPtr(); |
631 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); | 686 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); |
632 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); | 687 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); |
633 } | 688 } |
634 | 689 |
635 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { | 690 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { |
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
959 it = stale_output_picture_buffers_.find(picture_buffer_id); | 1014 it = stale_output_picture_buffers_.find(picture_buffer_id); |
960 RETURN_AND_NOTIFY_ON_FAILURE(it != stale_output_picture_buffers_.end(), | 1015 RETURN_AND_NOTIFY_ON_FAILURE(it != stale_output_picture_buffers_.end(), |
961 "Invalid picture id: " << picture_buffer_id, INVALID_ARGUMENT,); | 1016 "Invalid picture id: " << picture_buffer_id, INVALID_ARGUMENT,); |
962 main_thread_task_runner_->PostTask( | 1017 main_thread_task_runner_->PostTask( |
963 FROM_HERE, | 1018 FROM_HERE, |
964 base::Bind(&DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer, | 1019 base::Bind(&DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer, |
965 weak_this_factory_.GetWeakPtr(), picture_buffer_id)); | 1020 weak_this_factory_.GetWeakPtr(), picture_buffer_id)); |
966 return; | 1021 return; |
967 } | 1022 } |
968 | 1023 |
969 it->second->ReusePictureBuffer(); | 1024 RETURN_AND_NOTIFY_ON_FAILURE(it->second->ReusePictureBuffer(), |
| 1025 "Failed to reuse picture buffer", |
| 1026 PLATFORM_FAILURE, ); |
| 1027 |
970 ProcessPendingSamples(); | 1028 ProcessPendingSamples(); |
971 if (pending_flush_) { | 1029 if (pending_flush_) { |
972 decoder_thread_task_runner_->PostTask( | 1030 decoder_thread_task_runner_->PostTask( |
973 FROM_HERE, | 1031 FROM_HERE, |
974 base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, | 1032 base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, |
975 base::Unretained(this))); | 1033 base::Unretained(this))); |
976 } | 1034 } |
977 } | 1035 } |
978 | 1036 |
979 void DXVAVideoDecodeAccelerator::Flush() { | 1037 void DXVAVideoDecodeAccelerator::Flush() { |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1236 // this. This should always be true for Windows 8+. | 1294 // this. This should always be true for Windows 8+. |
1237 // 3. ANGLE is using DX11. | 1295 // 3. ANGLE is using DX11. |
1238 DCHECK(gl_context_); | 1296 DCHECK(gl_context_); |
1239 if (create_dxgi_device_manager_ && | 1297 if (create_dxgi_device_manager_ && |
1240 (gl_context_->GetGLRenderer().find("Direct3D11") != | 1298 (gl_context_->GetGLRenderer().find("Direct3D11") != |
1241 std::string::npos)) { | 1299 std::string::npos)) { |
1242 UINT32 dx11_aware = 0; | 1300 UINT32 dx11_aware = 0; |
1243 attributes->GetUINT32(MF_SA_D3D11_AWARE, &dx11_aware); | 1301 attributes->GetUINT32(MF_SA_D3D11_AWARE, &dx11_aware); |
1244 use_dx11_ = !!dx11_aware; | 1302 use_dx11_ = !!dx11_aware; |
1245 } | 1303 } |
| 1304 |
| 1305 use_keyed_mutex_ = |
| 1306 use_dx11_ && gfx::GLSurfaceEGL::HasEGLExtension("EGL_ANGLE_keyed_mutex"); |
| 1307 |
1246 return true; | 1308 return true; |
1247 } | 1309 } |
1248 | 1310 |
1249 bool DXVAVideoDecodeAccelerator::SetDecoderMediaTypes() { | 1311 bool DXVAVideoDecodeAccelerator::SetDecoderMediaTypes() { |
1250 RETURN_ON_FAILURE(SetDecoderInputMediaType(), | 1312 RETURN_ON_FAILURE(SetDecoderInputMediaType(), |
1251 "Failed to set decoder input media type", false); | 1313 "Failed to set decoder input media type", false); |
1252 return SetDecoderOutputMediaType(MFVideoFormat_NV12); | 1314 return SetDecoderOutputMediaType(MFVideoFormat_NV12); |
1253 } | 1315 } |
1254 | 1316 |
1255 bool DXVAVideoDecodeAccelerator::SetDecoderInputMediaType() { | 1317 bool DXVAVideoDecodeAccelerator::SetDecoderInputMediaType() { |
(...skipping 677 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1933 // was a Reset operation which dropped the output frame. | 1995 // was a Reset operation which dropped the output frame. |
1934 DXVAPictureBuffer* picture_buffer = it->second.get(); | 1996 DXVAPictureBuffer* picture_buffer = it->second.get(); |
1935 if (picture_buffer->available()) | 1997 if (picture_buffer->available()) |
1936 return; | 1998 return; |
1937 | 1999 |
1938 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), | 2000 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), |
1939 "Failed to make context current", PLATFORM_FAILURE,); | 2001 "Failed to make context current", PLATFORM_FAILURE,); |
1940 | 2002 |
1941 DCHECK(!output_picture_buffers_.empty()); | 2003 DCHECK(!output_picture_buffers_.empty()); |
1942 | 2004 |
1943 picture_buffer->CopySurfaceComplete(src_surface, | 2005 bool result = picture_buffer->CopySurfaceComplete(src_surface, dest_surface); |
1944 dest_surface); | 2006 RETURN_AND_NOTIFY_ON_FAILURE(result, "Failed to complete copying surface", |
| 2007 PLATFORM_FAILURE, ); |
1945 | 2008 |
1946 NotifyPictureReady(picture_buffer->id(), input_buffer_id); | 2009 NotifyPictureReady(picture_buffer->id(), input_buffer_id); |
1947 | 2010 |
1948 { | 2011 { |
1949 base::AutoLock lock(decoder_lock_); | 2012 base::AutoLock lock(decoder_lock_); |
1950 if (!pending_output_samples_.empty()) | 2013 if (!pending_output_samples_.empty()) |
1951 pending_output_samples_.pop_front(); | 2014 pending_output_samples_.pop_front(); |
1952 } | 2015 } |
1953 | 2016 |
1954 if (pending_flush_) { | 2017 if (pending_flush_) { |
1955 decoder_thread_task_runner_->PostTask( | 2018 decoder_thread_task_runner_->PostTask( |
1956 FROM_HERE, | 2019 FROM_HERE, |
1957 base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, | 2020 base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, |
1958 base::Unretained(this))); | 2021 base::Unretained(this))); |
1959 return; | 2022 return; |
1960 } | 2023 } |
1961 decoder_thread_task_runner_->PostTask( | 2024 decoder_thread_task_runner_->PostTask( |
1962 FROM_HERE, | 2025 FROM_HERE, |
1963 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, | 2026 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
1964 base::Unretained(this))); | 2027 base::Unretained(this))); |
1965 } | 2028 } |
1966 | 2029 |
1967 void DXVAVideoDecodeAccelerator::CopyTexture(ID3D11Texture2D* src_texture, | 2030 void DXVAVideoDecodeAccelerator::CopyTexture( |
1968 ID3D11Texture2D* dest_texture, | 2031 ID3D11Texture2D* src_texture, |
1969 IMFSample* video_frame, | 2032 ID3D11Texture2D* dest_texture, |
1970 int picture_buffer_id, | 2033 base::win::ScopedComPtr<IDXGIKeyedMutex> dest_keyed_mutex, |
1971 int input_buffer_id) { | 2034 uint64_t keyed_mutex_value, |
| 2035 IMFSample* video_frame, |
| 2036 int picture_buffer_id, |
| 2037 int input_buffer_id) { |
1972 HRESULT hr = E_FAIL; | 2038 HRESULT hr = E_FAIL; |
1973 | 2039 |
1974 DCHECK(use_dx11_); | 2040 DCHECK(use_dx11_); |
1975 | 2041 |
1976 if (!decoder_thread_task_runner_->BelongsToCurrentThread()) { | 2042 if (!decoder_thread_task_runner_->BelongsToCurrentThread()) { |
1977 // The media foundation H.264 decoder outputs YUV12 textures which we | 2043 // The media foundation H.264 decoder outputs YUV12 textures which we |
1978 // cannot copy into ANGLE as they expect ARGB textures. In D3D land | 2044 // cannot copy into ANGLE as they expect ARGB textures. In D3D land |
1979 // the StretchRect API in the IDirect3DDevice9Ex interface did the color | 2045 // the StretchRect API in the IDirect3DDevice9Ex interface did the color |
1980 // space conversion for us. Sadly in DX11 land the API does not provide | 2046 // space conversion for us. Sadly in DX11 land the API does not provide |
1981 // a straightforward way to do this. | 2047 // a straightforward way to do this. |
(...skipping 16 matching lines...) Expand all Loading... |
1998 | 2064 |
1999 // The input to the video processor is the output sample. | 2065 // The input to the video processor is the output sample. |
2000 base::win::ScopedComPtr<IMFSample> input_sample_for_conversion; | 2066 base::win::ScopedComPtr<IMFSample> input_sample_for_conversion; |
2001 { | 2067 { |
2002 base::AutoLock lock(decoder_lock_); | 2068 base::AutoLock lock(decoder_lock_); |
2003 PendingSampleInfo& sample_info = pending_output_samples_.front(); | 2069 PendingSampleInfo& sample_info = pending_output_samples_.front(); |
2004 input_sample_for_conversion = sample_info.output_sample; | 2070 input_sample_for_conversion = sample_info.output_sample; |
2005 } | 2071 } |
2006 | 2072 |
2007 decoder_thread_task_runner_->PostTask( | 2073 decoder_thread_task_runner_->PostTask( |
2008 FROM_HERE, | 2074 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopyTexture, |
2009 base::Bind(&DXVAVideoDecodeAccelerator::CopyTexture, | 2075 base::Unretained(this), src_texture, dest_texture, |
2010 base::Unretained(this), | 2076 dest_keyed_mutex, keyed_mutex_value, |
2011 src_texture, | 2077 input_sample_for_conversion.Detach(), |
2012 dest_texture, | 2078 picture_buffer_id, input_buffer_id)); |
2013 input_sample_for_conversion.Detach(), | |
2014 picture_buffer_id, | |
2015 input_buffer_id)); | |
2016 return; | 2079 return; |
2017 } | 2080 } |
2018 | 2081 |
2019 DCHECK(video_frame); | 2082 DCHECK(video_frame); |
2020 | 2083 |
2021 base::win::ScopedComPtr<IMFSample> input_sample; | 2084 base::win::ScopedComPtr<IMFSample> input_sample; |
2022 input_sample.Attach(video_frame); | 2085 input_sample.Attach(video_frame); |
2023 | 2086 |
2024 DCHECK(video_format_converter_mft_.get()); | 2087 DCHECK(video_format_converter_mft_.get()); |
2025 | 2088 |
| 2089 if (dest_keyed_mutex) { |
| 2090 HRESULT hr = |
| 2091 dest_keyed_mutex->AcquireSync(keyed_mutex_value, kAcquireSyncWaitMs); |
| 2092 RETURN_AND_NOTIFY_ON_FAILURE( |
| 2093 hr == S_OK, "D3D11 failed to acquire keyed mutex for texture.", |
| 2094 PLATFORM_FAILURE, ); |
| 2095 } |
2026 // The video processor MFT requires output samples to be allocated by the | 2096 // The video processor MFT requires output samples to be allocated by the |
2027 // caller. We create a sample with a buffer backed with the ID3D11Texture2D | 2097 // caller. We create a sample with a buffer backed with the ID3D11Texture2D |
2028 // interface exposed by ANGLE. This works nicely as this ensures that the | 2098 // interface exposed by ANGLE. This works nicely as this ensures that the |
2029 // video processor coverts the color space of the output frame and copies | 2099 // video processor coverts the color space of the output frame and copies |
2030 // the result into the ANGLE texture. | 2100 // the result into the ANGLE texture. |
2031 base::win::ScopedComPtr<IMFSample> output_sample; | 2101 base::win::ScopedComPtr<IMFSample> output_sample; |
2032 hr = MFCreateSample(output_sample.Receive()); | 2102 hr = MFCreateSample(output_sample.Receive()); |
2033 if (FAILED(hr)) { | 2103 if (FAILED(hr)) { |
2034 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2104 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
2035 "Failed to create output sample.", PLATFORM_FAILURE,); | 2105 "Failed to create output sample.", PLATFORM_FAILURE,); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2070 if (FAILED(hr)) { | 2140 if (FAILED(hr)) { |
2071 base::debug::Alias(&hr); | 2141 base::debug::Alias(&hr); |
2072 // TODO(ananta) | 2142 // TODO(ananta) |
2073 // Remove this CHECK when the change to use DX11 for H/W decoding | 2143 // Remove this CHECK when the change to use DX11 for H/W decoding |
2074 // stablizes. | 2144 // stablizes. |
2075 CHECK(false); | 2145 CHECK(false); |
2076 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2146 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
2077 "Failed to convert output sample format.", PLATFORM_FAILURE,); | 2147 "Failed to convert output sample format.", PLATFORM_FAILURE,); |
2078 } | 2148 } |
2079 | 2149 |
2080 d3d11_device_context_->Flush(); | 2150 if (dest_keyed_mutex) { |
2081 d3d11_device_context_->End(d3d11_query_.get()); | 2151 HRESULT hr = dest_keyed_mutex->ReleaseSync(keyed_mutex_value + 1); |
| 2152 RETURN_AND_NOTIFY_ON_FAILURE(hr == S_OK, "Failed to release keyed mutex.", |
| 2153 PLATFORM_FAILURE, ); |
2082 | 2154 |
2083 decoder_thread_task_runner_->PostDelayedTask( | 2155 main_thread_task_runner_->PostTask( |
2084 FROM_HERE, | 2156 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, |
2085 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, | 2157 weak_this_factory_.GetWeakPtr(), nullptr, nullptr, |
2086 base::Unretained(this), 0, | 2158 picture_buffer_id, input_buffer_id)); |
2087 reinterpret_cast<IDirect3DSurface9*>(NULL), | 2159 } else { |
2088 reinterpret_cast<IDirect3DSurface9*>(NULL), | 2160 d3d11_device_context_->Flush(); |
2089 picture_buffer_id, input_buffer_id), | 2161 d3d11_device_context_->End(d3d11_query_.get()); |
2090 base::TimeDelta::FromMilliseconds( | 2162 |
2091 kFlushDecoderSurfaceTimeoutMs)); | 2163 decoder_thread_task_runner_->PostDelayedTask( |
| 2164 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, |
| 2165 base::Unretained(this), 0, |
| 2166 reinterpret_cast<IDirect3DSurface9*>(NULL), |
| 2167 reinterpret_cast<IDirect3DSurface9*>(NULL), |
| 2168 picture_buffer_id, input_buffer_id), |
| 2169 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); |
| 2170 } |
2092 } | 2171 } |
2093 | 2172 |
2094 void DXVAVideoDecodeAccelerator::FlushDecoder( | 2173 void DXVAVideoDecodeAccelerator::FlushDecoder( |
2095 int iterations, | 2174 int iterations, |
2096 IDirect3DSurface9* src_surface, | 2175 IDirect3DSurface9* src_surface, |
2097 IDirect3DSurface9* dest_surface, | 2176 IDirect3DSurface9* dest_surface, |
2098 int picture_buffer_id, | 2177 int picture_buffer_id, |
2099 int input_buffer_id) { | 2178 int input_buffer_id) { |
2100 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 2179 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
2101 | 2180 |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2298 } | 2377 } |
2299 RETURN_ON_HR_FAILURE(hr, "Failed to set output type", false); | 2378 RETURN_ON_HR_FAILURE(hr, "Failed to set output type", false); |
2300 return true; | 2379 return true; |
2301 } | 2380 } |
2302 media_type.Release(); | 2381 media_type.Release(); |
2303 } | 2382 } |
2304 return false; | 2383 return false; |
2305 } | 2384 } |
2306 | 2385 |
2307 } // namespace content | 2386 } // namespace content |
OLD | NEW |