VideoProcessorD3D11.cpp (8278B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "VideoProcessorD3D11.h" 8 9 #include <d3d11.h> 10 #include <d3d11_1.h> 11 12 #include "mozilla/gfx/Logging.h" 13 #include "mozilla/gfx/Types.h" 14 #include "mozilla/layers/TextureD3D11.h" 15 #include "mozilla/Maybe.h" 16 17 namespace mozilla { 18 namespace layers { 19 20 // TODO: Replace with YUVRangedColorSpace 21 static Maybe<DXGI_COLOR_SPACE_TYPE> GetSourceDXGIColorSpace( 22 const gfx::YUVColorSpace aYUVColorSpace, const gfx::ColorRange aColorRange, 23 const bool aContentIsHDR) { 24 if (aYUVColorSpace == gfx::YUVColorSpace::BT601) { 25 if (aColorRange == gfx::ColorRange::FULL) { 26 return Some(DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601); 27 } else { 28 return Some(DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601); 29 } 30 } else if (aYUVColorSpace == gfx::YUVColorSpace::BT709) { 31 if (aColorRange == gfx::ColorRange::FULL) { 32 return Some(DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709); 33 } else { 34 return Some(DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709); 35 } 36 } else if (aYUVColorSpace == gfx::YUVColorSpace::BT2020) { 37 if (aColorRange == gfx::ColorRange::FULL) { 38 if (aContentIsHDR) { 39 // DXGI doesn't have a full range PQ YCbCr format, hopefully we won't 40 // have to deal with this case. 41 gfxCriticalNoteOnce 42 << "GetSourceDXGIColorSpace: DXGI has no full range " 43 "BT2020 PQ YCbCr format, using studio range instead"; 44 return Some(DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020); 45 } else { 46 return Some(DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020); 47 } 48 } else { 49 if (aContentIsHDR) { 50 return Some(DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020); 51 } else { 52 return Some(DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020); 53 } 54 } 55 } 56 57 return Nothing(); 58 } 59 60 static Maybe<DXGI_COLOR_SPACE_TYPE> GetSourceDXGIColorSpace( 61 const gfx::YUVRangedColorSpace aYUVColorSpace, const bool aContentIsHDR) { 62 const auto info = FromYUVRangedColorSpace(aYUVColorSpace); 63 return GetSourceDXGIColorSpace(info.space, info.range, aContentIsHDR); 64 } 65 66 /* static */ 67 RefPtr<VideoProcessorD3D11> VideoProcessorD3D11::Create(ID3D11Device* aDevice) { 68 MOZ_ASSERT(aDevice); 69 70 if (!aDevice) { 71 return nullptr; 72 } 73 74 RefPtr<ID3D11DeviceContext> context; 75 aDevice->GetImmediateContext(getter_AddRefs(context)); 76 if (!context) { 77 return nullptr; 78 } 79 80 HRESULT hr; 81 RefPtr<ID3D11VideoDevice> videoDevice; 82 hr = 83 aDevice->QueryInterface((ID3D11VideoDevice**)getter_AddRefs(videoDevice)); 84 if (FAILED(hr)) { 85 gfxCriticalNoteOnce << "Failed to get D3D11VideoDevice: " << gfx::hexa(hr); 86 return nullptr; 87 } 88 89 RefPtr<ID3D11VideoContext> videoContext; 90 hr = context->QueryInterface( 91 (ID3D11VideoContext**)getter_AddRefs(videoContext)); 92 if (FAILED(hr)) { 93 gfxCriticalNoteOnce << "Failed to get D3D11VideoContext: " << gfx::hexa(hr); 94 return nullptr; 95 } 96 97 RefPtr<ID3D11VideoContext1> videoContext1; 98 hr = videoContext->QueryInterface( 99 (ID3D11VideoContext1**)getter_AddRefs(videoContext1)); 100 if (FAILED(hr)) { 101 gfxCriticalNoteOnce << "Failed to get D3D11VideoContext1: " 102 << gfx::hexa(hr); 103 return nullptr; 104 } 105 106 RefPtr<VideoProcessorD3D11> videoProcessor = new VideoProcessorD3D11( 107 aDevice, context, videoDevice, videoContext, videoContext1); 108 109 return videoProcessor; 110 } 111 112 VideoProcessorD3D11::VideoProcessorD3D11(ID3D11Device* aDevice, 113 ID3D11DeviceContext* aDeviceContext, 114 ID3D11VideoDevice* aVideoDevice, 115 ID3D11VideoContext* aVideoContext, 116 ID3D11VideoContext1* aVideoContext1) 117 : mDevice(aDevice), 118 mDeviceContext(aDeviceContext), 119 mVideoDevice(aVideoDevice), 120 mVideoContext(aVideoContext), 121 mVideoContext1(aVideoContext1) {} 122 123 VideoProcessorD3D11::~VideoProcessorD3D11() {} 124 125 HRESULT VideoProcessorD3D11::Init(const gfx::IntSize& aSize) { 126 if (mSize == aSize) { 127 return S_OK; 128 } 129 130 mVideoProcessorEnumerator = nullptr; 131 mVideoProcessor = nullptr; 132 mSize = gfx::IntSize(); 133 134 D3D11_VIDEO_PROCESSOR_CONTENT_DESC desc; 135 desc.InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE; 136 desc.InputFrameRate.Numerator = 60; 137 desc.InputFrameRate.Denominator = 1; 138 desc.InputWidth = aSize.width; 139 desc.InputHeight = aSize.height; 140 desc.OutputFrameRate.Numerator = 60; 141 desc.OutputFrameRate.Denominator = 1; 142 desc.OutputWidth = aSize.width; 143 desc.OutputHeight = aSize.height; 144 desc.Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL; 145 146 HRESULT hr = mVideoDevice->CreateVideoProcessorEnumerator( 147 &desc, getter_AddRefs(mVideoProcessorEnumerator)); 148 if (FAILED(hr)) { 149 gfxCriticalNoteOnce << "Failed to create VideoProcessorEnumerator: " 150 << gfx::hexa(hr); 151 return hr; 152 } 153 154 hr = mVideoDevice->CreateVideoProcessor(mVideoProcessorEnumerator, 0, 155 getter_AddRefs(mVideoProcessor)); 156 if (FAILED(hr)) { 157 gfxCriticalNoteOnce << "Failed to create VideoProcessor: " << gfx::hexa(hr); 158 return hr; 159 } 160 161 // Turn off auto stream processing (the default) that will hurt power 162 // consumption. 163 mVideoContext->VideoProcessorSetStreamAutoProcessingMode(mVideoProcessor, 0, 164 FALSE); 165 166 mSize = aSize; 167 168 return S_OK; 169 } 170 171 bool VideoProcessorD3D11::CallVideoProcessorBlt( 172 InputTextureInfo& aTextureInfo, ID3D11Texture2D* aOutputTexture) { 173 MOZ_ASSERT(mVideoProcessorEnumerator); 174 MOZ_ASSERT(mVideoProcessor); 175 MOZ_ASSERT(aTextureInfo.mTexture); 176 MOZ_ASSERT(aOutputTexture); 177 178 HRESULT hr; 179 180 auto yuvRangedColorSpace = gfx::ToYUVRangedColorSpace( 181 gfx::ToYUVColorSpace(aTextureInfo.mColorSpace), aTextureInfo.mColorRange); 182 auto sourceColorSpace = 183 GetSourceDXGIColorSpace(yuvRangedColorSpace, mContentIsHDR); 184 if (sourceColorSpace.isNothing()) { 185 gfxCriticalNoteOnce << "Unsupported color space"; 186 return false; 187 } 188 189 DXGI_COLOR_SPACE_TYPE inputColorSpace = sourceColorSpace.ref(); 190 mVideoContext1->VideoProcessorSetStreamColorSpace1(mVideoProcessor, 0, 191 inputColorSpace); 192 193 const DXGI_COLOR_SPACE_TYPE outputColorSpace = 194 DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; 195 196 mVideoContext1->VideoProcessorSetOutputColorSpace1(mVideoProcessor, 197 outputColorSpace); 198 199 D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inputDesc = {}; 200 inputDesc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D; 201 inputDesc.Texture2D.ArraySlice = aTextureInfo.mIndex; 202 203 RefPtr<ID3D11VideoProcessorInputView> inputView; 204 hr = mVideoDevice->CreateVideoProcessorInputView( 205 aTextureInfo.mTexture, mVideoProcessorEnumerator, &inputDesc, 206 getter_AddRefs(inputView)); 207 if (FAILED(hr)) { 208 gfxCriticalNoteOnce << "ID3D11VideoProcessorInputView creation failed: " 209 << gfx::hexa(hr); 210 return false; 211 } 212 213 D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outputDesc = {}; 214 outputDesc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D; 215 outputDesc.Texture2D.MipSlice = 0; 216 217 RefPtr<ID3D11VideoProcessorOutputView> outputView; 218 hr = mVideoDevice->CreateVideoProcessorOutputView( 219 aOutputTexture, mVideoProcessorEnumerator, &outputDesc, 220 getter_AddRefs(outputView)); 221 if (FAILED(hr)) { 222 gfxCriticalNoteOnce << "ID3D11VideoProcessorOutputView creation failed: " 223 << gfx::hexa(hr); 224 return false; 225 } 226 227 D3D11_VIDEO_PROCESSOR_STREAM stream = {}; 228 stream.Enable = true; 229 stream.pInputSurface = inputView.get(); 230 231 hr = mVideoContext->VideoProcessorBlt(mVideoProcessor, outputView, 0, 1, 232 &stream); 233 if (FAILED(hr)) { 234 gfxCriticalNoteOnce << "VideoProcessorBlt failed: " << gfx::hexa(hr); 235 return false; 236 } 237 238 return true; 239 } 240 241 } // namespace layers 242 } // namespace mozilla