| Index: content/common/gpu/media/dxva_video_decode_accelerator_win.cc
|
| diff --git a/content/common/gpu/media/dxva_video_decode_accelerator_win.cc b/content/common/gpu/media/dxva_video_decode_accelerator_win.cc
|
| index 40a3239cb2581f977a6cbb5a58df23ff176ad0f0..d356852d2544dbd773e20c8dcb5511c99fa43a10 100644
|
| --- a/content/common/gpu/media/dxva_video_decode_accelerator_win.cc
|
| +++ b/content/common/gpu/media/dxva_video_decode_accelerator_win.cc
|
| @@ -166,6 +166,9 @@ enum {
|
| // the decoded samples. These buffers are then reused when the client tells
|
| // us that it is done with the buffer.
|
| kNumPictureBuffers = 5,
|
| + // The keyed mutex should always be released before the other thread
|
| + // attempts to acquire it, so AcquireSync should always return immediately.
|
| + kAcquireSyncWaitMs = 0,
|
| };
|
|
|
| static IMFSample* CreateEmptySample() {
|
| @@ -349,7 +352,10 @@ struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer {
|
| EGLConfig egl_config);
|
| ~DXVAPictureBuffer();
|
|
|
| - void ReusePictureBuffer();
|
| + bool InitializeTexture(const DXVAVideoDecodeAccelerator& decoder,
|
| + bool use_rgb);
|
| +
|
| + bool ReusePictureBuffer();
|
| // Copies the output sample data to the picture buffer provided by the
|
| // client.
|
| // The dest_surface parameter contains the decoded bits.
|
| @@ -377,7 +383,7 @@ struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer {
|
|
|
| // Called when the source surface |src_surface| is copied to the destination
|
| // |dest_surface|
|
| - void CopySurfaceComplete(IDirect3DSurface9* src_surface,
|
| + bool CopySurfaceComplete(IDirect3DSurface9* src_surface,
|
| IDirect3DSurface9* dest_surface);
|
|
|
| private:
|
| @@ -386,9 +392,17 @@ struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer {
|
| bool available_;
|
| media::PictureBuffer picture_buffer_;
|
| EGLSurface decoding_surface_;
|
| +
|
| + HANDLE texture_share_handle_;
|
| base::win::ScopedComPtr<IDirect3DTexture9> decoding_texture_;
|
| base::win::ScopedComPtr<ID3D11Texture2D> dx11_decoding_texture_;
|
|
|
| + base::win::ScopedComPtr<IDXGIKeyedMutex> egl_keyed_mutex_;
|
| + base::win::ScopedComPtr<IDXGIKeyedMutex> dx11_keyed_mutex_;
|
| +
|
| + // This is the last value that was used to release the keyed mutex.
|
| + uint64_t keyed_mutex_value_;
|
| +
|
| // The following |IDirect3DSurface9| interface pointers are used to hold
|
| // references on the surfaces during the course of a StretchRect operation
|
| // to copy the source surface to the target. The references are released
|
| @@ -422,6 +436,9 @@ DXVAVideoDecodeAccelerator::DXVAPictureBuffer::Create(
|
| eglGetConfigAttrib(egl_display, egl_config, EGL_BIND_TO_TEXTURE_RGB,
|
| &use_rgb);
|
|
|
| + if (!picture_buffer->InitializeTexture(decoder, !!use_rgb))
|
| + return linked_ptr<DXVAPictureBuffer>(nullptr);
|
| +
|
| EGLint attrib_list[] = {
|
| EGL_WIDTH, buffer.size().width(),
|
| EGL_HEIGHT, buffer.size().height(),
|
| @@ -430,50 +447,73 @@ DXVAVideoDecodeAccelerator::DXVAPictureBuffer::Create(
|
| EGL_NONE
|
| };
|
|
|
| - picture_buffer->decoding_surface_ = eglCreatePbufferSurface(
|
| - egl_display,
|
| - egl_config,
|
| - attrib_list);
|
| + picture_buffer->decoding_surface_ = eglCreatePbufferFromClientBuffer(
|
| + egl_display, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
|
| + picture_buffer->texture_share_handle_, egl_config, attrib_list);
|
| RETURN_ON_FAILURE(picture_buffer->decoding_surface_,
|
| "Failed to create surface",
|
| linked_ptr<DXVAPictureBuffer>(NULL));
|
| + if (decoder.d3d11_device_ && decoder.use_keyed_mutex_) {
|
| + void* keyed_mutex = nullptr;
|
| + EGLBoolean ret = eglQuerySurfacePointerANGLE(
|
| + egl_display, picture_buffer->decoding_surface_,
|
| + EGL_DXGI_KEYED_MUTEX_ANGLE, &keyed_mutex);
|
| + RETURN_ON_FAILURE(keyed_mutex && ret == EGL_TRUE,
|
| + "Failed to query ANGLE keyed mutex",
|
| + linked_ptr<DXVAPictureBuffer>(nullptr));
|
| + picture_buffer->egl_keyed_mutex_ = base::win::ScopedComPtr<IDXGIKeyedMutex>(
|
| + static_cast<IDXGIKeyedMutex*>(keyed_mutex));
|
| + }
|
| + picture_buffer->use_rgb_ = !!use_rgb;
|
| + return picture_buffer;
|
| +}
|
|
|
| - HANDLE share_handle = NULL;
|
| - EGLBoolean ret = eglQuerySurfacePointerANGLE(
|
| - egl_display,
|
| - picture_buffer->decoding_surface_,
|
| - EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
|
| - &share_handle);
|
| +bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::InitializeTexture(
|
| + const DXVAVideoDecodeAccelerator& decoder,
|
| + bool use_rgb) {
|
| + DCHECK(!texture_share_handle_);
|
| + if (decoder.d3d11_device_) {
|
| + D3D11_TEXTURE2D_DESC desc;
|
| + desc.Width = picture_buffer_.size().width();
|
| + desc.Height = picture_buffer_.size().height();
|
| + desc.MipLevels = 1;
|
| + desc.ArraySize = 1;
|
| + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
| + desc.SampleDesc.Count = 1;
|
| + desc.SampleDesc.Quality = 0;
|
| + desc.Usage = D3D11_USAGE_DEFAULT;
|
| + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
|
| + desc.CPUAccessFlags = 0;
|
| + desc.MiscFlags = decoder.use_keyed_mutex_
|
| + ? D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX
|
| + : D3D11_RESOURCE_MISC_SHARED;
|
| +
|
| + HRESULT hr = decoder.d3d11_device_->CreateTexture2D(
|
| + &desc, nullptr, dx11_decoding_texture_.Receive());
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to create texture", false);
|
| + if (decoder.use_keyed_mutex_) {
|
| + hr = dx11_keyed_mutex_.QueryFrom(dx11_decoding_texture_.get());
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to get keyed mutex", false);
|
| + }
|
|
|
| - RETURN_ON_FAILURE(share_handle && ret == EGL_TRUE,
|
| - "Failed to query ANGLE surface pointer",
|
| - linked_ptr<DXVAPictureBuffer>(NULL));
|
| + base::win::ScopedComPtr<IDXGIResource> resource;
|
| + hr = resource.QueryFrom(dx11_decoding_texture_.get());
|
| + DCHECK(SUCCEEDED(hr));
|
| + hr = resource->GetSharedHandle(&texture_share_handle_);
|
| + RETURN_ON_FAILURE(SUCCEEDED(hr) && texture_share_handle_,
|
| + "Failed to query shared handle", false);
|
|
|
| - HRESULT hr = E_FAIL;
|
| - if (decoder.d3d11_device_) {
|
| - base::win::ScopedComPtr<ID3D11Resource> resource;
|
| - hr = decoder.d3d11_device_->OpenSharedResource(
|
| - share_handle,
|
| - __uuidof(ID3D11Resource),
|
| - reinterpret_cast<void**>(resource.Receive()));
|
| - RETURN_ON_HR_FAILURE(hr, "Failed to open shared resource",
|
| - linked_ptr<DXVAPictureBuffer>(NULL));
|
| - hr = picture_buffer->dx11_decoding_texture_.QueryFrom(resource.get());
|
| } else {
|
| + HRESULT hr = E_FAIL;
|
| hr = decoder.d3d9_device_ex_->CreateTexture(
|
| - buffer.size().width(),
|
| - buffer.size().height(),
|
| - 1,
|
| - D3DUSAGE_RENDERTARGET,
|
| - use_rgb ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8,
|
| - D3DPOOL_DEFAULT,
|
| - picture_buffer->decoding_texture_.Receive(),
|
| - &share_handle);
|
| - }
|
| - RETURN_ON_HR_FAILURE(hr, "Failed to create texture",
|
| - linked_ptr<DXVAPictureBuffer>(NULL));
|
| - picture_buffer->use_rgb_ = !!use_rgb;
|
| - return picture_buffer;
|
| + picture_buffer_.size().width(), picture_buffer_.size().height(), 1,
|
| + D3DUSAGE_RENDERTARGET, use_rgb ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8,
|
| + D3DPOOL_DEFAULT, decoding_texture_.Receive(), &texture_share_handle_);
|
| + RETURN_ON_HR_FAILURE(hr, "Failed to create texture", false);
|
| + RETURN_ON_FAILURE(texture_share_handle_, "Failed to query shared handle",
|
| + false);
|
| + }
|
| + return true;
|
| }
|
|
|
| DXVAVideoDecodeAccelerator::DXVAPictureBuffer::DXVAPictureBuffer(
|
| @@ -481,8 +521,9 @@ DXVAVideoDecodeAccelerator::DXVAPictureBuffer::DXVAPictureBuffer(
|
| : available_(true),
|
| picture_buffer_(buffer),
|
| decoding_surface_(NULL),
|
| - use_rgb_(true) {
|
| -}
|
| + texture_share_handle_(nullptr),
|
| + keyed_mutex_value_(0),
|
| + use_rgb_(true) {}
|
|
|
| DXVAVideoDecodeAccelerator::DXVAPictureBuffer::~DXVAPictureBuffer() {
|
| if (decoding_surface_) {
|
| @@ -500,7 +541,7 @@ DXVAVideoDecodeAccelerator::DXVAPictureBuffer::~DXVAPictureBuffer() {
|
| }
|
| }
|
|
|
| -void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() {
|
| +bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() {
|
| DCHECK(decoding_surface_);
|
| EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
|
| eglReleaseTexImage(
|
| @@ -511,6 +552,11 @@ void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() {
|
| target_surface_.Release();
|
| decoder_dx11_texture_.Release();
|
| set_available(true);
|
| + if (egl_keyed_mutex_) {
|
| + HRESULT hr = egl_keyed_mutex_->ReleaseSync(++keyed_mutex_value_);
|
| + RETURN_ON_FAILURE(hr == S_OK, "Could not release sync mutex", false);
|
| + }
|
| + return true;
|
| }
|
|
|
| bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::
|
| @@ -525,8 +571,9 @@ bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::
|
| // when we receive a notification that the copy was completed or when the
|
| // DXVAPictureBuffer instance is destroyed.
|
| decoder_dx11_texture_ = dx11_texture;
|
| - decoder->CopyTexture(dx11_texture, dx11_decoding_texture_.get(), NULL,
|
| - id(), input_buffer_id);
|
| + decoder->CopyTexture(dx11_texture, dx11_decoding_texture_.get(),
|
| + dx11_keyed_mutex_, keyed_mutex_value_, NULL, id(),
|
| + input_buffer_id);
|
| return true;
|
| }
|
| D3DSURFACE_DESC surface_desc;
|
| @@ -566,7 +613,7 @@ bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::
|
| return true;
|
| }
|
|
|
| -void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::CopySurfaceComplete(
|
| +bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::CopySurfaceComplete(
|
| IDirect3DSurface9* src_surface,
|
| IDirect3DSurface9* dest_surface) {
|
| DCHECK(!available());
|
| @@ -587,6 +634,12 @@ void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::CopySurfaceComplete(
|
| DCHECK(decoder_dx11_texture_.get());
|
| decoder_dx11_texture_.Release();
|
| }
|
| + if (egl_keyed_mutex_) {
|
| + keyed_mutex_value_++;
|
| + HRESULT result =
|
| + egl_keyed_mutex_->AcquireSync(keyed_mutex_value_, kAcquireSyncWaitMs);
|
| + RETURN_ON_FAILURE(result == S_OK, "Could not acquire sync mutex", false);
|
| + }
|
|
|
| EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
|
| eglBindTexImage(
|
| @@ -596,6 +649,7 @@ void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::CopySurfaceComplete(
|
|
|
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
| glBindTexture(GL_TEXTURE_2D, current_texture);
|
| + return true;
|
| }
|
|
|
| DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo(
|
| @@ -623,6 +677,7 @@ DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator(
|
| decoder_thread_("DXVAVideoDecoderThread"),
|
| pending_flush_(false),
|
| use_dx11_(false),
|
| + use_keyed_mutex_(false),
|
| dx11_video_format_converter_media_type_needs_init_(true),
|
| gl_context_(gl_context),
|
| using_angle_device_(false),
|
| @@ -966,7 +1021,10 @@ void DXVAVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_buffer_id) {
|
| return;
|
| }
|
|
|
| - it->second->ReusePictureBuffer();
|
| + RETURN_AND_NOTIFY_ON_FAILURE(it->second->ReusePictureBuffer(),
|
| + "Failed to reuse picture buffer",
|
| + PLATFORM_FAILURE, );
|
| +
|
| ProcessPendingSamples();
|
| if (pending_flush_) {
|
| decoder_thread_task_runner_->PostTask(
|
| @@ -1243,6 +1301,10 @@ bool DXVAVideoDecodeAccelerator::CheckDecoderDxvaSupport() {
|
| attributes->GetUINT32(MF_SA_D3D11_AWARE, &dx11_aware);
|
| use_dx11_ = !!dx11_aware;
|
| }
|
| +
|
| + use_keyed_mutex_ =
|
| + use_dx11_ && gfx::GLSurfaceEGL::HasEGLExtension("EGL_ANGLE_keyed_mutex");
|
| +
|
| return true;
|
| }
|
|
|
| @@ -1940,8 +2002,9 @@ void DXVAVideoDecodeAccelerator::CopySurfaceComplete(
|
|
|
| DCHECK(!output_picture_buffers_.empty());
|
|
|
| - picture_buffer->CopySurfaceComplete(src_surface,
|
| - dest_surface);
|
| + bool result = picture_buffer->CopySurfaceComplete(src_surface, dest_surface);
|
| + RETURN_AND_NOTIFY_ON_FAILURE(result, "Failed to complete copying surface",
|
| + PLATFORM_FAILURE, );
|
|
|
| NotifyPictureReady(picture_buffer->id(), input_buffer_id);
|
|
|
| @@ -1964,11 +2027,14 @@ void DXVAVideoDecodeAccelerator::CopySurfaceComplete(
|
| base::Unretained(this)));
|
| }
|
|
|
| -void DXVAVideoDecodeAccelerator::CopyTexture(ID3D11Texture2D* src_texture,
|
| - ID3D11Texture2D* dest_texture,
|
| - IMFSample* video_frame,
|
| - int picture_buffer_id,
|
| - int input_buffer_id) {
|
| +void DXVAVideoDecodeAccelerator::CopyTexture(
|
| + ID3D11Texture2D* src_texture,
|
| + ID3D11Texture2D* dest_texture,
|
| + base::win::ScopedComPtr<IDXGIKeyedMutex> dest_keyed_mutex,
|
| + uint64_t keyed_mutex_value,
|
| + IMFSample* video_frame,
|
| + int picture_buffer_id,
|
| + int input_buffer_id) {
|
| HRESULT hr = E_FAIL;
|
|
|
| DCHECK(use_dx11_);
|
| @@ -2005,14 +2071,11 @@ void DXVAVideoDecodeAccelerator::CopyTexture(ID3D11Texture2D* src_texture,
|
| }
|
|
|
| decoder_thread_task_runner_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&DXVAVideoDecodeAccelerator::CopyTexture,
|
| - base::Unretained(this),
|
| - src_texture,
|
| - dest_texture,
|
| - input_sample_for_conversion.Detach(),
|
| - picture_buffer_id,
|
| - input_buffer_id));
|
| + FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopyTexture,
|
| + base::Unretained(this), src_texture, dest_texture,
|
| + dest_keyed_mutex, keyed_mutex_value,
|
| + input_sample_for_conversion.Detach(),
|
| + picture_buffer_id, input_buffer_id));
|
| return;
|
| }
|
|
|
| @@ -2023,6 +2086,13 @@ void DXVAVideoDecodeAccelerator::CopyTexture(ID3D11Texture2D* src_texture,
|
|
|
| DCHECK(video_format_converter_mft_.get());
|
|
|
| + if (dest_keyed_mutex) {
|
| + HRESULT hr =
|
| + dest_keyed_mutex->AcquireSync(keyed_mutex_value, kAcquireSyncWaitMs);
|
| + RETURN_AND_NOTIFY_ON_FAILURE(
|
| + hr == S_OK, "D3D11 failed to acquire keyed mutex for texture.",
|
| + PLATFORM_FAILURE, );
|
| + }
|
| // The video processor MFT requires output samples to be allocated by the
|
| // caller. We create a sample with a buffer backed with the ID3D11Texture2D
|
| // interface exposed by ANGLE. This works nicely as this ensures that the
|
| @@ -2077,18 +2147,27 @@ void DXVAVideoDecodeAccelerator::CopyTexture(ID3D11Texture2D* src_texture,
|
| "Failed to convert output sample format.", PLATFORM_FAILURE,);
|
| }
|
|
|
| - d3d11_device_context_->Flush();
|
| - d3d11_device_context_->End(d3d11_query_.get());
|
| + if (dest_keyed_mutex) {
|
| + HRESULT hr = dest_keyed_mutex->ReleaseSync(keyed_mutex_value + 1);
|
| + RETURN_AND_NOTIFY_ON_FAILURE(hr == S_OK, "Failed to release keyed mutex.",
|
| + PLATFORM_FAILURE, );
|
|
|
| - decoder_thread_task_runner_->PostDelayedTask(
|
| - FROM_HERE,
|
| - base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder,
|
| - base::Unretained(this), 0,
|
| - reinterpret_cast<IDirect3DSurface9*>(NULL),
|
| - reinterpret_cast<IDirect3DSurface9*>(NULL),
|
| - picture_buffer_id, input_buffer_id),
|
| - base::TimeDelta::FromMilliseconds(
|
| - kFlushDecoderSurfaceTimeoutMs));
|
| + main_thread_task_runner_->PostTask(
|
| + FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete,
|
| + weak_this_factory_.GetWeakPtr(), nullptr, nullptr,
|
| + picture_buffer_id, input_buffer_id));
|
| + } else {
|
| + d3d11_device_context_->Flush();
|
| + d3d11_device_context_->End(d3d11_query_.get());
|
| +
|
| + decoder_thread_task_runner_->PostDelayedTask(
|
| + FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder,
|
| + base::Unretained(this), 0,
|
| + reinterpret_cast<IDirect3DSurface9*>(NULL),
|
| + reinterpret_cast<IDirect3DSurface9*>(NULL),
|
| + picture_buffer_id, input_buffer_id),
|
| + base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs));
|
| + }
|
| }
|
|
|
| void DXVAVideoDecodeAccelerator::FlushDecoder(
|
|
|