1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127

media / gpu / windows / d3d11_picture_buffer.cc [blame]

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/gpu/windows/d3d11_picture_buffer.h"

#include <windows.h>

#include "base/metrics/histogram_functions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "media/base/media_log.h"
#include "media/base/win/mf_helpers.h"
#include "third_party/angle/include/EGL/egl.h"
#include "third_party/angle/include/EGL/eglext.h"
#include "ui/gfx/color_space.h"

namespace media {

D3D11PictureBuffer::D3D11PictureBuffer(
    scoped_refptr<base::SequencedTaskRunner> delete_task_runner,
    ComD3D11Texture2D texture,
    size_t array_slice,
    std::unique_ptr<Texture2DWrapper> texture_wrapper,
    gfx::Size size,
    size_t picture_index)
    : RefCountedDeleteOnSequence<D3D11PictureBuffer>(
          std::move(delete_task_runner)),
      texture_(std::move(texture)),
      array_slice_(array_slice),
      texture_wrapper_(std::move(texture_wrapper)),
      size_(size),
      picture_index_(picture_index) {}

D3D11PictureBuffer::~D3D11PictureBuffer() = default;

D3D11Status D3D11PictureBuffer::Init(
    scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
    GetCommandBufferHelperCB get_helper_cb,
    ComD3D11VideoDevice video_device,
    const GUID& decoder_guid,
    std::unique_ptr<MediaLog> media_log,
    PictureBufferGPUResourceInitDoneCB
        picture_buffer_gpu_resource_init_done_cb) {
  D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC view_desc = {};
  view_desc.DecodeProfile = decoder_guid;
  view_desc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
  view_desc.Texture2D.ArraySlice = array_slice_;

  media_log_ = std::move(media_log);
  D3D11Status result = texture_wrapper_->Init(
      std::move(gpu_task_runner), std::move(get_helper_cb), texture_,
      array_slice_, this, std::move(picture_buffer_gpu_resource_init_done_cb));
  if (!result.is_ok()) {
    MEDIA_LOG(ERROR, media_log_) << "Failed to Initialize the wrapper";
    return result;
  }

  HRESULT hr = video_device->CreateVideoDecoderOutputView(
      Texture().Get(), &view_desc, &output_view_);

  if (!SUCCEEDED(hr)) {
    MEDIA_LOG(ERROR, media_log_) << "Failed to CreateVideoDecoderOutputView";
    return {D3D11Status::Codes::kCreateDecoderOutputViewFailed, hr};
  }

  return D3D11Status::Codes::kOk;
}

D3D11Status D3D11PictureBuffer::ProcessTexture(
    const gfx::ColorSpace& input_color_space,
    scoped_refptr<gpu::ClientSharedImage>& shared_image_dest) {
  return texture_wrapper_->ProcessTexture(input_color_space, shared_image_dest);
}

ComD3D11Texture2D D3D11PictureBuffer::Texture() const {
  return texture_;
}

D3D11Status::Or<ID3D11VideoDecoderOutputView*>
D3D11PictureBuffer::AcquireOutputView() const {
  D3D11Status result = texture_wrapper_->BeginSharedImageAccess();
  if (!result.is_ok()) {
    MEDIA_LOG(ERROR, media_log_)
        << "Failed to acquired key mutex for native texture resource";
    base::UmaHistogramSparse("Media.D3D11.PictureBuffer",
                             static_cast<int>(result.code()));
    return result;
  }

  return output_view_.Get();
}

D3D11Status::Or<ComD3D12Resource> D3D11PictureBuffer::ToD3D12Resource(
    ID3D12Device* device) {
  HRESULT hr;
  if (!d3d12_resource_) {
    ComDXGIResource1 dxgi_resource;
    CHECK_EQ(texture_.As(&dxgi_resource), S_OK);

    HANDLE handle;
    hr = dxgi_resource->CreateSharedHandle(nullptr, GENERIC_ALL, nullptr,
                                           &handle);
    if (FAILED(hr)) {
      MEDIA_LOG(ERROR, media_log_) << "Cannot create shared handle";
      return {D3D11StatusCode::kCreateSharedHandleFailed, hr};
    }
    base::win::ScopedHandle handle_holder(handle);
    hr = device->OpenSharedHandle(handle_holder.get(),
                                  IID_PPV_ARGS(&d3d12_resource_));
    if (FAILED(hr)) {
      LOG(ERROR) << "Open shared handle as D3D12 resource failed.";
      return {D3D11StatusCode::kCreateSharedHandleFailed, hr};
    }
  }
  ComD3D12Device used_device;
  hr = d3d12_resource_->GetDevice(IID_PPV_ARGS(&used_device));
  if (FAILED(hr)) {
    LOG(ERROR) << "ID3D12Resource::GetDevice failed.";
    return {D3D11StatusCode::kGetDeviceFailed, hr};
  }
  CHECK_EQ(used_device.Get(), device);
  return d3d12_resource_;
}

}  // namespace media