diff options
Diffstat (limited to 'chromium/media/gpu/windows/dxva_video_decode_accelerator_win.cc')
-rw-r--r-- | chromium/media/gpu/windows/dxva_video_decode_accelerator_win.cc | 206 |
1 files changed, 200 insertions, 6 deletions
diff --git a/chromium/media/gpu/windows/dxva_video_decode_accelerator_win.cc b/chromium/media/gpu/windows/dxva_video_decode_accelerator_win.cc index 753b70533c2..be7e2ec2a6a 100644 --- a/chromium/media/gpu/windows/dxva_video_decode_accelerator_win.cc +++ b/chromium/media/gpu/windows/dxva_video_decode_accelerator_win.cc @@ -21,6 +21,7 @@ #include "base/atomicops.h" #include "base/base_paths_win.h" #include "base/bind.h" +#include "base/bind_post_task.h" #include "base/callback.h" #include "base/command_line.h" #include "base/file_version_info.h" @@ -38,12 +39,19 @@ #include "base/win/scoped_co_mem.h" #include "base/win/windows_version.h" #include "build/build_config.h" +#include "components/viz/common/resources/resource_format_utils.h" +#include "gpu/command_buffer/common/shared_image_usage.h" +#include "gpu/command_buffer/service/shared_image_backing_d3d.h" +#include "gpu/command_buffer/service/shared_image_factory.h" #include "gpu/config/gpu_driver_bug_workarounds.h" #include "gpu/config/gpu_preferences.h" +#include "gpu/ipc/service/shared_image_stub.h" #include "media/base/media_log.h" #include "media/base/media_switches.h" +#include "media/base/video_frame.h" #include "media/base/win/mf_helpers.h" #include "media/filters/vp9_parser.h" +#include "media/gpu/command_buffer_helper.h" #include "media/gpu/windows/d3d11_video_device_format_support.h" #include "media/gpu/windows/dxva_picture_buffer_win.h" #include "media/gpu/windows/supported_profile_helpers.h" @@ -59,6 +67,7 @@ #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_fence.h" +#include "ui/gl/gl_image_dxgi.h" #include "ui/gl/gl_surface_egl.h" #include "ui/gl/gl_switches.h" @@ -172,6 +181,36 @@ HRESULT g_last_device_removed_reason; namespace media { +bool VideoPixelFormatToVizFormat( + VideoPixelFormat pixel_format, + size_t textures_per_picture, + std::array<viz::ResourceFormat, VideoFrame::kMaxPlanes>& texture_formats) { + switch (pixel_format) { + case PIXEL_FORMAT_ARGB: + case PIXEL_FORMAT_XRGB: + case PIXEL_FORMAT_ABGR: + case PIXEL_FORMAT_BGRA: + DCHECK_EQ(textures_per_picture, 1u); + texture_formats[0] = + (pixel_format == PIXEL_FORMAT_ABGR) ? viz::RGBA_8888 : viz::BGRA_8888; + return true; + case PIXEL_FORMAT_NV12: + DCHECK_EQ(textures_per_picture, 2u); + texture_formats[0] = viz::RED_8; // Y + texture_formats[1] = viz::RG_88; // UV + return true; + case PIXEL_FORMAT_P016LE: + // TODO(crbug.com/1011555): P010 formats are not fully supported. + // The required Viz formats (viz::R16_EXT and viz::RG16_EXT) are not yet + // supported. + DCHECK_EQ(textures_per_picture, 2u); + return false; + default: // Unsupported + NOTREACHED(); + return false; + } +} + constexpr VideoCodecProfile kSupportedProfiles[] = { H264PROFILE_BASELINE, H264PROFILE_MAIN, H264PROFILE_HIGH, VP8PROFILE_ANY, VP9PROFILE_PROFILE0, VP9PROFILE_PROFILE2, @@ -638,6 +677,9 @@ bool DXVAVideoDecodeAccelerator::Initialize(const Config& config, if (media_log_) MEDIA_LOG(INFO, media_log_) << "Starting Initialization of DXVAVDA"; + AddPlaybackSucceededLifetimeStageIfNeeded(); + AddLifetimeProgressionStage(DXVALifetimeProgression::kInitializeStarted); + if (!get_gl_context_cb_ || !make_context_current_cb_) { NOTREACHED() << "GL callbacks are required for this VDA"; return false; @@ -776,6 +818,10 @@ bool DXVAVideoDecodeAccelerator::Initialize(const Config& config, UMA_HISTOGRAM_ENUMERATION("Media.DXVAVDA.PictureBufferMechanism", GetPictureBufferMechanism()); + AddLifetimeProgressionStage( + use_dx11_ ? DXVALifetimeProgression::kDX11InitializeSucceeded + : DXVALifetimeProgression::kDX9InitializeSucceeded); + return StartDecoderThread(); } @@ -1319,6 +1365,9 @@ void DXVAVideoDecodeAccelerator::Reset() { void DXVAVideoDecodeAccelerator::Destroy() { DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); + + AddPlaybackSucceededLifetimeStageIfNeeded(); + Invalidate(); delete this; } @@ -1333,6 +1382,13 @@ GLenum DXVAVideoDecodeAccelerator::GetSurfaceInternalFormat() const { return GL_BGRA_EXT; } +bool DXVAVideoDecodeAccelerator::SupportsSharedImagePictureBuffers() const { + // Shared image is needed to display overlays which can be used directly + // by the video processor. + // TODO(crbug.com/1011555): Support for non-bind cases. + return GetPictureBufferMechanism() == PictureBufferMechanism::BIND; +} + // static VideoDecodeAccelerator::SupportedProfiles DXVAVideoDecodeAccelerator::GetSupportedProfiles( @@ -1423,8 +1479,9 @@ bool DXVAVideoDecodeAccelerator::InitDecoder(VideoCodecProfile profile) { RETURN_ON_FAILURE(version_info, "unable to get version of msmpeg2vdec.dll", false); base::string16 file_version = version_info->file_version(); - RETURN_ON_FAILURE(file_version.find(L"6.1.7140") == base::string16::npos, - "blocked version of msmpeg2vdec.dll 6.1.7140", false); + RETURN_ON_FAILURE( + file_version.find(STRING16_LITERAL("6.1.7140")) == base::string16::npos, + "blocked version of msmpeg2vdec.dll 6.1.7140", false); codec_ = kCodecH264; clsid = __uuidof(CMSH264DecoderMFT); } else if ((profile >= VP9PROFILE_PROFILE0 && @@ -1814,7 +1871,7 @@ void DXVAVideoDecodeAccelerator::DoDecode(const gfx::Rect& visible_rect, } TRACE_EVENT_ASYNC_END0("gpu", "DXVAVideoDecodeAccelerator.Decoding", this); - TRACE_COUNTER1("DXVA Decoding", "TotalPacketsBeforeDecode", + TRACE_COUNTER1("DXVA_Decoding", "TotalPacketsBeforeDecode", inputs_before_decode_); inputs_before_decode_ = 0; @@ -1967,6 +2024,20 @@ void DXVAVideoDecodeAccelerator::StopOnError( return; } + DXVALifetimeProgression result; + if (use_dx11_) { + if (decoded_any_frames_) + result = DXVALifetimeProgression::kDX11PlaybackFailedAfterFirstFrame; + else + result = DXVALifetimeProgression::kDX11PlaybackFailedBeforeFirstFrame; + } else { + if (decoded_any_frames_) + result = DXVALifetimeProgression::kDX9PlaybackFailedAfterFirstFrame; + else + result = DXVALifetimeProgression::kDX9PlaybackFailedBeforeFirstFrame; + } + AddLifetimeProgressionStage(result); + if (client_) client_->NotifyError(error); client_ = nullptr; @@ -2126,12 +2197,19 @@ void DXVAVideoDecodeAccelerator::NotifyPictureReady( int input_buffer_id, const gfx::Rect& visible_rect, const gfx::ColorSpace& color_space, - bool allow_overlay) { + bool allow_overlay, + std::vector<scoped_refptr<Picture::ScopedSharedImage>> shared_images) { DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); // This task could execute after the decoder has been torn down. if (GetState() != kUninitialized && client_) { Picture picture(picture_buffer_id, input_buffer_id, visible_rect, color_space, allow_overlay); + + for (uint32_t i = 0; i < shared_images.size(); i++) { + picture.set_scoped_shared_image(shared_images[i], i); + } + + decoded_any_frames_ = true; client_->PictureReady(picture); } } @@ -2604,13 +2682,100 @@ void DXVAVideoDecodeAccelerator::BindPictureBufferToSample( DCHECK(!output_picture_buffers_.empty()); + // BindSampleToTexture configures GLImage with the DX11 output texture. + // The DX11 texture is then accessed through the GLImage to create a shared + // image backing below. bool result = picture_buffer->BindSampleToTexture(this, sample); - RETURN_AND_NOTIFY_ON_FAILURE(result, "Failed to complete copying surface", + RETURN_AND_NOTIFY_ON_FAILURE(result, "Failed to bind sample to texture", PLATFORM_FAILURE, ); + // Create the DX11 texture backed shared images (texture per plane). + std::vector<scoped_refptr<Picture::ScopedSharedImage>> scoped_shared_images; + if (SupportsSharedImagePictureBuffers()) { + gl::GLImageDXGI* gl_image_dxgi = + gl::GLImageDXGI::FromGLImage(picture_buffer->gl_image().get()); + DCHECK(gl_image_dxgi); + + const size_t textures_per_picture = + picture_buffer->service_texture_ids().size(); + + // Get the viz resource format per texture. + std::array<viz::ResourceFormat, VideoFrame::kMaxPlanes> viz_formats; + { + const bool result = VideoPixelFormatToVizFormat( + picture_buffer->pixel_format(), textures_per_picture, viz_formats); + RETURN_AND_NOTIFY_ON_FAILURE( + result, "Could not convert pixel format to viz format", + PLATFORM_FAILURE, ); + } + + CommandBufferHelper* helper = client_->GetCommandBufferHelper(); + DCHECK(helper); + + for (uint32_t texture_idx = 0; texture_idx < textures_per_picture; + texture_idx++) { + // Usage flags to allow the display compositor to draw from it, video + // to decode, and allow webgl/canvas access. + constexpr uint32_t shared_image_usage = + gpu::SHARED_IMAGE_USAGE_VIDEO_DECODE | gpu::SHARED_IMAGE_USAGE_GLES2 | + gpu::SHARED_IMAGE_USAGE_RASTER | gpu::SHARED_IMAGE_USAGE_DISPLAY | + gpu::SHARED_IMAGE_USAGE_SCANOUT; + + // Create a shared image + // TODO(crbug.com/1011555): Need key shared mutex if shared image is ever + // used by another device. + scoped_refptr<gpu::gles2::TexturePassthrough> gl_texture = + gpu::gles2::TexturePassthrough::CheckedCast(helper->GetTexture( + picture_buffer->service_texture_ids()[texture_idx])); + + // Create a new shared image mailbox. The existing mailbox belonging to + // this |picture_buffer| will be updated when the video frame is created. + const auto& mailbox = gpu::Mailbox::GenerateForSharedImage(); + + auto shared_image = std::make_unique<gpu::SharedImageBackingD3D>( + mailbox, viz_formats[texture_idx], + picture_buffer->texture_size(texture_idx), + picture_buffer->color_space(), kTopLeft_GrSurfaceOrigin, + kPremul_SkAlphaType, shared_image_usage, + /*swap_chain=*/nullptr, std::move(gl_texture), + picture_buffer->gl_image(), + /*buffer_index=*/0, gl_image_dxgi->texture(), + base::win::ScopedHandle(), + /*dxgi_keyed_mutex=*/nullptr); + + // Caller is assumed to provide cleared d3d textures. + shared_image->SetCleared(); + + gpu::SharedImageStub* shared_image_stub = client_->GetSharedImageStub(); + DCHECK(shared_image_stub); + const bool success = shared_image_stub->factory()->RegisterBacking( + std::move(shared_image), /* legacy_mailbox */ true); + if (!success) { + RETURN_AND_NOTIFY_ON_FAILURE(false, "Failed to register shared image", + PLATFORM_FAILURE, ); + } + + auto destroy_shared_image_callback = base::BindPostTask( + main_thread_task_runner_, + base::BindOnce( + shared_image_stub->GetSharedImageDestructionCallback(mailbox), + gpu::SyncToken())); + + // Wrap the factory ref with a scoped shared image. The factory ref + // is used instead of requiring a destruction call-back. + auto scoped_shared_image = + base::MakeRefCounted<Picture::ScopedSharedImage>( + mailbox, GetTextureTarget(), + std::move(destroy_shared_image_callback)); + + scoped_shared_images.push_back(std::move(scoped_shared_image)); + } + } + NotifyPictureReady( picture_buffer->id(), input_buffer_id, picture_buffer->visible_rect(), - picture_buffer->color_space(), picture_buffer->AllowOverlay()); + picture_buffer->color_space(), picture_buffer->AllowOverlay(), + std::move(scoped_shared_images)); { base::AutoLock lock(decoder_lock_); @@ -3127,8 +3292,37 @@ bool DXVAVideoDecodeAccelerator::ShouldUseANGLEDevice() const { NOTREACHED(); return false; } + ID3D11Device* DXVAVideoDecodeAccelerator::D3D11Device() const { return ShouldUseANGLEDevice() ? angle_device_.Get() : d3d11_device_.Get(); } +void DXVAVideoDecodeAccelerator::AddLifetimeProgressionStage( + DXVALifetimeProgression stage) { + // If we're starting init, then forget about any previously output frames. + if (stage == DXVALifetimeProgression::kInitializeStarted) + decoded_any_frames_ = false; + + // If init has succeeded, then we can output a playback success / failure when + // we fail / re-init / are destroyed, as needed. + already_initialized_ = + (stage == DXVALifetimeProgression::kDX11InitializeSucceeded || + stage == DXVALifetimeProgression::kDX9InitializeSucceeded); + + base::UmaHistogramEnumeration("Media.DXVAVDA.DecoderLifetimeProgression", + stage); +} + +void DXVAVideoDecodeAccelerator::AddPlaybackSucceededLifetimeStageIfNeeded() { + // If we didn't complete initialization, then we didn't complete playback. + // This will also prevent us from sending "playback succeeded" more than once + // per init, or after a playback error. + if (!already_initialized_) + return; + + AddLifetimeProgressionStage( + use_dx11_ ? DXVALifetimeProgression::kDX11PlaybackSucceeded + : DXVALifetimeProgression::kDX9PlaybackSucceeded); +} + } // namespace media |