SharedTextureD3D11.cpp (7525B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "SharedTextureD3D11.h" 7 8 #include <d3d11.h> 9 10 #include "mozilla/gfx/DeviceManagerDx.h" 11 #include "mozilla/gfx/Logging.h" 12 #include "mozilla/layers/CompositeProcessD3D11FencesHolderMap.h" 13 #include "mozilla/layers/FenceD3D11.h" 14 #include "mozilla/layers/ImageDataSerializer.h" 15 #include "mozilla/webgpu/WebGPUParent.h" 16 17 namespace mozilla::webgpu { 18 19 // static 20 UniquePtr<SharedTextureD3D11> SharedTextureD3D11::Create( 21 WebGPUParent* aParent, const ffi::WGPUDeviceId aDeviceId, 22 const uint32_t aWidth, const uint32_t aHeight, 23 const struct ffi::WGPUTextureFormat aFormat, 24 const ffi::WGPUTextureUsages aUsage) { 25 auto* fencesHolderMap = layers::CompositeProcessD3D11FencesHolderMap::Get(); 26 if (!fencesHolderMap) { 27 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 28 gfxCriticalNoteOnce << "Failed to get FencesHolderMap"; 29 return nullptr; 30 } 31 32 RefPtr<gfx::FileHandleWrapper> fenceHandle = 33 aParent->GetDeviceFenceHandle(aDeviceId); 34 if (!fenceHandle) { 35 gfxCriticalNoteOnce << "Failed to get fenceHandle"; 36 return nullptr; 37 } 38 39 RefPtr<layers::FenceD3D11> fence = 40 layers::FenceD3D11::CreateFromHandle(fenceHandle, /* aDevice */ nullptr); 41 if (!fence) { 42 gfxCriticalNoteOnce << "Failed create FenceD3D11"; 43 return nullptr; 44 } 45 46 const RefPtr<ID3D11Device> d3d11Device = 47 gfx::DeviceManagerDx::Get()->GetCompositorDevice(); 48 if (!d3d11Device) { 49 gfxCriticalNoteOnce << "CompositorDevice does not exist"; 50 return nullptr; 51 } 52 53 if (aFormat.tag != ffi::WGPUTextureFormat_Bgra8Unorm) { 54 gfxCriticalNoteOnce << "Non supported format: " << aFormat.tag; 55 return nullptr; 56 } 57 58 CD3D11_TEXTURE2D_DESC desc( 59 DXGI_FORMAT_B8G8R8A8_UNORM, aWidth, aHeight, 1, 1, 60 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); 61 62 if (aUsage & WGPUTextureUsages_STORAGE_BINDING) { 63 desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS; 64 } 65 66 desc.MiscFlags = 67 D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED; 68 69 RefPtr<ID3D11Texture2D> texture; 70 HRESULT hr = 71 d3d11Device->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture)); 72 if (FAILED(hr)) { 73 gfxCriticalNoteOnce << "CreateTexture2D failed: " << gfx::hexa(hr); 74 return nullptr; 75 } 76 77 RefPtr<IDXGIResource1> resource; 78 texture->QueryInterface((IDXGIResource1**)getter_AddRefs(resource)); 79 if (!resource) { 80 gfxCriticalNoteOnce << "Failed to get IDXGIResource"; 81 return nullptr; 82 } 83 84 HANDLE sharedHandle; 85 hr = resource->CreateSharedHandle( 86 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr, 87 &sharedHandle); 88 if (FAILED(hr) || !sharedHandle) { 89 gfxCriticalNoteOnce << "GetSharedHandle failed: " << gfx::hexa(hr); 90 return nullptr; 91 } 92 93 RefPtr<gfx::FileHandleWrapper> handle = 94 new gfx::FileHandleWrapper(UniqueFileHandle(sharedHandle)); 95 96 auto fencesHolderId = layers::CompositeProcessFencesHolderId::GetNext(); 97 fencesHolderMap->Register(fencesHolderId); 98 99 return MakeUnique<SharedTextureD3D11>(aWidth, aHeight, aFormat, aUsage, 100 texture, std::move(handle), 101 fencesHolderId, std::move(fence)); 102 } 103 104 SharedTextureD3D11::SharedTextureD3D11( 105 const uint32_t aWidth, const uint32_t aHeight, 106 const struct ffi::WGPUTextureFormat aFormat, 107 const ffi::WGPUTextureUsages aUsage, const RefPtr<ID3D11Texture2D> aTexture, 108 RefPtr<gfx::FileHandleWrapper>&& aSharedHandle, 109 const layers::CompositeProcessFencesHolderId aFencesHolderId, 110 RefPtr<layers::FenceD3D11>&& aWriteFence) 111 : SharedTexture(aWidth, aHeight, aFormat, aUsage), 112 mTexture(aTexture), 113 mSharedHandle(std::move(aSharedHandle)), 114 mFencesHolderId(aFencesHolderId), 115 mWriteFence(std::move(aWriteFence)) { 116 MOZ_ASSERT(mTexture); 117 } 118 119 SharedTextureD3D11::~SharedTextureD3D11() { 120 auto* fencesHolderMap = layers::CompositeProcessD3D11FencesHolderMap::Get(); 121 if (fencesHolderMap) { 122 fencesHolderMap->Unregister(mFencesHolderId); 123 } else { 124 gfxCriticalNoteOnce 125 << "CompositeProcessD3D11FencesHolderMap does not exist"; 126 } 127 } 128 129 void* SharedTextureD3D11::GetSharedTextureHandle() { 130 RefPtr<ID3D11Device> device; 131 mTexture->GetDevice(getter_AddRefs(device)); 132 auto* fencesHolderMap = layers::CompositeProcessD3D11FencesHolderMap::Get(); 133 MOZ_ASSERT(fencesHolderMap); 134 135 // XXX deliver fences to wgpu 136 fencesHolderMap->WaitAllFencesAndForget(mFencesHolderId, device); 137 138 return mSharedHandle->GetHandle(); 139 } 140 141 Maybe<layers::SurfaceDescriptor> SharedTextureD3D11::ToSurfaceDescriptor() { 142 MOZ_ASSERT(mSubmissionIndex > 0); 143 144 mWriteFence->Update(mSubmissionIndex); 145 146 auto* fencesHolderMap = layers::CompositeProcessD3D11FencesHolderMap::Get(); 147 MOZ_ASSERT(fencesHolderMap); 148 fencesHolderMap->SetWriteFence(mFencesHolderId, mWriteFence); 149 150 const auto format = gfx::SurfaceFormat::B8G8R8A8; 151 return Some(layers::SurfaceDescriptorD3D10( 152 mSharedHandle, 153 /* gpuProcessTextureId */ Nothing(), 154 /* arrayIndex */ 0, format, gfx::IntSize(mWidth, mHeight), 155 gfx::ColorSpace2::SRGB, gfx::ColorRange::FULL, 156 /* hasKeyedMutex */ false, Some(mFencesHolderId))); 157 } 158 159 void SharedTextureD3D11::GetSnapshot(const ipc::Shmem& aDestShmem, 160 const gfx::IntSize& aSize) { 161 RefPtr<ID3D11Device> device; 162 mTexture->GetDevice(getter_AddRefs(device)); 163 if (!device) { 164 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 165 gfxCriticalNoteOnce << "Failed to get ID3D11Device"; 166 return; 167 } 168 169 RefPtr<ID3D11DeviceContext> deviceContext; 170 device->GetImmediateContext(getter_AddRefs(deviceContext)); 171 if (!deviceContext) { 172 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 173 gfxCriticalNoteOnce << "Failed to get ID3D11DeviceContext"; 174 return; 175 } 176 177 D3D11_TEXTURE2D_DESC textureDesc = {0}; 178 mTexture->GetDesc(&textureDesc); 179 180 textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; 181 textureDesc.Usage = D3D11_USAGE_STAGING; 182 textureDesc.BindFlags = 0; 183 textureDesc.MiscFlags = 0; 184 textureDesc.MipLevels = 1; 185 186 RefPtr<ID3D11Texture2D> cpuTexture; 187 HRESULT hr = device->CreateTexture2D(&textureDesc, nullptr, 188 getter_AddRefs(cpuTexture)); 189 if (FAILED(hr)) { 190 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 191 gfxCriticalNote << "Failed to create ID3D11Texture2D: " << gfx::hexa(hr); 192 return; 193 } 194 195 deviceContext->CopyResource(cpuTexture, mTexture); 196 197 D3D11_MAPPED_SUBRESOURCE map; 198 hr = deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &map); 199 if (FAILED(hr)) { 200 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 201 gfxCriticalNote << "Failed to map ID3D11Texture2D: " << gfx::hexa(hr); 202 return; 203 } 204 205 const uint32_t stride = layers::ImageDataSerializer::ComputeRGBStride( 206 gfx::SurfaceFormat::B8G8R8A8, aSize.width); 207 uint8_t* src = static_cast<uint8_t*>(map.pData); 208 uint8_t* dst = aDestShmem.get<uint8_t>(); 209 210 MOZ_ASSERT(stride * aSize.height <= aDestShmem.Size<uint8_t>()); 211 MOZ_ASSERT(map.RowPitch >= stride); 212 213 for (int y = 0; y < aSize.height; y++) { 214 memcpy(dst, src, stride); 215 src += map.RowPitch; 216 dst += stride; 217 } 218 deviceContext->Unmap(cpuTexture, 0); 219 } 220 221 } // namespace mozilla::webgpu