D3D11ShareHandleImage.cpp (10286B)
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 "D3D11ShareHandleImage.h" 8 #include "DXVA2Manager.h" 9 #include "WMF.h" 10 #include "d3d11.h" 11 #include "gfxImageSurface.h" 12 #include "gfxWindowsPlatform.h" 13 #include "libyuv.h" 14 #include "mozilla/StaticPrefs_media.h" 15 #include "mozilla/gfx/DeviceManagerDx.h" 16 #include "mozilla/layers/CompositableClient.h" 17 #include "mozilla/layers/CompositableForwarder.h" 18 #include "mozilla/layers/CompositeProcessD3D11FencesHolderMap.h" 19 #include "mozilla/layers/FenceD3D11.h" 20 #include "mozilla/layers/TextureClient.h" 21 #include "mozilla/layers/TextureD3D11.h" 22 23 namespace mozilla { 24 namespace layers { 25 26 using namespace gfx; 27 28 D3D11ShareHandleImage::D3D11ShareHandleImage(const gfx::IntSize& aSize, 29 const gfx::IntRect& aRect, 30 gfx::ColorSpace2 aColorSpace, 31 gfx::ColorRange aColorRange, 32 gfx::ColorDepth aColorDepth) 33 : Image(nullptr, ImageFormat::D3D11_SHARE_HANDLE_TEXTURE), 34 mSize(aSize), 35 mPictureRect(aRect), 36 mColorSpace(aColorSpace), 37 mColorRange(aColorRange), 38 mColorDepth(aColorDepth) {} 39 40 bool D3D11ShareHandleImage::AllocateTexture(D3D11RecycleAllocator* aAllocator, 41 ID3D11Device* aDevice) { 42 if (aAllocator) { 43 mTextureClient = 44 aAllocator->CreateOrRecycleClient(mColorSpace, mColorRange, mSize); 45 if (mTextureClient) { 46 D3D11TextureData* textureData = GetData(); 47 MOZ_DIAGNOSTIC_ASSERT(textureData, "Wrong TextureDataType"); 48 mTexture = textureData->GetD3D11Texture(); 49 return true; 50 } 51 return false; 52 } else { 53 MOZ_ASSERT(aDevice); 54 auto format = mColorDepth > gfx::ColorDepth::COLOR_8 55 ? DXGI_FORMAT_R16G16B16A16_FLOAT 56 : DXGI_FORMAT_B8G8R8A8_UNORM; 57 CD3D11_TEXTURE2D_DESC newDesc( 58 format, mSize.width, mSize.height, 1, 1, 59 D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE); 60 newDesc.MiscFlags = 61 D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED; 62 63 HRESULT hr = 64 aDevice->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(mTexture)); 65 return SUCCEEDED(hr); 66 } 67 } 68 69 gfx::IntSize D3D11ShareHandleImage::GetSize() const { return mSize; } 70 71 TextureClient* D3D11ShareHandleImage::GetTextureClient( 72 KnowsCompositor* aKnowsCompositor) { 73 return mTextureClient; 74 } 75 76 already_AddRefed<gfx::SourceSurface> 77 D3D11ShareHandleImage::GetAsSourceSurface() { 78 RefPtr<ID3D11Texture2D> src = GetTexture(); 79 if (!src) { 80 gfxWarning() << "Cannot readback from shared texture because no texture is " 81 "available."; 82 return nullptr; 83 } 84 85 return gfx::Factory::CreateBGRA8DataSourceSurfaceForD3D11Texture( 86 src, 0, mColorSpace, mColorRange); 87 } 88 89 nsresult D3D11ShareHandleImage::BuildSurfaceDescriptorBuffer( 90 SurfaceDescriptorBuffer& aSdBuffer, BuildSdbFlags aFlags, 91 const std::function<MemoryOrShmem(uint32_t)>& aAllocate) { 92 RefPtr<ID3D11Texture2D> src = GetTexture(); 93 if (!src) { 94 gfxWarning() << "Cannot readback from shared texture because no texture is " 95 "available."; 96 return NS_ERROR_FAILURE; 97 } 98 99 nsresult rv = 100 gfx::Factory::CreateSdbForD3D11Texture(src, mSize, aSdBuffer, aAllocate); 101 if (rv != NS_ERROR_NOT_IMPLEMENTED) { 102 // TODO(aosmond): We only support BGRA on this path, but depending on 103 // aFlags, we may be able to return a YCbCr format without conversion. 104 return rv; 105 } 106 107 return Image::BuildSurfaceDescriptorBuffer(aSdBuffer, aFlags, aAllocate); 108 } 109 110 ID3D11Texture2D* D3D11ShareHandleImage::GetTexture() const { return mTexture; } 111 112 class MOZ_RAII D3D11TextureClientAllocationHelper 113 : public ITextureClientAllocationHelper { 114 public: 115 D3D11TextureClientAllocationHelper(gfx::SurfaceFormat aFormat, 116 gfx::ColorSpace2 aColorSpace, 117 gfx::ColorRange aColorRange, 118 const gfx::IntSize& aSize, 119 TextureAllocationFlags aAllocFlags, 120 ID3D11Device* aDevice, 121 TextureFlags aTextureFlags) 122 : ITextureClientAllocationHelper(aFormat, aSize, BackendSelector::Content, 123 aTextureFlags, aAllocFlags), 124 mColorSpace(aColorSpace), 125 mColorRange(aColorRange), 126 mDevice(aDevice) {} 127 128 bool IsCompatible(TextureClient* aTextureClient) override { 129 D3D11TextureData* textureData = 130 aTextureClient->GetInternalData()->AsD3D11TextureData(); 131 if (!textureData || aTextureClient->GetFormat() != mFormat || 132 aTextureClient->GetSize() != mSize) { 133 return false; 134 } 135 // TODO: Should we also check for change in the allocation flags if RGBA? 136 return (aTextureClient->GetFormat() != gfx::SurfaceFormat::NV12 && 137 aTextureClient->GetFormat() != gfx::SurfaceFormat::P010 && 138 aTextureClient->GetFormat() != gfx::SurfaceFormat::P016) || 139 (textureData->mColorSpace == mColorSpace && 140 textureData->GetColorRange() == mColorRange && 141 textureData->GetTextureAllocationFlags() == mAllocationFlags); 142 } 143 144 already_AddRefed<TextureClient> Allocate( 145 KnowsCompositor* aAllocator) override { 146 D3D11TextureData* data = 147 D3D11TextureData::Create(mSize, mFormat, mAllocationFlags, mDevice); 148 if (!data) { 149 return nullptr; 150 } 151 data->mColorSpace = mColorSpace; 152 data->SetColorRange(mColorRange); 153 return MakeAndAddRef<TextureClient>(data, mTextureFlags, 154 aAllocator->GetTextureForwarder()); 155 } 156 157 private: 158 const gfx::ColorSpace2 mColorSpace; 159 const gfx::ColorRange mColorRange; 160 const RefPtr<ID3D11Device> mDevice; 161 }; 162 163 D3D11RecycleAllocator::D3D11RecycleAllocator( 164 KnowsCompositor* aAllocator, ID3D11Device* aDevice, 165 gfx::SurfaceFormat aPreferredFormat) 166 : TextureClientRecycleAllocator(aAllocator), 167 mDevice(aDevice), 168 mCanUseNV12(StaticPrefs::media_wmf_use_nv12_format() && 169 gfx::DeviceManagerDx::Get()->CanUseNV12()), 170 mCanUseP010(StaticPrefs::media_wmf_use_nv12_format() && 171 gfx::DeviceManagerDx::Get()->CanUseP010()), 172 mCanUseP016(StaticPrefs::media_wmf_use_nv12_format() && 173 gfx::DeviceManagerDx::Get()->CanUseP016()) { 174 SetPreferredSurfaceFormat(aPreferredFormat); 175 } 176 177 void D3D11RecycleAllocator::SetPreferredSurfaceFormat( 178 gfx::SurfaceFormat aPreferredFormat) { 179 if ((aPreferredFormat == gfx::SurfaceFormat::NV12 && mCanUseNV12) || 180 (aPreferredFormat == gfx::SurfaceFormat::P010 && mCanUseP010) || 181 (aPreferredFormat == gfx::SurfaceFormat::P016 && mCanUseP016) || 182 (aPreferredFormat == gfx::SurfaceFormat::R10G10B10A2_UINT32) || 183 (aPreferredFormat == gfx::SurfaceFormat::R10G10B10X2_UINT32) || 184 (aPreferredFormat == gfx::SurfaceFormat::R16G16B16A16F)) { 185 mUsableSurfaceFormat = aPreferredFormat; 186 return; 187 } 188 // We can't handle the native source format, set it to BGRA which will 189 // force the caller to convert it later. 190 mUsableSurfaceFormat = gfx::SurfaceFormat::B8G8R8A8; 191 } 192 193 already_AddRefed<TextureClient> D3D11RecycleAllocator::CreateOrRecycleClient( 194 gfx::ColorSpace2 aColorSpace, gfx::ColorRange aColorRange, 195 const gfx::IntSize& aSize) { 196 // When CompositorDevice or ContentDevice is updated, 197 // we could not reuse old D3D11Textures. It could cause video flickering. 198 RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetImageDevice(); 199 if (!!mImageDevice && mImageDevice != device) { 200 ShrinkToMinimumSize(); 201 } 202 mImageDevice = device; 203 204 auto* fencesHolderMap = CompositeProcessD3D11FencesHolderMap::Get(); 205 const bool useFence = 206 fencesHolderMap && FenceD3D11::IsSupported(mImageDevice); 207 TextureAllocationFlags allocFlags = TextureAllocationFlags::ALLOC_DEFAULT; 208 if (!useFence && (StaticPrefs::media_wmf_use_sync_texture_AtStartup() || 209 mDevice == DeviceManagerDx::Get()->GetCompositorDevice())) { 210 // If our device is the compositor device, we don't need any synchronization 211 // in practice. 212 allocFlags = TextureAllocationFlags::ALLOC_MANUAL_SYNCHRONIZATION; 213 } 214 215 D3D11TextureClientAllocationHelper helper( 216 mUsableSurfaceFormat, aColorSpace, aColorRange, aSize, allocFlags, 217 mDevice, layers::TextureFlags::DEFAULT); 218 219 RefPtr<TextureClient> textureClient = 220 CreateOrRecycle(helper).unwrapOr(nullptr); 221 222 if (textureClient) { 223 auto* textureData = textureClient->GetInternalData()->AsD3D11TextureData(); 224 MOZ_ASSERT(textureData); 225 if (textureData && textureData->mFencesHolderId.isSome() && 226 fencesHolderMap) { 227 fencesHolderMap->WaitAllFencesAndForget( 228 textureData->mFencesHolderId.ref(), mDevice); 229 } 230 } 231 return textureClient.forget(); 232 } 233 234 RefPtr<ID3D11Texture2D> D3D11RecycleAllocator::GetStagingTextureNV12( 235 gfx::IntSize aSize) { 236 if (!mStagingTexture || mStagingTextureSize != aSize) { 237 mStagingTexture = nullptr; 238 239 D3D11_TEXTURE2D_DESC desc = {}; 240 desc.Width = aSize.width; 241 desc.Height = aSize.height; 242 desc.Format = DXGI_FORMAT_NV12; 243 desc.MipLevels = 1; 244 desc.ArraySize = 1; 245 desc.Usage = D3D11_USAGE_STAGING; 246 desc.BindFlags = 0; 247 desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 248 desc.MiscFlags = 0; 249 desc.SampleDesc.Count = 1; 250 251 HRESULT hr = mDevice->CreateTexture2D(&desc, nullptr, 252 getter_AddRefs(mStagingTexture)); 253 if (FAILED(hr)) { 254 gfxCriticalNoteOnce << "allocating D3D11 NV12 staging texture failed: " 255 << gfx::hexa(hr); 256 return nullptr; 257 } 258 MOZ_ASSERT(mStagingTexture); 259 mStagingTextureSize = aSize; 260 } 261 262 return mStagingTexture; 263 } 264 265 } // namespace layers 266 } // namespace mozilla