1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef MEDIA_GPU_WINDOWS_DXVA_PICTURE_BUFFER_WIN_H_
6 #define MEDIA_GPU_WINDOWS_DXVA_PICTURE_BUFFER_WIN_H_
7 
8 #include <d3d11.h>
9 #include <d3d9.h>
10 #include <mfidl.h>
11 #include <wrl/client.h>
12 
13 #include <memory>
14 
15 #include "media/gpu/windows/d3d11_com_defs.h"
16 #include "media/video/picture.h"
17 #include "third_party/angle/include/EGL/egl.h"
18 #include "third_party/angle/include/EGL/eglext.h"
19 #include "ui/gfx/geometry/rect.h"
20 #include "ui/gl/gl_fence.h"
21 #include "ui/gl/gl_image.h"
22 
23 interface IMFSample;
24 
25 namespace media {
26 class DXVAVideoDecodeAccelerator;
27 
28 // Maintains information about a DXVA picture buffer, i.e. whether it is
29 // available for rendering, the texture information, etc.
30 class DXVAPictureBuffer {
31  public:
32   enum State { UNUSED, BOUND, COPYING, IN_CLIENT, WAITING_TO_REUSE };
33   static std::unique_ptr<DXVAPictureBuffer> Create(
34       const DXVAVideoDecodeAccelerator& decoder,
35       const PictureBuffer& buffer,
36       EGLConfig egl_config);
37   virtual ~DXVAPictureBuffer();
38 
39   virtual bool ReusePictureBuffer() = 0;
40   virtual void ResetReuseFence();
41   // Copies the output sample data to the picture buffer provided by the
42   // client.
43   // The dest_surface parameter contains the decoded bits.
44   virtual bool CopyOutputSampleDataToPictureBuffer(
45       DXVAVideoDecodeAccelerator* decoder,
46       IDirect3DSurface9* dest_surface,
47       ID3D11Texture2D* dx11_texture,
48       int input_buffer_id);
49 
available()50   bool available() const { return state_ == UNUSED; }
state()51   State state() const { return state_; }
picture_buffer()52   const PictureBuffer& picture_buffer() const { return picture_buffer_; }
53 
id()54   int id() const { return picture_buffer_.id(); }
55 
size()56   gfx::Size size() const { return picture_buffer_.size(); }
57   void set_bound();
58 
gl_image()59   scoped_refptr<gl::GLImage> gl_image() { return gl_image_; }
60 
visible_rect()61   const gfx::Rect& visible_rect() const { return visible_rect_; }
set_visible_rect(const gfx::Rect & visible_rect)62   void set_visible_rect(const gfx::Rect& visible_rect) {
63     visible_rect_ = visible_rect;
64   }
65 
color_space()66   const gfx::ColorSpace& color_space() const { return color_space_; }
set_color_space(const gfx::ColorSpace & color_space)67   void set_color_space(const gfx::ColorSpace& color_space) {
68     color_space_ = color_space;
69   }
70 
71   // Returns true if these could in theory be used as an overlay. May
72   // still be drawn using GL depending on the scene and precise hardware
73   // support.
74   virtual bool AllowOverlay() const = 0;
75 
76   // Returns true if BindSampleToTexture should be used. Otherwise
77   // CopyOutputSampleDataToPicture should be used.
78   virtual bool CanBindSamples() const = 0;
79 
waiting_to_reuse()80   bool waiting_to_reuse() const { return state_ == WAITING_TO_REUSE; }
81   virtual gl::GLFence* reuse_fence();
82 
83   // Called when the source surface |src_surface| is copied to the destination
84   // |dest_surface|
85   virtual bool CopySurfaceComplete(IDirect3DSurface9* src_surface,
86                                    IDirect3DSurface9* dest_surface);
87   virtual bool BindSampleToTexture(DXVAVideoDecodeAccelerator* decoder,
88                                    Microsoft::WRL::ComPtr<IMFSample> sample);
89 
90  protected:
91   explicit DXVAPictureBuffer(const PictureBuffer& buffer);
92 
93   State state_ = UNUSED;
94   PictureBuffer picture_buffer_;
95   gfx::Rect visible_rect_;
96   gfx::ColorSpace color_space_;
97   scoped_refptr<gl::GLImage> gl_image_;
98 
99   DISALLOW_COPY_AND_ASSIGN(DXVAPictureBuffer);
100 };
101 
102 // Copies the video result into an RGBA EGL pbuffer.
103 class PbufferPictureBuffer : public DXVAPictureBuffer {
104  public:
105   explicit PbufferPictureBuffer(const PictureBuffer& buffer);
106   ~PbufferPictureBuffer() override;
107 
108   bool Initialize(const DXVAVideoDecodeAccelerator& decoder,
109                   EGLConfig egl_config);
110   bool InitializeTexture(const DXVAVideoDecodeAccelerator& decoder,
111                          bool use_rgb,
112                          bool use_fp16);
113 
114   bool ReusePictureBuffer() override;
115   void ResetReuseFence() override;
116   bool CopyOutputSampleDataToPictureBuffer(DXVAVideoDecodeAccelerator* decoder,
117                                            IDirect3DSurface9* dest_surface,
118                                            ID3D11Texture2D* dx11_texture,
119                                            int input_buffer_id) override;
120   gl::GLFence* reuse_fence() override;
121   bool CopySurfaceComplete(IDirect3DSurface9* src_surface,
122                            IDirect3DSurface9* dest_surface) override;
123   bool AllowOverlay() const override;
124   bool CanBindSamples() const override;
125 
126  protected:
127   EGLSurface decoding_surface_;
128 
129   std::unique_ptr<gl::GLFence> reuse_fence_;
130 
131   HANDLE texture_share_handle_;
132   Microsoft::WRL::ComPtr<IDirect3DTexture9> decoding_texture_;
133   ComD3D11Texture2D dx11_decoding_texture_;
134 
135   Microsoft::WRL::ComPtr<IDXGIKeyedMutex> egl_keyed_mutex_;
136   Microsoft::WRL::ComPtr<IDXGIKeyedMutex> dx11_keyed_mutex_;
137 
138   // This is the last value that was used to release the keyed mutex.
139   uint64_t keyed_mutex_value_;
140 
141   // The following |IDirect3DSurface9| interface pointers are used to hold
142   // references on the surfaces during the course of a StretchRect operation
143   // to copy the source surface to the target. The references are released
144   // when the StretchRect operation i.e. the copy completes.
145   Microsoft::WRL::ComPtr<IDirect3DSurface9> decoder_surface_;
146   Microsoft::WRL::ComPtr<IDirect3DSurface9> target_surface_;
147 
148   // This ID3D11Texture2D interface pointer is used to hold a reference to the
149   // decoder texture during the course of a copy operation. This reference is
150   // released when the copy completes.
151   ComD3D11Texture2D decoder_dx11_texture_;
152 
153   // Set to true if RGB is supported by the texture.
154   // Defaults to true.
155   bool use_rgb_;
156 };
157 
158 // Shares the decoded texture with ANGLE without copying by using an EGL stream.
159 class EGLStreamPictureBuffer : public DXVAPictureBuffer {
160  public:
161   explicit EGLStreamPictureBuffer(const PictureBuffer& buffer);
162   ~EGLStreamPictureBuffer() override;
163 
164   bool Initialize();
165   bool ReusePictureBuffer() override;
166   bool BindSampleToTexture(DXVAVideoDecodeAccelerator* decoder,
167                            Microsoft::WRL::ComPtr<IMFSample> sample) override;
168   bool AllowOverlay() const override;
169   bool CanBindSamples() const override;
170 
171  private:
172   EGLStreamKHR stream_;
173 
174   Microsoft::WRL::ComPtr<IMFSample> current_d3d_sample_;
175   ComD3D11Texture2D dx11_decoding_texture_;
176 };
177 
178 // Shares the decoded texture with ANGLE without copying by using an EGL stream.
179 class EGLStreamDelayedCopyPictureBuffer : public DXVAPictureBuffer {
180  public:
181   explicit EGLStreamDelayedCopyPictureBuffer(const PictureBuffer& buffer);
182   ~EGLStreamDelayedCopyPictureBuffer() override;
183 
184   bool Initialize(const DXVAVideoDecodeAccelerator& decoder);
185   bool ReusePictureBuffer() override;
186   bool BindSampleToTexture(DXVAVideoDecodeAccelerator* decoder,
187                            Microsoft::WRL::ComPtr<IMFSample> sample) override;
188   bool AllowOverlay() const override;
189   bool CanBindSamples() const override;
190 
191  private:
192   EGLStreamKHR stream_;
193 
194   Microsoft::WRL::ComPtr<IMFSample> current_d3d_sample_;
195   ComD3D11Texture2D dx11_decoding_texture_;
196 };
197 
198 // Creates an NV12 texture and copies to it, then shares that with ANGLE.
199 class EGLStreamCopyPictureBuffer : public DXVAPictureBuffer {
200  public:
201   explicit EGLStreamCopyPictureBuffer(const PictureBuffer& buffer);
202   ~EGLStreamCopyPictureBuffer() override;
203 
204   bool Initialize(const DXVAVideoDecodeAccelerator& decoder);
205   bool ReusePictureBuffer() override;
206 
207   bool CopyOutputSampleDataToPictureBuffer(DXVAVideoDecodeAccelerator* decoder,
208                                            IDirect3DSurface9* dest_surface,
209                                            ID3D11Texture2D* dx11_texture,
210                                            int input_buffer_id) override;
211   bool CopySurfaceComplete(IDirect3DSurface9* src_surface,
212                            IDirect3DSurface9* dest_surface) override;
213   bool AllowOverlay() const override;
214   bool CanBindSamples() const override;
215 
216  private:
217   EGLStreamKHR stream_;
218 
219   // This ID3D11Texture2D interface pointer is used to hold a reference to the
220   // MFT decoder texture during the course of a copy operation. This reference
221   // is released when the copy completes.
222   ComD3D11Texture2D dx11_decoding_texture_;
223 
224   Microsoft::WRL::ComPtr<IDXGIKeyedMutex> egl_keyed_mutex_;
225   Microsoft::WRL::ComPtr<IDXGIKeyedMutex> dx11_keyed_mutex_;
226 
227   HANDLE texture_share_handle_;
228   // This is the texture (created on ANGLE's device) that will be put in the
229   // EGLStream.
230   ComD3D11Texture2D angle_copy_texture_;
231   // This is another copy of that shared resource that will be copied to from
232   // the decoder.
233   ComD3D11Texture2D decoder_copy_texture_;
234 
235   // This is the last value that was used to release the keyed mutex.
236   uint64_t keyed_mutex_value_ = 0;
237 };
238 
239 }  // namespace media
240 
241 #endif  // MEDIA_GPU_WINDOWS_DXVA_PICTURE_BUFFER_WIN_H_
242