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 if (hr != S_OK) | |
558 return false; | |
ananta
2016/01/26 23:09:16
Should we be logging errors here?
| |
559 } | |
560 return true; | |
514 } | 561 } |
515 | 562 |
516 bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer:: | 563 bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer:: |
517 CopyOutputSampleDataToPictureBuffer( | 564 CopyOutputSampleDataToPictureBuffer( |
518 DXVAVideoDecodeAccelerator* decoder, | 565 DXVAVideoDecodeAccelerator* decoder, |
519 IDirect3DSurface9* dest_surface, | 566 IDirect3DSurface9* dest_surface, |
520 ID3D11Texture2D* dx11_texture, | 567 ID3D11Texture2D* dx11_texture, |
521 int input_buffer_id) { | 568 int input_buffer_id) { |
522 DCHECK(dest_surface || dx11_texture); | 569 DCHECK(dest_surface || dx11_texture); |
523 if (dx11_texture) { | 570 if (dx11_texture) { |
524 // Grab a reference on the decoder texture. This reference will be released | 571 // 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 | 572 // when we receive a notification that the copy was completed or when the |
526 // DXVAPictureBuffer instance is destroyed. | 573 // DXVAPictureBuffer instance is destroyed. |
527 decoder_dx11_texture_ = dx11_texture; | 574 decoder_dx11_texture_ = dx11_texture; |
528 decoder->CopyTexture(dx11_texture, dx11_decoding_texture_.get(), NULL, | 575 decoder->CopyTexture(dx11_texture, dx11_decoding_texture_.get(), |
529 id(), input_buffer_id); | 576 dx11_keyed_mutex_, keyed_mutex_value_, NULL, id(), |
577 input_buffer_id); | |
530 return true; | 578 return true; |
531 } | 579 } |
532 D3DSURFACE_DESC surface_desc; | 580 D3DSURFACE_DESC surface_desc; |
533 HRESULT hr = dest_surface->GetDesc(&surface_desc); | 581 HRESULT hr = dest_surface->GetDesc(&surface_desc); |
534 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); | 582 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); |
535 | 583 |
536 D3DSURFACE_DESC texture_desc; | 584 D3DSURFACE_DESC texture_desc; |
537 decoding_texture_->GetLevelDesc(0, &texture_desc); | 585 decoding_texture_->GetLevelDesc(0, &texture_desc); |
538 | 586 |
539 if (texture_desc.Width != surface_desc.Width || | 587 if (texture_desc.Width != surface_desc.Width || |
(...skipping 19 matching lines...) Expand all Loading... | |
559 hr = decoding_texture_->GetSurfaceLevel(0, target_surface_.Receive()); | 607 hr = decoding_texture_->GetSurfaceLevel(0, target_surface_.Receive()); |
560 RETURN_ON_HR_FAILURE(hr, "Failed to get surface from texture", false); | 608 RETURN_ON_HR_FAILURE(hr, "Failed to get surface from texture", false); |
561 | 609 |
562 decoder_surface_ = dest_surface; | 610 decoder_surface_ = dest_surface; |
563 | 611 |
564 decoder->CopySurface(decoder_surface_.get(), target_surface_.get(), id(), | 612 decoder->CopySurface(decoder_surface_.get(), target_surface_.get(), id(), |
565 input_buffer_id); | 613 input_buffer_id); |
566 return true; | 614 return true; |
567 } | 615 } |
568 | 616 |
569 void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::CopySurfaceComplete( | 617 bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::CopySurfaceComplete( |
570 IDirect3DSurface9* src_surface, | 618 IDirect3DSurface9* src_surface, |
571 IDirect3DSurface9* dest_surface) { | 619 IDirect3DSurface9* dest_surface) { |
572 DCHECK(!available()); | 620 DCHECK(!available()); |
573 | 621 |
574 GLint current_texture = 0; | 622 GLint current_texture = 0; |
575 glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); | 623 glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); |
576 | 624 |
577 glBindTexture(GL_TEXTURE_2D, picture_buffer_.texture_id()); | 625 glBindTexture(GL_TEXTURE_2D, picture_buffer_.texture_id()); |
578 | 626 |
579 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 627 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
580 | 628 |
581 if (src_surface && dest_surface) { | 629 if (src_surface && dest_surface) { |
582 DCHECK_EQ(src_surface, decoder_surface_.get()); | 630 DCHECK_EQ(src_surface, decoder_surface_.get()); |
583 DCHECK_EQ(dest_surface, target_surface_.get()); | 631 DCHECK_EQ(dest_surface, target_surface_.get()); |
584 decoder_surface_.Release(); | 632 decoder_surface_.Release(); |
585 target_surface_.Release(); | 633 target_surface_.Release(); |
586 } else { | 634 } else { |
587 DCHECK(decoder_dx11_texture_.get()); | 635 DCHECK(decoder_dx11_texture_.get()); |
588 decoder_dx11_texture_.Release(); | 636 decoder_dx11_texture_.Release(); |
589 } | 637 } |
638 if (egl_keyed_mutex_) { | |
639 keyed_mutex_value_++; | |
640 HRESULT result = | |
641 egl_keyed_mutex_->AcquireSync(keyed_mutex_value_, kAcquireSyncWaitMs); | |
642 if (result != S_OK) | |
ananta
2016/01/26 23:09:16
Ditto for logging errors
| |
643 return false; | |
644 } | |
590 | 645 |
591 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); | 646 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); |
592 eglBindTexImage( | 647 eglBindTexImage( |
593 egl_display, | 648 egl_display, |
594 decoding_surface_, | 649 decoding_surface_, |
595 EGL_BACK_BUFFER); | 650 EGL_BACK_BUFFER); |
596 | 651 |
597 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 652 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
598 glBindTexture(GL_TEXTURE_2D, current_texture); | 653 glBindTexture(GL_TEXTURE_2D, current_texture); |
654 return true; | |
599 } | 655 } |
600 | 656 |
601 DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo( | 657 DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo( |
602 int32_t buffer_id, | 658 int32_t buffer_id, |
603 IMFSample* sample) | 659 IMFSample* sample) |
604 : input_buffer_id(buffer_id), picture_buffer_id(-1) { | 660 : input_buffer_id(buffer_id), picture_buffer_id(-1) { |
605 output_sample.Attach(sample); | 661 output_sample.Attach(sample); |
606 } | 662 } |
607 | 663 |
608 DXVAVideoDecodeAccelerator::PendingSampleInfo::~PendingSampleInfo() {} | 664 DXVAVideoDecodeAccelerator::PendingSampleInfo::~PendingSampleInfo() {} |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
959 it = stale_output_picture_buffers_.find(picture_buffer_id); | 1015 it = stale_output_picture_buffers_.find(picture_buffer_id); |
960 RETURN_AND_NOTIFY_ON_FAILURE(it != stale_output_picture_buffers_.end(), | 1016 RETURN_AND_NOTIFY_ON_FAILURE(it != stale_output_picture_buffers_.end(), |
961 "Invalid picture id: " << picture_buffer_id, INVALID_ARGUMENT,); | 1017 "Invalid picture id: " << picture_buffer_id, INVALID_ARGUMENT,); |
962 main_thread_task_runner_->PostTask( | 1018 main_thread_task_runner_->PostTask( |
963 FROM_HERE, | 1019 FROM_HERE, |
964 base::Bind(&DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer, | 1020 base::Bind(&DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer, |
965 weak_this_factory_.GetWeakPtr(), picture_buffer_id)); | 1021 weak_this_factory_.GetWeakPtr(), picture_buffer_id)); |
966 return; | 1022 return; |
967 } | 1023 } |
968 | 1024 |
969 it->second->ReusePictureBuffer(); | 1025 RETURN_AND_NOTIFY_ON_FAILURE(it->second->ReusePictureBuffer(), |
1026 "Failed to reuse picture buffer", | |
1027 PLATFORM_FAILURE, ); | |
1028 | |
970 ProcessPendingSamples(); | 1029 ProcessPendingSamples(); |
971 if (pending_flush_) { | 1030 if (pending_flush_) { |
972 decoder_thread_task_runner_->PostTask( | 1031 decoder_thread_task_runner_->PostTask( |
973 FROM_HERE, | 1032 FROM_HERE, |
974 base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, | 1033 base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, |
975 base::Unretained(this))); | 1034 base::Unretained(this))); |
976 } | 1035 } |
977 } | 1036 } |
978 | 1037 |
979 void DXVAVideoDecodeAccelerator::Flush() { | 1038 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+. | 1295 // this. This should always be true for Windows 8+. |
1237 // 3. ANGLE is using DX11. | 1296 // 3. ANGLE is using DX11. |
1238 DCHECK(gl_context_); | 1297 DCHECK(gl_context_); |
1239 if (create_dxgi_device_manager_ && | 1298 if (create_dxgi_device_manager_ && |
1240 (gl_context_->GetGLRenderer().find("Direct3D11") != | 1299 (gl_context_->GetGLRenderer().find("Direct3D11") != |
1241 std::string::npos)) { | 1300 std::string::npos)) { |
1242 UINT32 dx11_aware = 0; | 1301 UINT32 dx11_aware = 0; |
1243 attributes->GetUINT32(MF_SA_D3D11_AWARE, &dx11_aware); | 1302 attributes->GetUINT32(MF_SA_D3D11_AWARE, &dx11_aware); |
1244 use_dx11_ = !!dx11_aware; | 1303 use_dx11_ = !!dx11_aware; |
1245 } | 1304 } |
1305 | |
1306 use_keyed_mutex_ = | |
1307 use_dx11_ && gfx::GLSurfaceEGL::HasEGLExtension("EGL_ANGLE_keyed_mutex"); | |
1308 | |
1246 return true; | 1309 return true; |
1247 } | 1310 } |
1248 | 1311 |
1249 bool DXVAVideoDecodeAccelerator::SetDecoderMediaTypes() { | 1312 bool DXVAVideoDecodeAccelerator::SetDecoderMediaTypes() { |
1250 RETURN_ON_FAILURE(SetDecoderInputMediaType(), | 1313 RETURN_ON_FAILURE(SetDecoderInputMediaType(), |
1251 "Failed to set decoder input media type", false); | 1314 "Failed to set decoder input media type", false); |
1252 return SetDecoderOutputMediaType(MFVideoFormat_NV12); | 1315 return SetDecoderOutputMediaType(MFVideoFormat_NV12); |
1253 } | 1316 } |
1254 | 1317 |
1255 bool DXVAVideoDecodeAccelerator::SetDecoderInputMediaType() { | 1318 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. | 1996 // was a Reset operation which dropped the output frame. |
1934 DXVAPictureBuffer* picture_buffer = it->second.get(); | 1997 DXVAPictureBuffer* picture_buffer = it->second.get(); |
1935 if (picture_buffer->available()) | 1998 if (picture_buffer->available()) |
1936 return; | 1999 return; |
1937 | 2000 |
1938 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), | 2001 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), |
1939 "Failed to make context current", PLATFORM_FAILURE,); | 2002 "Failed to make context current", PLATFORM_FAILURE,); |
1940 | 2003 |
1941 DCHECK(!output_picture_buffers_.empty()); | 2004 DCHECK(!output_picture_buffers_.empty()); |
1942 | 2005 |
1943 picture_buffer->CopySurfaceComplete(src_surface, | 2006 bool result = picture_buffer->CopySurfaceComplete(src_surface, dest_surface); |
1944 dest_surface); | 2007 RETURN_AND_NOTIFY_ON_FAILURE(result, "Failed to complete copying surface", |
2008 PLATFORM_FAILURE, ); | |
1945 | 2009 |
1946 NotifyPictureReady(picture_buffer->id(), input_buffer_id); | 2010 NotifyPictureReady(picture_buffer->id(), input_buffer_id); |
1947 | 2011 |
1948 { | 2012 { |
1949 base::AutoLock lock(decoder_lock_); | 2013 base::AutoLock lock(decoder_lock_); |
1950 if (!pending_output_samples_.empty()) | 2014 if (!pending_output_samples_.empty()) |
1951 pending_output_samples_.pop_front(); | 2015 pending_output_samples_.pop_front(); |
1952 } | 2016 } |
1953 | 2017 |
1954 if (pending_flush_) { | 2018 if (pending_flush_) { |
1955 decoder_thread_task_runner_->PostTask( | 2019 decoder_thread_task_runner_->PostTask( |
1956 FROM_HERE, | 2020 FROM_HERE, |
1957 base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, | 2021 base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, |
1958 base::Unretained(this))); | 2022 base::Unretained(this))); |
1959 return; | 2023 return; |
1960 } | 2024 } |
1961 decoder_thread_task_runner_->PostTask( | 2025 decoder_thread_task_runner_->PostTask( |
1962 FROM_HERE, | 2026 FROM_HERE, |
1963 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, | 2027 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
1964 base::Unretained(this))); | 2028 base::Unretained(this))); |
1965 } | 2029 } |
1966 | 2030 |
1967 void DXVAVideoDecodeAccelerator::CopyTexture(ID3D11Texture2D* src_texture, | 2031 void DXVAVideoDecodeAccelerator::CopyTexture( |
1968 ID3D11Texture2D* dest_texture, | 2032 ID3D11Texture2D* src_texture, |
1969 IMFSample* video_frame, | 2033 ID3D11Texture2D* dest_texture, |
1970 int picture_buffer_id, | 2034 base::win::ScopedComPtr<IDXGIKeyedMutex> dest_keyed_mutex, |
1971 int input_buffer_id) { | 2035 uint64_t keyed_mutex_value, |
2036 IMFSample* video_frame, | |
2037 int picture_buffer_id, | |
2038 int input_buffer_id) { | |
1972 HRESULT hr = E_FAIL; | 2039 HRESULT hr = E_FAIL; |
1973 | 2040 |
1974 DCHECK(use_dx11_); | 2041 DCHECK(use_dx11_); |
1975 | 2042 |
1976 if (!decoder_thread_task_runner_->BelongsToCurrentThread()) { | 2043 if (!decoder_thread_task_runner_->BelongsToCurrentThread()) { |
1977 // The media foundation H.264 decoder outputs YUV12 textures which we | 2044 // The media foundation H.264 decoder outputs YUV12 textures which we |
1978 // cannot copy into ANGLE as they expect ARGB textures. In D3D land | 2045 // cannot copy into ANGLE as they expect ARGB textures. In D3D land |
1979 // the StretchRect API in the IDirect3DDevice9Ex interface did the color | 2046 // the StretchRect API in the IDirect3DDevice9Ex interface did the color |
1980 // space conversion for us. Sadly in DX11 land the API does not provide | 2047 // space conversion for us. Sadly in DX11 land the API does not provide |
1981 // a straightforward way to do this. | 2048 // a straightforward way to do this. |
(...skipping 16 matching lines...) Expand all Loading... | |
1998 | 2065 |
1999 // The input to the video processor is the output sample. | 2066 // The input to the video processor is the output sample. |
2000 base::win::ScopedComPtr<IMFSample> input_sample_for_conversion; | 2067 base::win::ScopedComPtr<IMFSample> input_sample_for_conversion; |
2001 { | 2068 { |
2002 base::AutoLock lock(decoder_lock_); | 2069 base::AutoLock lock(decoder_lock_); |
2003 PendingSampleInfo& sample_info = pending_output_samples_.front(); | 2070 PendingSampleInfo& sample_info = pending_output_samples_.front(); |
2004 input_sample_for_conversion = sample_info.output_sample; | 2071 input_sample_for_conversion = sample_info.output_sample; |
2005 } | 2072 } |
2006 | 2073 |
2007 decoder_thread_task_runner_->PostTask( | 2074 decoder_thread_task_runner_->PostTask( |
2008 FROM_HERE, | 2075 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopyTexture, |
2009 base::Bind(&DXVAVideoDecodeAccelerator::CopyTexture, | 2076 base::Unretained(this), src_texture, dest_texture, |
2010 base::Unretained(this), | 2077 dest_keyed_mutex, keyed_mutex_value, |
2011 src_texture, | 2078 input_sample_for_conversion.Detach(), |
2012 dest_texture, | 2079 picture_buffer_id, input_buffer_id)); |
2013 input_sample_for_conversion.Detach(), | |
2014 picture_buffer_id, | |
2015 input_buffer_id)); | |
2016 return; | 2080 return; |
2017 } | 2081 } |
2018 | 2082 |
2019 DCHECK(video_frame); | 2083 DCHECK(video_frame); |
2020 | 2084 |
2021 base::win::ScopedComPtr<IMFSample> input_sample; | 2085 base::win::ScopedComPtr<IMFSample> input_sample; |
2022 input_sample.Attach(video_frame); | 2086 input_sample.Attach(video_frame); |
2023 | 2087 |
2024 DCHECK(video_format_converter_mft_.get()); | 2088 DCHECK(video_format_converter_mft_.get()); |
2025 | 2089 |
2090 if (dest_keyed_mutex) { | |
2091 HRESULT hr = | |
2092 dest_keyed_mutex->AcquireSync(keyed_mutex_value, kAcquireSyncWaitMs); | |
2093 RETURN_AND_NOTIFY_ON_FAILURE( | |
2094 hr == S_OK, "D3D11 failed to acquire keyed mutex for texture.", | |
2095 PLATFORM_FAILURE, ); | |
2096 } | |
2026 // The video processor MFT requires output samples to be allocated by the | 2097 // 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 | 2098 // 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 | 2099 // 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 | 2100 // video processor coverts the color space of the output frame and copies |
2030 // the result into the ANGLE texture. | 2101 // the result into the ANGLE texture. |
2031 base::win::ScopedComPtr<IMFSample> output_sample; | 2102 base::win::ScopedComPtr<IMFSample> output_sample; |
2032 hr = MFCreateSample(output_sample.Receive()); | 2103 hr = MFCreateSample(output_sample.Receive()); |
2033 if (FAILED(hr)) { | 2104 if (FAILED(hr)) { |
2034 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2105 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
2035 "Failed to create output sample.", PLATFORM_FAILURE,); | 2106 "Failed to create output sample.", PLATFORM_FAILURE,); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2070 if (FAILED(hr)) { | 2141 if (FAILED(hr)) { |
2071 base::debug::Alias(&hr); | 2142 base::debug::Alias(&hr); |
2072 // TODO(ananta) | 2143 // TODO(ananta) |
2073 // Remove this CHECK when the change to use DX11 for H/W decoding | 2144 // Remove this CHECK when the change to use DX11 for H/W decoding |
2074 // stablizes. | 2145 // stablizes. |
2075 CHECK(false); | 2146 CHECK(false); |
2076 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2147 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
2077 "Failed to convert output sample format.", PLATFORM_FAILURE,); | 2148 "Failed to convert output sample format.", PLATFORM_FAILURE,); |
2078 } | 2149 } |
2079 | 2150 |
2080 d3d11_device_context_->Flush(); | 2151 if (dest_keyed_mutex) { |
2081 d3d11_device_context_->End(d3d11_query_.get()); | 2152 HRESULT hr = dest_keyed_mutex->ReleaseSync(keyed_mutex_value + 1); |
2153 RETURN_AND_NOTIFY_ON_FAILURE(hr == S_OK, "Failed to release keyed mutex.", | |
2154 PLATFORM_FAILURE, ); | |
2082 | 2155 |
2083 decoder_thread_task_runner_->PostDelayedTask( | 2156 main_thread_task_runner_->PostTask( |
2084 FROM_HERE, | 2157 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, |
2085 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, | 2158 weak_this_factory_.GetWeakPtr(), nullptr, nullptr, |
2086 base::Unretained(this), 0, | 2159 picture_buffer_id, input_buffer_id)); |
2087 reinterpret_cast<IDirect3DSurface9*>(NULL), | 2160 } else { |
2088 reinterpret_cast<IDirect3DSurface9*>(NULL), | 2161 d3d11_device_context_->Flush(); |
2089 picture_buffer_id, input_buffer_id), | 2162 d3d11_device_context_->End(d3d11_query_.get()); |
2090 base::TimeDelta::FromMilliseconds( | 2163 |
2091 kFlushDecoderSurfaceTimeoutMs)); | 2164 decoder_thread_task_runner_->PostDelayedTask( |
2165 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, | |
2166 base::Unretained(this), 0, | |
2167 reinterpret_cast<IDirect3DSurface9*>(NULL), | |
2168 reinterpret_cast<IDirect3DSurface9*>(NULL), | |
2169 picture_buffer_id, input_buffer_id), | |
2170 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); | |
2171 } | |
2092 } | 2172 } |
2093 | 2173 |
2094 void DXVAVideoDecodeAccelerator::FlushDecoder( | 2174 void DXVAVideoDecodeAccelerator::FlushDecoder( |
2095 int iterations, | 2175 int iterations, |
2096 IDirect3DSurface9* src_surface, | 2176 IDirect3DSurface9* src_surface, |
2097 IDirect3DSurface9* dest_surface, | 2177 IDirect3DSurface9* dest_surface, |
2098 int picture_buffer_id, | 2178 int picture_buffer_id, |
2099 int input_buffer_id) { | 2179 int input_buffer_id) { |
2100 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 2180 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
2101 | 2181 |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2298 } | 2378 } |
2299 RETURN_ON_HR_FAILURE(hr, "Failed to set output type", false); | 2379 RETURN_ON_HR_FAILURE(hr, "Failed to set output type", false); |
2300 return true; | 2380 return true; |
2301 } | 2381 } |
2302 media_type.Release(); | 2382 media_type.Release(); |
2303 } | 2383 } |
2304 return false; | 2384 return false; |
2305 } | 2385 } |
2306 | 2386 |
2307 } // namespace content | 2387 } // namespace content |
OLD | NEW |