D3D12: Dynamically load D3D12, DXGI and D3DCompiler

Linking against their .lib makes loading Dawn fail on systems that don't
have the DLLs. This happens for example on Windows7 that doesn't have
d3d12.dll. Instead we dynamically load functions pointers from these
DLLs at d3d12::Device startup.

Change-Id: I4d01a12d0f91bec45bf125450d2c08aaa9ff9fac
This commit is contained in:
Corentin Wallez 2018-08-30 14:20:28 +02:00 committed by Corentin Wallez
parent 748a5d5b28
commit d8597b2e1f
9 changed files with 194 additions and 26 deletions

View File

@ -389,12 +389,7 @@ source_set("libdawn_native_sources") {
]
if (dawn_enable_d3d12) {
libs += [
"d3d12.lib",
"dxgi.lib",
"dxguid.lib",
"d3dcompiler.lib",
]
libs += [ "dxguid.lib" ]
sources += [
"src/dawn_native/d3d12/BindGroupD3D12.cpp",
"src/dawn_native/d3d12/BindGroupD3D12.h",
@ -423,6 +418,8 @@ source_set("libdawn_native_sources") {
"src/dawn_native/d3d12/NativeSwapChainImplD3D12.h",
"src/dawn_native/d3d12/PipelineLayoutD3D12.cpp",
"src/dawn_native/d3d12/PipelineLayoutD3D12.h",
"src/dawn_native/d3d12/PlatformFunctions.cpp",
"src/dawn_native/d3d12/PlatformFunctions.h",
"src/dawn_native/d3d12/QueueD3D12.cpp",
"src/dawn_native/d3d12/QueueD3D12.h",
"src/dawn_native/d3d12/RenderPassDescriptorD3D12.cpp",

View File

@ -225,6 +225,8 @@ if (DAWN_ENABLE_D3D12)
${D3D12_DIR}/NativeSwapChainImplD3D12.h
${D3D12_DIR}/PipelineLayoutD3D12.cpp
${D3D12_DIR}/PipelineLayoutD3D12.h
${D3D12_DIR}/PlatformFunctions.cpp
${D3D12_DIR}/PlatformFunctions.h
${D3D12_DIR}/QueueD3D12.cpp
${D3D12_DIR}/QueueD3D12.h
${D3D12_DIR}/RenderPassDescriptorD3D12.cpp

View File

@ -17,10 +17,9 @@
#include "common/Assert.h"
#include "dawn_native/d3d12/DeviceD3D12.h"
#include "dawn_native/d3d12/PipelineLayoutD3D12.h"
#include "dawn_native/d3d12/PlatformFunctions.h"
#include "dawn_native/d3d12/ShaderModuleD3D12.h"
#include <d3dcompiler.h>
namespace dawn_native { namespace d3d12 {
ComputePipeline::ComputePipeline(ComputePipelineBuilder* builder)
@ -40,9 +39,10 @@ namespace dawn_native { namespace d3d12 {
ComPtr<ID3DBlob> compiledShader;
ComPtr<ID3DBlob> errors;
if (FAILED(D3DCompile(hlslSource.c_str(), hlslSource.length(), nullptr, nullptr, nullptr,
entryPoint.c_str(), "cs_5_1", compileFlags, 0, &compiledShader,
&errors))) {
const PlatformFunctions* functions = ToBackend(builder->GetDevice())->GetFunctions();
if (FAILED(functions->d3dCompile(hlslSource.c_str(), hlslSource.length(), nullptr, nullptr,
nullptr, entryPoint.c_str(), "cs_5_1", compileFlags, 0,
&compiledShader, &errors))) {
printf("%s\n", reinterpret_cast<char*>(errors->GetBufferPointer()));
ASSERT(false);
}

View File

@ -29,6 +29,7 @@
#include "dawn_native/d3d12/InputStateD3D12.h"
#include "dawn_native/d3d12/NativeSwapChainImplD3D12.h"
#include "dawn_native/d3d12/PipelineLayoutD3D12.h"
#include "dawn_native/d3d12/PlatformFunctions.h"
#include "dawn_native/d3d12/QueueD3D12.h"
#include "dawn_native/d3d12/RenderPassDescriptorD3D12.h"
#include "dawn_native/d3d12/RenderPipelineD3D12.h"
@ -66,7 +67,7 @@ namespace dawn_native { namespace d3d12 {
}
namespace {
ComPtr<IDXGIFactory4> CreateFactory() {
ComPtr<IDXGIFactory4> CreateFactory(const PlatformFunctions* functions) {
ComPtr<IDXGIFactory4> factory;
uint32_t dxgiFactoryFlags = 0;
@ -74,7 +75,7 @@ namespace dawn_native { namespace d3d12 {
// Enable the debug layer (requires the Graphics Tools "optional feature").
{
ComPtr<ID3D12Debug> debugController;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
if (SUCCEEDED(functions->d3d12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
debugController->EnableDebugLayer();
// Enable additional debug layers.
@ -82,18 +83,19 @@ namespace dawn_native { namespace d3d12 {
}
ComPtr<IDXGIDebug1> dxgiDebug;
if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiDebug)))) {
if (SUCCEEDED(functions->dxgiGetDebugInterface1(0, IID_PPV_ARGS(&dxgiDebug)))) {
dxgiDebug->ReportLiveObjects(DXGI_DEBUG_ALL,
DXGI_DEBUG_RLO_FLAGS(DXGI_DEBUG_RLO_ALL));
}
}
#endif // defined(DAWN_ENABLE_ASSERTS)
ASSERT_SUCCESS(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&factory)));
ASSERT_SUCCESS(functions->createDxgiFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&factory)));
return factory;
}
ComPtr<IDXGIAdapter1> GetHardwareAdapter(ComPtr<IDXGIFactory4> factory) {
ComPtr<IDXGIAdapter1> GetHardwareAdapter(ComPtr<IDXGIFactory4> factory,
const PlatformFunctions* functions) {
for (uint32_t adapterIndex = 0;; ++adapterIndex) {
IDXGIAdapter1* adapter = nullptr;
if (factory->EnumAdapters1(adapterIndex, &adapter) == DXGI_ERROR_NOT_FOUND) {
@ -102,8 +104,8 @@ namespace dawn_native { namespace d3d12 {
// Check to see if the adapter supports Direct3D 12, but don't create the actual
// device yet.
if (SUCCEEDED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0,
_uuidof(ID3D12Device), nullptr))) {
if (SUCCEEDED(functions->d3d12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0,
_uuidof(ID3D12Device), nullptr))) {
return adapter;
}
adapter->Release();
@ -114,15 +116,22 @@ namespace dawn_native { namespace d3d12 {
} // anonymous namespace
Device::Device() {
mFunctions = new PlatformFunctions();
{
MaybeError status = mFunctions->LoadFunctions();
ASSERT(status.IsSuccess());
}
// Create the connection to DXGI and the D3D12 device
mFactory = CreateFactory();
mFactory = CreateFactory(mFunctions);
ASSERT(mFactory.Get() != nullptr);
mHardwareAdapter = GetHardwareAdapter(mFactory);
mHardwareAdapter = GetHardwareAdapter(mFactory, mFunctions);
ASSERT(mHardwareAdapter.Get() != nullptr);
ASSERT_SUCCESS(D3D12CreateDevice(mHardwareAdapter.Get(), D3D_FEATURE_LEVEL_11_0,
IID_PPV_ARGS(&mD3d12Device)));
ASSERT_SUCCESS(mFunctions->d3d12CreateDevice(mHardwareAdapter.Get(), D3D_FEATURE_LEVEL_11_0,
IID_PPV_ARGS(&mD3d12Device)));
// Create device-global objects
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
@ -157,6 +166,7 @@ namespace dawn_native { namespace d3d12 {
delete mMapRequestTracker;
delete mResourceAllocator;
delete mResourceUploader;
delete mFunctions;
}
ComPtr<IDXGIFactory4> Device::GetFactory() {
@ -175,6 +185,10 @@ namespace dawn_native { namespace d3d12 {
return mDescriptorHeapAllocator;
}
const PlatformFunctions* Device::GetFunctions() {
return mFunctions;
}
MapRequestTracker* Device::GetMapRequestTracker() const {
return mMapRequestTracker;
}

View File

@ -27,6 +27,7 @@ namespace dawn_native { namespace d3d12 {
class CommandAllocatorManager;
class DescriptorHeapAllocator;
class MapRequestTracker;
class PlatformFunctions;
class ResourceAllocator;
class ResourceUploader;
@ -59,6 +60,7 @@ namespace dawn_native { namespace d3d12 {
DescriptorHeapAllocator* GetDescriptorHeapAllocator();
MapRequestTracker* GetMapRequestTracker() const;
const PlatformFunctions* GetFunctions();
ResourceAllocator* GetResourceAllocator();
ResourceUploader* GetResourceUploader();
@ -97,6 +99,7 @@ namespace dawn_native { namespace d3d12 {
CommandAllocatorManager* mCommandAllocatorManager = nullptr;
DescriptorHeapAllocator* mDescriptorHeapAllocator = nullptr;
MapRequestTracker* mMapRequestTracker = nullptr;
PlatformFunctions* mFunctions = nullptr;
ResourceAllocator* mResourceAllocator = nullptr;
ResourceUploader* mResourceUploader = nullptr;

View File

@ -18,6 +18,7 @@
#include "common/BitSetIterator.h"
#include "dawn_native/d3d12/BindGroupLayoutD3D12.h"
#include "dawn_native/d3d12/DeviceD3D12.h"
#include "dawn_native/d3d12/PlatformFunctions.h"
using Microsoft::WRL::ComPtr;
@ -92,7 +93,7 @@ namespace dawn_native { namespace d3d12 {
ComPtr<ID3DBlob> signature;
ComPtr<ID3DBlob> error;
ASSERT_SUCCESS(D3D12SerializeRootSignature(
ASSERT_SUCCESS(device->GetFunctions()->d3d12SerializeRootSignature(
&rootSignatureDescriptor, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error));
ASSERT_SUCCESS(device->GetD3D12Device()->CreateRootSignature(
0, signature->GetBufferPointer(), signature->GetBufferSize(),

View File

@ -0,0 +1,74 @@
// Copyright 2018 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 "dawn_native/d3d12/PlatformFunctions.h"
#include "common/DynamicLib.h"
namespace dawn_native { namespace d3d12 {
PlatformFunctions::PlatformFunctions() {
}
PlatformFunctions::~PlatformFunctions() {
}
MaybeError PlatformFunctions::LoadFunctions() {
DAWN_TRY(LoadD3D12());
DAWN_TRY(LoadDXGI());
DAWN_TRY(LoadD3DCompiler());
return {};
}
MaybeError PlatformFunctions::LoadD3D12() {
std::string error;
if (!mD3D12Lib.Open("d3d12.dll", &error) ||
!mD3D12Lib.GetProc(&d3d12CreateDevice, "D3D12CreateDevice", &error) ||
!mD3D12Lib.GetProc(&d3d12GetDebugInterface, "D3D12GetDebugInterface", &error) ||
!mD3D12Lib.GetProc(&d3d12SerializeRootSignature, "D3D12SerializeRootSignature",
&error) ||
!mD3D12Lib.GetProc(&d3d12CreateRootSignatureDeserializer,
"D3D12CreateRootSignatureDeserializer", &error) ||
!mD3D12Lib.GetProc(&d3d12SerializeVersionedRootSignature,
"D3D12SerializeVersionedRootSignature", &error) ||
!mD3D12Lib.GetProc(&d3d12CreateVersionedRootSignatureDeserializer,
"D3D12CreateVersionedRootSignatureDeserializer", &error)) {
DAWN_RETURN_ERROR(error.c_str());
}
return {};
}
MaybeError PlatformFunctions::LoadDXGI() {
std::string error;
if (!mDXGILib.Open("dxgi.dll", &error) ||
!mDXGILib.GetProc(&dxgiGetDebugInterface1, "DXGIGetDebugInterface1", &error) ||
!mDXGILib.GetProc(&createDxgiFactory2, "CreateDXGIFactory2", &error)) {
DAWN_RETURN_ERROR(error.c_str());
}
return {};
}
MaybeError PlatformFunctions::LoadD3DCompiler() {
std::string error;
if (!mD3DCompilerLib.Open("d3dcompiler_47.dll", &error) ||
!mD3DCompilerLib.GetProc(&d3dCompile, "D3DCompile", &error)) {
DAWN_RETURN_ERROR(error.c_str());
}
return {};
}
}} // namespace dawn_native::d3d12

View File

@ -0,0 +1,75 @@
// Copyright 2018 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.
#ifndef DAWNNATIVE_D3D12_PLATFORMFUNCTIONS_H_
#define DAWNNATIVE_D3D12_PLATFORMFUNCTIONS_H_
#include "dawn_native/d3d12/d3d12_platform.h"
#include "common/DynamicLib.h"
#include "dawn_native/Error.h"
#include <d3dcompiler.h>
class DynamicLib;
namespace dawn_native { namespace d3d12 {
// Loads the functions required from the platform dynamically so that we don't need to rely on
// them being present in the system. For example linking against d3d12.lib would prevent
// dawn_native from loading on Windows 7 system where d3d12.dll doesn't exist.
class PlatformFunctions {
public:
PlatformFunctions();
~PlatformFunctions();
MaybeError LoadFunctions();
// Functions from d3d12.dll
PFN_D3D12_CREATE_DEVICE d3d12CreateDevice = nullptr;
PFN_D3D12_GET_DEBUG_INTERFACE d3d12GetDebugInterface = nullptr;
PFN_D3D12_SERIALIZE_ROOT_SIGNATURE d3d12SerializeRootSignature = nullptr;
PFN_D3D12_CREATE_ROOT_SIGNATURE_DESERIALIZER d3d12CreateRootSignatureDeserializer = nullptr;
PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE d3d12SerializeVersionedRootSignature = nullptr;
PFN_D3D12_CREATE_VERSIONED_ROOT_SIGNATURE_DESERIALIZER
d3d12CreateVersionedRootSignatureDeserializer = nullptr;
// Functions from dxgi.dll
using PFN_DXGI_GET_DEBUG_INTERFACE1 = HRESULT(WINAPI*)(UINT Flags,
REFIID riid,
_COM_Outptr_ void** pDebug);
PFN_DXGI_GET_DEBUG_INTERFACE1 dxgiGetDebugInterface1 = nullptr;
using PFN_CREATE_DXGI_FACTORY2 = HRESULT(WINAPI*)(UINT Flags,
REFIID riid,
_COM_Outptr_ void** ppFactory);
PFN_CREATE_DXGI_FACTORY2 createDxgiFactory2 = nullptr;
// Functions from d3d3compiler.dll
pD3DCompile d3dCompile = nullptr;
private:
MaybeError LoadD3D12();
MaybeError LoadDXGI();
MaybeError LoadD3DCompiler();
DynamicLib mD3D12Lib;
DynamicLib mDXGILib;
DynamicLib mD3DCompilerLib;
};
}} // namespace dawn_native::d3d12
#endif // DAWNNATIVE_VULKAN_VULKANFUNCTIONS_H_

View File

@ -20,6 +20,7 @@
#include "dawn_native/d3d12/DeviceD3D12.h"
#include "dawn_native/d3d12/InputStateD3D12.h"
#include "dawn_native/d3d12/PipelineLayoutD3D12.h"
#include "dawn_native/d3d12/PlatformFunctions.h"
#include "dawn_native/d3d12/ShaderModuleD3D12.h"
#include "dawn_native/d3d12/TextureD3D12.h"
@ -101,9 +102,10 @@ namespace dawn_native { namespace d3d12 {
break;
}
if (FAILED(D3DCompile(hlslSource.c_str(), hlslSource.length(), nullptr, nullptr,
nullptr, entryPoint.c_str(), compileTarget, compileFlags, 0,
&compiledShader[stage], &errors))) {
const PlatformFunctions* functions = ToBackend(builder->GetDevice())->GetFunctions();
if (FAILED(functions->d3dCompile(hlslSource.c_str(), hlslSource.length(), nullptr,
nullptr, nullptr, entryPoint.c_str(), compileTarget,
compileFlags, 0, &compiledShader[stage], &errors))) {
printf("%s\n", reinterpret_cast<char*>(errors->GetBufferPointer()));
ASSERT(false);
}