Add WrapSharedHandle to D3D12 backend
WrapSharedHandle uses a HANDLE and an acquire key to create a Dawn texture object. A future change will use the acquire key to manage a keyed shared mutex with Chromium code. Bug: dawn:27 Change-Id: I1c0ef8d022158abf3f1c6731a37ee3f51632fcf9 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/10540 Commit-Queue: Rafael Cintron <rafael.cintron@microsoft.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
824424fa35
commit
179d7b28a3
8
BUILD.gn
8
BUILD.gn
|
@ -810,6 +810,14 @@ source_set("dawn_end2end_tests_sources") {
|
|||
libs += [ "IOSurface.framework" ]
|
||||
}
|
||||
|
||||
if (dawn_enable_d3d12) {
|
||||
sources += [ "src/tests/end2end/D3D12ResourceWrappingTests.cpp" ]
|
||||
libs += [
|
||||
"d3d11.lib",
|
||||
"dxgi.lib",
|
||||
]
|
||||
}
|
||||
|
||||
if (dawn_enable_opengl) {
|
||||
deps += [ "third_party:glfw" ]
|
||||
}
|
||||
|
|
|
@ -23,6 +23,12 @@
|
|||
|
||||
namespace dawn_native { namespace d3d12 {
|
||||
|
||||
ComPtr<ID3D12Device> GetD3D12Device(DawnDevice device) {
|
||||
Device* backendDevice = reinterpret_cast<Device*>(device);
|
||||
|
||||
return backendDevice->GetD3D12Device();
|
||||
}
|
||||
|
||||
DawnSwapChainImplementation CreateNativeSwapChainImpl(DawnDevice device, HWND window) {
|
||||
Device* backendDevice = reinterpret_cast<Device*>(device);
|
||||
|
||||
|
@ -39,4 +45,13 @@ namespace dawn_native { namespace d3d12 {
|
|||
return static_cast<DawnTextureFormat>(impl->GetPreferredFormat());
|
||||
}
|
||||
|
||||
DawnTexture WrapSharedHandle(DawnDevice device,
|
||||
const DawnTextureDescriptor* descriptor,
|
||||
HANDLE sharedHandle) {
|
||||
Device* backendDevice = reinterpret_cast<Device*>(device);
|
||||
const TextureDescriptor* backendDescriptor =
|
||||
reinterpret_cast<const TextureDescriptor*>(descriptor);
|
||||
TextureBase* texture = backendDevice->WrapSharedHandle(backendDescriptor, sharedHandle);
|
||||
return reinterpret_cast<DawnTexture>(texture);
|
||||
}
|
||||
}} // namespace dawn_native::d3d12
|
||||
|
|
|
@ -380,4 +380,28 @@ namespace dawn_native { namespace d3d12 {
|
|||
|
||||
return allocation;
|
||||
}
|
||||
|
||||
TextureBase* Device::WrapSharedHandle(const TextureDescriptor* descriptor,
|
||||
HANDLE sharedHandle) {
|
||||
if (ConsumedError(ValidateTextureDescriptor(this, descriptor))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (ConsumedError(ValidateTextureDescriptorCanBeWrapped(descriptor))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ComPtr<ID3D12Resource> d3d12Resource;
|
||||
const HRESULT hr =
|
||||
mD3d12Device->OpenSharedHandle(sharedHandle, IID_PPV_ARGS(&d3d12Resource));
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (ConsumedError(ValidateD3D12TextureCanBeWrapped(d3d12Resource.Get(), descriptor))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new Texture(this, descriptor, d3d12Resource.Get());
|
||||
}
|
||||
}} // namespace dawn_native::d3d12
|
||||
|
|
|
@ -90,6 +90,8 @@ namespace dawn_native { namespace d3d12 {
|
|||
|
||||
void DeallocateMemory(ResourceMemoryAllocation& allocation);
|
||||
|
||||
TextureBase* WrapSharedHandle(const TextureDescriptor* descriptor, HANDLE sharedHandle);
|
||||
|
||||
private:
|
||||
ResultOrError<BindGroupBase*> CreateBindGroupImpl(
|
||||
const BindGroupDescriptor* descriptor) override;
|
||||
|
|
|
@ -100,7 +100,6 @@ namespace dawn_native { namespace d3d12 {
|
|||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DXGI_FORMAT D3D12TextureFormat(dawn::TextureFormat format) {
|
||||
|
@ -221,6 +220,56 @@ namespace dawn_native { namespace d3d12 {
|
|||
}
|
||||
}
|
||||
|
||||
MaybeError ValidateTextureDescriptorCanBeWrapped(const TextureDescriptor* descriptor) {
|
||||
if (descriptor->dimension != dawn::TextureDimension::e2D) {
|
||||
return DAWN_VALIDATION_ERROR("Texture must be 2D");
|
||||
}
|
||||
|
||||
if (descriptor->mipLevelCount != 1) {
|
||||
return DAWN_VALIDATION_ERROR("Mip level count must be 1");
|
||||
}
|
||||
|
||||
if (descriptor->arrayLayerCount != 1) {
|
||||
return DAWN_VALIDATION_ERROR("Array layer count must be 1");
|
||||
}
|
||||
|
||||
if (descriptor->sampleCount != 1) {
|
||||
return DAWN_VALIDATION_ERROR("Sample count must be 1");
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
MaybeError ValidateD3D12TextureCanBeWrapped(ID3D12Resource* d3d12Resource,
|
||||
const TextureDescriptor* dawnDescriptor) {
|
||||
const D3D12_RESOURCE_DESC d3dDescriptor = d3d12Resource->GetDesc();
|
||||
if ((dawnDescriptor->size.width != d3dDescriptor.Width) ||
|
||||
(dawnDescriptor->size.height != d3dDescriptor.Height) ||
|
||||
(dawnDescriptor->size.depth != 1)) {
|
||||
return DAWN_VALIDATION_ERROR("D3D12 texture size doesn't match descriptor");
|
||||
}
|
||||
|
||||
const DXGI_FORMAT dxgiFormatFromDescriptor = D3D12TextureFormat(dawnDescriptor->format);
|
||||
if (dxgiFormatFromDescriptor != d3dDescriptor.Format) {
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"D3D12 texture format must be compatible with descriptor format.");
|
||||
}
|
||||
|
||||
if (d3dDescriptor.MipLevels != 1) {
|
||||
return DAWN_VALIDATION_ERROR("D3D12 texture number of miplevels must be 1.");
|
||||
}
|
||||
|
||||
if (d3dDescriptor.DepthOrArraySize != 1) {
|
||||
return DAWN_VALIDATION_ERROR("D3D12 texture array size must be 1.");
|
||||
}
|
||||
|
||||
// Shared textures cannot be multi-sample so no need to check those.
|
||||
ASSERT(d3dDescriptor.SampleDesc.Count == 1);
|
||||
ASSERT(d3dDescriptor.SampleDesc.Quality == 0);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Texture::Texture(Device* device, const TextureDescriptor* descriptor)
|
||||
: TextureBase(device, descriptor, TextureState::OwnedInternal) {
|
||||
D3D12_RESOURCE_DESC resourceDescriptor;
|
||||
|
@ -258,6 +307,8 @@ namespace dawn_native { namespace d3d12 {
|
|||
const TextureDescriptor* descriptor,
|
||||
ID3D12Resource* nativeTexture)
|
||||
: TextureBase(device, descriptor, TextureState::OwnedExternal), mResource(nativeTexture) {
|
||||
SetIsSubresourceContentInitialized(0, descriptor->mipLevelCount, 0,
|
||||
descriptor->arrayLayerCount);
|
||||
}
|
||||
|
||||
Texture::~Texture() {
|
||||
|
|
|
@ -25,6 +25,9 @@ namespace dawn_native { namespace d3d12 {
|
|||
class Device;
|
||||
|
||||
DXGI_FORMAT D3D12TextureFormat(dawn::TextureFormat format);
|
||||
MaybeError ValidateD3D12TextureCanBeWrapped(ID3D12Resource* d3d12Resource,
|
||||
const TextureDescriptor* descriptor);
|
||||
MaybeError ValidateTextureDescriptorCanBeWrapped(const TextureDescriptor* descriptor);
|
||||
|
||||
class Texture : public TextureBase {
|
||||
public:
|
||||
|
|
|
@ -19,12 +19,20 @@
|
|||
#include <dawn_native/DawnNative.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <wrl/client.h>
|
||||
|
||||
struct ID3D12Device;
|
||||
|
||||
namespace dawn_native { namespace d3d12 {
|
||||
DAWN_NATIVE_EXPORT Microsoft::WRL::ComPtr<ID3D12Device> GetD3D12Device(DawnDevice device);
|
||||
DAWN_NATIVE_EXPORT DawnSwapChainImplementation CreateNativeSwapChainImpl(DawnDevice device,
|
||||
HWND window);
|
||||
DAWN_NATIVE_EXPORT DawnTextureFormat
|
||||
GetNativeSwapChainPreferredFormat(const DawnSwapChainImplementation* swapChain);
|
||||
|
||||
DAWN_NATIVE_EXPORT DawnTexture WrapSharedHandle(DawnDevice device,
|
||||
const DawnTextureDescriptor* descriptor,
|
||||
HANDLE sharedHandle);
|
||||
}} // namespace dawn_native::d3d12
|
||||
|
||||
#endif // DAWNNATIVE_D3D12BACKEND_H_
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
// Copyright 2019 The Dawn Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "tests/DawnTest.h"
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <d3d12.h>
|
||||
#include <dxgi1_4.h>
|
||||
#include <wrl/client.h>
|
||||
|
||||
#include "dawn_native/D3D12Backend.h"
|
||||
#include "utils/ComboRenderPipelineDescriptor.h"
|
||||
#include "utils/DawnHelpers.h"
|
||||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
namespace {
|
||||
|
||||
class D3D12ResourceTestBase : public DawnTest {
|
||||
public:
|
||||
void SetUp() override {
|
||||
DawnTest::SetUp();
|
||||
if (UsesWire()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the D3D11 device/contexts that will be used in subsequent tests
|
||||
ComPtr<ID3D12Device> d3d12Device = dawn_native::d3d12::GetD3D12Device(device.Get());
|
||||
|
||||
const LUID adapterLuid = d3d12Device->GetAdapterLuid();
|
||||
|
||||
ComPtr<IDXGIFactory4> dxgiFactory;
|
||||
HRESULT hr = ::CreateDXGIFactory2(0, IID_PPV_ARGS(&dxgiFactory));
|
||||
ASSERT_EQ(hr, S_OK);
|
||||
|
||||
ComPtr<IDXGIAdapter> dxgiAdapter;
|
||||
hr = dxgiFactory->EnumAdapterByLuid(adapterLuid, IID_PPV_ARGS(&dxgiAdapter));
|
||||
ASSERT_EQ(hr, S_OK);
|
||||
|
||||
ComPtr<ID3D11Device> d3d11Device;
|
||||
D3D_FEATURE_LEVEL d3dFeatureLevel;
|
||||
ComPtr<ID3D11DeviceContext> d3d11DeviceContext;
|
||||
hr = ::D3D11CreateDevice(dxgiAdapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0,
|
||||
nullptr, 0, D3D11_SDK_VERSION, &d3d11Device, &d3dFeatureLevel,
|
||||
&d3d11DeviceContext);
|
||||
ASSERT_EQ(hr, S_OK);
|
||||
|
||||
mD3d11Device = std::move(d3d11Device);
|
||||
mD3d11DeviceContext = std::move(d3d11DeviceContext);
|
||||
}
|
||||
|
||||
protected:
|
||||
void WrapSharedHandle(const dawn::TextureDescriptor* dawnDescriptor,
|
||||
const D3D11_TEXTURE2D_DESC* d3dDescriptor,
|
||||
dawn::Texture* dawnTexture) const {
|
||||
ComPtr<ID3D11Texture2D> d3d11Texture;
|
||||
HRESULT hr = mD3d11Device->CreateTexture2D(d3dDescriptor, nullptr, &d3d11Texture);
|
||||
ASSERT_EQ(hr, S_OK);
|
||||
|
||||
ComPtr<IDXGIResource1> dxgiResource;
|
||||
hr = d3d11Texture.As(&dxgiResource);
|
||||
ASSERT_EQ(hr, S_OK);
|
||||
|
||||
HANDLE sharedHandle;
|
||||
hr = dxgiResource->CreateSharedHandle(
|
||||
nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr,
|
||||
&sharedHandle);
|
||||
ASSERT_EQ(hr, S_OK);
|
||||
|
||||
DawnTexture texture = dawn_native::d3d12::WrapSharedHandle(
|
||||
device.Get(), reinterpret_cast<const DawnTextureDescriptor*>(dawnDescriptor),
|
||||
sharedHandle);
|
||||
// Now that we've created all of our resources, we can close the handle
|
||||
// since we no longer need it.
|
||||
::CloseHandle(sharedHandle);
|
||||
|
||||
*dawnTexture = dawn::Texture::Acquire(texture);
|
||||
}
|
||||
|
||||
static constexpr size_t kTestWidth = 10;
|
||||
static constexpr size_t kTestHeight = 10;
|
||||
|
||||
ComPtr<ID3D11Device> mD3d11Device;
|
||||
ComPtr<ID3D11DeviceContext> mD3d11DeviceContext;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// A small fixture used to initialize default data for the D3D12Resource validation tests.
|
||||
// These tests are skipped if the harness is using the wire.
|
||||
class D3D12SharedHandleValidation : public D3D12ResourceTestBase {
|
||||
public:
|
||||
void SetUp() override {
|
||||
D3D12ResourceTestBase::SetUp();
|
||||
|
||||
dawnDescriptor.dimension = dawn::TextureDimension::e2D;
|
||||
dawnDescriptor.format = dawn::TextureFormat::BGRA8Unorm;
|
||||
dawnDescriptor.size = {kTestWidth, kTestHeight, 1};
|
||||
dawnDescriptor.sampleCount = 1;
|
||||
dawnDescriptor.arrayLayerCount = 1;
|
||||
dawnDescriptor.mipLevelCount = 1;
|
||||
dawnDescriptor.usage = dawn::TextureUsage::OutputAttachment;
|
||||
|
||||
d3dDescriptor.Width = kTestWidth;
|
||||
d3dDescriptor.Height = kTestHeight;
|
||||
d3dDescriptor.MipLevels = 1;
|
||||
d3dDescriptor.ArraySize = 1;
|
||||
d3dDescriptor.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
d3dDescriptor.SampleDesc.Count = 1;
|
||||
d3dDescriptor.SampleDesc.Quality = 0;
|
||||
d3dDescriptor.Usage = D3D11_USAGE_DEFAULT;
|
||||
d3dDescriptor.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
|
||||
d3dDescriptor.CPUAccessFlags = 0;
|
||||
d3dDescriptor.MiscFlags =
|
||||
D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
|
||||
}
|
||||
|
||||
protected:
|
||||
D3D11_TEXTURE2D_DESC d3dDescriptor;
|
||||
dawn::TextureDescriptor dawnDescriptor;
|
||||
};
|
||||
|
||||
// Test a successful wrapping of an D3D12Resource in a texture
|
||||
TEST_P(D3D12SharedHandleValidation, Success) {
|
||||
DAWN_SKIP_TEST_IF(UsesWire());
|
||||
|
||||
dawn::Texture texture;
|
||||
WrapSharedHandle(&dawnDescriptor, &d3dDescriptor, &texture);
|
||||
|
||||
ASSERT_NE(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
// Test an error occurs if the texture descriptor is invalid
|
||||
TEST_P(D3D12SharedHandleValidation, InvalidTextureDescriptor) {
|
||||
DAWN_SKIP_TEST_IF(UsesWire());
|
||||
dawnDescriptor.nextInChain = this;
|
||||
|
||||
dawn::Texture texture;
|
||||
ASSERT_DEVICE_ERROR(WrapSharedHandle(&dawnDescriptor, &d3dDescriptor, &texture));
|
||||
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
// Test an error occurs if the descriptor mip level count isn't 1
|
||||
TEST_P(D3D12SharedHandleValidation, InvalidMipLevelCount) {
|
||||
DAWN_SKIP_TEST_IF(UsesWire());
|
||||
dawnDescriptor.mipLevelCount = 2;
|
||||
|
||||
dawn::Texture texture;
|
||||
ASSERT_DEVICE_ERROR(WrapSharedHandle(&dawnDescriptor, &d3dDescriptor, &texture));
|
||||
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
// Test an error occurs if the descriptor array layer count isn't 1
|
||||
TEST_P(D3D12SharedHandleValidation, InvalidArrayLayerCount) {
|
||||
DAWN_SKIP_TEST_IF(UsesWire());
|
||||
dawnDescriptor.arrayLayerCount = 2;
|
||||
|
||||
dawn::Texture texture;
|
||||
ASSERT_DEVICE_ERROR(WrapSharedHandle(&dawnDescriptor, &d3dDescriptor, &texture));
|
||||
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
// Test an error occurs if the descriptor sample count isn't 1
|
||||
TEST_P(D3D12SharedHandleValidation, InvalidSampleCount) {
|
||||
DAWN_SKIP_TEST_IF(UsesWire());
|
||||
dawnDescriptor.sampleCount = 4;
|
||||
|
||||
dawn::Texture texture;
|
||||
ASSERT_DEVICE_ERROR(WrapSharedHandle(&dawnDescriptor, &d3dDescriptor, &texture));
|
||||
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
// Test an error occurs if the descriptor width doesn't match the texture's
|
||||
TEST_P(D3D12SharedHandleValidation, InvalidWidth) {
|
||||
DAWN_SKIP_TEST_IF(UsesWire());
|
||||
dawnDescriptor.size.width = kTestWidth + 1;
|
||||
|
||||
dawn::Texture texture;
|
||||
ASSERT_DEVICE_ERROR(WrapSharedHandle(&dawnDescriptor, &d3dDescriptor, &texture));
|
||||
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
// Test an error occurs if the descriptor height doesn't match the texture's
|
||||
TEST_P(D3D12SharedHandleValidation, InvalidHeight) {
|
||||
DAWN_SKIP_TEST_IF(UsesWire());
|
||||
dawnDescriptor.size.height = kTestHeight + 1;
|
||||
|
||||
dawn::Texture texture;
|
||||
ASSERT_DEVICE_ERROR(WrapSharedHandle(&dawnDescriptor, &d3dDescriptor, &texture));
|
||||
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
// Test an error occurs if the descriptor format isn't compatible with the D3D12 Resource
|
||||
TEST_P(D3D12SharedHandleValidation, InvalidFormat) {
|
||||
DAWN_SKIP_TEST_IF(UsesWire());
|
||||
dawnDescriptor.format = dawn::TextureFormat::R8Unorm;
|
||||
|
||||
dawn::Texture texture;
|
||||
ASSERT_DEVICE_ERROR(WrapSharedHandle(&dawnDescriptor, &d3dDescriptor, &texture));
|
||||
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
// Test an error occurs if the number of D3D mip levels is greater than 1.
|
||||
TEST_P(D3D12SharedHandleValidation, InvalidNumD3DMipLevels) {
|
||||
DAWN_SKIP_TEST_IF(UsesWire());
|
||||
d3dDescriptor.MipLevels = 2;
|
||||
|
||||
dawn::Texture texture;
|
||||
ASSERT_DEVICE_ERROR(WrapSharedHandle(&dawnDescriptor, &d3dDescriptor, &texture));
|
||||
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
// Test an error occurs if the number of array levels is greater than 1.
|
||||
TEST_P(D3D12SharedHandleValidation, InvalidD3DArraySize) {
|
||||
DAWN_SKIP_TEST_IF(UsesWire());
|
||||
d3dDescriptor.ArraySize = 2;
|
||||
|
||||
dawn::Texture texture;
|
||||
ASSERT_DEVICE_ERROR(WrapSharedHandle(&dawnDescriptor, &d3dDescriptor, &texture));
|
||||
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(D3D12SharedHandleValidation, D3D12Backend);
|
Loading…
Reference in New Issue